8e324fa1045568e9bc6cadfff8bc983e1c05bb07
[charm.git] / src / ck-core / ckmemcheckpoint.C
1
2 /*
3 Charm++ support for fault tolerance of
4 In memory synchronous checkpointing and restart
5
6 written by Gengbin Zheng, gzheng@uiuc.edu
7            Lixia Shi,     lixiashi@uiuc.edu
8
9 added 12/18/03
10
11 To ensure fault tolerance while allowing migration, it uses double
12 checkpointing scheme for each array element.
13 In this version, checkpointing is done based on array elements. 
14 Each array element individully sends its checkpoint data to two buddies.
15
16 In this implementation, assume at a time only one failure happens,
17 and there is no failure during a checkpointing or restarting phase.
18
19 Restart phase contains two steps:
20 1. Converse level restart where only the newly created process for the failed
21    processor is working on restoring the system data (except array elements)
22    from its backup processor.
23 2. CkMemCheckPT gets control and recover array elements and reset all
24    states to be consistent.
25
26 TODO:
27  checkpoint scheme can be reimplemented based on per processor scheme;
28  restart phase should restore/reset group table, etc on all processors, thus flushStates() can be eliminated.
29
30 */
31
32 #include "charm++.h"
33 #include "ck.h"
34 #include "register.h"
35 #include "conv-ccs.h"
36
37 #define DEBUGF      CkPrintf
38
39 CkGroupID ckCheckPTGroupID;             // readonly
40
41 CkCallback CkMemCheckPT::cpCallback;    // static
42
43 CpvStaticDeclare(CkProcCheckPTMessage*, procChkptBuf);
44
45 // compute the backup processor
46 // FIXME: avoid crashed processors
47 inline int ChkptOnPe() { return (CkMyPe()+1)%CkNumPes(); }
48
49 // called in array element constructor
50 // choose and register with 2 buggies for checkpoiting 
51 void ArrayElement::init_checkpt() {
52         // CmiPrintf("[%d] ArrayElement::init_checkpt %d\n", CkMyPe(), info.fromMigration);
53         budPEs[0] = (CkMyPe()-1+CkNumPes())%CkNumPes();
54         budPEs[1] = (CkMyPe()+1)%CkNumPes();
55         // inform checkPTMgr
56         CProxy_CkMemCheckPT checkptMgr(ckCheckPTGroupID);
57         checkptMgr[budPEs[0]].createEntry(thisArrayID, thisArray->getLocMgr()->getGroupID(), thisIndexMax, budPEs[1]);        
58         checkptMgr[budPEs[1]].createEntry(thisArrayID, thisArray->getLocMgr()->getGroupID(), thisIndexMax, budPEs[0]);
59 }
60
61 // entry function invoked by checkpoint mgr asking for checkpoint data
62 void ArrayElement::inmem_checkpoint(CkArrayCheckPTReqMessage *m) {
63   //DEBUGF("[p%d] HERE checkpoint to %d %d \n", CkMyPe(), budPEs[0], budPEs[1]);
64   CkLocMgr *locMgr = thisArray->getLocMgr();
65   CmiAssert(myRec!=NULL);
66   int size;
67   {
68         PUP::sizer p;
69         locMgr->pupElementsFor (p, myRec, CkElementCreation_migrate);
70         size = p.size();
71   }
72   int packSize = size/sizeof(double) +1;
73   CkArrayCheckPTMessage *msg =
74                  new (packSize, 0) CkArrayCheckPTMessage;
75   msg->len = size;
76   msg->index =thisIndexMax;
77   msg->aid = thisArrayID;
78   msg->locMgr = locMgr->getGroupID();
79   msg->cp_flag = 1;
80   {
81         PUP::toMem p(msg->packData);
82         locMgr->pupElementsFor (p, myRec, CkElementCreation_migrate);
83   }
84
85   CProxy_CkMemCheckPT checkptMgr(ckCheckPTGroupID);
86   checkptMgr.recvData(msg, 2, budPEs);
87   delete m;
88 }
89
90 // called by checkpoint mgr to restore an array element
91 void CkMemCheckPT::inmem_restore(CkArrayCheckPTMessage *m) 
92 {
93   //DEBUGF("[%d] inmem_restore restore", CmiMyPe());  m->index.print();
94   PUP::fromMem p(m->packData);
95   CkLocMgr *mgr = CProxy_CkLocMgr(m->locMgr).ckLocalBranch();
96   mgr->resume(m->index, p);
97   //    reset, may not needed now
98   ArrayElement *elt = (ArrayElement *)mgr->lookup(m->index, m->aid);
99   CmiAssert(elt);
100   elt->budPEs[0] = m->bud1;
101   elt->budPEs[1] = m->bud2;
102   // for now.
103   for (int i=0; i<CK_ARRAYLISTENER_MAXLEN; i++) {
104     contributorInfo *c=(contributorInfo *)&elt->listenerData[i];
105     if (c) c->redNo = 0;
106   }
107 /*
108   contributorInfo *c=(contributorInfo *)&elt->listenerData[elt->thisArray->reducer->ckGetOffset()];
109   if (c) c->redNo = 0;
110 */
111 }
112
113 CkMemCheckPT::CkMemCheckPT()
114 {
115   if (CkNumPes() <= 3 && CkMyPe() == 0) 
116     CkPrintf("CkMemCheckPT disabled!\n");
117   inRestarting = 0;
118   recvCount = peCount = 0;
119 }
120
121 CkMemCheckPT::~CkMemCheckPT()
122 {
123 }
124
125 void CkMemCheckPT::pup(PUP::er& p) 
126
127   CBase_CkMemCheckPT::pup(p); 
128   p|cpStarter;
129   p|thisFailedPe;
130   p|failedPes;
131   p|ckCheckPTGroupID;           // recover global variable
132   p|cpCallback;                 // store callback
133   if (p.isUnpacking()) {
134     recvCount = peCount = 0;
135   }
136 }
137
138 // return 1 is pe was a crashed processor
139 int CkMemCheckPT::isFailed(int pe)
140 {
141   for (int i=0; i<failedPes.length(); i++)
142     if (failedPes[i] == pe) return 1;
143   return 0;
144 }
145
146 // add pe into history list of all failed processors
147 void CkMemCheckPT::failed(int pe)
148 {
149   if (isFailed(pe)) return;
150   failedPes.push_back(pe);
151 }
152
153 // create an checkpoint entry for array element of aid with index.
154 void CkMemCheckPT::createEntry(CkArrayID aid, CkGroupID loc, CkArrayIndexMax index, int buddy)
155 {
156   // error check, no duplicate
157   int idx, len = ckTable.size();
158   for (idx=0; idx<len; idx++) {
159     CkMemCheckPTInfo *entry = ckTable[idx];
160     if (aid == entry->aid && index == entry->index) break;
161   }
162   if (idx<len) {
163     CkPrintf("[%d] CkMemCheckPT::createEntry a duplciated entry. \n", CkMyPe());
164     CmiAbort("CkMemCheckPT::createEntry a duplciated entry");
165   }
166   CkMemCheckPTInfo *newEntry = new CkMemCheckPTInfo(aid, loc, index, buddy);
167   ckTable.push_back(newEntry);
168 }
169
170 // loop through my checkpoint table and ask checkpointed array elements
171 // to send me checkpoint data.
172 void CkMemCheckPT::doItNow(int starter, CkCallback &cb)
173 {
174   cpCallback = cb;
175   cpStarter = starter;
176   CkPrintf("[%d] Start checkpointing ... \n", CkMyPe());
177
178 //  if (iFailed()) return;
179   int len = ckTable.length();
180   for (int i=0; i<len; i++) {
181     CkMemCheckPTInfo *entry = ckTable[i];
182       // always let the bigger number processor send request
183     if (CkMyPe() < entry->pNo) continue;
184       // call inmem_checkpoint to the array element, ask it to send
185       // back checkpoint data via recvData().
186     CkArrayCheckPTReqMessage *msg = new CkArrayCheckPTReqMessage;
187     CkSendMsgArray(CkIndex_ArrayElement::inmem_checkpoint(NULL),(CkArrayMessage *)msg,entry->aid,entry->index);
188   }
189     // if my table is empty, then I am done
190   if (len == 0) thisProxy[cpStarter].cpFinish();
191
192   // pack and send proc level data
193   sendProcData();
194 }
195
196 // don't handle array elements
197 static void _handleProcData(PUP::er &p)
198 {
199     // save readonlys, and callback BTW
200     CkPupROData(p);
201
202     // save mainchares into MainChares.dat
203     if(CkMyPe()==0) {
204         CkPupMainChareData(p);
205     }
206         
207     // save groups into Groups.dat
208     CkPupGroupData(p);
209
210     // save nodegroups into NodeGroups.dat
211     CkPupNodeGroupData(p);
212 }
213
214 void CkMemCheckPT::sendProcData()
215 {
216   // find out size of buffer
217   int size;
218   {
219     PUP::sizer p;
220     _handleProcData(p);
221     size = p.size();
222   }
223   int packSize = size;
224   CkProcCheckPTMessage *msg =
225                  new (packSize, 0) CkProcCheckPTMessage;
226   DEBUGF("[%d] CkMemCheckPT::sendProcData - size: %d\n", CkMyPe(), size);
227   {
228     PUP::toMem p(msg->packData);
229     _handleProcData(p);
230   }
231   msg->pe = CkMyPe();
232   msg->len = size;
233   thisProxy[ChkptOnPe()].recvProcData(msg);
234 }
235
236 void CkMemCheckPT::recvProcData(CkProcCheckPTMessage *msg)
237 {
238   if (CpvAccess(procChkptBuf)) delete CpvAccess(procChkptBuf);
239   CpvAccess(procChkptBuf) = msg;
240   cpStarter = 0;    // fix me
241   thisProxy[cpStarter].cpFinish();
242 }
243
244 // ArrayElement call this function to give us the checkpointed data
245 void CkMemCheckPT::recvData(CkArrayCheckPTMessage *msg)
246 {
247   int len = ckTable.length();
248   int idx;
249   for (idx=0; idx<len; idx++) {
250     CkMemCheckPTInfo *entry = ckTable[idx];
251     if (msg->aid == entry->aid && msg->index == entry->index) break;
252   }
253   CkAssert(idx < len);
254   ckTable[idx]->updateBuffer(msg);
255     // all my array elements have returned their inmem data
256     // inform starter processor that I am done.
257   if (msg->cp_flag) {
258     recvCount ++;
259     if (recvCount == ckTable.length()) {
260       thisProxy[cpStarter].cpFinish();
261       recvCount = 0;
262     } 
263   }
264 }
265
266 // only is called on cpStarter
267 void CkMemCheckPT::cpFinish()
268 {
269   CmiAssert(CkMyPe() == 0);
270   peCount++;
271     // now all processors have finished, activate callback
272   if (peCount == 2*(CkNumPes())) {
273     CmiPrintf("[%d] Checkpoint finished, sending callback ... \n", CkMyPe());
274     cpCallback.send();
275     peCount = 0;
276   }
277 }
278
279 /*****************************************************************************
280                         RESTART Procedure
281 *****************************************************************************/
282
283 // loop over all CkLocMgr and do "code"
284 #define  CKLOCMGR_LOOP(code)    {       \
285   int numGroups = CkpvAccess(_groupIDTable)->size();    \
286   for(int i=0;i<numGroups;i++) {        \
287     IrrGroup *obj = CkpvAccess(_groupTable)->find((*CkpvAccess(_groupIDTable))[i]).getObj();    \
288     if(obj->isLocMgr())  {      \
289       CkLocMgr *mgr = (CkLocMgr*)obj;   \
290       code      \
291     }   \
292   }     \
293  }
294
295 // restore the bitmap vector for LB
296 void CkMemCheckPT::resetLB(int diepe)
297 {
298   int i;
299   char *bitmap = new char[CkNumPes()];
300   // set processor available bitmap
301   get_avail_vector(bitmap);
302
303   for (i=0; i<failedPes.length(); i++)
304     bitmap[failedPes[i]] = 0; 
305   bitmap[diepe] = 0;
306   set_avail_vector(bitmap);
307
308   // if I am the crashed pe, rebuild my failedPEs array
309   if (CkMyPe() == diepe)
310   for (i=0; i<CkNumPes(); i++) 
311     if (bitmap[i]==0) failed(bitmap[i]);
312
313   delete [] bitmap;
314 }
315
316 // in case when failedPe dies, everybody go through its check point table:
317 // destory all array elements
318 // recover lost buddies
319 // reconstruct all array elements from check point data
320 // called on all processors
321 void CkMemCheckPT::restart(int diePe)
322 {
323   failed(diePe);        // add into the list of failed pes
324   thisFailedPe = diePe;
325
326   CkPrintf("[%d] CkMemCheckPT ----- restart.\n",CkMyPe());
327   // clean array chkpt table
328   if (CkMyPe() == diePe) ckTable.length() = 0;
329
330   inRestarting = 1;
331                                                                                 
332   // disable load balancer's barrier
333   if (CkMyPe() != diePe) resetLB(diePe);
334
335   CKLOCMGR_LOOP(mgr->startInserting(););
336
337   thisProxy[0].quiescence(CkCallback(CkIndex_CkMemCheckPT::removeArrayElements(), thisProxy));
338   // afterwards, the QD detection should work again
339 }
340
341 void CkMemCheckPT::removeArrayElements()
342 {
343   int len = ckTable.length();
344   CkPrintf("[%d] CkMemCheckPT ----- removeArrayElements len:%d.\n",CkMyPe(),len);
345
346   if (cpCallback.isInvalid()) CkAbort("Don't set restart callback\n");;
347   if (CkMyPe()==thisFailedPe) CmiAssert(len == 0);
348
349   // get rid of all buffering and remote recs
350   CKLOCMGR_LOOP(mgr->flushStates(););
351
352   // first phase: destroy all existing array elements
353   for (int idx=0; idx<len; idx++) {
354     CkMemCheckPTInfo *entry = ckTable[idx];
355     // the bigger number PE do the destory
356     if (CkMyPe() < entry->pNo && entry->pNo != thisFailedPe) continue;
357     CkArrayMessage *msg = (CkArrayMessage *)CkAllocSysMsg();
358     msg->array_setIfNotThere(CkArray_IfNotThere_buffer);
359     CkSendMsgArray(CkIndex_ArrayElement::ckDestroy(),msg,entry->aid,entry->index);
360     //CkCallback cb(CkIndex_ArrayElement::ckDestroy(), entry->index, entry->aid);
361     //cb.send(msg);
362 //CkPrintf("[%d] Destory: ", CkMyPe()); entry->index.print();
363   }
364
365   if (CkMyPe() == 0)
366   CkStartQD(CkCallback(CkIndex_CkMemCheckPT::resetReductionMgr(), thisProxy));
367 }
368
369 // flush state in reduction manager
370 void CkMemCheckPT::resetReductionMgr()
371 {
372   CkPrintf("[%d] CkMemCheckPT ----- resetReductionMgr\n",CkMyPe());
373   int numGroups = CkpvAccess(_groupIDTable)->size();
374   for(int i=0;i<numGroups;i++) {
375     CkGroupID gID = (*CkpvAccess(_groupIDTable))[i];
376     IrrGroup *obj = CkpvAccess(_groupTable)->find(gID).getObj();
377     obj->flushStates();
378     obj->ckJustMigrated();
379   }
380   // reset again
381   //CkResetQD();
382   if (CkMyPe() == 0)
383     CkStartQD(CkCallback(CkIndex_CkMemCheckPT::recoverBuddies(), thisProxy));
384 }
385
386 // recover the lost buddies
387 void CkMemCheckPT::recoverBuddies()
388 {
389   int idx;
390   int len = ckTable.length();
391   // ready to flush reduction manager
392   // cannot be CkMemCheckPT::restart because destory will modify states
393   CkPrintf("[%d] CkMemCheckPT ----- recoverBuddies  len: %d\n",CkMyPe(),len);
394
395   //if (iFailed()) return;   ??????
396
397   // recover buddies
398   for (idx=0; idx<len; idx++) {
399     CkMemCheckPTInfo *entry = ckTable[idx];
400     if (entry->pNo == thisFailedPe) {
401       int budPe = CkMyPe();
402       while (budPe == CkMyPe() || isFailed(budPe)) budPe = CrnRand()%CkNumPes();
403       entry->pNo = budPe;
404       thisProxy[budPe].createEntry(entry->aid, entry->locMgr, entry->index, CkMyPe());
405       CmiAssert(entry->ckBuffer);
406       CkArrayCheckPTMessage *msg = (CkArrayCheckPTMessage *)CkCopyMsg((void **)&entry->ckBuffer);
407       msg->cp_flag = 0;            // not checkpointing
408       thisProxy[budPe].recvData(msg);
409     }
410   }
411
412   if (CkMyPe() == 0)
413     CkStartQD(CkCallback(CkIndex_CkMemCheckPT::recoverArrayElements(), thisProxy));
414 }
415
416 // restore 
417 void CkMemCheckPT::recoverArrayElements()
418 {
419   CkPrintf("[%d] CkMemCheckPT ----- recoverArrayElements\n",CkMyPe());
420   //if (iFailed()) return;
421
422   // recover all array elements
423   int len = ckTable.length();
424   for (int idx=0; idx<len; idx++)
425   {
426     CkMemCheckPTInfo *entry = ckTable[idx];
427     // the bigger one will do 
428     if (CkMyPe() < entry->pNo) continue;
429 //CkPrintf("[%d] restore idx:%d  ", CkMyPe(), idx); entry->index.print();
430     if (entry->ckBuffer == NULL) CmiAbort("recoverArrayElements: element does not have checkpoint data.");
431     entry->ckBuffer->bud1 = CkMyPe(); entry->ckBuffer->bud2 = entry->pNo;
432     CProxy_CkMemCheckPT checkptMgr(ckCheckPTGroupID);
433     CkArrayCheckPTMessage *msg = (CkArrayCheckPTMessage *)CkCopyMsg((void **)&entry->ckBuffer);
434     checkptMgr[CkMyPe()].inmem_restore(msg);
435   }
436
437   if (CkMyPe() == 0)
438     CkStartQD(CkCallback(CkIndex_CkMemCheckPT::finishUp(), thisProxy));
439 }
440
441 // on every processor
442 // turn load balancer back on
443 void CkMemCheckPT::finishUp()
444 {
445   int i;
446   int numGroups = CkpvAccess(_groupIDTable)->size();
447   for(i=0;i<numGroups;i++) {
448     CkGroupID gID = (*CkpvAccess(_groupIDTable))[i];
449     IrrGroup *obj = CkpvAccess(_groupTable)->find(gID).getObj();
450     if (obj->isLocMgr()) 
451       ((CkLocMgr *)obj)->doneInserting();
452   }
453   
454   inRestarting = 0;
455
456   if (CkMyPe() == 0)
457   {
458        CkPrintf("Restart finished, sending out callback ...\n");
459        CkStartQD(cpCallback);
460   } 
461 }
462
463 // called only on 0
464 void CkMemCheckPT::quiescence(CkCallback &cb)
465 {
466   static int pe_count = 0;
467   pe_count ++;
468   CmiAssert(CkMyPe() == 0);
469   CkPrintf("quiescence %d\n", pe_count);
470   if (pe_count == CkNumPes()) {
471     pe_count = 0;
472     cb.send();
473   }
474 }
475
476 // function called by user to start a check point
477 // callback cb is used to pass control back
478 void CkStartCheckPoint(CkCallback &cb)
479 {
480 #if CMK_MEM_CHECKPOINT
481     // store user callback and user data
482   CkMemCheckPT::cpCallback = cb;
483
484     // broadcast to start check pointing
485   CProxy_CkMemCheckPT checkptMgr(ckCheckPTGroupID);
486   checkptMgr.doItNow(CkMyPe(), cb);
487 #endif
488 }
489
490 void CkRestartCheckPoint(int diePe)
491 {
492 CkPrintf("CkRestartCheckPoint  CkMemCheckPT GID:%d\n", ckCheckPTGroupID.idx);
493   CProxy_CkMemCheckPT checkptMgr(ckCheckPTGroupID);
494   // broadcast
495   checkptMgr.restart(diePe);
496 }
497
498 static int _diePE;
499
500 // callback function used locally by ccs handler
501 static void CkRestartCheckPointCallback(void *ignore, void *msg)
502 {
503 CkPrintf("CkRestartCheckPointCallback activated for diePe: %d\n", _diePE);
504   CkRestartCheckPoint(_diePE);
505 }
506
507 static int askProcDataHandlerIdx;
508 static int restartBcastHandlerIdx;
509 static int recoverProcDataHandlerIdx;
510
511 static void restartBcastHandler(char *msg)
512 {
513   // advance phase counter
514   cur_restart_phase ++;
515   _diePE = *(int *)(msg+CmiMsgHeaderSizeBytes);
516
517   CkPrintf("[%d] restartBcastHandler cur_restart_phase=%d _diePE:%d.\n", CkMyPe(), cur_restart_phase, _diePE);
518
519   // reset QD counters
520   CpvAccess(_qd)->flushStates();
521
522   if (CkMyPe()==_diePE)
523       CkRestartCheckPointCallback(NULL, NULL);
524   CmiFree(msg);
525 }
526
527 extern void _initDone();
528
529 // called on crashed processor
530 static void recoverProcDataHandler(char *msg)
531 {
532    int i;
533    CmiPrintf("[%d] ----- recoverProcDataHandler  cur_restart_phase:%d\n", CkMyPe(), cur_restart_phase);
534    envelope *env = (envelope *)msg;
535    CkUnpackMessage(&env);
536    CkProcCheckPTMessage* procMsg = (CkProcCheckPTMessage *)(EnvToUsr(env));
537    cur_restart_phase = procMsg->cur_restart_phase;
538    // restore readonly, mainchare, group, nodegroup
539    PUP::fromMem p(procMsg->packData);
540    _handleProcData(p);
541
542    CProxy_CkMemCheckPT(ckCheckPTGroupID).ckLocalBranch()->resetLB(CkMyPe());
543
544    char reqmsg[CmiMsgHeaderSizeBytes+sizeof(int)];
545    *(int *)(&reqmsg[CmiMsgHeaderSizeBytes]) = CkMyPe();
546    CmiSetHandler(reqmsg, restartBcastHandlerIdx);
547    CmiSyncBroadcastAll(CmiMsgHeaderSizeBytes+sizeof(int), (char *)&reqmsg);
548    CmiFree(msg);
549
550    _initDone();
551 }
552
553 // called on its backup processor
554 // get backup message buffer and sent to crashed processor
555 static void askProcDataHandler(char *msg)
556 {
557     int diePe = *(int *)(msg+CmiMsgHeaderSizeBytes);
558     CkPrintf("[%d] restartBcastHandler called with '%d' cur_restart_phase:%d.\n",CmiMyPe(),diePe, cur_restart_phase);
559     envelope *env = (envelope *)(UsrToEnv(CpvAccess(procChkptBuf)));
560     CmiAssert(CpvAccess(procChkptBuf)!=NULL);
561     CmiAssert(CpvAccess(procChkptBuf)->pe == diePe);
562
563     CpvAccess(procChkptBuf)->cur_restart_phase = cur_restart_phase;
564
565     CkPackMessage(&env);
566     CmiSetHandler(env, recoverProcDataHandlerIdx);
567     CmiSyncSendAndFree(CpvAccess(procChkptBuf)->pe, env->getTotalsize(), (char *)env);
568     CpvAccess(procChkptBuf) = NULL;
569 }
570
571 void CkMemRestart(){
572    CmiPrintf("[%d] I am restarting  cur_restart_phase:%d \n",CmiMyPe(), cur_restart_phase);
573    char msg[CmiMsgHeaderSizeBytes+sizeof(int)];
574    *(int *)(&msg[CmiMsgHeaderSizeBytes]) = CkMyPe();
575    cur_restart_phase = 999999;             // big enough to get it processed
576    CmiSetHandler(msg, askProcDataHandlerIdx);
577    int pe = ChkptOnPe();
578    CmiSyncSend(pe, CmiMsgHeaderSizeBytes+sizeof(int), (char *)&msg);
579    cur_restart_phase=-1;
580 }
581
582 // can be called in other files
583 // return true if it is in restarting
584 int CkInRestart()
585 {
586   return CProxy_CkMemCheckPT(ckCheckPTGroupID).ckLocalBranch()->inRestarting;
587 }
588
589 /*****************************************************************************
590                 module initialization
591 *****************************************************************************/
592
593 class CkMemCheckPTInit: public Chare {
594 public:
595   CkMemCheckPTInit(CkArgMsg *m) {
596 #if CMK_MEM_CHECKPOINT
597     ckCheckPTGroupID = CProxy_CkMemCheckPT::ckNew();
598     CkPrintf("CkMemCheckPTInit main chare created!\n");
599 #endif
600   }
601 };
602
603 // initproc
604 void CkRegisterRestartHandler( )
605 {
606 #if CMK_MEM_CHECKPOINT
607   askProcDataHandlerIdx = CkRegisterHandler((CmiHandler)askProcDataHandler);
608   recoverProcDataHandlerIdx = CkRegisterHandler((CmiHandler)recoverProcDataHandler);
609   restartBcastHandlerIdx = CkRegisterHandler((CmiHandler)restartBcastHandler);
610
611   CpvInitialize(CkProcCheckPTMessage *, procChkptBuf);
612   CpvAccess(procChkptBuf) = NULL;
613
614 #if 1
615   // for debugging
616   CkPrintf("[%d] PID %d\n", CkMyPe(), getpid());
617   sleep(6);
618 #endif
619 #endif
620 }
621
622 #include "CkMemCheckpoint.def.h"
623
624