Actual source code: fwk.c

  1: #define PETSC_DLL

 3:  #include petscsys.h
 4:  #include petscfwk.h

  6: PetscCookie PETSC_FWK_COOKIE;
  7: static char PETSC_FWK_CLASS_NAME[] = "PetscFwk";

  9: static PetscTruth PetscFwkPackageInitialized = PETSC_FALSE;


 12: /* 
 13:    Graph/topological sort stuff from BOOST.
 14:    May need to be replaced with a custom, all-C implementation
 15: */
 16: // >> C++
 17: #include <iostream>
 18: #include <map>
 19: #include <vector>
 20: #include <list>

 22: #include <boost/graph/graph_traits.hpp>
 23: #include <boost/graph/adjacency_list.hpp>
 24: #include <boost/graph/topological_sort.hpp>


 27: struct vertex_id {
 28:   PetscInt id;
 29: };
 30: //
 31: // We use bundled properties to store id with the vertex.
 32: typedef ::boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS, vertex_id>             dependence_graph_type;
 33: typedef boost::graph_traits<dependence_graph_type>::vertex_descriptor                                   vertex_type;
 34: //
 35: struct dependence_graph_cycle_detector_type : public boost::default_dfs_visitor {
 36:   void back_edge(boost::graph_traits<dependence_graph_type>::edge_descriptor e, const dependence_graph_type& g) {
 37:     std::basic_ostringstream<char> ss;
 38:     ss << "Edge creates dependence loop: [" << (g[::boost::source(e,g)].id) << " --> " << (g[::boost::target(e,g)].id) << "]; ";
 39:     throw ss.str();
 40:   }//back_edge()
 41: };// dependence_graph_cycle_detector_type
 42: // << C++

 44: struct _p_PetscFwk {
 45:   PETSCHEADER(int);
 46:   // >> C++
 47:   // Since PetscFwk is allocated using the C-style PetscMalloc, the C++-object data members have to be 'newed', hance must be pointers
 48:   std::map<std::string, PetscInt>         *id;
 49:   std::vector<std::string>                *url;
 50:   std::vector<PetscFwkComponentConfigure> *configure;
 51:   std::vector<PetscObject>                *component;
 52:   std::vector<vertex_type>                *vertex;
 53:   dependence_graph_type                   *dependence_graph;
 54:   // << C++
 55: };

 57: // >> C++
 58: #undef  __FUNCT__
 60: PetscErrorCode PetscFwkConfigure_Sort(PetscFwk fwk, std::list<vertex_type>& antitopological_vertex_order){
 62:   // >> C++
 63:   /* Run a cycle detector on the dependence graph */
 64:   try {
 65:     dependence_graph_cycle_detector_type cycle_detector;
 66:     ::boost::depth_first_search(*(fwk->dependence_graph), boost::visitor(cycle_detector));
 67:   }
 68:   catch(const std::string& s) {
 69:     SETERRQ1(PETSC_ERR_ARG_WRONGSTATE, "Component dependence graph has a loop: %s", s.c_str());
 70:   }
 71:   catch(...) {
 72:     SETERRQ(PETSC_ERR_ARG_WRONGSTATE, "Exception caught while detecting loops in the dependence graph");
 73:   }
 74:   /* 
 75:      Run topological sort on the dependence graph; remember that the vertices are returned in the "antitopological" order.
 76:      This, in fact, is just what we need, since edges in the graph are entered as (client, server), implying that server 
 77:      must be configured *before* the client and BOOSTs topological sort will in fact order server before client.
 78:    */
 79:   try{
 80:     ::boost::topological_sort(*(fwk->dependence_graph), std::back_inserter(antitopological_vertex_order));
 81:   }
 82:   catch(...) {
 83:     SETERRQ(PETSC_ERR_ARG_WRONGSTATE, "Exception caught while performing topological_sort in the dependence graph");
 84:   }

 86:   return(0);
 87: }/* PetscFwkConfigure_Sort() */
 88: // << C++

 90: #undef  __FUNCT__
 92: PetscErrorCode PetscFwkViewConfigurationOrder(PetscFwk fwk, PetscViewer viewerASCII){
 95:   // >> C++
 96:   std::list<vertex_type> antitopological_vertex_order;
 97:   PetscFwkConfigure_Sort(fwk, antitopological_vertex_order);
 98:   /* traverse the vertices in their antitopological, extract component ids from vertices and  configure each corresponding component */
 99:   /* current_state starts with 1, since 0 was used during Preconfigure */
100:   for(std::list<vertex_type>::iterator iter = antitopological_vertex_order.begin(); iter != antitopological_vertex_order.end(); ++iter) {
101:     PetscInt id = (*(fwk->dependence_graph))[*iter].id;
102:     std::string urlstring = (*fwk->url)[id];
103:     if(iter != antitopological_vertex_order.begin()) {
104:       PetscViewerASCIIPrintf(viewerASCII, ", ");
105:     }
106:     PetscViewerASCIIPrintf(viewerASCII, "%d: %s", id, urlstring.c_str());
107:   }
108:   // << C++
109:   PetscViewerASCIIPrintf(viewerASCII, "\n");
110:   return(0);
111: }/* PetscFwkViewConfigurationOrder() */

113: #undef  __FUNCT__
115: PetscErrorCode PetscFwkConfigure(PetscFwk fwk, PetscInt state){
118:   // >> C++
119:   std::list<vertex_type> antitopological_vertex_order;
120:   PetscFwkConfigure_Sort(fwk, antitopological_vertex_order);
121:   /* traverse the vertices in their antitopological, extract component ids from vertices and  configure each corresponding component */
122:   for(PetscInt current_state=0;current_state<=state; ++current_state) {
123:     PetscObjectSetState((PetscObject)fwk,current_state);
124:     for(std::list<vertex_type>::iterator iter = antitopological_vertex_order.begin(); iter != antitopological_vertex_order.end(); ++iter) {
125:       PetscInt id = (*(fwk->dependence_graph))[*iter].id;
126:       PetscObject component = (*fwk->component)[id];
127:       PetscFwkComponentConfigure configure = (*fwk->configure)[id];
128:       if(configure != PETSC_NULL) {
129:         (*configure)(fwk,current_state,&component);
130:       }
131:     }
132:   }
133:   // << C++
134:   return(0);
135: }/* PetscFwkConfigure() */



139: static PetscDLLibrary PetscFwkDLList = PETSC_NULL;
140: #define PETSC_FWK_MAX_URL_LENGTH 1024

142: #undef  __FUNCT__
144: PetscErrorCode  PetscFwkNormalizeURL_Private(PetscFwk fwk, const char url[], char nurl[], char npath[], char nname[]){
145:   char *n, *s;
146:   char lpath[PETSC_FWK_MAX_URL_LENGTH+1], lname[PETSC_FWK_MAX_URL_LENGTH+1];
147:   char *path, *name;
148:   static PetscInt nlen = PETSC_FWK_MAX_URL_LENGTH;
151:   /* FIX: this should replace the filesystem path by an abolute path for real normalization */
152:   /* Use local buffers if npath or nname is NULL */
153:   if(npath == PETSC_NULL) {
154:     path = lpath;
155:   }
156:   else {
157:     path = npath;
158:   }
159:   if(nname == PETSC_NULL) {
160:     name = lname;
161:   }
162:   else {
163:     name = nname;
164:   }
165:   /* Copy the url so we can manipulate it inplace and also truncate to the max allowable length */
166:   PetscStrncpy(path, url, nlen);
167:   /* Split url <path>:<name> into <path> and <name> */
168:   PetscStrrchr(path,':',&n);
169:   /* Make sure it's not the ":/" of the "://" separator */
170:   if(!n[0] || n[0] == '/') {
171:     SETERRQ2(PETSC_ERR_ARG_WRONG,
172:              "Could not locate component name within the URL.\n"
173:              "Must have url = [<path>:]<name>, instead got %s\n"
174:              "Remember: URL was truncated past the max allowed length of %d",
175:              path, nlen);
176:   }
177:   /* Copy n to name */
178:   PetscStrcpy(name, n);
179:   /* If n isn't the whole path (i.e., there is no ':' separator), end 'path' right before the located ':' */
180:   if(n != path) {
181:     n[-1] = '\0';
182:   }
183:   /* Find and remove the library suffix */
184:   PetscStrrchr(path,'.',&s);
185:   /* Make sure this isn't part of a relative path name (i.e.., "./" or "../") */
186:   /* FIX: we should really be using PETSc's internally defined suffices, because otherwise, 
187:      we might be removing names of hidden files (e.g., '${PETSC_DIR}/lib/${PETSC_ARCH}/.myhiddenlib.a') */
188:   if(s[0] != '/') {
189:     s[-1] = '\0';
190:   }
191:   PetscStrcpy(nurl, path);
192:   PetscStrcat(nurl, ":");
193:   PetscStrcat(nurl, name);
194:   return(0);
195: }/* PetscFwkNormalizeURL_Private() */

197: #undef  __FUNCT__
199: PetscErrorCode  PetscFwkInsertComponent_Private(PetscFwk fwk, const char url[], PetscObject component, PetscFwkComponentConfigure configure, PetscInt *_id){
200:   /* 
201:      WARNING: This routine will not check whether url has already been registered.  
202:      It will assign a new id to the url and insert the corresponding component and configure objects. 
203:   */
204:   PetscObject old_component;
205:   PetscInt id;
208:   // >> C++
209:   std::string urlstring(url);
210:   // Check whether url has already been registered
211:   if((*(fwk->id)).count(urlstring)) {
212:     // Retrieve the existing id
213:     id = (*(fwk->id))[urlstring];
214:     // Reset the existing component and configure objects
215:     old_component = (*(fwk->component))[id];
216:     if(old_component) {
217:       PetscObjectDereference(old_component);
218:     }
219:     if(component) {
220:       PetscObjectReference(component);
221:     }
222:     (*(fwk->component))[id] = component;
223:     (*(fwk->configure))[id] = configure;
224:   }
225:   else {
226:     // Assign and store the new id for urlstring.
227:     id = (*(fwk->id)).size();
228:     (*(fwk->id))[urlstring] = id;
229:     (*(fwk->url)).push_back(urlstring);
230:     /* Push new component and configure objects onto the list */
231:     if(component) {
232:       PetscObjectReference(component);
233:     }
234:     (*(fwk->component)).push_back(component);
235:     (*(fwk->configure)).push_back(configure);
236:     /* Add a new vertex to the dependence graph.  This vertex will correspond to the newly registered component. */
237:     vertex_type v = ::boost::add_vertex(*(fwk->dependence_graph));
238:     /* Attach id to v */
239:     (*(fwk->dependence_graph))[v].id = id;
240:     /* Store v in fwk */
241:     (*(fwk->vertex)).push_back(v);
242:   }
243:   // << C++
244:   if(_id) {
245:     *_id = id;
246:   }
247:   return(0);
248: }/* PetscFwkInsertComponent_Private()*/


251: #undef  __FUNCT__
253: PetscErrorCode  PetscFwkRegisterComponentWithID(PetscFwk fwk, const char url[], PetscInt *_id){
254:   PetscFwkComponentConfigure configure = PETSC_NULL;
255:   PetscObject component = PETSC_NULL;
256:   char nurl[PETSC_FWK_MAX_URL_LENGTH+1], path[PETSC_FWK_MAX_URL_LENGTH+1], name[PETSC_FWK_MAX_URL_LENGTH+1];
257:   char sym[PETSC_FWK_MAX_URL_LENGTH+26+1];
258:   //PetscInt id;
259:   MPI_Comm comm;
262:   PetscFwkNormalizeURL_Private(fwk, url, nurl, path, name);
263:   // >> C++
264:   // Check whether a component with the given url has already been registered.  If so, return its id, if it has been requested.
265:   std::string urlstring(nurl);
266:   if((*(fwk->id)).count(urlstring)) {
267:     if(_id) {
268:       *_id = (*(fwk->id))[urlstring];
269:     }
270:     return(0);
271:   }
272:   // Insert a new url with empty corresponding component and configure objects
273:   PetscFwkInsertComponent_Private(fwk, nurl, PETSC_NULL, PETSC_NULL, PETSC_NULL);
274:   /* Build the configure symbol from name and standard prefix */
275:   PetscStrcpy(sym, "PetscFwkComponentConfigure");
276:   PetscStrcat(sym, name);
277:   /* Load the library designated by 'path' and retrieve from it the configure routine designated by the constructed symbol */
278:   PetscObjectGetComm((PetscObject)fwk, &comm);
279:   PetscDLLibrarySym(comm, &PetscFwkDLList, path, sym, (void**)(&configure));
280:   /* Run the configure routine, which should return a valid component object */
281:   (*configure)(fwk, 0, &component);
282:   if(component == PETSC_NULL) {
283:     SETERRQ2(PETSC_ERR_LIB, "Configure routine %s from library %s returned a NULL component", path, sym);
284:   }
285:   /* Reinsert nurl with the correct component and configure objects, and retrieve its id. */
286:   PetscFwkInsertComponent_Private(fwk, nurl, component, configure, _id);
287:   return(0);
288: }/* PetscFwkRegisterComponentWithID()*/

290: #undef  __FUNCT__
292: PetscErrorCode  PetscFwkRegisterComponent(PetscFwk fwk, const char url[]){
295:   PetscFwkRegisterComponentWithID(fwk, url, PETSC_NULL);
296:   return(0);
297: }/* PetscFwkRegisterComponent()*/


300: #undef  __FUNCT__
302: PetscErrorCode  PetscFwkRegisterDependence(PetscFwk fwk, const char clienturl[], const char serverurl[])
303: {
304:   PetscInt clientid, serverid;
309:   /* Register urls */
310:   PetscFwkRegisterComponentWithID(fwk, clienturl, &clientid);
311:   PetscFwkRegisterComponentWithID(fwk, serverurl, &serverid);

313:   /*
314:     Add the dependency edge to the dependence_graph as follows (clienturl, serverurl): 
315:      this means "client depends on server", so server should be configured first.
316:     For this reason we need to order components using an "antitopological" sort of the dependence_graph.
317:     BOOST Graph Library does just that, but keep that in mind if reimplementing the graph/sort in C.
318:   */
319:   vertex_type c,s;
320:   c = (*(fwk->vertex))[clientid];
321:   s = (*(fwk->vertex))[serverid];
322:   ::boost::add_edge(c,s, *(fwk->dependence_graph));
323:   return(0);
324: }/* PetscFwkRegisterDependence()*/



328: #undef  __FUNCT__
330: PetscErrorCode  PetscFwkDestroy(PetscFwk fwk)
331: {
333:   // >> C++
334:   delete fwk->id;
335:   delete fwk->url;
336:   delete fwk->configure;
337:   delete fwk->component;
338:   delete fwk->vertex;
339:   delete fwk->dependence_graph;
340:   // << C++
341:   PetscHeaderDestroy(fwk);
342:   fwk = PETSC_NULL;
343:   return(0);
344: }/* PetscFwkDestroy()*/

346: #undef  __FUNCT__
348: PetscErrorCode  PetscFwkCreate(MPI_Comm comm, PetscFwk *framework){
349:   PetscFwk fwk;
352:   /*#if !defined(PETSC_USE_DYNAMIC_LIBRARIES)*/
353:   PetscFwkInitializePackage(PETSC_NULL);
354:   /*#endif*/
356:   PetscHeaderCreate(fwk,_p_PetscFwk,PetscInt,PETSC_FWK_COOKIE,0,"PetscFwk",comm,PetscFwkDestroy,0);
357:   // >> C++
358:   fwk->id               = new std::map<std::string, PetscInt>;
359:   fwk->url              = new std::vector<std::string>;
360:   fwk->configure        = new std::vector<PetscFwkComponentConfigure>;
361:   fwk->component        = new std::vector<PetscObject>;
362:   fwk->vertex           = new std::vector<vertex_type>;
363:   fwk->dependence_graph = new dependence_graph_type;
364:   // << C++
365:   *framework = fwk;
366:   return(0);
367: }/* PetscFwkCreate() */

369: #undef  __FUNCT__
371: PetscErrorCode  PetscFwkGetComponentByID(PetscFwk fwk, PetscInt id, PetscObject *component) {
373:   // >> C++
374:   try{
375:     *component = (*fwk->component)[id];
376:   }
377:   catch(...){
378:     SETERRQ1(PETSC_ERR_ARG_WRONG, "Couldn't retrieve PetscFwk component with id %d", id);
379:   }
380:   // << C++
381:   return(0);
382: }/* PetscFwkGetComponentByID() */

384: #undef  __FUNCT__
386: PetscErrorCode  PetscFwkGetComponent(PetscFwk fwk, const char url[], PetscObject *component) {
389:   // >> C++
390:   try{
391:     *component = (*fwk->component)[(*fwk->id)[url]];
392:   }
393:   catch(...){
394:     SETERRQ1(PETSC_ERR_ARG_WRONG, "Couldn't retrieve PetscFwk component with url %s", url);
395:   }
396:   // << C++
397:   return(0);
398: }/* PetscFwkGetComponent() */

400: #undef  __FUNCT__
402: PetscErrorCode PetscFwkFinalizePackage(void){
405:   PetscFwkPackageInitialized = PETSC_FALSE;
406:   if(PetscFwkDLList != PETSC_NULL) {
407:     PetscDLLibraryClose(PetscFwkDLList);
408:     PetscFwkDLList = PETSC_NULL;
409:   }
410:   return(0);
411: }/* PetscFwkFinalizePackage() */



415: #undef  __FUNCT__
417: PetscErrorCode PetscFwkInitializePackage(const char path[]){
420:   if(PetscFwkPackageInitialized) {
421:     PetscFwkPackageInitialized = PETSC_TRUE;
422:   }
423:   /* Regster classes */
424:   PetscCookieRegister(PETSC_FWK_CLASS_NAME, &PETSC_FWK_COOKIE);
425:   PetscRegisterFinalize(PetscFwkFinalizePackage);
426:   return(0);
427: }/* PetscFwkInitializePackage() */