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
00077 global_starttime = realtime_now();
00078 timestamp_set_tz(NULL);
00079
00080
00081 random_init();
00082
00083
00084 getcwd(global_workdir,1024);
00085
00086
00087 locale_push();
00088
00089 #if 0
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;
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};
00129
00130
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
00137 for (i=0; i<sizeof(passtype)/sizeof(passtype[0]); i++)
00138 {
00139 if (ranks[i]==NULL)
00140 return FAILED;
00141
00142
00143 for (obj=object_get_first(); obj!=NULL; obj=object_get_next(obj))
00144 {
00145
00146 if ((obj->oclass->passconfig&passtype[i])==0)
00147 continue;
00148
00149
00150 if (index_insert(ranks[i],obj,obj->rank)==FAILED)
00151 return FAILED;
00152 }
00153 #ifndef NOLOCKS
00154
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
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
00183 if (global_clock<obj->in_svc)
00184 this_t = obj->in_svc;
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;
00189
00190
00191 if (this_t < -1)
00192 this_t = -this_t;
00193 else if (this_t != TS_NEVER)
00194 data->hard_event++;
00195
00196
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
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
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
00245 if (ranks[pass_index] != NULL)
00246 {
00247 int i;
00248
00249
00250 for (i = PASSINIT(pass_index); PASSCMP(i, pass_index); i += PASSINC(pass_index))
00251 {
00252 LISTITEM *item;
00253
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
00283 if (init_all() == FAILED)
00284 {
00285 output_error("model initialization failed");
00286 return FAILED;
00287 }
00288
00289
00290 if (ranks == NULL && setup_ranks() == FAILED)
00291 {
00292 output_error("ranks setup failed");
00293 return FAILED;
00294 }
00295
00296
00297 if (global_runchecks)
00298 return module_checkall();
00299
00300
00301 if (!global_debug_mode)
00302 {
00303
00304 realtime_schedule_event(realtime_now()+1,show_progress);
00305
00306
00307 if (global_threadcount == 0)
00308 global_threadcount = processor_count();
00309 output_verbose("detected %d processor(s)", processor_count());
00310
00311
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
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
00342 signal(SIGINT, exec_sighandler);
00343 signal(SIGTERM, exec_sighandler);
00344
00345
00346 TRY {
00347
00348
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
00363 for (pass = 0; ranks[pass] != NULL; pass++)
00364 {
00365 int i;
00366
00367
00368 for (i = PASSINIT(pass); PASSCMP(i, pass); i += PASSINC(pass))
00369 {
00370
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
00407 realtime_run_schedule();
00408 }
00409
00410
00411 passes++;
00412
00413
00414 if (sync.step_to != global_clock)
00415 {
00416
00417 iteration_counter = global_iteration_limit;
00418
00419
00420 tsteps++;
00421 }
00422
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
00432 signal(SIGINT,NULL);
00433
00434
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
00449 if (!global_debug_mode)
00450 {
00451 tp_release(threadpool);
00452 free(thread_data);
00453
00454 #ifdef NEVER
00455
00456 if (!global_keep_progress)
00457 output_raw(" \r");
00458 #endif
00459 }
00460
00461
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
00502 if (global_clock<obj->in_svc)
00503 this_t = obj->in_svc;
00504 else if (global_clock<=obj->out_svc)
00505 this_t = object_sync(obj, global_clock, pass);
00506 else
00507 this_t = TS_NEVER;
00508
00509
00510 if (this_t < -1)
00511 this_t = -this_t;
00512 else if (this_t != TS_NEVER)
00513 data->hard_event++;
00514
00515
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
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
00531 if (data->step_to > this_t)
00532 data->step_to = this_t;
00533 data->status = SUCCESS;
00534 }
00535 return data->status;
00536 }
00537