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