00001
00042 #include <signal.h>
00043 #include <ctype.h>
00044 #include <string.h>
00045 #ifdef WIN32
00046 #include <direct.h>
00047 #else
00048 #include <unistd.h>
00049 #endif
00050 #include "output.h"
00051 #include "exec.h"
00052 #include "class.h"
00053 #include "convert.h"
00054 #include "object.h"
00055 #include "index.h"
00056 #include "realtime.h"
00057 #include "module.h"
00058 #include "threadpool.h"
00059 #include "debug.h"
00060 #include "exception.h"
00061 #include "random.h"
00062 #include "local.h"
00063 #include "schedule.h"
00064 #include "loadshape.h"
00065 #include "enduse.h"
00066 #include "globals.h"
00067
00072 int exec_init()
00073 {
00074 #if 0
00075 #ifdef WIN32
00076 char glpathvar[1024];
00077 #endif
00078 #endif
00079
00080 size_t glpathlen=0;
00081
00082 global_starttime = realtime_now();
00083 timestamp_set_tz(NULL);
00084
00085
00086 getcwd(global_workdir,1024);
00087
00088
00089 locale_push();
00090
00091 #if 0
00092 #ifdef WIN32
00093 glpathlen=strlen("GLPATH=");
00094 sprintf(glpathvar, "GLPATH=");
00095 ExpandEnvironmentStrings(getenv("GLPATH"), glpathvar+glpathlen, (DWORD)(1024-glpathlen));
00096 #endif
00097 #endif
00098
00099 if (global_init()==FAILED)
00100 return 0;
00101 return 1;
00102 }
00103
00104 #ifndef _MAX_PATH
00105 #define _MAX_PATH 1024
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;
00117
00118 #ifndef NOLOCKS
00119 int64 lock_count = 0, lock_spin = 0;
00120 #endif
00121
00122 extern int stop_now;
00123
00124 INDEX **exec_getranks(void)
00125 {
00126 return ranks;
00127 }
00128
00129 static STATUS setup_ranks(void)
00130 {
00131 OBJECT *obj;
00132 int i;
00133 static INDEX *passlist[] = {NULL,NULL,NULL,NULL};
00134
00135
00136 ranks = passlist;
00137 ranks[0] = index_create(0,10);
00138 ranks[1] = index_create(0,10);
00139 ranks[2] = index_create(0,10);
00140
00141
00142 for (i=0; i<sizeof(passtype)/sizeof(passtype[0]); i++)
00143 {
00144 if (ranks[i]==NULL)
00145 return FAILED;
00146
00147
00148 for (obj=object_get_first(); obj!=NULL; obj=object_get_next(obj))
00149 {
00150
00151 if ((obj->oclass->passconfig&passtype[i])==0)
00152 continue;
00153
00154
00155 if (index_insert(ranks[i],obj,obj->rank)==FAILED)
00156 return FAILED;
00157 }
00158
00159 if (global_debug_mode==0 && global_nolocks==0)
00160
00161
00162 index_shuffle(ranks[i]);
00163 }
00164
00165 return SUCCESS;
00166 }
00167
00168 char *simtime(void)
00169 {
00170 static char buffer[64];
00171 return convert_from_timestamp(global_clock,buffer,sizeof(buffer))>0?buffer:"(invalid)";
00172 }
00173
00174 static STATUS show_progress(void)
00175 {
00176 output_progress();
00177
00178 realtime_schedule_event(realtime_now()+1,show_progress);
00179 return SUCCESS;
00180 }
00181
00182 static void do_object_sync(int thread, void *item)
00183 {
00184 struct sync_data *data = &thread_data->data[thread];
00185 OBJECT *obj = (OBJECT *) item;
00186 TIMESTAMP this_t;
00187
00188
00189 if (global_clock<obj->in_svc)
00190 this_t = obj->in_svc;
00191 else if (global_clock<=obj->out_svc)
00192 {
00193 this_t = object_sync(obj, global_clock, passtype[pass]);
00194 #ifdef _DEBUG
00195
00196 if (global_sync_dumpfile[0]!='\0')
00197 {
00198 static FILE *fp = NULL;
00199 if (fp==NULL)
00200 {
00201 static int tried = 0;
00202 if (!tried)
00203 {
00204 fp = fopen(global_sync_dumpfile,"wt");
00205 if (fp==NULL)
00206 output_error("sync_dumpfile '%s' is not writeable", global_sync_dumpfile);
00207 else
00208 fprintf(fp,"timestamp,pass,iteration,thread,object,sync\n");
00209 tried = 1;
00210 }
00211 }
00212 if (fp!=NULL)
00213 {
00214 static int64 lasttime = 0;
00215 static char lastdate[64]="";
00216 char syncdate[64]="";
00217 static char *passname;
00218 static int lastpass = -1;
00219 char objname[1024];
00220 if (lastpass!=passtype[pass])
00221 {
00222 lastpass=passtype[pass];
00223 switch(lastpass) {
00224 case PC_PRETOPDOWN: passname = "PRESYNC"; break;
00225 case PC_BOTTOMUP: passname = "SYNC"; break;
00226 case PC_POSTTOPDOWN: passname = "POSTSYNC"; break;
00227 default: passname = "UNKNOWN"; break;
00228 }
00229 }
00230 if (lasttime!=global_clock)
00231 {
00232 lasttime = global_clock;
00233 convert_from_timestamp(global_clock,lastdate,sizeof(lastdate));
00234 }
00235 convert_from_timestamp(this_t<0?-this_t:this_t,syncdate,sizeof(syncdate));
00236 if (obj->name==NULL) sprintf(objname,"%s:%d", obj->oclass->name, obj->id);
00237 else strcpy(objname,obj->name);
00238 fprintf(fp,"%s,%s,%d,%d,%s,%s\n",lastdate,passname,global_iteration_limit-iteration_counter,thread,objname,syncdate);
00239 }
00240 }
00241 #endif
00242 }
00243 else
00244 this_t = TS_NEVER;
00245
00246
00247 if (this_t < -1)
00248 this_t = -this_t;
00249 else if (this_t != TS_NEVER)
00250 data->hard_event++;
00251
00252
00253 if (this_t < global_clock) {
00254 output_error("%s: object %s stopped its clock (exec)!", simtime(), object_name(obj));
00255
00256
00257
00258
00259
00260 data->status = FAILED;
00261 } else {
00262
00263 if (iteration_counter == 2 && this_t == global_clock) {
00264 output_verbose("%s: object %s iteration limit imminent",
00265 simtime(), object_name(obj));
00266 }
00267 else if (iteration_counter == 1 && this_t == global_clock) {
00268 output_error("convergence iteration limit reached for object %s:%d", obj->oclass->name, obj->id);
00269
00270
00271
00272
00273
00274
00275 }
00276
00277
00278 if (global_minimum_timestep>1 && this_t>global_clock && this_t<TS_NEVER)
00279 this_t = (((this_t-1)/global_minimum_timestep)+1)*global_minimum_timestep;
00280
00281
00282 if (data->step_to > this_t)
00283 data->step_to = this_t;
00284 }
00285 }
00286
00287 static STATUS init_all(void)
00288 {
00289 OBJECT *obj;
00290 output_verbose("initializing objects...");
00291
00292
00293 if (loadshape_initall()==FAILED || enduse_initall()==FAILED)
00294 return FAILED;
00295
00296 TRY {
00297 for (obj=object_get_first(); obj!=NULL; obj=object_get_next(obj))
00298 {
00299 if (object_init(obj)==FAILED){
00300 throw_exception("init_all(): object %s initialization failed", object_name(obj));
00301
00302
00303
00304
00305 }
00306 if((obj->oclass->passconfig & PC_FORCE_NAME) == PC_FORCE_NAME){
00307 if(0 == strcmp(obj->name, "")){
00308 output_warning("init: object %s:%d should have a name, but doesn't", obj->oclass->name, obj->id);
00309
00310
00311
00312
00313 }
00314 }
00315 }
00316 } CATCH (char *msg) {
00317 output_error("init failure: %s", msg);
00318
00319
00320
00321
00322
00323 return FAILED;
00324 } ENDCATCH;
00325 return SUCCESS;
00326 }
00327
00328 static STATUS commit_all(TIMESTAMP t0){
00329 OBJECT *obj;
00330 TRY {
00331 for (obj=object_get_first(); obj!=NULL; obj=object_get_next(obj))
00332 {
00333 if(obj->in_svc <= t0 && obj->out_svc >= t0){
00334 if(object_commit(obj) == FAILED){
00335 throw_exception("commit_all(): object %s commit failed", object_name(obj));
00336
00337
00338
00339
00340 }
00341 }
00342 }
00343 } CATCH(char *msg){
00344 output_error("commit() failure: %s", msg);
00345
00346
00347
00348
00349
00350 return FAILED;
00351 } ENDCATCH;
00352 return SUCCESS;
00353 }
00354
00355 STATUS exec_test(struct sync_data *data, int pass, OBJECT *obj);
00356
00357 STATUS t_setup_ranks(void){
00358 return setup_ranks();
00359 }
00360 STATUS t_sync_all(PASSCONFIG pass)
00361 {
00362 struct sync_data sync = {TS_NEVER,0,SUCCESS};
00363 TIMESTAMP start_time = global_clock;
00364 int pass_index = ((int)(pass/2));
00365
00366
00367 if (ranks[pass_index] != NULL)
00368 {
00369 int i;
00370
00371
00372 for (i = PASSINIT(pass_index); PASSCMP(i, pass_index); i += PASSINC(pass_index))
00373 {
00374 LISTITEM *item;
00375
00376 if (ranks[pass_index]->ordinal[i] == NULL)
00377 continue;
00378
00379
00380 for (item=ranks[pass_index]->ordinal[i]->first; item!=NULL; item=item->next)
00381 {
00382 OBJECT *obj = item->data;
00383 if (exec_test(&sync,pass,obj)==FAILED)
00384 return FAILED;
00385 }
00386 }
00387 }
00388
00389
00390 {
00391 TIMESTAMP st = scheduletransform_syncall(global_clock,XS_DOUBLE|XS_COMPLEX|XS_ENDUSE);
00392 if (st<sync.step_to)
00393 sync.step_to = st;
00394 }
00395
00396 return SUCCESS;
00397 }
00398
00399
00400 TIMESTAMP syncall_internals(TIMESTAMP t1)
00401 {
00402 TIMESTAMP sc, ls, st, eu, t2;
00403 sc = schedule_syncall(t1);
00404 ls = loadshape_syncall(t1);
00405 st = scheduletransform_syncall(t1,XS_SCHEDULE|XS_LOADSHAPE);
00406
00407 eu = enduse_syncall(t1);
00408
00409 t2 = TS_NEVER;
00410 if(sc < t2) t2 = sc;
00411 if(ls < t2) t2 = ls;
00412 if(st < t2) t2 = st;
00413 if(eu < t2) t2 = eu;
00414 return t2;
00415 }
00416
00421 STATUS exec_start(void)
00422 {
00423 threadpool_t threadpool = INVALID_THREADPOOL;
00424 struct sync_data sync = {TS_NEVER,0,SUCCESS};
00425 TIMESTAMP start_time = global_clock;
00426 int64 passes = 0, tsteps = 0;
00427 time_t started_at = realtime_now();
00428 int j;
00429
00430
00431 if (init_all() == FAILED)
00432 {
00433 output_error("model initialization failed");
00434
00435
00436
00437
00438
00439 return FAILED;
00440 }
00441
00442
00443 if (ranks == NULL && setup_ranks() == FAILED)
00444 {
00445 output_error("ranks setup failed");
00446
00447
00448
00449
00450
00451 return FAILED;
00452 }
00453
00454
00455 if (global_runchecks)
00456 return module_checkall();
00457
00458
00459 if (global_compileonly)
00460 return SUCCESS;
00461
00462
00463 if (global_randomseed!=0 && global_threadcount>1)
00464 global_nondeterminism_warning = 1;
00465
00466 if (!global_debug_mode)
00467 {
00468
00469 realtime_schedule_event(realtime_now()+1,show_progress);
00470
00471
00472 if (global_threadcount == 0)
00473 global_threadcount = processor_count();
00474 output_verbose("detected %d processor(s)", processor_count());
00475
00476
00477 threadpool = tp_alloc(&global_threadcount, do_object_sync);
00478 if (threadpool == INVALID_THREADPOOL) {
00479 output_error("threadpool creation failed");
00480
00481
00482
00483
00484
00485 return FAILED;
00486 }
00487 output_verbose("using %d helper thread(s)", global_threadcount);
00488
00489
00490 thread_data = (struct thread_data *) malloc(sizeof(struct thread_data) +
00491 sizeof(struct sync_data) * global_threadcount);
00492 if (!thread_data) {
00493 output_error("thread memory allocation failed");
00494
00495
00496
00497
00498 return FAILED;
00499 }
00500 thread_data->count = global_threadcount;
00501 thread_data->data = (struct sync_data *) (thread_data + 1);
00502 for (j = 0; j < thread_data->count; j++)
00503 thread_data->data[j].status = SUCCESS;
00504 }
00505 else
00506 {
00507 output_debug("debug mode running single threaded");
00508 output_message("GridLAB-D entering debug mode");
00509 }
00510
00511 #ifndef WIN32
00512
00513 if (global_run_realtime)
00514 {
00515 time(&global_clock);
00516 output_verbose("realtime mode requires using now (%d) as starttime", global_clock);
00517 if (global_stoptime<global_clock)
00518 global_stoptime=TS_NEVER;
00519 }
00520 #endif
00521 iteration_counter = global_iteration_limit;
00522 sync.step_to = global_clock;
00523 sync.hard_event = 1;
00524
00525
00526 signal(SIGABRT, exec_sighandler);
00527 signal(SIGINT, exec_sighandler);
00528 signal(SIGTERM, exec_sighandler);
00529
00530
00531 TRY {
00532
00533
00534 while (iteration_counter>0 && sync.step_to <= global_stoptime && sync.step_to < TS_NEVER && sync.hard_event>0 && !stop_now)
00535 {
00536
00537 output_set_time_context(sync.step_to);
00538
00539 sync.hard_event = (global_stoptime == TS_NEVER ? 0 : 1);
00540
00541 #ifndef WIN32
00542
00543 if (global_run_realtime)
00544 {
00545 struct timeval tv;
00546 gettimeofday(&tv);
00547 output_verbose("waiting %d usec", 1000000-tv.tv_usec);
00548 usleep(1000000-tv.tv_usec);
00549 global_clock = tv.tv_sec+1;
00550 output_verbose("realtime clock advancing to %d", (int)global_clock);
00551 }
00552 else
00553 #endif
00554 global_clock = sync.step_to;
00555
00556
00557 sync.step_to = syncall_internals(global_clock);
00558 if(sync.step_to <= global_clock)
00559 THROW("internal property sync failure");
00560
00561
00562
00563
00564
00565
00566 if (!global_debug_mode)
00567 {
00568 for (j = 0; j < thread_data->count; j++) {
00569 thread_data->data[j].hard_event = 0;
00570 thread_data->data[j].step_to = TS_NEVER;
00571 }
00572 }
00573
00574 for (pass = 0; ranks[pass] != NULL; pass++)
00575 {
00576 int i;
00577
00578
00579 for (i = PASSINIT(pass); PASSCMP(i, pass); i += PASSINC(pass))
00580 {
00581
00582 if (ranks[pass]->ordinal[i] == NULL)
00583 continue;
00584
00585 if (global_debug_mode)
00586 {
00587 LISTITEM *item;
00588 for (item=ranks[pass]->ordinal[i]->first; item!=NULL; item=item->next)
00589 {
00590 OBJECT *obj = item->data;
00591 if (exec_debug(&sync,pass,i,obj)==FAILED)
00592 THROW("debugger quit");
00593 }
00594 }
00595 else
00596 {
00597 tp_exec(threadpool, ranks[pass]->ordinal[i]);
00598
00599 for (j = 0; j < thread_data->count; j++) {
00600 if (thread_data->data[j].status == FAILED) {
00601 sync.status = FAILED;
00602 THROW("synchonization failed");
00603 }
00604 }
00605 }
00606 }
00607
00608
00609 {
00610 TIMESTAMP st = scheduletransform_syncall(global_clock,XS_DOUBLE|XS_COMPLEX|XS_ENDUSE);
00611 if (st<sync.step_to)
00612 sync.step_to = st;
00613 }
00614 }
00615
00616 if (!global_debug_mode)
00617 {
00618 for (j = 0; j < thread_data->count; j++) {
00619 sync.hard_event += thread_data->data[j].hard_event;
00620 if (thread_data->data[j].step_to < sync.step_to)
00621 sync.step_to = thread_data->data[j].step_to;
00622 }
00623
00624
00625 realtime_run_schedule();
00626 }
00627
00628
00629 passes++;
00630
00631
00632 if (sync.step_to != global_clock)
00633 {
00634 if (commit_all(global_clock) == FAILED)
00635 {
00636 output_error("model commit failed");
00637
00638
00639
00640
00641
00642 return FAILED;
00643 }
00644
00645
00646 iteration_counter = global_iteration_limit;
00647
00648
00649 tsteps++;
00650 }
00651
00652 else if (--iteration_counter == 0)
00653 {
00654 output_error("convergence iteration limit reached at %s (exec)", simtime());
00655
00656
00657
00658
00659
00660
00661 sync.status = FAILED;
00662 THROW("convergence failure");
00663 }
00664 }
00665
00666
00667 signal(SIGINT,NULL);
00668
00669
00670 if (sync.step_to==TS_NEVER)
00671 {
00672 char buffer[64];
00673 output_verbose("simulation at steady state at %s", convert_from_timestamp(global_clock,buffer,sizeof(buffer))?buffer:"invalid time");
00674 }
00675 }
00676 CATCH(char *msg)
00677 {
00678 output_error("exec halted: %s", msg);
00679 sync.status = FAILED;
00680
00681
00682
00683
00684
00685 }
00686 ENDCATCH
00687
00688
00689 if (!global_debug_mode)
00690 {
00691 tp_release(threadpool);
00692 free(thread_data);
00693
00694 #ifdef NEVER
00695
00696 if (!global_keep_progress)
00697 output_raw(" \r");
00698 #endif
00699 }
00700
00701
00702 if (global_profiler && sync.status==SUCCESS)
00703 {
00704 double elapsed_sim = (timestamp_to_hours(global_clock<start_time?start_time:global_clock)-timestamp_to_hours(start_time));
00705 double elapsed_wall = (double)(realtime_now()-started_at+1);
00706 double sync_time = 0;
00707 double sim_speed = object_get_count()/1000.0*elapsed_sim/elapsed_wall;
00708 CLASS *cl;
00709 if (global_threadcount==0) global_threadcount=1;
00710 for (cl=class_get_first_class(); cl!=NULL; cl=cl->next)
00711 sync_time += ((double)cl->profiler.clocks)/CLOCKS_PER_SEC;
00712 sync_time /= global_threadcount;
00713
00714 output_profile("\nCore profiler results");
00715 output_profile("======================\n");
00716 output_profile("Total objects %8d objects", object_get_count());
00717 output_profile("Parallelism %8d thread%s", global_threadcount,global_threadcount>1?"s":"");
00718 output_profile("Total time %8.1f seconds", elapsed_wall);
00719 output_profile(" Core time %8.1f seconds (%.1f%%)", (elapsed_wall-sync_time),(elapsed_wall-sync_time)/elapsed_wall*100);
00720 output_profile(" Model time %8.1f seconds/thread (%.1f%%)", sync_time,sync_time/elapsed_wall*100);
00721 output_profile("Simulation time %8.0f days", elapsed_sim/24);
00722 if (sim_speed>10.0)
00723 output_profile("Simulation speed %7.0lfk object.hours/second", sim_speed);
00724 else if (sim_speed>1.0)
00725 output_profile("Simulation speed %7.1lfk object.hours/second", sim_speed);
00726 else
00727 output_profile("Simulation speed %7.0lf object.hours/second", sim_speed*1000);
00728 output_profile("Syncs completed %8d passes", passes);
00729 output_profile("Time steps completed %8d timesteps", tsteps);
00730 output_profile("Convergence efficiency %8.02lf passes/timestep", (double)passes/tsteps);
00731 #ifndef NOLOCKS
00732 output_profile("Memory lock contention %7.01lf%%", (lock_spin>0 ? (1-(double)lock_count/(double)lock_spin)*100 : 0));
00733 #endif
00734 output_profile("Average timestep %7.0lf seconds/timestep", (double)(global_clock<start_time?0:global_clock-start_time)/tsteps);
00735 output_profile("Simulation rate %7.0lf x realtime", (double)(global_clock<start_time?0:global_clock-start_time)/elapsed_wall);
00736 output_profile("\n");
00737 }
00738
00739 return sync.status;
00740 }
00741
00745 STATUS exec_test(struct sync_data *data,
00746 int pass,
00747 OBJECT *obj){
00748 TIMESTAMP this_t;
00749
00750 if (global_clock<obj->in_svc)
00751 this_t = obj->in_svc;
00752 else if (global_clock<=obj->out_svc)
00753 this_t = object_sync(obj, global_clock, pass);
00754 else
00755 this_t = TS_NEVER;
00756
00757
00758 if (this_t < -1)
00759 this_t = -this_t;
00760 else if (this_t != TS_NEVER)
00761 data->hard_event++;
00762
00763
00764 if (this_t < global_clock) {
00765 output_error("%s: object %s stopped its clock! (test)", simtime(), object_name(obj));
00766
00767
00768
00769
00770
00771 data->status = FAILED;
00772 } else {
00773
00774 if (iteration_counter == 2 && this_t == global_clock) {
00775 output_verbose("%s: object %s iteration limit imminent",
00776 simtime(), object_name(obj));
00777 }
00778 else if (iteration_counter == 1 && this_t == global_clock) {
00779 output_error("convergence iteration limit reached for object %s:%d (test)", obj->oclass->name, obj->id);
00780
00781
00782
00783
00784
00785 }
00786
00787
00788 if (global_minimum_timestep>1 && this_t>global_clock && this_t<TS_NEVER)
00789 this_t = ((this_t/global_minimum_timestep)+1)*global_minimum_timestep;
00790
00791
00792 if (data->step_to > this_t)
00793 data->step_to = this_t;
00794 data->status = SUCCESS;
00795 }
00796 return data->status;
00797 }
00798