00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <math.h>
00004
00005 #include "converse.h"
00006 #include "charm-api.h"
00007
00011 typedef struct _ccd_callback {
00012 CcdVoidFn fn;
00013 void *arg;
00014 int pe;
00015 } ccd_callback;
00016
00017
00018
00022 typedef struct _ccd_cblist_elem {
00023 ccd_callback cb;
00024 short int next;
00025 short int prev;
00026 } ccd_cblist_elem;
00027
00028
00029
00033 typedef struct _ccd_cblist {
00034 unsigned short int maxlen;
00035 unsigned short int len;
00036 short int first, last;
00037 short int first_free;
00038 unsigned char flag;
00039 ccd_cblist_elem *elems;
00040 } ccd_cblist;
00041
00042
00043
00045 static void init_cblist(ccd_cblist *l, unsigned int ml)
00046 {
00047 int i;
00048 l->elems = (ccd_cblist_elem*) malloc(ml*sizeof(ccd_cblist_elem));
00049 _MEMCHECK(l->elems);
00050 for(i=0;i<ml;i++) {
00051 l->elems[i].next = i+1;
00052 l->elems[i].prev = i-1;
00053 }
00054 l->elems[ml-1].next = -1;
00055 l->len = 0;
00056 l->maxlen = ml;
00057 l->first = l->last = -1;
00058 l->first_free = 0;
00059 l->flag = 0;
00060 }
00061
00062
00063
00065 static void expand_cblist(ccd_cblist *l, unsigned int ml)
00066 {
00067 ccd_cblist_elem *old_elems = l->elems;
00068 int i = 0;
00069 l->elems = (ccd_cblist_elem*) malloc(ml*sizeof(ccd_cblist_elem));
00070 _MEMCHECK(l->elems);
00071 for(i=0;i<(l->len);i++)
00072 l->elems[i] = old_elems[i];
00073 free(old_elems);
00074 for(i=l->len;i<ml;i++) {
00075 l->elems[i].next = i+1;
00076 l->elems[i].prev = i-1;
00077 }
00078 l->elems[ml-1].next = -1;
00079 l->elems[l->len].prev = -1;
00080 l->maxlen = ml;
00081 l->first_free = l->len;
00082 }
00083
00084
00085
00087 static void remove_elem(ccd_cblist *l, int idx)
00088 {
00089 ccd_cblist_elem *e = l->elems;
00090
00091 if(e[idx].next != (-1))
00092 e[e[idx].next].prev = e[idx].prev;
00093 if(e[idx].prev != (-1))
00094 e[e[idx].prev].next = e[idx].next;
00095 if(idx==(l->first))
00096 l->first = e[idx].next;
00097 if(idx==(l->last))
00098 l->last = e[idx].prev;
00099
00100 e[idx].prev = -1;
00101 e[idx].next = l->first_free;
00102 if(e[idx].next != (-1))
00103 e[e[idx].next].prev = idx;
00104 l->first_free = idx;
00105 l->len--;
00106 }
00107
00108
00109
00111 static void remove_n_elems(ccd_cblist *l, int n)
00112 {
00113 int i;
00114 if(n==0 || (l->len < n))
00115 return;
00116 for(i=0;i<n;i++) {
00117 remove_elem(l, l->first);
00118 }
00119 }
00120
00121
00122
00124 static int append_elem(ccd_cblist *l, CcdVoidFn fn, void *arg, int pe)
00125 {
00126 int idx;
00127 ccd_cblist_elem *e;
00128 if(l->len == l->maxlen)
00129 expand_cblist(l, l->maxlen*2);
00130 idx = l->first_free;
00131 e = l->elems;
00132 l->first_free = e[idx].next;
00133 e[idx].next = -1;
00134 e[idx].prev = l->last;
00135 if(l->first == (-1))
00136 l->first = idx;
00137 if(l->last != (-1))
00138 e[l->last].next = idx;
00139 l->last = idx;
00140 e[idx].cb.fn = fn;
00141 e[idx].cb.arg = arg;
00142 e[idx].cb.pe = pe;
00143 l->len++;
00144 return idx;
00145 }
00146
00147
00148
00157 static void call_cblist_keep(ccd_cblist *l,double curWallTime)
00158 {
00159 int i, len = l->len, idx;
00160 for(i=0, idx=l->first;i<len;i++) {
00161 int old = CmiSwitchToPE(l->elems[idx].cb.pe);
00162 (*(l->elems[idx].cb.fn))(l->elems[idx].cb.arg,curWallTime);
00163 int unused = CmiSwitchToPE(old);
00164 idx = l->elems[idx].next;
00165 }
00166 }
00167
00168
00169
00178 static void call_cblist_remove(ccd_cblist *l,double curWallTime)
00179 {
00180 int i, len = l->len, idx;
00181
00182 if (l->flag) return;
00183 l->flag = 1;
00184 #if ! CMK_BIGSIM_CHARM
00185 for(i=0, idx=l->first;i<len;i++) {
00186 int old = CmiSwitchToPE(l->elems[idx].cb.pe);
00187 (*(l->elems[idx].cb.fn))(l->elems[idx].cb.arg,curWallTime);
00188 int unused = CmiSwitchToPE(old);
00189 idx = l->elems[idx].next;
00190 }
00191 #else
00192 for(i=0, idx=l->last;i<len;i++) {
00193 int old = CmiSwitchToPE(l->elems[idx].cb.pe);
00194 (*(l->elems[idx].cb.fn))(l->elems[idx].cb.arg,curWallTime);
00195 int unused = CmiSwitchToPE(old);
00196 idx = l->elems[idx].prev;
00197 }
00198 #endif
00199 remove_n_elems(l,len);
00200 l->flag = 0;
00201 }
00202
00203
00204
00205 #define CBLIST_INIT_LEN 8
00206 #define MAXNUMCONDS (CcdUSERMAX + 1)
00207
00211 typedef struct {
00212 ccd_cblist condcb[MAXNUMCONDS];
00213 ccd_cblist condcb_keep[MAXNUMCONDS];
00214 } ccd_cond_callbacks;
00215
00216
00217 CpvStaticDeclare(ccd_cond_callbacks, conds);
00218
00219
00220
00221 #define CCD_DEFAULT_RESOLUTION 5.0e-3
00222
00223
00224 #define CCD_PERIODIC_MAX 13
00225 const static double periodicCallInterval[CCD_PERIODIC_MAX]=
00226 {0.001, 0.010, 0.100, 1.0, 5.0, 10.0, 60.0, 2*60.0, 5*60.0, 10*60.0, 3600.0, 12*3600.0, 24*3600.0};
00227
00231 typedef struct {
00232 int nSkip;
00233 double lastCheck;
00234 double resolution;
00235 double nextCall[CCD_PERIODIC_MAX];
00236 } ccd_periodic_callbacks;
00237
00239 CpvStaticDeclare(ccd_periodic_callbacks, pcb);
00240 CpvDeclare(int, _ccd_numchecks);
00241
00242
00243
00244 #define MAXTIMERHEAPENTRIES 128
00245
00249 typedef struct {
00250 double time;
00251 ccd_callback cb;
00252 } ccd_heap_elem;
00253
00254
00255
00256
00257
00258
00260 CpvStaticDeclare(ccd_heap_elem*, ccd_heap);
00262 CpvStaticDeclare(int, ccd_heaplen);
00264 CpvStaticDeclare(int, ccd_heapmaxlen);
00265
00266
00267
00269 static void ccd_heap_swap(int index1, int index2)
00270 {
00271 ccd_heap_elem *h = CpvAccess(ccd_heap);
00272 ccd_heap_elem temp;
00273
00274 temp = h[index1];
00275 h[index1] = h[index2];
00276 h[index2] = temp;
00277 }
00278
00279
00280
00289 static void expand_ccd_heap(void)
00290 {
00291 int i;
00292 int oldlen = CpvAccess(ccd_heapmaxlen);
00293 int newlen = oldlen*2;
00294 ccd_heap_elem *newheap;
00295
00296 CmiPrintf("[%d] Warning: ccd_heap expand from %d to %d\n", CmiMyPe(),oldlen, newlen);
00297
00298 newheap = (ccd_heap_elem*) malloc(sizeof(ccd_heap_elem)*2*(newlen+1));
00299 _MEMCHECK(newheap);
00300
00301 for (i=0; i<=oldlen; i++) {
00302 newheap[i] = CpvAccess(ccd_heap)[i];
00303 newheap[i+newlen] = CpvAccess(ccd_heap)[i+oldlen];
00304 }
00305 free(CpvAccess(ccd_heap));
00306 CpvAccess(ccd_heap) = newheap;
00307 CpvAccess(ccd_heapmaxlen) = newlen;
00308 }
00309
00310
00311
00315 static void ccd_heap_insert(double t, CcdVoidFn fnp, void *arg, int pe)
00316 {
00317 int child, parent;
00318 ccd_heap_elem *h;
00319
00320 if(CpvAccess(ccd_heaplen) >= CpvAccess(ccd_heapmaxlen)) {
00321
00322 expand_ccd_heap();
00323 }
00324
00325 h = CpvAccess(ccd_heap);
00326
00327 {
00328 ccd_heap_elem *e = &(h[++CpvAccess(ccd_heaplen)]);
00329 e->time = t;
00330 e->cb.fn = fnp;
00331 e->cb.arg = arg;
00332 e->cb.pe = pe;
00333 child = CpvAccess(ccd_heaplen);
00334 parent = child / 2;
00335 while((parent>0) && (h[child].time<h[parent].time)) {
00336 ccd_heap_swap(child, parent);
00337 child = parent;
00338 parent = parent / 2;
00339 }
00340 }
00341 }
00342
00343
00344
00348 static void ccd_heap_remove(void)
00349 {
00350 int parent,child;
00351 ccd_heap_elem *h = CpvAccess(ccd_heap);
00352
00353 parent = 1;
00354 if(CpvAccess(ccd_heaplen)>0) {
00355
00356 ccd_heap_swap(1,CpvAccess(ccd_heaplen));
00357 CpvAccess(ccd_heaplen)--;
00358 if(CpvAccess(ccd_heaplen)) {
00359
00360 child = 2 * parent;
00361 while(child <= CpvAccess(ccd_heaplen)) {
00362 if(((child + 1) <= CpvAccess(ccd_heaplen)) &&
00363 (h[child].time > h[child+1].time))
00364 child++;
00365 if(h[parent].time <= h[child].time)
00366 break;
00367 ccd_heap_swap(parent,child);
00368 parent = child;
00369 child = 2 * child;
00370 }
00371 }
00372 }
00373 }
00374
00375
00376
00381 static void ccd_heap_update(double curWallTime)
00382 {
00383 ccd_heap_elem *h = CpvAccess(ccd_heap);
00384 ccd_heap_elem *e = h+CpvAccess(ccd_heapmaxlen);
00385 int i,ne=0;
00386
00387 while ((CpvAccess(ccd_heaplen)>0) && (h[1].time<curWallTime)) {
00388 e[ne++]=h[1];
00389 ccd_heap_remove();
00390 }
00391
00392
00393
00394
00395 for (i=0;i<ne;i++) {
00396
00397
00398
00399
00400 int old = CmiSwitchToPE(e[i].cb.pe);
00401 (*(e[i].cb.fn))(e[i].cb.arg,curWallTime);
00402 int unused = CmiSwitchToPE(old);
00403 }
00404 }
00405
00406
00407
00408 CLINKAGE void CcdCallBacksReset(void *ignored,double curWallTime);
00409
00413 void CcdModuleInit(char **ignored)
00414 {
00415 int i;
00416 double curTime;
00417 CpvInitialize(ccd_heap_elem*, ccd_heap);
00418 CpvInitialize(ccd_cond_callbacks, conds);
00419 CpvInitialize(ccd_periodic_callbacks, pcb);
00420 CpvInitialize(int, ccd_heaplen);
00421 CpvInitialize(int, ccd_heapmaxlen);
00422 CpvInitialize(int, _ccd_numchecks);
00423
00424 CpvAccess(ccd_heaplen) = 0;
00425 CpvAccess(ccd_heapmaxlen) = MAXTIMERHEAPENTRIES;
00426 CpvAccess(ccd_heap) =
00427 (ccd_heap_elem*) malloc(sizeof(ccd_heap_elem)*2*(MAXTIMERHEAPENTRIES + 1));
00428 _MEMCHECK(CpvAccess(ccd_heap));
00429 for(i=0;i<MAXNUMCONDS;i++) {
00430 init_cblist(&(CpvAccess(conds).condcb[i]), CBLIST_INIT_LEN);
00431 init_cblist(&(CpvAccess(conds).condcb_keep[i]), CBLIST_INIT_LEN);
00432 }
00433 CpvAccess(_ccd_numchecks) = 1;
00434 CpvAccess(pcb).nSkip = 1;
00435 curTime=CmiWallTimer();
00436 CpvAccess(pcb).lastCheck = curTime;
00437 for (i=0;i<CCD_PERIODIC_MAX;i++)
00438 CpvAccess(pcb).nextCall[i]=curTime+periodicCallInterval[i];
00439 CpvAccess(pcb).resolution = CCD_DEFAULT_RESOLUTION;
00440 CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,CcdCallBacksReset,0);
00441 CcdCallOnConditionKeep(CcdPROCESSOR_END_IDLE,CcdCallBacksReset,0);
00442 }
00443
00444
00445
00450 int CcdCallOnCondition(int condnum, CcdVoidFn fnp, void *arg)
00451 {
00452 CmiAssert(condnum < MAXNUMCONDS);
00453 return append_elem(&(CpvAccess(conds).condcb[condnum]), fnp, arg, CcdIGNOREPE);
00454 }
00455
00460 int CcdCallOnConditionOnPE(int condnum, CcdVoidFn fnp, void *arg, int pe)
00461 {
00462 CmiAssert(condnum < MAXNUMCONDS);
00463 return append_elem(&(CpvAccess(conds).condcb[condnum]), fnp, arg, pe);
00464 }
00465
00470 int CcdCallOnConditionKeep(int condnum, CcdVoidFn fnp, void *arg)
00471 {
00472 CmiAssert(condnum < MAXNUMCONDS);
00473 return append_elem(&(CpvAccess(conds).condcb_keep[condnum]), fnp, arg, CcdIGNOREPE);
00474 }
00475
00480 int CcdCallOnConditionKeepOnPE(int condnum, CcdVoidFn fnp, void *arg, int pe)
00481 {
00482 CmiAssert(condnum < MAXNUMCONDS);
00483 return append_elem(&(CpvAccess(conds).condcb_keep[condnum]), fnp, arg, pe);
00484 }
00485
00486
00490 void CcdCancelCallOnCondition(int condnum, int idx)
00491 {
00492 CmiAssert(condnum < MAXNUMCONDS);
00493 remove_elem(&(CpvAccess(conds).condcb[condnum]), idx);
00494 }
00495
00496
00500 void CcdCancelCallOnConditionKeep(int condnum, int idx)
00501 {
00502 CmiAssert(condnum < MAXNUMCONDS);
00503 remove_elem(&(CpvAccess(conds).condcb_keep[condnum]), idx);
00504 }
00505
00506
00511 void CcdCallFnAfterOnPE(CcdVoidFn fnp, void *arg, double deltaT, int pe)
00512 {
00513 double ctime = CmiWallTimer();
00514 double tcall = ctime + deltaT/1000.0;
00515 ccd_heap_insert(tcall, fnp, arg, pe);
00516 }
00517
00522 void CcdCallFnAfter(CcdVoidFn fnp, void *arg, double deltaT)
00523 {
00524 CcdCallFnAfterOnPE(fnp, arg, deltaT, CcdIGNOREPE);
00525 }
00526
00527
00532 void CcdRaiseCondition(int condnum)
00533 {
00534 CmiAssert(condnum < MAXNUMCONDS);
00535 double curWallTime=CmiWallTimer();
00536 call_cblist_remove(&(CpvAccess(conds).condcb[condnum]),curWallTime);
00537 call_cblist_keep(&(CpvAccess(conds).condcb_keep[condnum]),curWallTime);
00538 }
00539
00540
00546 double CcdSetMinResolution(double newResolution, double minResolution) {
00547 ccd_periodic_callbacks* o = &CpvAccess(pcb);
00548 double oldResolution = o->resolution;
00549
00550 o->resolution = fmin(newResolution, minResolution);
00551
00552
00553 if (o->resolution < oldResolution) {
00554 CcdCallBacksReset(NULL, CmiWallTimer());
00555 }
00556
00557 return oldResolution;
00558 }
00559
00563 double CcdSetResolution(double newResolution) {
00564 return CcdSetMinResolution(newResolution, CCD_DEFAULT_RESOLUTION);
00565 }
00566
00570 double CcdResetResolution() {
00571 ccd_periodic_callbacks* o = &CpvAccess(pcb);
00572 double oldResolution = o->resolution;
00573
00574 o->resolution = CCD_DEFAULT_RESOLUTION;
00575
00576 return oldResolution;
00577 }
00578
00583 double CcdIncreaseResolution(double newResolution) {
00584 return CcdSetMinResolution(newResolution, CpvAccess(pcb).resolution);
00585 }
00586
00587
00588
00589
00590
00591 void CcdCallBacks(void)
00592 {
00593 int i;
00594 ccd_periodic_callbacks *o=&CpvAccess(pcb);
00595
00596
00597 double curWallTime = CmiWallTimer();
00598
00599 unsigned int nSkip=o->nSkip;
00600 #if 1
00601
00602 double elapsed = curWallTime - o->lastCheck;
00603
00604
00605
00606 if (elapsed > 0.0) {
00607 nSkip = (int)(nSkip * fmax(0.5, fmin(2.0, o->resolution / elapsed)));
00608 }
00609
00610
00611 #define minSkip 1u
00612 #define maxSkip 20u
00613 if (nSkip<minSkip) nSkip=minSkip;
00614 else if (nSkip>maxSkip) nSkip=maxSkip;
00615 #else
00616
00617 nSkip=1;
00618 #endif
00619
00620 CpvAccess(_ccd_numchecks)=o->nSkip=nSkip;
00621 o->lastCheck=curWallTime;
00622
00623 ccd_heap_update(curWallTime);
00624
00625 for (i=0;i<CCD_PERIODIC_MAX;i++)
00626 if (o->nextCall[i]<=curWallTime) {
00627 CcdRaiseCondition(CcdPERIODIC+i);
00628 o->nextCall[i]=curWallTime+periodicCallInterval[i];
00629 }
00630 else
00631 break;
00632 }
00633
00634
00635
00639 void CcdCallBacksReset(void *ignored,double curWallTime)
00640 {
00641 ccd_periodic_callbacks *o=&CpvAccess(pcb);
00642 CpvAccess(_ccd_numchecks)=o->nSkip=1;
00643 o->lastCheck=curWallTime;
00644 }
00645
00646