core/exec.c

Go to the documentation of this file.
00001 
00041 #include <signal.h>
00042 #include <ctype.h>
00043 #include <string.h>
00044 #ifdef WIN32
00045 #include <direct.h>
00046 #else
00047 #include <unistd.h>
00048 #endif
00049 #include "output.h"
00050 #include "exec.h"
00051 #include "class.h"
00052 #include "convert.h"
00053 #include "object.h"
00054 #include "index.h"
00055 #include "realtime.h"
00056 #include "module.h"
00057 #include "threadpool.h"
00058 #include "debug.h"
00059 #include "exception.h"
00060 #include "random.h" 
00061 #include "local.h"
00062 
00067 int exec_init()
00068 {
00069 #if 0
00070 #ifdef WIN32
00071     char glpathvar[1024];
00072 #endif
00073 #endif
00074 
00075     size_t glpathlen=0;
00076     /* setup clocks */
00077     global_starttime = realtime_now();
00078     timestamp_set_tz(NULL);
00079 
00080     /* setup the random number generator */
00081     random_init();
00082 
00083     /* determine current working directory */
00084     getcwd(global_workdir,1024);
00085 
00086     /* save locale for simulation */
00087     locale_push();
00088 
00089 #if 0 /* isn't cooperating for strange reasons -mh */
00090 #ifdef WIN32
00091     glpathlen=strlen("GLPATH=");
00092     sprintf(glpathvar, "GLPATH=");
00093     ExpandEnvironmentStrings(getenv("GLPATH"), glpathvar+glpathlen, (DWORD)(1024-glpathlen));
00094 #endif
00095 #endif
00096 
00097     if (global_init()==FAILED)
00098         return 0;
00099 
00100     return 1;
00101 }
00102 
00103 #ifndef _MAX_PATH
00104 #include <linux/limits.h>
00105 #define _MAX_PATH PATH_MAX
00106 #endif
00107 
00108 #define PASSINIT(p) (p % 2 ? ranks[p]->first_used : ranks[p]->last_used)
00109 #define PASSCMP(i, p) (p % 2 ? i <= ranks[p]->last_used : i >= ranks[p]->first_used)
00110 #define PASSINC(p) (p % 2 ? 1 : -1)
00111 
00112 static struct thread_data *thread_data = NULL;
00113 static INDEX **ranks = NULL;
00114 const PASSCONFIG passtype[] = {PC_PRETOPDOWN, PC_BOTTOMUP, PC_POSTTOPDOWN};
00115 static unsigned int pass;
00116 int iteration_counter = 0;   /* number of redos completed */
00117 
00118 #ifndef NOLOCKS
00119 int64 lock_count = 0, lock_spin = 0;
00120 #endif
00121 
00122 extern int stop_now;
00123 
00124 static STATUS setup_ranks(void)
00125 {
00126     OBJECT *obj;
00127     int i;
00128     static INDEX *passlist[] = {NULL,NULL,NULL,NULL}; /* extra NULL marks the end of the list */
00129 
00130     /* create index object */
00131     ranks = passlist;
00132     ranks[0] = index_create(0,10);
00133     ranks[1] = index_create(0,10);
00134     ranks[2] = index_create(0,10);
00135 
00136     /* build the ranks of each pass type */
00137     for (i=0; i<sizeof(passtype)/sizeof(passtype[0]); i++)
00138     {
00139         if (ranks[i]==NULL)
00140             return FAILED;
00141 
00142         /* add every object to index based on rank */
00143         for (obj=object_get_first(); obj!=NULL; obj=object_get_next(obj))
00144         {
00145             /* ignore objects that don't use this passconfig */
00146             if ((obj->oclass->passconfig&passtype[i])==0)
00147                 continue;
00148 
00149             /* add this object to the ranks for this passconfig */
00150             if (index_insert(ranks[i],obj,obj->rank)==FAILED)
00151                 return FAILED;
00152         }
00153 #ifndef NOLOCKS
00154         /* shuffle the objects in the index */
00155         index_shuffle(ranks[i]);
00156 #endif
00157     }
00158 
00159     return SUCCESS;
00160 }
00161 
00162 char *simtime(void)
00163 {
00164     static char buffer[64];
00165     return convert_from_timestamp(global_clock,buffer,sizeof(buffer))>0?buffer:"(invalid)";
00166 }
00167 
00168 static STATUS show_progress(void)
00169 {
00170     output_progress();
00171     /* reschedule report */
00172     realtime_schedule_event(realtime_now()+1,show_progress);
00173     return SUCCESS;
00174 }
00175 
00176 static void do_object_sync(int thread, void *item)
00177 {
00178     struct sync_data *data = &thread_data->data[thread];
00179     OBJECT *obj = (OBJECT *) item;
00180     TIMESTAMP this_t;
00181 
00182     /* check in and out-of-service dates */
00183     if (global_clock<obj->in_svc)
00184         this_t = obj->in_svc; /* yet to go in service */
00185     else if (global_clock<=obj->out_svc)
00186         this_t = object_sync(obj, global_clock, passtype[pass]);
00187     else 
00188         this_t = TS_NEVER; /* already out of service */
00189 
00190     /* check for "soft" event (events that are ignored when stopping) */
00191     if (this_t < -1)
00192         this_t = -this_t;
00193     else if (this_t != TS_NEVER)
00194         data->hard_event++;  /* this counts the number of hard events */
00195 
00196     /* check for stopped clock */
00197     if (this_t < global_clock) {
00198         output_error("%s: object %s stopped its clock!", simtime(), object_name(obj));
00199         data->status = FAILED;
00200     } else {
00201         /* check for iteration limit approach */
00202         if (iteration_counter == 2 && this_t == global_clock) {
00203             output_verbose("%s: object %s iteration limit imminent",
00204                                 simtime(), object_name(obj));
00205         }
00206         else if (iteration_counter == 1 && this_t == global_clock) {
00207             output_error("convergence iteration limit reached for object %s:%d",
00208                            obj->oclass->name, obj->id);
00209         }
00210 
00211         /* if this event precedes next step, next step is now this event */
00212         if (data->step_to > this_t)
00213             data->step_to = this_t;
00214     }
00215 }
00216 
00217 static STATUS init_all(void)
00218 {
00219     OBJECT *obj;
00220     output_verbose("initializing objects...");
00221     TRY {
00222         for (obj=object_get_first(); obj!=NULL; obj=object_get_next(obj))
00223         {
00224             if (object_init(obj)==FAILED)
00225                 throw_exception("init_all(): object %s initialization failed", object_name(obj));
00226         }
00227     } CATCH (char *msg) {
00228         output_error("init failure: %s", msg);
00229         return FAILED;
00230     } ENDCATCH;
00231     return SUCCESS;
00232 }
00233 
00234 STATUS exec_test(struct sync_data *data, int pass, OBJECT *obj);
00235  
00236 STATUS t_setup_ranks(void){
00237     return setup_ranks();
00238 }
00239 STATUS t_sync_all(PASSCONFIG pass){
00240     struct sync_data sync = {TS_NEVER,0,SUCCESS};
00241     TIMESTAMP start_time = global_clock;
00242     int pass_index = ((int)(pass/2));
00243 
00244     /* scan the ranks of objects */
00245     if (ranks[pass_index] != NULL)
00246     {
00247         int i;
00248 
00249         /* process object in order of rank using index */
00250         for (i = PASSINIT(pass_index); PASSCMP(i, pass_index); i += PASSINC(pass_index))
00251         {
00252             LISTITEM *item;
00253             /* skip empty lists */
00254             if (ranks[pass_index]->ordinal[i] == NULL) 
00255                 continue;
00256             
00257             
00258             for (item=ranks[pass_index]->ordinal[i]->first; item!=NULL; item=item->next)
00259             {
00260                 OBJECT *obj = item->data;
00261                 if (exec_test(&sync,pass,obj)==FAILED)
00262                     return FAILED;
00263             }
00264         }
00265     }
00266     return SUCCESS;
00267 }
00268 
00273 STATUS exec_start(void)
00274 {
00275     threadpool_t threadpool = INVALID_THREADPOOL;
00276     struct sync_data sync = {TS_NEVER,0,SUCCESS};
00277     TIMESTAMP start_time = global_clock;
00278     int64 passes = 0, tsteps = 0;
00279     time_t started_at = realtime_now();
00280     int j;
00281 
00282     /* perform object initialization */
00283     if (init_all() == FAILED)
00284     {
00285         output_error("model initialization failed");
00286         return FAILED;
00287     }
00288 
00289     /* establish rank index if necessary */
00290     if (ranks == NULL && setup_ranks() == FAILED)
00291     {
00292         output_error("ranks setup failed");
00293         return FAILED;
00294     }
00295 
00296     /* run checks */
00297     if (global_runchecks)
00298         return module_checkall();
00299 
00300 
00301     if (!global_debug_mode)
00302     {
00303         /* schedule progress report event */
00304         realtime_schedule_event(realtime_now()+1,show_progress);
00305 
00306         /* set thread count equal to processor count if not passed on command-line */
00307         if (global_threadcount == 0)
00308             global_threadcount = processor_count();
00309         output_verbose("detected %d processor(s)", processor_count());
00310 
00311         /* allocate and initialize threadpool */
00312         threadpool = tp_alloc(&global_threadcount, do_object_sync);
00313         if (threadpool == INVALID_THREADPOOL) {
00314             output_error("threadpool creation failed");
00315             return FAILED;
00316         }
00317         output_verbose("using %d helper thread(s)", global_threadcount);
00318 
00319         /* allocate thread synchronization data */
00320         thread_data = (struct thread_data *) malloc(sizeof(struct thread_data) +
00321                       sizeof(struct sync_data) * global_threadcount);
00322         if (!thread_data) {
00323             output_error("thread data allocation failed");
00324             return FAILED;
00325         }
00326         thread_data->count = global_threadcount;
00327         thread_data->data = (struct sync_data *) (thread_data + 1);
00328         for (j = 0; j < thread_data->count; j++)
00329             thread_data->data[j].status = SUCCESS;
00330     }
00331     else
00332     {
00333         output_debug("debug mode running single threaded");
00334         output_message("GridLAB-D entering debug mode");
00335     }
00336 
00337     iteration_counter = global_iteration_limit;
00338     sync.step_to = global_clock;
00339     sync.hard_event = 1;
00340 
00341     /* signal handler */
00342     signal(SIGINT, exec_sighandler);
00343     signal(SIGTERM, exec_sighandler);
00344 
00345     /* main loop exception handler */
00346     TRY {
00347 
00348         /* main loop runs for iteration limit, or when nothing futher occurs (ignoring soft events) */
00349         while (iteration_counter>0 && sync.step_to!=TS_NEVER && sync.hard_event>0 && !stop_now) 
00350         {
00351             sync.hard_event = 0;
00352             global_clock = sync.step_to;
00353             sync.step_to = TS_NEVER;
00354 
00355             if (!global_debug_mode)
00356             {
00357                 for (j = 0; j < thread_data->count; j++) {
00358                     thread_data->data[j].hard_event = 0;
00359                     thread_data->data[j].step_to = TS_NEVER;
00360                 }
00361             }
00362             /* scan the ranks of objects */
00363             for (pass = 0; ranks[pass] != NULL; pass++)
00364             {
00365                 int i;
00366 
00367                 /* process object in order of rank using index */
00368                 for (i = PASSINIT(pass); PASSCMP(i, pass); i += PASSINC(pass))
00369                 {
00370                     /* skip empty lists */
00371                     if (ranks[pass]->ordinal[i] == NULL) 
00372                         continue;
00373                     
00374                     if (global_debug_mode)
00375                     {
00376                         LISTITEM *item;
00377                         for (item=ranks[pass]->ordinal[i]->first; item!=NULL; item=item->next)
00378                         {
00379                             OBJECT *obj = item->data;
00380                             if (exec_debug(&sync,pass,i,obj)==FAILED)
00381                                 THROW("debugger quit");
00382                         }
00383                     }
00384                     else
00385                     {
00386                         tp_exec(threadpool, ranks[pass]->ordinal[i]);
00387 
00388                         for (j = 0; j < thread_data->count; j++) {
00389                             if (thread_data->data[j].status == FAILED) {
00390                                 sync.status = FAILED;
00391                                 THROW("synchonization failed");
00392                             }
00393                         }
00394                     }
00395                 }
00396             }
00397 
00398             if (!global_debug_mode)
00399             {
00400                 for (j = 0; j < thread_data->count; j++) {
00401                     sync.hard_event += thread_data->data[j].hard_event;
00402                     if (thread_data->data[j].step_to < sync.step_to)
00403                         sync.step_to = thread_data->data[j].step_to;
00404                 }
00405 
00406                 /* report progress */
00407                 realtime_run_schedule();
00408             }
00409 
00410             /* count number of passes */
00411             passes++;
00412 
00413             /* check for clock advance */
00414             if (sync.step_to != global_clock)
00415             {
00416                 /* reset iteration count */
00417                 iteration_counter = global_iteration_limit;
00418 
00419                 /* count number of timesteps */
00420                 tsteps++;
00421             }
00422             /* check iteration limit */
00423             else if (--iteration_counter == 0)
00424             {
00425                 output_error("convergence iteration limit reached at %s", simtime());
00426                 sync.status = FAILED;
00427                 THROW("convergence failure");
00428             }
00429         }
00430 
00431         /* disable signal handler */
00432         signal(SIGINT,NULL);
00433 
00434         /* check end state */
00435         if (sync.step_to==TS_NEVER)
00436         {
00437             char buffer[64];
00438             output_verbose("simulation at steady state at %s", convert_from_timestamp(global_clock,buffer,sizeof(buffer))?buffer:"invalid time");
00439         }
00440 
00441     }
00442     CATCH(char *msg)
00443     {
00444         output_error("exec halted: %s", msg);
00445     }
00446     ENDCATCH
00447 
00448     /* deallocate threadpool */
00449     if (!global_debug_mode)
00450     {
00451         tp_release(threadpool);
00452         free(thread_data);
00453 
00454 #ifdef NEVER
00455         /* wipe out progress report */
00456         if (!global_keep_progress)
00457             output_raw("                                                           \r"); 
00458 #endif
00459     }
00460 
00461     /* report performance */
00462     if (global_profiler && sync.status==SUCCESS)
00463     {
00464         double elapsed_sim = (timestamp_to_hours(global_clock)-timestamp_to_hours(start_time));
00465         double elapsed_wall = (double)(realtime_now()-started_at+1);
00466         double sync_time = 0;
00467         CLASS *cl;
00468         if (global_threadcount==0) global_threadcount=1;
00469         for (cl=class_get_first_class(); cl!=NULL; cl=cl->next)
00470             sync_time += ((double)cl->profiler.clocks)/CLOCKS_PER_SEC;
00471         sync_time /= global_threadcount;
00472 
00473         output_profile("Core profilers results");
00474         output_profile("======================\n");
00475         output_profile("Total objects           %8d objects", object_get_count());
00476         output_profile("Parallelism             %8d thread%s", global_threadcount,global_threadcount>1?"s":"");
00477         output_profile("Total time              %8.1f seconds", elapsed_wall);
00478         output_profile("  Core time             %8.1f seconds (%.1f%%)", (elapsed_wall-sync_time),(elapsed_wall-sync_time)/elapsed_wall*100);
00479         output_profile("  Model time            %8.1f seconds/thread (%.1f%%)", sync_time,sync_time/elapsed_wall*100);
00480         output_profile("Simulation time         %8.0f days", elapsed_sim/24);
00481         output_profile("Simulation speed        %7.0lfk object.hours/second", object_get_count()/1000.0*elapsed_sim/elapsed_wall);
00482         output_profile("Syncs completed         %8d passes", passes);
00483         output_profile("Time steps completed    %8d timesteps", tsteps);
00484         output_profile("Convergence efficiency  %8.02lf passes/timestep", (double)passes/tsteps);
00485 #ifndef NOLOCKS
00486         output_profile("Memory lock contention  %7.01lf%%", (lock_spin>0 ? (1-(double)lock_count/(double)lock_spin)*100 : 0));
00487 #endif
00488         output_profile("\n");
00489     }
00490 
00491     return sync.status;
00492 }
00493 
00497 STATUS exec_test(struct sync_data *data, 
00498                  int pass, 
00499                  OBJECT *obj){ 
00500     TIMESTAMP this_t;
00501     /* check in and out-of-service dates */
00502     if (global_clock<obj->in_svc)
00503         this_t = obj->in_svc; /* yet to go in service */
00504     else if (global_clock<=obj->out_svc)
00505         this_t = object_sync(obj, global_clock, pass);
00506     else 
00507         this_t = TS_NEVER; /* already out of service */
00508 
00509     /* check for "soft" event (events that are ignored when stopping) */
00510     if (this_t < -1)
00511         this_t = -this_t;
00512     else if (this_t != TS_NEVER)
00513         data->hard_event++;  /* this counts the number of hard events */
00514 
00515     /* check for stopped clock */
00516     if (this_t < global_clock) {
00517         output_error("%s: object %s stopped its clock!", simtime(), object_name(obj));
00518         data->status = FAILED;
00519     } else {
00520         /* check for iteration limit approach */
00521         if (iteration_counter == 2 && this_t == global_clock) {
00522             output_verbose("%s: object %s iteration limit imminent",
00523                                 simtime(), object_name(obj));
00524         }
00525         else if (iteration_counter == 1 && this_t == global_clock) {
00526             output_error("convergence iteration limit reached for object %s:%d",
00527                            obj->oclass->name, obj->id);
00528         }
00529 
00530         /* if this event precedes next step, next step is now this event */
00531         if (data->step_to > this_t)
00532             data->step_to = this_t;
00533         data->status = SUCCESS;
00534     }
00535     return data->status;
00536 }
00537 

GridLAB-DTM Version 1.0
An open-source project initiated by the US Department of Energy