00001 #include <stdio.h>
00002 #include <stdlib.h>
00003
00004 #include "converse.h"
00005
00009 typedef struct _ccd_callback {
00010 CcdVoidFn fn;
00011 void *arg;
00012 int pe;
00013 } ccd_callback;
00014
00015
00016
00020 typedef struct _ccd_cblist_elem {
00021 ccd_callback cb;
00022 int next;
00023 int prev;
00024 } ccd_cblist_elem;
00025
00026
00027
00031 typedef struct _ccd_cblist {
00032 unsigned int maxlen;
00033 unsigned int len;
00034 int first, last;
00035 int first_free;
00036 ccd_cblist_elem *elems;
00037 int flag;
00038 } ccd_cblist;
00039
00040
00041
00043 static void init_cblist(ccd_cblist *l, unsigned int ml)
00044 {
00045 int i;
00046 l->elems = (ccd_cblist_elem*) malloc(ml*sizeof(ccd_cblist_elem));
00047 _MEMCHECK(l->elems);
00048 for(i=0;i<ml;i++) {
00049 l->elems[i].next = i+1;
00050 l->elems[i].prev = i-1;
00051 }
00052 l->elems[ml-1].next = -1;
00053 l->len = 0;
00054 l->maxlen = ml;
00055 l->first = l->last = -1;
00056 l->first_free = 0;
00057 l->flag = 0;
00058 }
00059
00060
00061
00063 static void expand_cblist(ccd_cblist *l, unsigned int ml)
00064 {
00065 ccd_cblist_elem *old_elems = l->elems;
00066 int i = 0;
00067 l->elems = (ccd_cblist_elem*) malloc(ml*sizeof(ccd_cblist_elem));
00068 _MEMCHECK(l->elems);
00069 for(i=0;i<(l->len);i++)
00070 l->elems[i] = old_elems[i];
00071 free(old_elems);
00072 for(i=l->len;i<ml;i++) {
00073 l->elems[i].next = i+1;
00074 l->elems[i].prev = i-1;
00075 }
00076 l->elems[ml-1].next = -1;
00077 l->elems[l->len].prev = -1;
00078 l->maxlen = ml;
00079 l->first_free = l->len;
00080 }
00081
00082
00083
00085 static void remove_elem(ccd_cblist *l, int idx)
00086 {
00087 ccd_cblist_elem *e = l->elems;
00088
00089 if(e[idx].next != (-1))
00090 e[e[idx].next].prev = e[idx].prev;
00091 if(e[idx].prev != (-1))
00092 e[e[idx].prev].next = e[idx].next;
00093 if(idx==(l->first))
00094 l->first = e[idx].next;
00095 if(idx==(l->last))
00096 l->last = e[idx].prev;
00097
00098 e[idx].prev = -1;
00099 e[idx].next = l->first_free;
00100 if(e[idx].next != (-1))
00101 e[e[idx].next].prev = idx;
00102 l->first_free = idx;
00103 l->len--;
00104 }
00105
00106
00107
00109 static void remove_n_elems(ccd_cblist *l, int n)
00110 {
00111 int i;
00112 if(n==0 || (l->len < n))
00113 return;
00114 for(i=0;i<n;i++) {
00115 remove_elem(l, l->first);
00116 }
00117 }
00118
00119
00120
00122 static int append_elem(ccd_cblist *l, CcdVoidFn fn, void *arg, int pe)
00123 {
00124 register int idx;
00125 register ccd_cblist_elem *e;
00126 if(l->len == l->maxlen)
00127 expand_cblist(l, l->maxlen*2);
00128 idx = l->first_free;
00129 e = l->elems;
00130 l->first_free = e[idx].next;
00131 e[idx].next = -1;
00132 e[idx].prev = l->last;
00133 if(l->first == (-1))
00134 l->first = idx;
00135 if(l->last != (-1))
00136 e[l->last].next = idx;
00137 l->last = idx;
00138 e[idx].cb.fn = fn;
00139 e[idx].cb.arg = arg;
00140 e[idx].cb.pe = pe;
00141 l->len++;
00142 return idx;
00143 }
00144
00145
00146
00155 static void call_cblist_keep(ccd_cblist *l,double curWallTime)
00156 {
00157 int i, len = l->len, idx;
00158 for(i=0, idx=l->first;i<len;i++) {
00159 int old = CmiSwitchToPE(l->elems[idx].cb.pe);
00160 (*(l->elems[idx].cb.fn))(l->elems[idx].cb.arg,curWallTime);
00161 CmiSwitchToPE(old);
00162 idx = l->elems[idx].next;
00163 }
00164 }
00165
00166
00167
00176 static void call_cblist_remove(ccd_cblist *l,double curWallTime)
00177 {
00178 int i, len = l->len, idx;
00179
00180 if (l->flag) return;
00181 l->flag = 1;
00182 #if ! CMK_BIGSIM_CHARM
00183 for(i=0, idx=l->first;i<len;i++) {
00184 int old = CmiSwitchToPE(l->elems[idx].cb.pe);
00185 (*(l->elems[idx].cb.fn))(l->elems[idx].cb.arg,curWallTime);
00186 CmiSwitchToPE(old);
00187 idx = l->elems[idx].next;
00188 }
00189 #else
00190 for(i=0, idx=l->last;i<len;i++) {
00191 int old = CmiSwitchToPE(l->elems[idx].cb.pe);
00192 (*(l->elems[idx].cb.fn))(l->elems[idx].cb.arg,curWallTime);
00193 CmiSwitchToPE(old);
00194 idx = l->elems[idx].prev;
00195 }
00196 #endif
00197 remove_n_elems(l,len);
00198 l->flag = 0;
00199 }
00200
00201
00202
00203 #define CBLIST_INIT_LEN 8
00204 #define MAXNUMCONDS 512
00205
00209 typedef struct {
00210 ccd_cblist condcb[MAXNUMCONDS];
00211 ccd_cblist condcb_keep[MAXNUMCONDS];
00212 } ccd_cond_callbacks;
00213
00214
00215 CpvStaticDeclare(ccd_cond_callbacks, conds);
00216
00217
00218
00219
00220 #define CCD_PERIODIC_MAX 13
00221 const static double periodicCallInterval[CCD_PERIODIC_MAX]=
00222 {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};
00223
00227 typedef struct {
00228 int nSkip;
00229 double lastCheck;
00230 double nextCall[CCD_PERIODIC_MAX];
00231 } ccd_periodic_callbacks;
00232
00234 CpvStaticDeclare(ccd_periodic_callbacks, pcb);
00235 CpvDeclare(int, _ccd_numchecks);
00236
00237
00238
00239 #define MAXTIMERHEAPENTRIES 256
00240
00244 typedef struct {
00245 double time;
00246 ccd_callback cb;
00247 } ccd_heap_elem;
00248
00249
00250
00251
00252
00253
00255 CpvStaticDeclare(ccd_heap_elem*, ccd_heap);
00257 CpvStaticDeclare(int, ccd_heaplen);
00259 CpvStaticDeclare(int, ccd_heapmaxlen);
00260
00261
00262
00264 static void ccd_heap_swap(int index1, int index2)
00265 {
00266 ccd_heap_elem *h = CpvAccess(ccd_heap);
00267 ccd_heap_elem temp;
00268
00269 temp = h[index1];
00270 h[index1] = h[index2];
00271 h[index2] = temp;
00272 }
00273
00274
00275
00284 static void expand_ccd_heap()
00285 {
00286 int i;
00287 int oldlen = CpvAccess(ccd_heapmaxlen);
00288 int newlen = oldlen*2;
00289 ccd_heap_elem *newheap;
00290
00291 CmiPrintf("[%d] Warning: ccd_heap expand from %d to %d\n", CmiMyPe(),oldlen, newlen);
00292
00293 newheap = (ccd_heap_elem*) malloc(sizeof(ccd_heap_elem)*2*(newlen+1));
00294 _MEMCHECK(newheap);
00295
00296 for (i=0; i<=oldlen; i++) {
00297 newheap[i] = CpvAccess(ccd_heap)[i];
00298 newheap[i+newlen] = CpvAccess(ccd_heap)[i+oldlen];
00299 }
00300 free(CpvAccess(ccd_heap));
00301 CpvAccess(ccd_heap) = newheap;
00302 CpvAccess(ccd_heapmaxlen) = newlen;
00303 }
00304
00305
00306
00310 static void ccd_heap_insert(double t, CcdVoidFn fnp, void *arg, int pe)
00311 {
00312 int child, parent;
00313 ccd_heap_elem *h;
00314
00315 if(CpvAccess(ccd_heaplen) >= CpvAccess(ccd_heapmaxlen)) {
00316
00317 expand_ccd_heap();
00318 }
00319
00320 h = CpvAccess(ccd_heap);
00321
00322 {
00323 ccd_heap_elem *e = &(h[++CpvAccess(ccd_heaplen)]);
00324 e->time = t;
00325 e->cb.fn = fnp;
00326 e->cb.arg = arg;
00327 e->cb.pe = pe;
00328 child = CpvAccess(ccd_heaplen);
00329 parent = child / 2;
00330 while((parent>0) && (h[child].time<h[parent].time)) {
00331 ccd_heap_swap(child, parent);
00332 child = parent;
00333 parent = parent / 2;
00334 }
00335 }
00336 }
00337
00338
00339
00343 static void ccd_heap_remove(void)
00344 {
00345 int parent,child;
00346 ccd_heap_elem *h = CpvAccess(ccd_heap);
00347
00348 parent = 1;
00349 if(CpvAccess(ccd_heaplen)>0) {
00350
00351 ccd_heap_swap(1,CpvAccess(ccd_heaplen));
00352 CpvAccess(ccd_heaplen)--;
00353 if(CpvAccess(ccd_heaplen)) {
00354
00355 child = 2 * parent;
00356 while(child <= CpvAccess(ccd_heaplen)) {
00357 if(((child + 1) <= CpvAccess(ccd_heaplen)) &&
00358 (h[child].time > h[child+1].time))
00359 child++;
00360 if(h[parent].time <= h[child].time)
00361 break;
00362 ccd_heap_swap(parent,child);
00363 parent = child;
00364 child = 2 * child;
00365 }
00366 }
00367 }
00368 }
00369
00370
00371
00376 static void ccd_heap_update(double curWallTime)
00377 {
00378 ccd_heap_elem *h = CpvAccess(ccd_heap);
00379 ccd_heap_elem *e = h+CpvAccess(ccd_heapmaxlen);
00380 int i,ne=0;
00381
00382 while ((CpvAccess(ccd_heaplen)>0) && (h[1].time<curWallTime)) {
00383 e[ne++]=h[1];
00384 ccd_heap_remove();
00385 }
00386
00387
00388
00389
00390 for (i=0;i<ne;i++) {
00391
00392
00393
00394
00395 int old = CmiSwitchToPE(e[i].cb.pe);
00396 (*(e[i].cb.fn))(e[i].cb.arg,curWallTime);
00397 CmiSwitchToPE(old);
00398 }
00399 }
00400
00401
00402
00403 void CcdCallBacksReset(void *ignored,double curWallTime);
00404
00408 void CcdModuleInit(void)
00409 {
00410 int i;
00411 double curTime;
00412 CpvInitialize(ccd_heap_elem*, ccd_heap);
00413 CpvInitialize(ccd_cond_callbacks, conds);
00414 CpvInitialize(ccd_periodic_callbacks, pcb);
00415 CpvInitialize(int, ccd_heaplen);
00416 CpvInitialize(int, ccd_heapmaxlen);
00417 CpvInitialize(int, _ccd_numchecks);
00418
00419 CpvAccess(ccd_heaplen) = 0;
00420 CpvAccess(ccd_heapmaxlen) = MAXTIMERHEAPENTRIES;
00421 CpvAccess(ccd_heap) =
00422 (ccd_heap_elem*) malloc(sizeof(ccd_heap_elem)*2*(MAXTIMERHEAPENTRIES + 1));
00423 _MEMCHECK(CpvAccess(ccd_heap));
00424 for(i=0;i<MAXNUMCONDS;i++) {
00425 init_cblist(&(CpvAccess(conds).condcb[i]), CBLIST_INIT_LEN);
00426 init_cblist(&(CpvAccess(conds).condcb_keep[i]), CBLIST_INIT_LEN);
00427 }
00428 CpvAccess(_ccd_numchecks) = 1;
00429 CpvAccess(pcb).nSkip = 1;
00430 curTime=CmiWallTimer();
00431 CpvAccess(pcb).lastCheck = curTime;
00432 for (i=0;i<CCD_PERIODIC_MAX;i++)
00433 CpvAccess(pcb).nextCall[i]=curTime+periodicCallInterval[i];
00434 CcdCallOnConditionKeep(CcdPROCESSOR_BEGIN_IDLE,CcdCallBacksReset,0);
00435 CcdCallOnConditionKeep(CcdPROCESSOR_END_IDLE,CcdCallBacksReset,0);
00436 }
00437
00438
00439
00444 int CcdCallOnCondition(int condnum, CcdVoidFn fnp, void *arg)
00445 {
00446 return append_elem(&(CpvAccess(conds).condcb[condnum]), fnp, arg, CcdIGNOREPE);
00447 }
00448
00453 int CcdCallOnConditionOnPE(int condnum, CcdVoidFn fnp, void *arg, int pe)
00454 {
00455 return append_elem(&(CpvAccess(conds).condcb[condnum]), fnp, arg, pe);
00456 }
00457
00462 int CcdCallOnConditionKeep(int condnum, CcdVoidFn fnp, void *arg)
00463 {
00464 return append_elem(&(CpvAccess(conds).condcb_keep[condnum]), fnp, arg, CcdIGNOREPE);
00465 }
00466
00471 int CcdCallOnConditionKeepOnPE(int condnum, CcdVoidFn fnp, void *arg, int pe)
00472 {
00473 return append_elem(&(CpvAccess(conds).condcb_keep[condnum]), fnp, arg, pe);
00474 }
00475
00476
00480 void CcdCancelCallOnCondition(int condnum, int idx)
00481 {
00482 remove_elem(&(CpvAccess(conds).condcb[condnum]), idx);
00483 }
00484
00485
00489 void CcdCancelCallOnConditionKeep(int condnum, int idx)
00490 {
00491 remove_elem(&(CpvAccess(conds).condcb_keep[condnum]), idx);
00492 }
00493
00494
00499 void CcdCallFnAfterOnPE(CcdVoidFn fnp, void *arg, double deltaT, int pe)
00500 {
00501 double ctime = CmiWallTimer();
00502 double tcall = ctime + deltaT/1000.0;
00503 ccd_heap_insert(tcall, fnp, arg, pe);
00504 }
00505
00510 void CcdCallFnAfter(CcdVoidFn fnp, void *arg, double deltaT)
00511 {
00512 CcdCallFnAfterOnPE(fnp, arg, deltaT, CcdIGNOREPE);
00513 }
00514
00515
00520 void CcdRaiseCondition(int condnum)
00521 {
00522 double curWallTime=CmiWallTimer();
00523 call_cblist_remove(&(CpvAccess(conds).condcb[condnum]),curWallTime);
00524 call_cblist_keep(&(CpvAccess(conds).condcb_keep[condnum]),curWallTime);
00525 }
00526
00527
00528
00529
00530
00531
00532 void CcdCallBacks()
00533 {
00534 int i;
00535 ccd_periodic_callbacks *o=&CpvAccess(pcb);
00536
00537
00538 double curWallTime = CmiWallTimer();
00539
00540 unsigned int nSkip=o->nSkip;
00541 #if 1
00542
00543 double elapsed = curWallTime - o->lastCheck;
00544 #define targetElapsed 5.0e-3
00545 if (elapsed<targetElapsed) nSkip*=2;
00546 else nSkip/=2;
00547
00548
00549 #define minSkip 1u
00550 #define maxSkip 20u
00551 if (nSkip<minSkip) nSkip=minSkip;
00552 else if (nSkip>maxSkip) nSkip=maxSkip;
00553 #else
00554
00555 nSkip=1;
00556 #endif
00557
00558 CpvAccess(_ccd_numchecks)=o->nSkip=nSkip;
00559 o->lastCheck=curWallTime;
00560
00561 ccd_heap_update(curWallTime);
00562
00563 for (i=0;i<CCD_PERIODIC_MAX;i++)
00564 if (o->nextCall[i]<=curWallTime) {
00565 CcdRaiseCondition(CcdPERIODIC+i);
00566 o->nextCall[i]=curWallTime+periodicCallInterval[i];
00567 }
00568 else
00569 break;
00570 }
00571
00572
00573
00577 void CcdCallBacksReset(void *ignored,double curWallTime)
00578 {
00579 ccd_periodic_callbacks *o=&CpvAccess(pcb);
00580 CpvAccess(_ccd_numchecks)=o->nSkip=1;
00581 o->lastCheck=curWallTime;
00582 }
00583
00584