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