Welcome    Usage    Browse    Find CID    Search     Log in

cM API Documentation

openme.c

Go to the documentation of this file.
00001 /*
00002 
00003  OpenME - Event-driven, plugin-based interactive interface to "open up" 
00004           any software (C/C++/Fortran/Java/PHP) and possibly connect it to cM
00005 
00006  cM - Collective Mind infrastructure to discover, collect,
00007       share and reuse knowledge
00008 
00009  Developer(s): (C) Grigori Fursin
00010  http://cTuning.org/lab/people/gfursin
00011 
00012  This library is free software; you can redistribute it and/or
00013  modify it under the terms of the GNU Lesser General Public
00014  License as published by the Free Software Foundation; either
00015  version 2.1 of the License, or (at your option) any later version.
00016 
00017  This library is distributed in the hope that it will be useful,
00018  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00020  Lesser General Public License for more details.
00021 
00022  You should have received a copy of the GNU Lesser General Public
00023  License along with this library; if not, write to the Free Software
00024  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00025 
00026 */
00027 
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 
00032 #include "openme.h"
00033 
00034 #ifdef WINDOWS
00035 #include <windows.h>
00036 static HINSTANCE dll=NULL; 
00037 #else
00038 #include <dlfcn.h>
00039 static void *dll;
00040 #endif
00041 
00042 /* set 'use' to 1 to process callbacks */
00043 static int openme_use=0;
00044 static int openme_initialized=0;
00045 
00046 static struct openme_hooks oh={NULL,NULL,NULL,NULL};
00047 static struct openme_info oi={NULL,NULL,""};
00048 
00049 static char bufx[1024];
00050 static char *bufy;
00051 static cJSON *json;
00052 static cJSON *json1;
00053 
00054 extern int openme_init (char *env_use, char *env_plugins, char *plugin_names, int force_use)
00055 {
00056   /*
00057      Initialize OpenME plugins
00058 
00059      Input: env_use -      if not NULL and not "", use this environment variable to check if openme is used or not
00060                            (i.e. if environment variable is set to 1, openme will be used).
00061                            This can be useful to transparently turn on or off usage of openme in tools or programs
00062                            (for example, transparent collective optimization)
00063             env_plugins  - if not NULL and not "", use this environment variable to describe/load plugins
00064                            (separated by ;)
00065             plugin_names - if not NULL and not "", use these plugins separated by ; (instead of checking in environment)
00066             force_use    - if 1, force usage of openme (skip checks for env_use and env_plugins)
00067                            if -1, just initialize malloc/free
00068                            0 - standard usage
00069 
00070      Output: 0 - if success
00071   */
00072 
00073   char *env=NULL;
00074   char *p;
00075   char *buf, *buf1, *buf2;
00076   int i=0;
00077 
00078   char xenv[1028];
00079 
00080   void (*func) (void*);
00081 
00082   if ( ((env = getenv(OPENME_DEBUG)) != NULL) && (atoi(env)==1) )
00083   {
00084     fflush(stdout); 
00085     printf ("Initializing OpenME\n");
00086   }
00087 
00088   /* Init malloc and free hooks to initialize memory in user space */
00089   if (oh.malloc==NULL)
00090   {
00091      oh.malloc=malloc;
00092      oh.free=free;
00093      oh.fopen=fopen;
00094      oh.fprintf=fprintf;
00095      oh.fseek=fseek;
00096      oh.ftell=ftell;
00097      oh.fread=fread;
00098      oh.fclose=fclose;
00099      oi.hooks=&oh;
00100   }
00101 
00102 // Various events from various plugins can coexist
00103 //  oi.event_list=NULL;
00104 
00105   openme_initialized=1;
00106 
00107   /* Check which env variable to use */
00108   strcpy(xenv, OPENME_USE);
00109   if ((env_use!=NULL) && (strlen(env_use)>0)) strcpy(xenv, env_use);
00110 
00111   if (force_use!=-1)
00112   {
00113     if ((force_use==1) || ((env = getenv(xenv)) != NULL))
00114     {
00115       if ((force_use==1) || (atoi(env)==1))
00116       {
00117         /* Check which env variable to use */
00118         strcpy(xenv, OPENME_PLUGINS);
00119         if ((env_plugins!=NULL) && (strlen(env_plugins)>0)) strcpy(xenv, env_plugins);
00120 
00121         if ((plugin_names!=NULL) && (strlen(plugin_names)>0))
00122           env=plugin_names;
00123         else if ((env=getenv(xenv))==NULL)
00124           return 1;
00125 
00126         buf=malloc(sizeof(char)*(strlen(env)+1));
00127         buf1=env;
00128 
00129         while (*buf1!=0)
00130         {
00131           buf2=buf;
00132           while ((*buf1!=0) && (*buf1!=';'))
00133             *buf2++=*buf1++;
00134           *buf2=0;
00135           if (*buf1!=0) buf1++;
00136 
00137   #ifdef WINDOWS
00138           dll = LoadLibrary(TEXT(buf));
00139           if (dll == NULL)
00140               printf("Error: Failed to load plugin (error=%u)!\n", GetLastError());
00141   #else
00142           dll=dlopen(env, RTLD_LAZY);
00143           if (dll == NULL)
00144               printf("Error: Failed to load plugin (%s)!\n", dlerror());
00145   #endif
00146           if (dll == NULL)
00147           {
00148               free(buf);
00149               return 1;
00150           }
00151 
00152   #ifdef WINDOWS
00153           func = (void (__cdecl *)(void *)) GetProcAddress(dll, OPENME_PLUGIN_INIT_FUNC);
00154   #else
00155           func = dlsym (dll, OPENME_PLUGIN_INIT_FUNC);
00156   #endif
00157           if (func == NULL)
00158           {
00159               printf("Error: Can't find openme_plugin_init function in the plugin!\n");
00160               free(buf);
00161               return 1;
00162           }
00163 
00164           (*func) (&oi);
00165 
00166           openme_use=1;
00167         }
00168 
00169   //      free(buf);
00170       }
00171     }
00172   }
00173 
00174   return 0;
00175 }
00176 
00177 extern void openme_init_hooks(struct openme_hooks *hooks)
00178 {
00179  /* Set local malloc and free to user program's malloc and free
00180     to be able to allocate memory in plugins */
00181 
00182   oh.malloc=hooks->malloc;
00183   oh.free=hooks->free;
00184   oh.fopen=hooks->fopen;
00185   oh.fprintf=hooks->fprintf;
00186   oh.fseek=hooks->fseek;
00187   oh.ftell=hooks->ftell;
00188   oh.fread=hooks->fread;
00189   oh.fclose=hooks->fclose;
00190   oi.hooks=&oh;
00191 }
00192 
00193 extern void openme_callback (char *event_name, void *params)
00194 {
00195   /* 
00196      Initiate callback
00197 
00198      Input: event_name   - name of the event. For now it's just a string and the search is not optimized.
00199                            We should add cM UIDs here too since events can be possibly shared across many plugins.
00200             params       - parameters passed to an event. If there are multiple parameters, 
00201                            we use either struct or cJSON similar to cM universal call
00202 
00203      Output: None - if we need to return some info from the event, we update variable "params".
00204                     For example, to update unroll factor in LLVM, Open64 ot GCC, we use a struct
00205                     with unroll factor
00206   */
00207 
00208   char *env=NULL;
00209   struct openme_event *es;
00210 
00211   if (openme_initialized==0)
00212   {
00213     fflush(stdout); 
00214     printf ("openme error: callback is used before init!\n");
00215     fflush(stdout); 
00216     exit(1);
00217   }
00218 
00219   if (openme_use==1)
00220   {
00221     if ( ((env = getenv(OPENME_DEBUG)) != NULL) && (atoi(env)==1) )
00222     {
00223       fflush(stdout);
00224       printf ("Searching event=%s\n", event_name);
00225     }
00226     es=oi.event_list;
00227     while (es!=NULL)
00228     {
00229       if (strcmp(es->name, event_name)==0)
00230       {
00231         (*(es->func)) (params);
00232         /* Don't stop here to allow the same events 
00233            called from other plugins - may be useful */
00234       }
00235       es=es->next;
00236     }
00237   }
00238 }
00239 
00240 extern void openme_register_callback (struct openme_info *info, char *event_name, void *func)
00241 {
00242   /*
00243      Register callback
00244 
00245      Input: info         - plugin initalization variable - passed to plugin init function
00246             event_name   - name of the event. For now it's just a string and the search is not optimized.
00247                            We should add cM UIDs here too since events can be possibly shared across many plugins.
00248             func         - address of the event function.
00249 
00250      Output: None
00251   */
00252 
00253   char *env=NULL;
00254   struct openme_event *e, *es;
00255   char *en;
00256 
00257 //  FGG removed it since we now have customized initializer ...
00258 //  if (openme_use==0 && openme_initialized==0)
00259 //     openme_init("");
00260   if ( ((env = getenv(OPENME_DEBUG)) != NULL) && (atoi(env)==1) )
00261   {
00262     fflush(stdout); 
00263     printf("Register callback %s\n", event_name);
00264   }
00265 
00266   if ((info==NULL) || (info->hooks==NULL))
00267   {
00268      printf("Error: attempt to use OpenME plugin before init\n");
00269      exit(1);
00270   }
00271 
00272   en=(char *) info->hooks->malloc(sizeof(char)*(strlen(event_name)+1));
00273   strcpy(en, event_name);
00274 
00275   e=(struct openme_event *) info->hooks->malloc(sizeof(struct openme_event));
00276   e->name=en;
00277   e->func=func;
00278   e->next=NULL;
00279 
00280   if (info->event_list==NULL)
00281     info->event_list=e;
00282   else
00283   {
00284     es=info->event_list;
00285     while ((es->next)!=NULL)
00286       es=es->next;
00287 
00288     es->next=e;
00289   }
00290 }
00291 
00292 /* Some functions to unify access to json structures so that we can use it in any language
00293    such as C, C++, Fortran, Java, etc; not completed */
00294 
00295 extern cJSON *openme_create_obj (char *str)
00296 {
00297   /*
00298      Create object {"a":"b"}
00299 
00300      Input: str   - string of format "a=b c=d ... (@file.json)"
00301                     if @ is in the string, load and parse json file after @
00302 
00303      Output: Pointer to created object
00304   */
00305 
00306   char str1[1024];
00307   char str2[1024];
00308   int i=0;
00309   int j=0;
00310   int il;
00311   int k, kl;
00312 
00313   cJSON *obj, *obj1, *obj2;
00314 
00315   obj=cJSON_CreateObject();
00316 
00317   il=strlen(str);
00318   while (i<il)
00319   {
00320     if (str[i]=='@')
00321     {
00322       /* Process file */
00323       i++;
00324 
00325       while (str[i]!=' ' && i<il)
00326         str1[j++]=str[i++];
00327       str1[j]=0;
00328 
00329       obj1=openme_load_json_file(str1);
00330       if (obj1==NULL)
00331          return NULL;
00332 
00333       kl=cJSON_GetArraySize(obj1);
00334       for (k=0; k<kl; k++)
00335       {
00336         if (cJSON_GetObjectItem(obj, cJSON_GetArrayItemName(obj1,k))!=NULL)
00337           cJSON_DeleteItemFromObject(obj, cJSON_GetArrayItemName(obj1,k));
00338         cJSON_AddItemReferenceToObject(obj, cJSON_GetArrayItemName(obj1,k), cJSON_GetArrayItem(obj1,k));
00339       }
00340     }
00341     else
00342     {
00343       j=0;
00344       while (str[i]!='=' && i<il)
00345         str1[j++]=str[i++];
00346       str1[j]=0;
00347 
00348       i++;
00349       if (i>=il) break;
00350 
00351       j=0;
00352       while (str[i]!=' ' && i<il)
00353         str2[j++]=str[i++];
00354       str2[j]=0;
00355       i++;
00356 
00357       cJSON_AddStringToObject(obj, str1, str2);
00358     }
00359   }
00360 
00361   return obj;
00362 }
00363 
00364 extern cJSON *openme_get_obj(cJSON *json, char *str)
00365 {
00366   /*
00367      Get pointer to object by name
00368 
00369      Input: json - current sub-object
00370             str  - parameter name
00371 
00372      Output: Pointer to found object or NULL
00373   */
00374 
00375    return cJSON_GetObjectItem(json, str);
00376 }
00377 
00378 extern void openme_print_obj (cJSON *obj)
00379 {
00380   /*
00381      Print cJSON object
00382 
00383      Input: json - object to print
00384 
00385      Output: None
00386   */
00387 
00388   printf("%s\n", cJSON_Print(obj));
00389 }
00390 
00391 extern cJSON *openme_load_json_file(char *file_name)
00392 {
00393   /*
00394      Load json file and create cJSON object
00395 
00396      Input: file_name - name of the file to load
00397 
00398      Output: cJSON object or NULL
00399   */
00400 
00401   cJSON *obj;
00402   FILE *fp;
00403   long len;
00404   char *data;
00405 
00406   fp = oh.fopen(file_name, "r");
00407   if(!fp)
00408   {
00409     openme_set_error("OpenME error: can't find json file %s\n", file_name);
00410     return NULL;
00411   }
00412 
00413   oh.fseek(fp,0,SEEK_END);
00414   len=oh.ftell(fp);
00415   oh.fseek(fp,0,SEEK_SET);
00416   data=oh.malloc(len+1);
00417   oh.fread(data,1,len,fp);
00418   oh.fclose(fp);
00419 
00420   obj=cJSON_Parse(data);
00421   oh.free(data);
00422 
00423   return obj;
00424 }
00425 
00426 extern int openme_store_json_file(cJSON *json, char *file_name)
00427 {
00428   /*
00429      Store json object in file
00430 
00431      Input:  json      - cJSON object
00432              file_name - name of the file to store json object
00433 
00434      Output: int r = 0 - if correct; >0 if error
00435   */
00436 
00437   FILE *fp = oh.fopen(file_name, "w");
00438   if(!fp)
00439   {
00440     openme_set_error("OpenME error: can't open json file %s for writing ...\n", file_name);
00441     return 1;
00442   }
00443   printf("%s\n", cJSON_Print(json));
00444   if (oh.fprintf(fp, "%s\n", cJSON_Print(json))<0)
00445   {
00446     openme_set_error("OpenME error: problems writing to json file %s ...\n", file_name);
00447     return 1;
00448   }
00449   oh.fclose(fp);
00450 
00451   return 0;
00452 }
00453 
00454 extern void openme_set_error(char *format, char *text)
00455 {
00456   /*
00457      Set OpenME error
00458 
00459      Input:  format - printf format
00460              text   - error text
00461 
00462      Output: None
00463   */
00464 
00465   sprintf(oi.error, format, text);
00466 }
00467 
00468 extern void openme_print_error(void)
00469 {
00470   /*
00471      Print OpenME error
00472 
00473      Input:  None
00474 
00475      Output: None
00476   */
00477 
00478   printf(oi.error);
00479 }
00480 
00481 extern cJSON *cm_action (cJSON *inp)
00482 {
00483   /*
00484      FGG: TBD - call local cM
00485 
00486      Input:  inp - json object
00487 
00488      Output: json object from cM or NULL if error (openme error is set)
00489   */
00490   char *fn;
00491   int r=0;
00492 
00493   char fn1[128];
00494   char fn2[128];
00495   char fn3[128];
00496 
00497   /* Get module name */
00498   json=openme_get_obj(inp, "cm_run_module_uoa");
00499   if (json==NULL)
00500   {
00501     openme_set_error("OpenME error - can't find cm_run_module_uoa in cm_action ...", NULL);
00502     return NULL;
00503   }
00504   bufy=json->valuestring;
00505 
00506   /* Generate tmp files with json and for output*/
00507   /* First file will be deleted automatically by cM */
00508   fn=tmpnam(NULL);
00509   sprintf(fn1, "%s-cm.tmp", fn);
00510 
00511   fn=tmpnam(NULL);
00512   sprintf(fn2, "%s-cm.tmp", fn);
00513 
00514   fn=tmpnam(NULL);
00515   sprintf(fn3, "%s-cm.tmp", fn);
00516 
00517   /* Record input file */
00518   r=openme_store_json_file(inp, fn1);
00519   if (r>0)
00520   {
00521     openme_set_error("OpenME error - can't save tmp file ...", NULL);
00522     return NULL;
00523   }
00524 
00525   /* Prepare command line */
00526   sprintf(bufx, "cm %s @%s > %s 2> %s", bufy, fn1, fn2, fn3);
00527 
00528   system(bufx);
00529 
00530   /* Try to read stdout */
00531   json=openme_load_json_file(fn2);
00532   if (json==NULL)
00533   {
00534     /* FGG TODO: We should add reading of stdout and stderr and put it here in case of error */
00535     sprintf(bufx, "STDOUT file=%s; STDERR file=%s", fn2);
00536     sprintf(bufx, "STDOUT file=%s; STDERR file=%s", fn3);
00537 
00538     openme_set_error("OpenME error - can't parse cM output; see files: %s...", bufx);
00539 
00540     return NULL;
00541   }
00542 
00543   /* Remove tmp files */
00544   remove(fn2);
00545   remove(fn3);
00546 
00547   return json;
00548 }
00549 
00550 /* Fortran interface for OpenME */
00551 
00552 extern int openme_init_f_ (char *env_use, char *env_plugins, char *plugin_names, int force_use) 
00553   {return openme_init(env_use, env_plugins, plugin_names, force_use);}
00554 extern int OPENME_INIT_F (char *env_use, char *env_plugins, char *plugin_names, int force_use) 
00555   {return openme_init(env_use, env_plugins, plugin_names, force_use);}
00556 
00557 extern void openme_callback_f_ (char *event_name, void *params) {openme_callback(event_name, params);}
00558 extern void OPENME_CALLBACK_F (char *event_name, void *params) {openme_callback(event_name, params);}
00559 
00560 extern cJSON *openme_create_obj_f_ (char *str) {return openme_create_obj(str);}
00561 extern cJSON *OPENME_CREATE_OBJ_F (char *str) {return openme_create_obj(str);}
00562 
00563 extern void openme_print_obj_f_ (cJSON **obj) {openme_print_obj(*obj);}
00564 extern void OPENME_PRINT_OBJ_F (cJSON **obj) {openme_print_obj(*obj);}
00565 
00566 extern cJSON *cm_action_f_ (cJSON **obj) {cm_action(*obj);}
00567 extern cJSON *CM_ACTION_F (cJSON **obj) {cm_action(*obj);}

Generated on Wed May 28 02:49:01 2014 for Collective Mind Framework by DoxyGen 1.6.1
Concept, design and coordination: Grigori Fursin (C) 1993-2013