Documentation #1638: Fix documentation for populateInitial
[charm.git] / src / ck-core / ckcheckpoint.C
1 /*
2 Charm++ File: Checkpoint Library
3 added 01/03/2003 by Chao Huang, chuang10@uiuc.edu
4
5 More documentation goes here...
6 --- Updated 12/14/2003 by Gengbin, gzheng@uiuc.edu
7     see ckcheckpoint.h for change log
8 */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #ifndef _WIN32
13 #include <unistd.h>
14 #endif
15 #include <string.h>
16 #include <sstream>
17 using std::ostringstream;
18 #include <errno.h>
19 #include "charm++.h"
20 #include "ck.h"
21 #include "ckcheckpoint.h"
22 #include "CkCheckpoint.decl.h"
23
24 void noopit(const char*, ...)
25 {}
26
27 //#define DEBCHK   CkPrintf
28 #define DEBCHK noopit
29
30 #define DEBUGC(x) x
31 //#define DEBUGC(x) 
32
33 CkGroupID _sysChkptMgr;
34
35 typedef struct _GroupInfo{
36         CkGroupID gID;
37         int MigCtor;
38         char name[256];
39         bool present;
40 } GroupInfo;
41 PUPbytes(GroupInfo)
42 PUPmarshall(GroupInfo)
43
44 bool _inrestart = false;
45 bool _restarted = false;
46 int _oldNumPes = 0;
47 bool _chareRestored = false;
48 double chkptStartTimer = 0;
49 #if CMK_SHRINK_EXPAND
50 int originalnumGroups = -1;
51 extern int Cmi_isOldProcess;
52 extern int Cmi_myoldpe;
53 extern char *_shrinkexpand_basedir;
54 #endif
55
56 void CkCreateLocalChare(int epIdx, envelope *env);
57
58 // helper class to get number of array elements
59 class ElementCounter : public CkLocIterator {
60 private:
61         int count;
62 public:
63         ElementCounter():count(0){};
64         void addLocation(CkLocation &loc)  { count++; }
65         int getCount() { return count; }
66 };
67
68 // helper class to pup all elements that belong to same ckLocMgr
69 class ElementCheckpointer : public CkLocIterator {
70 private:
71         CkLocMgr *locMgr;
72         PUP::er &p;
73 public:
74         ElementCheckpointer(CkLocMgr* mgr_, PUP::er &p_):locMgr(mgr_),p(p_){};
75         void addLocation(CkLocation &loc) {
76                 CkArrayIndex idx=loc.getIndex();
77                 CkGroupID gID = locMgr->ckGetGroupID();
78                 CmiUInt8 id = loc.getID();
79                 p|gID;      // store loc mgr's GID as well for easier restore
80                 p|idx;
81                 p|id;
82                 p|loc;
83                 //CkPrintf("[%d] addLocation: ", CkMyPe()), idx.print();
84         }
85 };
86
87
88 extern void _initDone();
89
90 static void bdcastRO(void){
91         int i;
92         // Determine the size of the RODataMessage
93         PUP::sizer ps;
94         for(i=0;i<_readonlyTable.size();i++) _readonlyTable[i]->pupData(ps);
95
96         // Allocate and fill out the RODataMessage
97         envelope *env = _allocEnv(RODataMsg, ps.size());
98         PUP::toMem pp((char *)EnvToUsr(env));
99         for(i=0;i<_readonlyTable.size();i++) _readonlyTable[i]->pupData(pp);
100         
101         env->setCount(++_numInitMsgs);
102         env->setSrcPe(CkMyPe());
103         CmiSetHandler(env, _roRestartHandlerIdx);
104         CmiSyncBroadcastAndFree(env->getTotalsize(), (char *)env);
105 }
106
107 #if CMK_SHRINK_EXPAND
108 static void bdcastROGroupData(void){
109         int i;
110         //Determine the size of the RODataMessage
111         PUP::sizer ps, ps1;
112         CkPupROData(ps);
113         int ROSize = ps.size();
114
115         CkPupGroupData(ps1);
116         int GroupSize = ps1.size();
117
118         char *msg = (char *)CmiAlloc(CmiMsgHeaderSizeBytes + 2*sizeof(int) + ps.size() + ps1.size());
119         char *payloadOffset = msg + CmiMsgHeaderSizeBytes;
120
121         // how much data to send
122         *(int*)payloadOffset = ps.size();
123         payloadOffset += sizeof(int);
124         *(int*)payloadOffset = ps1.size();
125         payloadOffset += sizeof(int);
126
127         //Allocate and fill out the RODataMessage
128         PUP::toMem pp((char *)payloadOffset);
129         CkPupROData(pp);
130
131         CkPupGroupData(pp);
132
133         CmiSetHandler(msg, _ROGroupRestartHandlerIdx);
134         CmiSyncBroadcastAllAndFree(CmiMsgHeaderSizeBytes + 2*sizeof(int) + pp.size(), msg);
135 }
136 #endif
137
138 // Print out an array index to this string as decimal fields
139 // separated by underscores.
140 void printIndex(const CkArrayIndex &idx,char *dest) {
141         const int *idxData=idx.data();
142         for (int i=0;i<idx.nInts;i++) {
143                 sprintf(dest,"%s%d",i==0?"":"_", idxData[i]);
144                 dest+=strlen(dest);
145         }
146 }
147
148 static bool checkpointOne(const char* dirname, CkCallback& cb, bool requestStatus);
149
150 static void addPartitionDirectory(ostringstream &path) {
151         if (CmiNumPartitions() > 1) {
152           path << "/part-" << CmiMyPartition() << '/';
153         }
154 }
155
156 static FILE* openCheckpointFile(const char *dirname, const char *basename,
157                                 const char *mode, int id = -1) {
158         ostringstream out;
159         out << dirname << '/';
160         addPartitionDirectory(out);
161         out << basename;
162         if (id != -1)
163                 out << '_' << id;
164         out << ".dat";
165
166         FILE *fp = CmiFopen(out.str().c_str(), mode);
167         if (!fp) {
168                 ostringstream error;
169                 error << "PE " << CkMyPe() << " failed to open checkpoint file: " << out.str()
170                       << ", mode: " << mode << " status: " << strerror(errno);
171                 CkAbort(error.str().c_str());
172         }
173         return fp;
174 }
175
176 /**
177  * There is only one Checkpoint Manager in the whole system
178 **/
179 class CkCheckpointMgr : public CBase_CkCheckpointMgr {
180 private:
181         CkCallback restartCB;
182         double chkptStartTimer;
183         bool requestStatus;
184         int chkpStatus;
185 public:
186         CkCheckpointMgr() { }
187         CkCheckpointMgr(CkMigrateMessage *m):CBase_CkCheckpointMgr(m) { }
188         void Checkpoint(const char *dirname, CkCallback cb, bool requestStatus = false);
189         void SendRestartCB(void);
190         void pup(PUP::er& p){ p|restartCB; }
191 };
192
193 // broadcast
194 void CkCheckpointMgr::Checkpoint(const char *dirname, CkCallback cb, bool _requestStatus){
195         chkptStartTimer = CmiWallTimer();
196         requestStatus = _requestStatus;
197         // make dir on all PEs in case it is a local directory
198         CmiMkdir(dirname);
199         bool success = true;
200         if (CmiNumPartitions() > 1) {
201           ostringstream partDir;
202           partDir << dirname;
203           addPartitionDirectory(partDir);
204           CmiMkdir(partDir.str().c_str());
205         }
206
207         if (CkMyPe() == 0) {
208 #if CMK_SHRINK_EXPAND
209     if (pending_realloc_state == REALLOC_IN_PROGRESS) {
210       // After restarting from this AtSync checkpoint, resume execution along the
211       // normal path (i.e. whatever the user defined as ResumeFromSync.)
212       CkCallback resumeFromSyncCB(CkIndex_LBDatabase::ResumeClients(), _lbdb);
213       success &= checkpointOne(dirname, resumeFromSyncCB, requestStatus);
214     } else
215 #endif
216     {
217       success &= checkpointOne(dirname, cb, requestStatus);
218     }
219   }
220
221 #ifndef CMK_CHARE_USE_PTR
222         // save plain singleton chares into Chares.dat
223         FILE* fChares = openCheckpointFile(dirname, "Chares", "wb", CkMyPe());
224         PUP::toDisk pChares(fChares);
225         CkPupChareData(pChares);
226         if(pChares.checkError())
227           success = false;
228         if(CmiFclose(fChares)!=0)
229           success = false;
230 #endif
231
232         // save groups into Groups.dat
233         // content of the file: numGroups, GroupInfo[numGroups], _groupTable(PUP'ed), groups(PUP'ed)
234         FILE* fGroups = openCheckpointFile(dirname, "Groups", "wb", CkMyPe());
235         PUP::toDisk pGroups(fGroups);
236 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
237         CkPupGroupData(pGroups, true);
238 #else
239         CkPupGroupData(pGroups);
240 #endif
241         if(pGroups.checkError())
242           success = false;
243         if(CmiFclose(fGroups)!=0)
244           success = false;
245
246         // save nodegroups into NodeGroups.dat
247         // content of the file: numNodeGroups, GroupInfo[numNodeGroups], _nodeGroupTable(PUP'ed), nodegroups(PUP'ed)
248         if (CkMyRank() == 0) {
249           FILE* fNodeGroups = openCheckpointFile(dirname, "NodeGroups", "wb", CkMyNode());
250           PUP::toDisk pNodeGroups(fNodeGroups);
251 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
252           CkPupNodeGroupData(pNodeGroups, true);
253 #else
254           CkPupNodeGroupData(pNodeGroups);
255 #endif
256           if(pNodeGroups.checkError())
257             success = false;
258           if(CmiFclose(fNodeGroups)!=0)
259             success = false;
260         }
261
262         //DEBCHK("[%d]CkCheckpointMgr::Checkpoint called dirname={%s}\n",CkMyPe(),dirname);
263         FILE *datFile = openCheckpointFile(dirname, "arr", "wb", CkMyPe());
264         PUP::toDisk  p(datFile);
265         CkPupArrayElementsData(p);
266         if(p.checkError())
267           success = false;
268         if(CmiFclose(datFile)!=0)
269           success = false;
270
271 #if ! CMK_DISABLE_SYNC
272 #if CMK_HAS_SYNC_FUNC
273         sync();
274 #elif CMK_HAS_SYNC
275         system("sync");
276 #endif
277 #endif
278         chkpStatus = success?CK_CHECKPOINT_SUCCESS:CK_CHECKPOINT_FAILURE;
279         restartCB = cb;
280         DEBCHK("[%d]restartCB installed\n",CkMyPe());
281
282         // Use barrier instead of contribute here:
283         // barrier is stateless and multiple calls to it do not overlap.
284         barrier(CkCallback(CkReductionTarget(CkCheckpointMgr, SendRestartCB), 0, thisgroup));
285 }
286
287 void CkCheckpointMgr::SendRestartCB(void){
288         DEBCHK("[%d]Sending out the cb\n",CkMyPe());
289         CkPrintf("Checkpoint to disk finished in %fs, sending out the cb...\n", CmiWallTimer() - chkptStartTimer);
290         if(requestStatus)
291         {
292           CkCheckpointStatusMsg * m = new CkCheckpointStatusMsg(chkpStatus);
293           restartCB.send(m);
294         }
295         else
296           restartCB.send();
297 }
298
299 void CkPupROData(PUP::er &p)
300 {
301         int _numReadonlies = 0;
302         int _numReadonlyMsgs = 0;
303         if (!p.isUnpacking()) _numReadonlies=_readonlyTable.size();
304
305         p|_numReadonlies;
306
307         if (p.isUnpacking()) {
308           if (_numReadonlies != _readonlyTable.size())
309             CkAbort("You cannot add readonlies and restore from checkpoint...");
310         }
311         for(int i=0;i<_numReadonlies;i++) _readonlyTable[i]->pupData(p);
312         if (!p.isUnpacking()) _numReadonlyMsgs=_readonlyMsgs.size();
313         p|_numReadonlyMsgs;
314         for(int i=0;i<_numReadonlyMsgs; i++){
315                 ReadonlyMsgInfo *c = _readonlyMsgs[i];
316                 CkPupMessage(p,c->pMsg);
317         }
318 }
319
320 // handle main chare
321 void CkPupMainChareData(PUP::er &p, CkArgMsg *args)
322 {
323         int nMains=_mainTable.size();
324         DEBCHK("[%d] CkPupMainChareData %s: nMains = %d\n", CkMyPe(),p.typeString(),nMains);
325         for(int i=0;i<nMains;i++){  /* Create all mainchares */
326                 ChareInfo *entry = _chareTable[_mainTable[i]->chareIdx];
327                 int entryMigCtor = entry->getMigCtor();
328                 if(entryMigCtor!=-1) {
329                         Chare* obj;
330                         if (p.isUnpacking()) {
331                                 int size = entry->size;
332                                 DEBCHK("MainChare PUP'ed: name = %s, idx = %d, size = %d\n", entry->name, i, size);
333                                 obj = (Chare*)malloc(size);
334                                 _MEMCHECK(obj);
335                                 _mainTable[i]->setObj(obj);
336                                 //void *m = CkAllocSysMsg();
337                                 _entryTable[entryMigCtor]->call(args, obj);
338                         }
339                         else 
340                                 obj = (Chare *)_mainTable[i]->getObj();
341                         obj->virtual_pup(p);
342                 }
343         }
344         // to update mainchare proxy
345         // only readonly variables of Chare Proxy are taken care of here;
346         // in general, if chare proxy is contained in some data structure,
347         // such as CkCallback, it is user's responsibility to
348         // update them after restarting
349 #if !CMK_SHRINK_EXPAND
350         if (p.isUnpacking() && CkMyPe()==0)
351                 bdcastRO();
352 #endif
353
354 }
355
356 #ifndef CMK_CHARE_USE_PTR
357
358 CkpvExtern(std::vector<void *>, chare_objs);
359 CkpvExtern(std::vector<int>, chare_types);
360 CkpvExtern(std::vector<VidBlock *>, vidblocks);
361
362 // handle plain non-migratable chare
363 void CkPupChareData(PUP::er &p)
364 {
365   int i, n = 0;
366   if (!p.isUnpacking()) n = CkpvAccess(chare_objs).size();
367   p|n;
368   for (i=0; i<n; i++) {
369         int chare_type = 0;
370         if (!p.isUnpacking()) {
371                 chare_type = CkpvAccess(chare_types)[i];
372         }
373         p | chare_type;
374         bool pup_flag = true;
375         if (!p.isUnpacking()) {
376           if(CkpvAccess(chare_objs)[i] == NULL){
377             pup_flag = false;
378           }
379         }
380         p|pup_flag;
381         if(pup_flag)
382         {
383           if (p.isUnpacking()) {
384                   int migCtor = _chareTable[chare_type]->migCtor;
385                   if(migCtor==-1) {
386                           char buf[512];
387                           sprintf(buf,"Chare %s needs a migration constructor and PUP'er routine for restart.\n", _chareTable[chare_type]->name);
388                           CkAbort(buf);
389                   }
390                   void *m = CkAllocSysMsg();
391                   envelope* env = UsrToEnv((CkMessage *)m);
392                   CkCreateLocalChare(migCtor, env);
393                   CkFreeSysMsg(m);
394           }
395           Chare *obj = (Chare*)CkpvAccess(chare_objs)[i];
396           obj->virtual_pup(p);
397         }
398         else
399         {
400           CkpvAccess(chare_objs)[i] = NULL;
401         }
402   }
403
404   if (!p.isUnpacking()) n = CkpvAccess(vidblocks).size();
405   p|n;
406   for (i=0; i<n; i++) {
407         VidBlock *v;
408         bool pup_flag = true;
409         if (!p.isUnpacking()) {
410           if(CkpvAccess(vidblocks)[i]==NULL)
411           {
412             pup_flag = false;
413           }
414         }
415         p|pup_flag;
416         if(pup_flag)
417         {
418           if (p.isUnpacking()) {
419                   v = new VidBlock();
420                   CkpvAccess(vidblocks).push_back(v);
421           }
422           else{
423                   v = CkpvAccess(vidblocks)[i];
424           }
425           v->pup(p);
426         }
427   }
428 }
429 #else
430 void CkPupChareData(PUP::er &p)
431 {
432    // not implemented
433 }
434 #endif
435
436 typedef void GroupCreationFn(CkGroupID groupID, int constructorIdx, envelope *env);
437
438 static void CkPupPerPlaceData(PUP::er &p, GroupIDTable *idTable, GroupTable *objectTable,
439                               unsigned int &numObjects, int constructionMsgType,
440                               GroupCreationFn creationFn
441 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
442                               , bool create
443 #endif
444                              )
445 {
446   int numGroups = 0, i;
447
448   if (!p.isUnpacking()) {
449     numGroups = idTable->size();
450   }
451   p|numGroups;
452   if (p.isUnpacking()) {
453     if(CkMyPe()==0)  
454       numObjects = numGroups+1; 
455     else 
456       numObjects = 1;
457   }
458   DEBCHK("[%d] CkPupPerPlaceData %s: numGroups = %d\n", CkMyPe(),p.typeString(),numGroups);
459
460   std::vector<GroupInfo> tmpInfo(numGroups);
461   if (!p.isUnpacking()) {
462     for (i = 0; i < numGroups; i++) {
463       tmpInfo[i].gID = (*idTable)[i];
464       TableEntry ent = objectTable->find(tmpInfo[i].gID);
465       tmpInfo[i].present = ent.getObj() != NULL;
466       tmpInfo[i].MigCtor = _chareTable[ent.getcIdx()]->migCtor;
467       strncpy(tmpInfo[i].name,_chareTable[ent.getcIdx()]->name,255);
468       //CkPrintf("[%d] CkPupPerPlaceData: %s group %s \n", CkMyPe(), p.typeString(), tmpInfo[i].name);
469
470       if(tmpInfo[i].MigCtor==-1) {
471         char buf[512];
472         sprintf(buf,"(Node)Group %s needs a migration constructor and PUP'er routine for restart.\n", tmpInfo[i].name);
473         CkAbort(buf);
474       }
475     }
476   }
477   p|tmpInfo;
478
479   for (i = 0; i < numGroups; i++) 
480   {
481     if (!tmpInfo[i].present)
482       continue;
483
484     CkGroupID gID = tmpInfo[i].gID;
485     if (p.isUnpacking()) {
486       int eIdx = tmpInfo[i].MigCtor;
487       if (eIdx == -1) {
488         CkPrintf("[%d] ERROR> (Node)Group %s's migration constructor is not defined!\n", CkMyPe(), tmpInfo[i].name);
489         CkAbort("Abort");
490       }
491       void *m = CkAllocSysMsg();
492       envelope* env = UsrToEnv((CkMessage *)m);
493       env->setMsgtype(constructionMsgType);
494
495 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
496       if(create)
497 #endif
498       {
499         creationFn(gID, eIdx, env);
500       }
501     }   // end of unPacking
502     IrrGroup *gobj = objectTable->find(gID).getObj();
503
504 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
505     if(creationFn == CkCreateLocalGroup && !create)
506     {
507       gobj->mlogData->teamRecoveryFlag = 1;
508     }
509 #endif
510
511     // if using migration constructor, you'd better have a pup
512     gobj->virtual_pup(p);
513   }
514 }
515
516 void CkPupGroupData(PUP::er &p
517 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
518                     , bool create
519 #endif
520   )
521 {
522         CkPupPerPlaceData(p, CkpvAccess(_groupIDTable), CkpvAccess(_groupTable),
523                           CkpvAccess(_numGroups), BocInitMsg, &CkCreateLocalGroup
524 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
525                           , create
526 #endif
527                          );
528 }
529
530 void CkPupNodeGroupData(PUP::er &p
531 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
532                         , bool create
533 #endif
534   )
535 {
536           CkPupPerPlaceData(p, &CksvAccess(_nodeGroupIDTable),
537                             CksvAccess(_nodeGroupTable), CksvAccess(_numNodeGroups),
538                             NodeBocInitMsg, &CkCreateLocalNodeGroup
539 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
540                             , create
541 #endif
542                            );
543 }
544
545 // handle chare array elements for this processor
546 void CkPupArrayElementsData(PUP::er &p, int notifyListeners)
547 {
548         int i;
549         // safe in both packing/unpacking at this stage
550         int numGroups = CkpvAccess(_groupIDTable)->size();
551
552         // number of array elements on this processor
553         int numElements = 0;
554         if (!p.isUnpacking()) {
555           ElementCounter  counter;
556           CKLOCMGR_LOOP(mgr->iterate(counter););
557           numElements = counter.getCount();
558         }
559         p|numElements;
560
561         DEBCHK("[%d] CkPupArrayElementsData %s numGroups:%d numElements:%d \n",CkMyPe(),p.typeString(), numGroups, numElements);
562
563         if (!p.isUnpacking())
564         {
565           // let CkLocMgr iterate over and store every array element
566           CKLOCMGR_LOOP(ElementCheckpointer chk(mgr, p); mgr->iterate(chk););
567         }
568         else {
569           // loop and create all array elements ourselves
570           //CkPrintf("total chare array cnts: %d\n", numElements);
571           for (int i=0; i<numElements; i++) {
572                 CkGroupID gID;
573                 CkArrayIndex idx;
574                 CmiUInt8 id;
575                 p|gID;
576                 p|idx;
577                 p|id;
578                 CkLocMgr *mgr = (CkLocMgr*)CkpvAccess(_groupTable)->find(gID).getObj();
579                 if (notifyListeners){
580                   mgr->resume(idx, id, p, true);
581                 }
582                 else{
583                   mgr->restore(idx, id, p);
584                 }
585           }
586         }
587         // finish up
588         if (notifyListeners)
589         for(i=0;i<numGroups;i++) {
590                 IrrGroup *obj = CkpvAccess(_groupTable)->find((*CkpvAccess(_groupIDTable))[i]).getObj();
591                 if (obj)
592                   obj->ckJustMigrated();
593         }
594 }
595
596 #if __FAULT__
597 int  CkCountArrayElements(){
598     int numGroups = CkpvAccess(_groupIDTable)->size();
599     int i;
600     ElementCounter  counter;
601     CKLOCMGR_LOOP(mgr->iterate(counter););
602   int numElements = counter.getCount();
603     return numElements;
604 }
605 #endif
606
607 void CkPupProcessorData(PUP::er &p)
608 {
609     // save readonlys, and callback BTW
610     if(CkMyRank()==0) {
611         CkPupROData(p);
612     }
613
614     // save mainchares into MainChares.dat
615     if(CkMyPe()==0) {
616       CkPupMainChareData(p, NULL);
617     }
618         
619     // save non-migratable chare
620     CkPupChareData(p);
621
622     // save groups 
623 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
624     CkPupGroupData(p,true);
625 #else
626     CkPupGroupData(p);
627 #endif
628
629     // save nodegroups
630     if(CkMyRank()==0) {
631 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
632         CkPupNodeGroupData(p,true);     
633 #else
634         CkPupNodeGroupData(p);
635 #endif
636     }
637
638     // pup array elements
639     CkPupArrayElementsData(p);
640 }
641
642 // called only on pe 0
643 static bool checkpointOne(const char* dirname, CkCallback& cb, bool requestStatus){
644         CmiAssert(CkMyPe()==0);
645         char filename[1024];
646         
647         // save readonlys, and callback BTW
648         FILE* fRO = openCheckpointFile(dirname, "RO", "wb", -1);
649         PUP::toDisk pRO(fRO);
650         int _numPes = CkNumPes();
651         pRO|_numPes;
652         int _numNodes = CkNumNodes();
653
654         pRO|_numNodes;
655         pRO|cb;
656         CkPupROData(pRO);
657         pRO|requestStatus;
658
659         if(pRO.checkError())
660         {
661           return false;
662         }
663
664         if(CmiFclose(fRO)!=0)
665         {
666           return false;
667         }
668
669         // save mainchares into MainChares.dat
670         {
671                 FILE* fMain = openCheckpointFile(dirname, "MainChares", "wb", -1);
672                 PUP::toDisk pMain(fMain);
673                 CkPupMainChareData(pMain, NULL);
674                 if(pMain.checkError())
675                 {
676                   return false;
677                 }
678                 if(CmiFclose(fMain) != 0)
679                 {
680                   return false;
681                 }
682         }
683         return true;
684 }
685
686 void CkRemoveArrayElements()
687 {
688   int i;
689   int numGroups = CkpvAccess(_groupIDTable)->size();
690   CKLOCMGR_LOOP(mgr->flushAllRecs(););
691 /*  GroupTable *gTbl = CkpvAccess(_groupTable);
692   for(i=0; i<numGroups; i++){
693     IrrGroup *obj = CkpvAccess(_groupTable)->find((*CkpvAccess(_groupIDTable))[i]).getObj();
694     if(obj->isLocMgr()) {
695         CkLocMgr *mgr = (CkLocMgr *)obj;
696         mgr->flushAllRecs();
697     }
698   }*/
699 }
700
701 /*
702 void CkTestArrayElements()
703 {
704   int i;
705   int numGroups = CkpvAccess(_groupIDTable)->size();
706   //CKLOCMGR_LOOP(mgr->flushAllRecs(););
707   GroupTable *gTbl = CkpvAccess(_groupTable);
708   for(i=0; i<numGroups; i++){
709     IrrGroup *obj = CkpvAccess(_groupTable)->find((*CkpvAccess(_groupIDTable))[i]).getObj();
710     CkPrintf("An object at [%d]: %p | isLocMgr: %d\n", i, obj, obj->isLocMgr());
711   }
712 }
713 */
714
715 void CkStartCheckpoint(const char* dirname,const CkCallback& cb, bool requestStatus)
716 {
717   if(cb.isInvalid()) 
718     CkAbort("callback after checkpoint is not set properly");
719
720   if(cb.containsPointer())
721     CkAbort("Cannot restart from a callback based on a pointer");
722
723
724         CkPrintf("[%d] Checkpoint starting in %s\n", CkMyPe(), dirname);
725         
726         // hand over to checkpoint managers for per-processor checkpointing
727         CProxy_CkCheckpointMgr(_sysChkptMgr).Checkpoint(dirname, cb, requestStatus);
728 }
729
730 /**
731   * Restart: There's no such object as restart manager is created
732   *          because a group cannot restore itself anyway.
733   *          The mechanism exists as converse code and get invoked by
734   *          broadcast message.
735   **/
736
737 CkCallback cb;
738 void CkRestartMain(const char* dirname, CkArgMsg *args){
739         int i;
740         char filename[1024];
741         
742         if (CmiMyRank() == 0) {
743           _inrestart = true;
744           _restarted = true;
745           CkMemCheckPT::inRestarting = true;
746         }
747
748         // restore readonlys
749         FILE* fRO = openCheckpointFile(dirname, "RO", "rb", -1);
750         int _numPes = -1;
751         PUP::fromDisk pRO(fRO);
752         pRO|_numPes;
753         int _numNodes = -1;
754         pRO|_numNodes;
755         pRO|cb;
756         if (CmiMyRank() == 0) CkPupROData(pRO);
757         bool requestStatus = false;
758         pRO|requestStatus;
759         CmiFclose(fRO);
760         DEBCHK("[%d]CkRestartMain: readonlys restored\n",CkMyPe());
761         _oldNumPes = _numPes;
762
763         CmiNodeBarrier();
764
765         // restore mainchares
766         FILE* fMain = openCheckpointFile(dirname, "MainChares", "rb");
767         if(fMain && CkMyPe()==0){ // only main chares have been checkpointed, we restart on PE0
768                 PUP::fromDisk pMain(fMain);
769                 CkPupMainChareData(pMain, args);
770                 CmiFclose(fMain);
771                 DEBCHK("[%d]CkRestartMain: mainchares restored\n",CkMyPe());
772                 //bdcastRO(); // moved to CkPupMainChareData()
773         }
774         
775 #ifndef CMK_CHARE_USE_PTR
776         // restore chares only when number of pes is the same 
777         if(CkNumPes() == _numPes) {
778                 FILE* fChares = openCheckpointFile(dirname, "Chares", "rb", CkMyPe());
779                 PUP::fromDisk pChares(fChares);
780                 CkPupChareData(pChares);
781                 CmiFclose(fChares);
782                 if (CmiMyRank() == 0) _chareRestored = true;
783         }
784 #endif
785
786         // restore groups
787         // content of the file: numGroups, GroupInfo[numGroups], _groupTable(PUP'ed), groups(PUP'ed)
788         // restore from PE0's copy if shrink/expand
789         FILE* fGroups = openCheckpointFile(dirname, "Groups", "rb",
790                                      (CkNumPes() == _numPes) ? CkMyPe() : 0);
791         PUP::fromDisk pGroups(fGroups);
792 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
793     CkPupGroupData(pGroups,true);
794 #else
795     CkPupGroupData(pGroups);
796 #endif
797         CmiFclose(fGroups);
798
799         // restore nodegroups
800         // content of the file: numNodeGroups, GroupInfo[numNodeGroups], _nodeGroupTable(PUP'ed), nodegroups(PUP'ed)
801         if(CkMyRank()==0){
802                 FILE* fNodeGroups = openCheckpointFile(dirname, "NodeGroups", "rb",
803                                                        (CkNumNodes() == _numNodes) ? CkMyNode() : 0);
804                 PUP::fromDisk pNodeGroups(fNodeGroups);
805 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
806         CkPupNodeGroupData(pNodeGroups,true);
807 #else
808         CkPupNodeGroupData(pNodeGroups);
809 #endif
810                 CmiFclose(fNodeGroups);
811         }
812
813         // for each location, restore arrays
814         //DEBCHK("[%d]Trying to find location manager\n",CkMyPe());
815         DEBCHK("[%d]Number of PE: %d -> %d\n",CkMyPe(),_numPes,CkNumPes());
816         if(CkMyPe() < _numPes)  // in normal range: restore, otherwise, do nothing
817           for (i=0; i<_numPes;i++) {
818             if (i%CkNumPes() == CkMyPe()) {
819               FILE *datFile = openCheckpointFile(dirname, "arr", "rb", i);
820               PUP::fromDisk  p(datFile);
821               CkPupArrayElementsData(p);
822               CmiFclose(datFile);
823             }
824           }
825
826         _inrestart = false;
827
828         if (CmiMyRank()==0) _initDone();  // this rank will trigger other ranks
829         //_initDone();
830         CkMemCheckPT::inRestarting = false;
831         if(CkMyPe()==0) {
832                 CmiPrintf("[%d]CkRestartMain done. sending out callback.\n",CkMyPe());
833                 if(requestStatus)
834                 {
835                   CkCheckpointStatusMsg * m = new CkCheckpointStatusMsg(CK_CHECKPOINT_SUCCESS);
836                   cb.send(m); 
837                 }
838                 else
839                 {
840                   cb.send();
841                 }
842         }
843 }
844
845 #if CMK_SHRINK_EXPAND
846 // after resume and getting message
847 void CkResumeRestartMain(char * msg) {
848   int i;
849   char filename[1024];
850   const char * dirname = "";
851   _inrestart = true;
852   _restarted = true;
853   CkMemCheckPT::inRestarting = true;
854   CmiPrintf("[%d]CkResumeRestartMain: Inside Resume Restart\n",CkMyPe());
855   CmiPrintf("[%d]CkResumeRestartMain: Group restored %d\n",CkMyPe(), CkpvAccess(_numGroups)-1);
856
857   int _numPes = -1;
858   if(CkMyPe()!=0) {
859     PUP::fromMem pRO((char *)(msg+CmiMsgHeaderSizeBytes+2*sizeof(int)));
860
861     CkPupROData(pRO);
862     CmiPrintf("[%d]CkRestartMain: readonlys restored\n",CkMyPe());
863
864 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
865     CkPupGroupData(pRO,true);
866 #else
867     CkPupGroupData(pRO);
868 #endif
869     CmiPrintf("[%d]CkResumeRestartMain: Group restored %d\n",CkMyPe(), CkpvAccess(_numGroups)-1);
870   }
871
872   CmiFree(msg);
873   CmiNodeBarrier();
874   if(Cmi_isOldProcess) {
875     /* CmiPrintf("[%d] For shrinkexpand newpe=%d, oldpe=%d \n",Cmi_myoldpe, CkMyPe(), Cmi_myoldpe); */
876     // non-shrink files would be empty since LB would take care
877     FILE *datFile = openCheckpointFile(dirname, "arr", "rb", Cmi_myoldpe);
878     PUP::fromDisk  p(datFile);
879     CkPupArrayElementsData(p);
880     CmiFclose(datFile);
881   }
882   _initDone();
883   _inrestart = false;
884   CkMemCheckPT::inRestarting = false;
885   if(CkMyPe()==0) {
886     CmiPrintf("[%d]CkResumeRestartMain done. sending out callback.\n",CkMyPe());
887     CkPrintf("Restart from shared memory  finished in %fs, sending out the cb...\n", CmiWallTimer() - chkptStartTimer);
888     cb.send();
889   }
890 }
891 #endif
892
893 // Main chare: initialize system checkpoint manager
894 class CkCheckpointInit : public Chare {
895 public:
896   CkCheckpointInit(CkArgMsg *msg) {
897     _sysChkptMgr = CProxy_CkCheckpointMgr::ckNew();
898     delete msg;
899   }
900   CkCheckpointInit(CkMigrateMessage *m) {delete m;}
901 };
902
903 #include "CkCheckpoint.def.h"
904 #include "CkCheckpointStatus.def.h"
905