build: fix travis MPI/SMP build
[charm.git] / src / ck-core / cklocation.C
1 /** \file cklocation.C
2  *  \addtogroup CkArrayImpl
3  *
4  *  The location manager keeps track of an indexed set of migratable objects.
5  *  It is used by the array manager to locate array elements, interact with the
6  *  load balancer, and perform migrations.
7  *
8  *  Orion Sky Lawlor, olawlor@acm.org 9/29/2001
9  */
10
11 #include "hilbert.h"
12 #include "partitioning_strategies.h"
13 #include "charm++.h"
14 #include "register.h"
15 #include "ck.h"
16 #include "trace.h"
17 #include "TopoManager.h"
18 #include <vector>
19 #include <algorithm>
20 #include <sstream>
21 #include <limits>
22 #include "pup_stl.h"
23
24 #if CMK_LBDB_ON
25 #include "LBDatabase.h"
26 #include "MetaBalancer.h"
27 #if CMK_GLOBAL_LOCATION_UPDATE
28 #include "BaseLB.h"
29 #include "init.h"
30 #endif
31 CkpvExtern(int, _lb_obj_index);                // for lbdb user data for obj index
32 #endif // CMK_LBDB_ON
33
34 #ifndef CMK_CHARE_USE_PTR
35 CkpvExtern(int, currentChareIdx);
36 #endif
37
38 #if CMK_GRID_QUEUE_AVAILABLE
39 CpvExtern(void *, CkGridObject);
40 #endif
41
42 #define ARRAY_DEBUG_OUTPUT 0
43
44 #if ARRAY_DEBUG_OUTPUT 
45 #   define DEB(x) CkPrintf x  //General debug messages
46 #   define DEBI(x) CkPrintf x  //Index debug messages
47 #   define DEBC(x) CkPrintf x  //Construction debug messages
48 #   define DEBS(x) CkPrintf x  //Send/recv/broadcast debug messages
49 #   define DEBM(x) CkPrintf x  //Migration debug messages
50 #   define DEBL(x) CkPrintf x  //Load balancing debug messages
51 #   define DEBN(x) CkPrintf x  //Location debug messages
52 #   define DEBB(x) CkPrintf x  //Broadcast debug messages
53 #   define AA "LocMgr on %d: "
54 #   define AB ,CkMyPe()
55 #   define DEBUG(x) CkPrintf x
56 #   define DEBAD(x) CkPrintf x
57 #else
58 #   define DEB(X) /*CkPrintf x*/
59 #   define DEBI(X) /*CkPrintf x*/
60 #   define DEBC(X) /*CkPrintf x*/
61 #   define DEBS(x) /*CkPrintf x*/
62 #   define DEBM(X) /*CkPrintf x*/
63 #   define DEBL(X) /*CkPrintf x*/
64 #   define DEBN(x) /*CkPrintf x*/
65 #   define DEBB(x) /*CkPrintf x*/
66 #   define str(x) /**/
67 #   define DEBUG(x)   /**/
68 #   define DEBAD(x) /*CkPrintf x*/
69 #endif
70
71 //whether to use block mapping in the SMP node level
72 bool useNodeBlkMapping;
73
74 /// Message size above which the runtime will buffer messages directed at
75 /// unlocated array elements
76 int _messageBufferingThreshold;
77
78 #if CMK_LBDB_ON
79
80 #if CMK_GLOBAL_LOCATION_UPDATE
81 void UpdateLocation(MigrateInfo& migData) {
82
83   CkGroupID locMgrGid = ck::ObjID(migData.obj.id).getCollectionID();
84   if (locMgrGid.idx == 0) {
85     return;
86   }
87
88   CkLocMgr *localLocMgr = (CkLocMgr *) CkLocalBranch(locMgrGid);
89   localLocMgr->updateLocation(migData.obj.id, migData.to_pe);
90 }
91 #endif
92
93 #endif
94
95 /*********************** Array Messages ************************/
96 CmiUInt8 CkArrayMessage::array_element_id(void)
97 {
98   return ck::ObjID(UsrToEnv((void *)this)->getRecipientID()).getElementID();
99 }
100 unsigned short &CkArrayMessage::array_ep(void)
101 {
102         return UsrToEnv((void *)this)->getsetArrayEp();
103 }
104 unsigned short &CkArrayMessage::array_ep_bcast(void)
105 {
106         return UsrToEnv((void *)this)->getsetArrayBcastEp();
107 }
108 unsigned char &CkArrayMessage::array_hops(void)
109 {
110         return UsrToEnv((void *)this)->getsetArrayHops();
111 }
112 unsigned int CkArrayMessage::array_getSrcPe(void)
113 {
114         return UsrToEnv((void *)this)->getsetArraySrcPe();
115 }
116 unsigned int CkArrayMessage::array_ifNotThere(void)
117 {
118         return UsrToEnv((void *)this)->getArrayIfNotThere();
119 }
120 void CkArrayMessage::array_setIfNotThere(unsigned int i)
121 {
122         UsrToEnv((void *)this)->setArrayIfNotThere(i);
123 }
124
125 /*********************** Array Map ******************
126 Given an array element index, an array map tells us 
127 the index's "home" Pe.  This is the Pe the element will
128 be created on, and also where messages to this element will
129 be forwarded by default.
130 */
131
132 CkArrayMap::CkArrayMap(void) { }
133 CkArrayMap::~CkArrayMap() { }
134 int CkArrayMap::registerArray(const CkArrayIndex& numElements, CkArrayID aid)
135 {return 0;}
136 void CkArrayMap::unregisterArray(int idx)
137 { }
138
139 #define CKARRAYMAP_POPULATE_INITIAL(POPULATE_CONDITION) \
140 int i; \
141 int index[6]; \
142 int start_data[6], end_data[6], step_data[6]; \
143 for (int d = 0; d < 6; d++) { \
144   start_data[d] = 0; \
145   end_data[d] = step_data[d] = 1; \
146   if (end.dimension >= 4 && d < end.dimension) { \
147     start_data[d] = ((short int*)start.data())[d]; \
148     end_data[d] = ((short int*)end.data())[d]; \
149     step_data[d] = ((short int*)step.data())[d]; \
150   } else if (d < end.dimension) { \
151     start_data[d] = start.data()[d]; \
152     end_data[d] = end.data()[d]; \
153     step_data[d] = step.data()[d]; \
154   } \
155 } \
156  \
157 for (index[0] = start_data[0]; index[0] < end_data[0]; index[0] += step_data[0]) { \
158   for (index[1] = start_data[1]; index[1] < end_data[1]; index[1] += step_data[1]) { \
159     for (index[2] = start_data[2]; index[2] < end_data[2]; index[2] += step_data[2]) { \
160       for (index[3] = start_data[3]; index[3] < end_data[3]; index[3] += step_data[3]) { \
161         for (index[4] = start_data[4]; index[4] < end_data[4]; index[4] += step_data[4]) { \
162           for (index[5] = start_data[5]; index[5] < end_data[5]; index[5] += step_data[5]) { \
163             if (end.dimension == 1) { \
164               i = index[0]; \
165               CkArrayIndex1D idx(index[0]); \
166               if (POPULATE_CONDITION) { \
167                 mgr->insertInitial(idx,CkCopyMsg(&ctorMsg)); \
168               } \
169             } else if (end.dimension == 2) { \
170               i = index[0] * end_data[1] + index[1]; \
171               CkArrayIndex2D idx(index[0], index[1]); \
172               if (POPULATE_CONDITION) { \
173                 mgr->insertInitial(idx,CkCopyMsg(&ctorMsg)); \
174               } \
175             } else if (end.dimension == 3) { \
176               i = (index[0]*end_data[1] + index[1]) * end_data[2] + index[2]; \
177               CkArrayIndex3D idx(index[0], index[1], index[2]); \
178               if (POPULATE_CONDITION) { \
179                 mgr->insertInitial(idx,CkCopyMsg(&ctorMsg)); \
180               } \
181             } else if (end.dimension == 4) { \
182               i = ((index[0]*end_data[1] + index[1]) * end_data[2] + index[2]) * end_data[3] + index[3]; \
183               CkArrayIndex4D idx(index[0], index[1], index[2], index[3]); \
184               if (POPULATE_CONDITION) { \
185                 mgr->insertInitial(idx,CkCopyMsg(&ctorMsg)); \
186               } \
187             } else if (end.dimension == 5) { \
188               i = (((index[0]*end_data[1] + index[1]) * end_data[2] + index[2]) * end_data[3] + index[3]) * end_data[4] + index[4]; \
189               CkArrayIndex5D idx(index[0], index[1], index[2], index[3], index[4]); \
190               if (POPULATE_CONDITION) { \
191                 mgr->insertInitial(idx,CkCopyMsg(&ctorMsg)); \
192               } \
193             } else if (end.dimension == 6) { \
194               i = ((((index[0]*end_data[1] + index[1]) * end_data[2] + index[2]) * end_data[3] + index[3]) * end_data[4] + index[4]) * end_data[5] + index[5]; \
195               CkArrayIndex6D idx(index[0], index[1], index[2], index[3], index[4], index[5]); \
196               if (POPULATE_CONDITION) { \
197                 mgr->insertInitial(idx,CkCopyMsg(&ctorMsg)); \
198               } \
199             } \
200           } \
201         } \
202       } \
203     } \
204   } \
205 }
206   
207 void CkArrayMap::populateInitial(int arrayHdl,CkArrayOptions& options,void *ctorMsg,CkArray *mgr)
208 {
209   CkArrayIndex start = options.getStart();
210   CkArrayIndex end = options.getEnd();
211   CkArrayIndex step = options.getStep();
212         if (end.nInts==0) {
213           CkFreeMsg(ctorMsg);
214           return;
215         }
216         int thisPe=CkMyPe();
217         /* The CkArrayIndex is supposed to have at most 3 dimensions, which
218            means that all the fields are ints, and numElements.nInts represents
219            how many of them are used */
220         CKARRAYMAP_POPULATE_INITIAL(CMK_RANK_0(procNum(arrayHdl,idx))==thisPe);
221
222 #if CMK_BIGSIM_CHARM
223         BgEntrySplit("split-array-new-end");
224 #endif
225
226         mgr->doneInserting();
227         CkFreeMsg(ctorMsg);
228 }
229
230 void CkArrayMap::storeCkArrayOpts(CkArrayOptions options) {
231 //options will not be used on demand_creation arrays
232   storeOpts = options;
233 }
234
235 void CkArrayMap::pup(PUP::er &p) {
236   p|storeOpts;
237   p|dynamicIns;
238 }
239
240 CkGroupID _defaultArrayMapID;
241 CkGroupID _fastArrayMapID;
242
243 class RRMap : public CkArrayMap
244 {
245 private:
246   CkArrayIndex maxIndex;
247   uint64_t products[2*CK_ARRAYINDEX_MAXLEN];
248   bool productsInit;
249
250 public:
251   RRMap(void)
252   {
253     DEBC((AA "Creating RRMap\n" AB));
254     productsInit = false;
255   }
256   RRMap(CkMigrateMessage *m):CkArrayMap(m){}
257
258   void indexInit() {
259     productsInit = true;
260     maxIndex = storeOpts.getEnd();
261     products[maxIndex.dimension - 1] = 1;
262     if(maxIndex.dimension <= CK_ARRAYINDEX_MAXLEN) {
263       for(int dim = maxIndex.dimension - 2; dim >= 0; dim--) {
264         products[dim] = products[dim + 1] * maxIndex.index[dim + 1];
265       }
266     } else {
267       for(int dim = maxIndex.dimension - 2; dim >= 0; dim--) {
268         products[dim] = products[dim + 1] * maxIndex.indexShorts[dim + 1];
269       }
270     }
271   } // End of indexInit
272
273   int procNum(int arrayHdl, const CkArrayIndex &i)
274   {
275     if (i.dimension == 1) {
276       //Map 1D integer indices in simple round-robin fashion
277       int ans = (i.data()[0])%CkNumPes();
278 #if CMK_FAULT_EVAC
279       while(!CmiNodeAlive(ans) || (ans == CkMyPe() && CkpvAccess(startedEvac))){
280         ans = (ans+1)%CkNumPes();
281       }
282 #endif
283       return ans;
284     }
285     else {
286       if(dynamicIns.find(arrayHdl) != dynamicIns.end()) {
287         //Finding indicates that current array uses dynamic insertion
288         //Map other indices based on their hash code, mod a big prime.
289         unsigned int hash=(i.hash()+739)%1280107;
290         int ans = (hash % CkNumPes());
291 #if CMK_FAULT_EVAC
292         while(!CmiNodeAlive(ans)){
293           ans = (ans+1)%CkNumPes();
294         }
295 #endif
296         return ans;
297       } else {
298         if(!productsInit) { indexInit(); }
299
300         int indexOffset = 0;
301         if(i.dimension <= CK_ARRAYINDEX_MAXLEN) {
302           for(int dim = i.dimension - 1; dim >= 0; dim--) {
303             indexOffset += (i.index[dim] * products[dim]);
304           }
305         } else {
306           for(int dim = maxIndex.dimension - 1; dim >= 0; dim--) {
307             indexOffset += (i.indexShorts[dim] * products[dim]);
308           }
309         }
310         return indexOffset % CkNumPes();
311       }
312     }
313   }
314
315   void pup(PUP::er& p) {
316     CkArrayMap::pup(p);
317     p|maxIndex;
318     p|productsInit;
319     PUParray(p, products, 2*CK_ARRAYINDEX_MAXLEN);
320   }
321 };
322
323 /** 
324  * Class used to store the dimensions of the array and precalculate numChares,
325  * binSize and other values for the DefaultArrayMap -- ASB
326  */
327 class arrayMapInfo {
328 public:
329   CkArrayIndex _nelems;
330   int _binSizeFloor;            /* floor of numChares/numPes */
331   int _binSizeCeil;             /* ceiling of numChares/numPes */
332   int _numChares;               /* initial total number of chares */
333   int _remChares;               /* numChares % numPes -- equals the number of
334                                    processors in the first set */
335   int _numFirstSet;             /* _remChares X (_binSize + 1) -- number of
336                                    chares in the first set */
337
338   int _nBinSizeFloor;           /* floor of numChares/numNodes */
339   int _nRemChares;              /* numChares % numNodes -- equals the number of
340                                    nodes in the first set */
341   int _nNumFirstSet;            /* _remChares X (_binSize + 1) -- number of
342                                    chares in the first set of nodes */
343
344   /** All processors are divided into two sets. Processors in the first set
345    *  have one chare more than the processors in the second set. */
346
347   arrayMapInfo(void) { }
348
349   arrayMapInfo(const CkArrayIndex& n) : _nelems(n), _numChares(0) {
350     compute_binsize();
351   }
352
353   ~arrayMapInfo() {}
354   
355   void compute_binsize()
356   {
357     int numPes = CkNumPes();
358     //Now assuming homogenous nodes where each node has the same number of PEs
359     int numNodes = CkNumNodes();
360
361     if (_nelems.dimension == 1) {
362       _numChares = _nelems.data()[0];
363     } else if (_nelems.dimension == 2) {
364       _numChares = _nelems.data()[0] * _nelems.data()[1];
365     } else if (_nelems.dimension == 3) {
366       _numChares = _nelems.data()[0] * _nelems.data()[1] * _nelems.data()[2];
367     } else if (_nelems.dimension == 4) {
368       _numChares = (int)(((short int*)_nelems.data())[0] * ((short int*)_nelems.data())[1] * ((short int*)_nelems.data())[2] *
369                    ((short int*)_nelems.data())[3]);
370     } else if (_nelems.dimension == 5) {
371       _numChares = (int)(((short int*)_nelems.data())[0] * ((short int*)_nelems.data())[1] * ((short int*)_nelems.data())[2] *
372                    ((short int*)_nelems.data())[3] * ((short int*)_nelems.data())[4]);
373     } else if (_nelems.dimension == 6) {
374       _numChares = (int)(((short int*)_nelems.data())[0] * ((short int*)_nelems.data())[1] * ((short int*)_nelems.data())[2] *
375                    ((short int*)_nelems.data())[3] * ((short int*)_nelems.data())[4] * ((short int*)_nelems.data())[5]);
376     }
377
378     _remChares = _numChares % numPes;
379     _binSizeFloor = (int)floor((double)_numChares/(double)numPes);
380     _binSizeCeil = (int)ceil((double)_numChares/(double)numPes);
381     _numFirstSet = _remChares * (_binSizeFloor + 1);
382
383     _nRemChares = _numChares % numNodes;
384     _nBinSizeFloor = _numChares/numNodes;
385     _nNumFirstSet = _nRemChares * (_nBinSizeFloor +1);
386   }
387
388   void pup(PUP::er& p){
389     p|_nelems;
390     p|_binSizeFloor;
391     p|_binSizeCeil;
392     p|_numChares;
393     p|_remChares;
394     p|_numFirstSet;
395     p|_nBinSizeFloor;
396     p|_nRemChares;
397     p|_nNumFirstSet;
398   }
399 };
400
401
402 /**
403  * The default map object -- This does blocked mapping in the general case and
404  * calls the round-robin procNum for the dynamic insertion case -- ASB
405  */
406 class DefaultArrayMap : public RRMap
407 {
408 public:
409   /** This array stores information about different chare arrays in a Charm
410    *  program (dimensions, binsize, numChares etc ... ) */
411   CkPupPtrVec<arrayMapInfo> amaps;
412
413 public:
414   DefaultArrayMap(void) {
415     DEBC((AA "Creating DefaultArrayMap\n" AB));
416   }
417
418   DefaultArrayMap(CkMigrateMessage *m) : RRMap(m){}
419
420   int registerArray(const CkArrayIndex& numElements, CkArrayID aid)
421   {
422     int idx = amaps.size();
423     amaps.resize(idx+1);
424     amaps[idx] = new arrayMapInfo(numElements);
425     return idx;
426   }
427
428   void unregisterArray(int idx)
429   {
430     delete amaps[idx];
431     amaps[idx] = NULL;
432   }
433  
434   int procNum(int arrayHdl, const CkArrayIndex &i) {
435     int flati;
436     if (amaps[arrayHdl]->_nelems.dimension == 0) {
437       dynamicIns[arrayHdl] = true;
438       return RRMap::procNum(arrayHdl, i);
439     }
440
441     if (i.dimension == 1) {
442       flati = i.data()[0];
443     } else if (i.dimension == 2) {
444       flati = i.data()[0] * amaps[arrayHdl]->_nelems.data()[1] + i.data()[1];
445     } else if (i.dimension == 3) {
446       flati = (i.data()[0] * amaps[arrayHdl]->_nelems.data()[1] + i.data()[1]) *
447               amaps[arrayHdl]->_nelems.data()[2] + i.data()[2];
448     } else if (i.dimension == 4) {
449       flati = (int)(((((short int*)i.data())[0] * ((short int*)amaps[arrayHdl]->_nelems.data())[1] + ((short int*)i.data())[1]) *
450               ((short int*)amaps[arrayHdl]->_nelems.data())[2] + ((short int*)i.data())[2]) *
451               ((short int*)amaps[arrayHdl]->_nelems.data())[3] + ((short int*)i.data())[3]);
452     } else if (i.dimension == 5) {
453       flati = (int)((((((short int*)i.data())[0] * ((short int*)amaps[arrayHdl]->_nelems.data())[1] + ((short int*)i.data())[1]) *
454               ((short int*)amaps[arrayHdl]->_nelems.data())[2] + ((short int*)i.data())[2]) *
455               ((short int*)amaps[arrayHdl]->_nelems.data())[3] + ((short int*)i.data())[3]) *
456               ((short int*)amaps[arrayHdl]->_nelems.data())[4] + ((short int*)i.data())[4]);
457     } else if (i.dimension == 6) {
458       flati = (int)(((((((short int*)i.data())[0] * ((short int*)amaps[arrayHdl]->_nelems.data())[1] + ((short int*)i.data())[1]) *
459               ((short int*)amaps[arrayHdl]->_nelems.data())[2] + ((short int*)i.data())[2]) *
460               ((short int*)amaps[arrayHdl]->_nelems.data())[3] + ((short int*)i.data())[3]) *
461               ((short int*)amaps[arrayHdl]->_nelems.data())[4] + ((short int*)i.data())[4]) *
462               ((short int*)amaps[arrayHdl]->_nelems.data())[5] + ((short int*)i.data())[5]);
463     }
464 #if CMK_ERROR_CHECKING
465     else {
466       CkAbort("CkArrayIndex has more than 6 dimensions!");
467     }
468 #endif
469
470     if(useNodeBlkMapping){
471       if(flati < amaps[arrayHdl]->_numChares){
472         int numCharesOnNode = amaps[arrayHdl]->_nBinSizeFloor;
473         int startNodeID, offsetInNode;
474         if(flati < amaps[arrayHdl]->_nNumFirstSet){
475           numCharesOnNode++;
476           startNodeID = flati/numCharesOnNode;
477           offsetInNode = flati%numCharesOnNode;
478         }else{
479           startNodeID = amaps[arrayHdl]->_nRemChares+(flati-amaps[arrayHdl]->_nNumFirstSet)/numCharesOnNode;
480           offsetInNode = (flati-amaps[arrayHdl]->_nNumFirstSet)%numCharesOnNode;
481         }
482         int nodeSize = CkMyNodeSize(); //assuming every node has same number of PEs
483         int elemsPerPE = numCharesOnNode/nodeSize;
484         int remElems = numCharesOnNode%nodeSize;
485         int firstSetPEs = remElems*(elemsPerPE+1);
486         if(offsetInNode<firstSetPEs){
487           return CkNodeFirst(startNodeID)+offsetInNode/(elemsPerPE+1);
488         }else{
489           return CkNodeFirst(startNodeID)+remElems+(offsetInNode-firstSetPEs)/elemsPerPE;
490         }
491       } else
492           return (flati % CkNumPes());
493     }
494     //regular PE-based block mapping
495     if(flati < amaps[arrayHdl]->_numFirstSet)
496       return (flati / (amaps[arrayHdl]->_binSizeFloor + 1));
497     else if (flati < amaps[arrayHdl]->_numChares)
498       return (amaps[arrayHdl]->_remChares + (flati - amaps[arrayHdl]->_numFirstSet) / (amaps[arrayHdl]->_binSizeFloor));
499     else
500       return (flati % CkNumPes());
501   }
502
503   void pup(PUP::er& p){
504     RRMap::pup(p);
505     int npes = CkNumPes();
506     p|npes;
507     p|amaps;
508     if (p.isUnpacking() && npes != CkNumPes())  {   // binSize needs update
509       for (int i=0; i<amaps.size(); i++)
510         if (amaps[i])
511           amaps[i]->compute_binsize();
512     }
513   }
514 };
515
516 /**
517  *  A fast map for chare arrays which do static insertions and promise NOT
518  *  to do late insertions -- ASB
519  */
520 class FastArrayMap : public DefaultArrayMap
521 {
522 public:
523   FastArrayMap(void) {
524     DEBC((AA "Creating FastArrayMap\n" AB));
525   }
526
527   FastArrayMap(CkMigrateMessage *m) : DefaultArrayMap(m){}
528
529   int registerArray(const CkArrayIndex& numElements, CkArrayID aid)
530   {
531     int idx;
532     idx = DefaultArrayMap::registerArray(numElements, aid);
533
534     return idx;
535   }
536
537   int procNum(int arrayHdl, const CkArrayIndex &i) {
538     int flati = 0;
539     if (amaps[arrayHdl]->_nelems.dimension == 0) {
540       return RRMap::procNum(arrayHdl, i);
541     }
542
543     if (i.dimension == 1) {
544       flati = i.data()[0];
545     } else if (i.dimension == 2) {
546       flati = i.data()[0] * amaps[arrayHdl]->_nelems.data()[1] + i.data()[1];
547     } else if (i.dimension == 3) {
548       flati = (i.data()[0] * amaps[arrayHdl]->_nelems.data()[1] + i.data()[1]) *
549               amaps[arrayHdl]->_nelems.data()[2] + i.data()[2];
550     } else if (i.dimension == 4) {
551       flati = (int)(((((short int*)i.data())[0] * ((short int*)amaps[arrayHdl]->_nelems.data())[1] + ((short int*)i.data())[1]) *
552               ((short int*)amaps[arrayHdl]->_nelems.data())[2] + ((short int*)i.data())[2]) *
553               ((short int*)amaps[arrayHdl]->_nelems.data())[3] + ((short int*)i.data())[3]);
554     } else if (i.dimension == 5) {
555       flati = (int)((((((short int*)i.data())[0] * ((short int*)amaps[arrayHdl]->_nelems.data())[1] + ((short int*)i.data())[1]) *
556               ((short int*)amaps[arrayHdl]->_nelems.data())[2] + ((short int*)i.data())[2]) *
557               ((short int*)amaps[arrayHdl]->_nelems.data())[3] + ((short int*)i.data())[3]) *
558               ((short int*)amaps[arrayHdl]->_nelems.data())[4] + ((short int*)i.data())[4]);
559     } else if (i.dimension == 6) {
560       flati = (int)(((((((short int*)i.data())[0] * ((short int*)amaps[arrayHdl]->_nelems.data())[1] + ((short int*)i.data())[1]) *
561               ((short int*)amaps[arrayHdl]->_nelems.data())[2] + ((short int*)i.data())[2]) *
562               ((short int*)amaps[arrayHdl]->_nelems.data())[3] + ((short int*)i.data())[3]) *
563               ((short int*)amaps[arrayHdl]->_nelems.data())[4] + ((short int*)i.data())[4]) *
564               ((short int*)amaps[arrayHdl]->_nelems.data())[5] + ((short int*)i.data())[5]);
565     }
566 #if CMK_ERROR_CHECKING
567     else {
568       CkAbort("CkArrayIndex has more than 6 dimensions!");
569     }
570 #endif
571
572     /** binSize used in DefaultArrayMap is the floor of numChares/numPes
573      *  but for this FastArrayMap, we need the ceiling */
574     return (flati / amaps[arrayHdl]->_binSizeCeil);
575   }
576
577   void pup(PUP::er& p){
578     DefaultArrayMap::pup(p);
579   }
580 };
581
582 /* *
583  * Hilbert map object -- This does hilbert mapping.
584  * Convert array indices into 1D fashion according to their Hilbert filling curve 
585  */
586
587 typedef struct {
588     int intIndex;
589     std::vector<int> coords;
590 }hilbert_pair;
591
592 bool operator== ( hilbert_pair p1, hilbert_pair p2) 
593 {
594     return p1.intIndex == p2.intIndex;
595 }
596
597 bool myCompare(hilbert_pair p1, hilbert_pair p2)
598 {
599     return p1.intIndex < p2.intIndex;
600 }
601
602 class HilbertArrayMap: public DefaultArrayMap
603 {
604   std::vector<int> allpairs;
605   std::vector<int> procList;
606 public:
607   HilbertArrayMap(void) {
608     procList.resize(CkNumPes());
609     getHilbertList(procList.data());
610     DEBC((AA "Creating HilbertArrayMap\n" AB));
611   }
612
613   HilbertArrayMap(CkMigrateMessage *m) : DefaultArrayMap(m){}
614
615   ~HilbertArrayMap() {}
616
617   int registerArray(const CkArrayIndex& i, CkArrayID aid)
618   {
619     int idx;
620     idx = DefaultArrayMap::registerArray(i, aid);
621    
622     if (i.dimension == 1) {
623       //CkPrintf("1D %d\n", amaps[idx]->_nelems.data()[0]); 
624     } else if (i.dimension == 2) {
625       //CkPrintf("2D %d:%d\n", amaps[idx]->_nelems.data()[0], amaps[idx]->_nelems.data()[1]); 
626       const int dims = 2;
627       int nDim0 = amaps[idx]->_nelems.data()[0];
628       int nDim1 = amaps[idx]->_nelems.data()[1];
629       int index;
630       int counter = 0;
631       std::vector<int> coords;
632       allpairs.resize(nDim0*nDim1);
633       coords.resize(dims);
634       for(int i=0; i<nDim0; i++)
635         for(int j=0; j<nDim1; j++)
636         {
637           coords[0] = i;
638           coords[1] = j;
639           index = Hilbert_to_int( coords, dims);
640           //CkPrintf("(%d:%d)----------> %d \n", i, j, index);
641           allpairs[counter] = index;
642           counter++;
643         }
644     } else if (i.dimension == 3) {
645       //CkPrintf("3D %d:%d:%d\n", amaps[idx]->_nelems.data()[0], amaps[idx]->_nelems.data()[1],
646       //        amaps[idx]->_nelems.data()[2]);
647       const int dims = 3;
648       int nDim0 = amaps[idx]->_nelems.data()[0];
649       int nDim1 = amaps[idx]->_nelems.data()[1];
650       int nDim2 = amaps[idx]->_nelems.data()[2];
651       int index;
652       int counter = 0;
653       std::vector<int> coords;
654       allpairs.resize(nDim0*nDim1*nDim2);
655       coords.resize(dims);
656       for(int i=0; i<nDim0; i++)
657         for(int j=0; j<nDim1; j++)
658           for(int k=0; k<nDim2; k++)
659           {
660             coords[0] = i;
661             coords[1] = j;
662             coords[2] = k;
663             index = Hilbert_to_int( coords, dims);
664             allpairs[counter] = index;
665             counter++;
666           }
667     } else if (i.dimension == 4) {
668       //CkPrintf("4D %hd:%hd:%hd:%hd\n", ((short int*)amaps[idx]->_nelems.data())[0],
669       //        ((short int*)amaps[idx]->_nelems.data())[1], ((short int*)amaps[idx]->_nelems.data())[2],
670       //        ((short int*)amaps[idx]->_nelems.data())[3]);
671       const int dims = 4;
672       int nDim[dims];
673       for(int k=0; k<dims; k++) {
674         nDim[k] = (int)((short int*)amaps[idx]->_nelems.data())[k];
675       }
676       int index;
677       int counter = 0;
678       std::vector<int> coords;
679       allpairs.resize(nDim[0]*nDim[1]*nDim[2]*nDim[3]);
680       coords.resize(dims);
681       for(int i=0; i<nDim[0]; i++)
682         for(int j=0; j<nDim[1]; j++)
683           for(int k=0; k<nDim[2]; k++)
684             for(int x=0; x<nDim[3]; x++)
685             {
686               coords[0] = i;
687               coords[1] = j;
688               coords[2] = k;
689               coords[3] = x;
690               index = Hilbert_to_int(coords, dims);
691               allpairs[counter] = index;
692               counter++;
693             }
694     } else if (i.dimension == 5) {
695       //CkPrintf("5D %hd:%hd:%hd:%hd:%hd\n", ((short int*)amaps[idx]->_nelems.data())[0],
696       //        ((short int*)amaps[idx]->_nelems.data())[1], ((short int*)amaps[idx]->_nelems.data())[2],
697       //        ((short int*)amaps[idx]->_nelems.data())[3], ((short int*)amaps[idx]->_nelems.data())[4]);
698       const int dims = 5;
699       int nDim[dims];
700       for(int k=0; k<dims; k++) {
701         nDim[k] = (int)((short int*)amaps[idx]->_nelems.data())[k];
702       }
703       int index;
704       int counter = 0;
705       std::vector<int> coords;
706       allpairs.resize(nDim[0]*nDim[1]*nDim[2]*nDim[3]*nDim[4]);
707       coords.resize(dims);
708       for(int i=0; i<nDim[0]; i++)
709         for(int j=0; j<nDim[1]; j++)
710           for(int k=0; k<nDim[2]; k++)
711             for(int x=0; x<nDim[3]; x++)
712               for(int y=0; y<nDim[4]; y++)
713               {
714                 coords[0] = i;
715                 coords[1] = j;
716                 coords[2] = k;
717                 coords[3] = x;
718                 coords[4] = y;
719                 index = Hilbert_to_int(coords, dims);
720                 allpairs[counter] = index;
721                 counter++;
722               }
723     } else if (i.dimension == 6) {
724       //CkPrintf("6D %hd:%hd:%hd:%hd:%hd:%hd\n", ((short int*)amaps[idx]->_nelems.data())[0],
725       //        ((short int*)amaps[idx]->_nelems.data())[1], ((short int*)amaps[idx]->_nelems.data())[2],
726       //        ((short int*)amaps[idx]->_nelems.data())[3], ((short int*)amaps[idx]->_nelems.data())[4],
727       //        ((short int*)amaps[idx]->_nelems.data())[5]);
728       const int dims = 6;
729       int nDim[dims];
730       for(int k=0; k<dims; k++) {
731         nDim[k] = (int)((short int*)amaps[idx]->_nelems.data())[k];
732       }
733       int index;
734       int counter = 0;
735       std::vector<int> coords;
736       allpairs.resize(nDim[0]*nDim[1]*nDim[2]*nDim[3]*nDim[4]*nDim[5]);
737       coords.resize(dims);
738       for(int i=0; i<nDim[0]; i++)
739         for(int j=0; j<nDim[1]; j++)
740           for(int k=0; k<nDim[2]; k++)
741             for(int x=0; x<nDim[3]; x++)
742               for(int y=0; y<nDim[4]; y++)
743                 for(int z=0; z<nDim[5]; z++)
744                 {
745                   coords[0] = i;
746                   coords[1] = j;
747                   coords[2] = k;
748                   coords[3] = x;
749                   coords[4] = y;
750                   coords[5] = y;
751                   index = Hilbert_to_int(coords, dims);
752                   allpairs[counter] = index;
753                   counter++;
754                 }
755     }
756     return idx;
757   }
758
759   int procNum(int arrayHdl, const CkArrayIndex &i) {
760     int flati = 0;
761     int myInt;
762     int dest;
763     if (amaps[arrayHdl]->_nelems.dimension == 0) {
764       return RRMap::procNum(arrayHdl, i);
765     }
766     if (i.dimension == 1) {
767       flati = i.data()[0];
768     } else if (i.dimension == 2) {
769       int nDim1 = amaps[arrayHdl]->_nelems.data()[1];
770       myInt = i.data()[0] * nDim1 + i.data()[1];
771       flati = allpairs[myInt];
772     } else if (i.dimension == 3) {
773       hilbert_pair mypair;
774       mypair.coords.resize(3);
775       int nDim[2];
776       for (int j = 0; j < 2; j++) {
777         nDim[j] = amaps[arrayHdl]->_nelems.data()[j+1];
778       }
779       myInt = i.data()[0] * nDim[0] * nDim[1] + i.data()[1] * nDim[1] + i.data()[2];
780       flati = allpairs[myInt];
781     } else if (i.dimension == 4) {
782       hilbert_pair mypair;
783       mypair.coords.resize(4);
784       short int nDim[3];
785       for (int j = 0; j < 3; j++) {
786         nDim[j] = ((short int*)amaps[arrayHdl]->_nelems.data())[j+1];
787       }
788       myInt = (int)(((short int*)i.data())[0] * nDim[0] * nDim[1] * nDim[2] +
789               ((short int*)i.data())[1] * nDim[1] * nDim[2] +
790               ((short int*)i.data())[2] * nDim[2] +
791               ((short int*)i.data())[3]);
792       flati = allpairs[myInt];
793     } else if (i.dimension == 5) {
794       hilbert_pair mypair;
795       mypair.coords.resize(5);
796       short int nDim[4];
797       for (int j = 0; j < 4; j++) {
798         nDim[j] = ((short int*)amaps[arrayHdl]->_nelems.data())[j+1];
799       }
800       myInt = (int)(((short int*)i.data())[0] * nDim[0] * nDim[1] * nDim[2] * nDim[3] +
801               ((short int*)i.data())[1] * nDim[1] * nDim[2] * nDim[3] +
802               ((short int*)i.data())[2] * nDim[2] * nDim[3] +
803               ((short int*)i.data())[3] * nDim[3] +
804               ((short int*)i.data())[4]);
805       flati = allpairs[myInt];
806     } else if (i.dimension == 6) {
807       hilbert_pair mypair;
808       mypair.coords.resize(6);
809       short int nDim[5];
810       for (int j = 0; j < 5; j++) {
811         nDim[j] = ((short int*)amaps[arrayHdl]->_nelems.data())[j+1];
812       }
813       myInt = (int)(((short int*)i.data())[0] * nDim[0] * nDim[1] * nDim[2] * nDim[3] * nDim[4] +
814               ((short int*)i.data())[1] * nDim[1] * nDim[2] * nDim[3] * nDim[4] +
815               ((short int*)i.data())[2] * nDim[2] * nDim[3] * nDim[4] +
816               ((short int*)i.data())[3] * nDim[3] * nDim[4] +
817               ((short int*)i.data())[4] * nDim[4] +
818               ((short int*)i.data())[5]);
819       flati = allpairs[myInt];
820     }
821 #if CMK_ERROR_CHECKING
822     else {
823       CkAbort("CkArrayIndex has more than 6 dimensions!");
824     }
825 #endif
826
827     /** binSize used in DefaultArrayMap is the floor of numChares/numPes
828      *  but for this FastArrayMap, we need the ceiling */
829     int block = flati / amaps[arrayHdl]->_binSizeCeil;
830     //for(int i=0; i<CkNumPes(); i++)
831     //    CkPrintf("(%d:%d) ", i, procList[i]);
832     //CkPrintf("\n");
833     //CkPrintf("block [%d:%d]\n", block, procList[block]);
834     return procList[block];
835   }
836
837   void pup(PUP::er& p){
838     DefaultArrayMap::pup(p);
839   }
840 };
841
842
843 /**
844  * This map can be used for topology aware mapping when the mapping is provided
845  * through a file -- ASB
846  */
847 class ReadFileMap : public DefaultArrayMap
848 {
849 private:
850   std::vector<int> mapping;
851
852 public:
853   ReadFileMap(void) {
854     DEBC((AA "Creating ReadFileMap\n" AB));
855   }
856
857   ReadFileMap(CkMigrateMessage *m) : DefaultArrayMap(m){}
858
859   int registerArray(const CkArrayIndex& numElements, CkArrayID aid)
860   {
861     int idx;
862     idx = DefaultArrayMap::registerArray(numElements, aid);
863
864     if(mapping.size() == 0) {
865       int numChares;
866
867       if (amaps[idx]->_nelems.dimension == 1) {
868         numChares = amaps[idx]->_nelems.data()[0];
869       } else if (amaps[idx]->_nelems.dimension == 2) {
870         numChares = amaps[idx]->_nelems.data()[0] * amaps[idx]->_nelems.data()[1];
871       } else if (amaps[idx]->_nelems.dimension == 3) {
872         numChares = amaps[idx]->_nelems.data()[0] * amaps[idx]->_nelems.data()[1] *
873                     amaps[idx]->_nelems.data()[2];
874       } else if (amaps[idx]->_nelems.dimension == 4) {
875         numChares = (int)(((short int*)amaps[idx]->_nelems.data())[0] * ((short int*)amaps[idx]->_nelems.data())[1] *
876                     ((short int*)amaps[idx]->_nelems.data())[2] * ((short int*)amaps[idx]->_nelems.data())[3]);
877       } else if (amaps[idx]->_nelems.dimension == 5) {
878         numChares = (int)(((short int*)amaps[idx]->_nelems.data())[0] * ((short int*)amaps[idx]->_nelems.data())[1] *
879                     ((short int*)amaps[idx]->_nelems.data())[2] * ((short int*)amaps[idx]->_nelems.data())[3] *
880                     ((short int*)amaps[idx]->_nelems.data())[4]);
881       } else if (amaps[idx]->_nelems.dimension == 6) {
882         numChares = (int)(((short int*)amaps[idx]->_nelems.data())[0] * ((short int*)amaps[idx]->_nelems.data())[1] *
883                     ((short int*)amaps[idx]->_nelems.data())[2] * ((short int*)amaps[idx]->_nelems.data())[3] *
884                     ((short int*)amaps[idx]->_nelems.data())[4] * ((short int*)amaps[idx]->_nelems.data())[5]);
885       } else {
886         CkAbort("CkArrayIndex has more than 6 dimension!");
887       }
888
889       mapping.resize(numChares);
890       FILE *mapf = fopen("mapfile", "r");
891       TopoManager tmgr;
892       int x, y, z, t;
893
894       for(int i=0; i<numChares; i++) {
895         if (fscanf(mapf, "%d %d %d %d", &x, &y, &z, &t) != 4) {
896           CkAbort("ReadFileMap> reading from mapfile failed!");
897         }
898         mapping[i] = tmgr.coordinatesToRank(x, y, z, t);
899       }
900       fclose(mapf);
901     }
902
903     return idx;
904   }
905
906   int procNum(int arrayHdl, const CkArrayIndex &i) {
907     int flati;
908
909     if (i.dimension == 1) {
910       flati = i.data()[0];
911     } else if (i.dimension == 2) {
912       flati = i.data()[0] * amaps[arrayHdl]->_nelems.data()[1] + i.data()[1];
913     } else if (i.dimension == 3) {
914       flati = (i.data()[0] * amaps[arrayHdl]->_nelems.data()[1] + i.data()[1]) *
915               amaps[arrayHdl]->_nelems.data()[2] + i.data()[2];
916     } else if (i.dimension == 4) {
917       flati = (int)(((((short int*)i.data())[0] * ((short int*)amaps[arrayHdl]->_nelems.data())[1] + ((short int*)i.data())[1]) *
918               ((short int*)amaps[arrayHdl]->_nelems.data())[2] + ((short int*)i.data())[2]) *
919               ((short int*)amaps[arrayHdl]->_nelems.data())[3] + ((short int*)i.data())[3]);
920     } else if (i.dimension == 5) {
921       flati = (int)((((((short int*)i.data())[0] * ((short int*)amaps[arrayHdl]->_nelems.data())[1] + ((short int*)i.data())[1]) *
922               ((short int*)amaps[arrayHdl]->_nelems.data())[2] + ((short int*)i.data())[2]) *
923               ((short int*)amaps[arrayHdl]->_nelems.data())[3] + ((short int*)i.data())[3]) *
924               ((short int*)amaps[arrayHdl]->_nelems.data())[4] + ((short int*)i.data())[4]);
925     } else if (i.dimension == 6) {
926       flati = (int)(((((((short int*)i.data())[0] * ((short int*)amaps[arrayHdl]->_nelems.data())[1] + ((short int*)i.data())[1]) *
927               ((short int*)amaps[arrayHdl]->_nelems.data())[2] + ((short int*)i.data())[2]) *
928               ((short int*)amaps[arrayHdl]->_nelems.data())[3] + ((short int*)i.data())[3]) *
929               ((short int*)amaps[arrayHdl]->_nelems.data())[4] + ((short int*)i.data())[4]) *
930               ((short int*)amaps[arrayHdl]->_nelems.data())[5] + ((short int*)i.data())[5]);
931     } else {
932       CkAbort("CkArrayIndex has more than 6 dimensions!");
933     }
934
935     return mapping[flati];
936   }
937
938   void pup(PUP::er& p){
939     DefaultArrayMap::pup(p);
940     p|mapping;
941   }
942 };
943
944 class BlockMap : public RRMap
945 {
946 public:
947   BlockMap(void){
948     DEBC((AA "Creating BlockMap\n" AB));
949   }
950   BlockMap(CkMigrateMessage *m):RRMap(m){ }
951   void populateInitial(int arrayHdl,CkArrayOptions& options,void *ctorMsg,CkArray *mgr){
952     CkArrayIndex start = options.getStart();
953     CkArrayIndex end = options.getEnd();
954     CkArrayIndex step = options.getStep();
955     if (end.dimension == 0) {
956       CkFreeMsg(ctorMsg);
957       return;
958     }
959     int thisPe=CkMyPe();
960     int numPes=CkNumPes();
961     int binSize;
962     if (end.dimension == 1) {
963       binSize = (int)ceil((double)(end.data()[0]) / (double)numPes);
964     } else if (end.dimension == 2) {
965       binSize = (int)ceil((double)(end.data()[0] * end.data()[1]) / (double)numPes);
966     } else if (end.dimension == 3) {
967       binSize = (int)ceil((double)(end.data()[0] * end.data()[1] * end.data()[2])) / (double)numPes;
968     } else if (end.dimension == 4) {
969       binSize = (int)ceil((double)(((short int*)end.data())[0] * ((short int*)end.data())[1] *
970                 ((short int*)end.data())[2] * ((short int*)end.data())[3]) / (double)numPes);
971     } else if (end.dimension == 5) {
972       binSize = (int)ceil((double)(((short int*)end.data())[0] * ((short int*)end.data())[1] *
973                 ((short int*)end.data())[2] * ((short int*)end.data())[3] * ((short int*)end.data())[4]) /
974                 (double)numPes);
975     } else if (end.dimension == 6) {
976       binSize = (int)ceil((double)(((short int*)end.data())[0] * ((short int*)end.data())[1] *
977                 ((short int*)end.data())[2] * ((short int*)end.data())[3] * ((short int*)end.data())[4] *
978                 ((short int*)end.data())[5]) / (double)numPes);
979     } else {
980       CkAbort("CkArrayIndex has more than 6 dimensions!");
981     }
982     CKARRAYMAP_POPULATE_INITIAL(i/binSize==thisPe);
983
984     /*CkArrayIndex idx;
985     for (idx=numElements.begin(); idx<numElements; idx.getNext(numElements)) {
986       int binSize = (int)ceil((double)numElements.getCombinedCount()/(double)numPes);
987       if (i/binSize==thisPe)
988         mgr->insertInitial(idx,CkCopyMsg(&ctorMsg));
989     }*/
990     mgr->doneInserting();
991     CkFreeMsg(ctorMsg);
992   }
993 };
994
995 /**
996  * map object-- use seed load balancer.  
997  */
998 class CldMap : public CkArrayMap
999 {
1000 public:
1001   CldMap(void)
1002   {
1003           DEBC((AA "Creating CldMap\n" AB));
1004   }
1005   CldMap(CkMigrateMessage *m):CkArrayMap(m){}
1006   int homePe(int /*arrayHdl*/, const CkArrayIndex &i)
1007   {
1008     if (i.dimension == 1) {
1009       //Map 1D integer indices in simple round-robin fashion
1010       return (i.data()[0])%CkNumPes();
1011     }
1012     else 
1013       {
1014         //Map other indices based on their hash code, mod a big prime.
1015         unsigned int hash=(i.hash()+739)%1280107;
1016         return (hash % CkNumPes());
1017       }
1018   }
1019   int procNum(int arrayHdl, const CkArrayIndex &i)
1020   {
1021      return CLD_ANYWHERE;   // -1
1022   }
1023   void populateInitial(int arrayHdl,CkArrayOptions& options,void *ctorMsg,CkArray *mgr)  {
1024         CkArrayIndex start = options.getStart();
1025         CkArrayIndex end = options.getEnd();
1026         CkArrayIndex step = options.getStep();
1027         if (end.dimension == 0) {
1028           CkFreeMsg(ctorMsg);
1029           return;
1030         }
1031         int thisPe=CkMyPe();
1032         int numPes=CkNumPes();
1033
1034         CKARRAYMAP_POPULATE_INITIAL(i%numPes==thisPe);
1035         mgr->doneInserting();
1036         CkFreeMsg(ctorMsg);
1037   }
1038 };
1039
1040
1041 /// A class responsible for parsing the command line arguments for the PE
1042 /// to extract the format string passed in with +ConfigurableRRMap
1043 class ConfigurableRRMapLoader {
1044 public:
1045   
1046   std::vector<int> locations;
1047   int objs_per_block;
1048   int PE_per_block;
1049
1050   /// labels for states used when parsing the ConfigurableRRMap from ARGV
1051   enum ConfigurableRRMapLoadStatus : uint8_t {
1052     not_loaded,
1053     loaded_found,
1054     loaded_not_found
1055   };
1056   
1057   enum ConfigurableRRMapLoadStatus state;
1058   
1059   ConfigurableRRMapLoader(){
1060     state = not_loaded;
1061     objs_per_block = 0;
1062     PE_per_block = 0;
1063   }
1064   
1065   /// load configuration if possible, and return whether a valid configuration exists
1066   bool haveConfiguration() {
1067     if(state == not_loaded) {
1068       DEBUG(("[%d] loading ConfigurableRRMap configuration\n", CkMyPe()));
1069       char **argv=CkGetArgv();
1070       char *configuration = NULL;
1071       bool found = CmiGetArgString(argv, "+ConfigurableRRMap", &configuration);
1072       if(!found){
1073         DEBUG(("Couldn't find +ConfigurableRRMap command line argument\n"));
1074         state = loaded_not_found;
1075         return false;
1076       } else {
1077
1078         DEBUG(("Found +ConfigurableRRMap command line argument in %p=\"%s\"\n", configuration, configuration));
1079
1080         std::istringstream instream(configuration);
1081         CkAssert(instream.good());
1082          
1083         // Example line:
1084         // 10 8 0 1 2 3 4 5 6 7 7 7 7
1085         // Map 10 objects to 8 PEs, with each object's index among the 8 PEs.
1086         
1087         // extract first integer
1088         instream >> objs_per_block >> PE_per_block;
1089         CkAssert(instream.good());
1090         CkAssert(objs_per_block > 0);
1091         CkAssert(PE_per_block > 0);
1092         locations.resize(objs_per_block);
1093         for(int i=0;i<objs_per_block;i++){
1094           locations[i] = 0;
1095           CkAssert(instream.good());
1096           instream >> locations[i];
1097           CkAssert(locations[i] < PE_per_block);
1098         }
1099         state = loaded_found;
1100         return true;
1101       }
1102
1103     } else {
1104       DEBUG(("[%d] ConfigurableRRMap has already been loaded\n", CkMyPe()));
1105       return state == loaded_found;
1106     }      
1107      
1108   }
1109   
1110 };
1111
1112 CkpvDeclare(ConfigurableRRMapLoader, myConfigRRMapState);
1113
1114 void _initConfigurableRRMap(){
1115   CkpvInitialize(ConfigurableRRMapLoader, myConfigRRMapState);
1116 }
1117
1118
1119 /// Try to load the command line arguments for ConfigurableRRMap
1120 bool haveConfigurableRRMap(){
1121   DEBUG(("haveConfigurableRRMap()\n"));
1122   ConfigurableRRMapLoader &loader =  CkpvAccess(myConfigRRMapState);
1123   return loader.haveConfiguration();
1124 }
1125
1126 class ConfigurableRRMap : public RRMap
1127 {
1128 public:
1129   ConfigurableRRMap(void){
1130         DEBC((AA "Creating ConfigurableRRMap\n" AB));
1131   }
1132   ConfigurableRRMap(CkMigrateMessage *m):RRMap(m){ }
1133
1134
1135   void populateInitial(int arrayHdl,CkArrayOptions& options,void *ctorMsg,CkArray *mgr){
1136     CkArrayIndex start = options.getStart();
1137     CkArrayIndex end = options.getEnd();
1138     CkArrayIndex step = options.getStep();
1139     // Try to load the configuration from command line argument
1140     CkAssert(haveConfigurableRRMap());
1141     ConfigurableRRMapLoader &loader =  CkpvAccess(myConfigRRMapState);
1142     if (end.dimension == 0) {
1143       CkFreeMsg(ctorMsg);
1144       return;
1145     }
1146     int thisPe=CkMyPe();
1147     int maxIndex = end.data()[0];
1148     DEBUG(("[%d] ConfigurableRRMap: index=%d,%d,%d\n", CkMyPe(),(int)end.data()[0], (int)end.data()[1], (int)end.data()[2]));
1149
1150     if (end.dimension != 1) {
1151       CkAbort("ConfigurableRRMap only supports dimension 1!");
1152     }
1153         
1154     for (int index=0; index<maxIndex; index++) {        
1155       CkArrayIndex1D idx(index);                
1156       
1157       int cyclic_block = index / loader.objs_per_block;
1158       int cyclic_local = index % loader.objs_per_block;
1159       int l = loader.locations[ cyclic_local ];
1160       int PE = (cyclic_block*loader.PE_per_block + l) % CkNumPes();
1161
1162       DEBUG(("[%d] ConfigurableRRMap: index=%d is located on PE %d l=%d\n", CkMyPe(), (int)index, (int)PE, l));
1163
1164       if(PE == thisPe)
1165         mgr->insertInitial(idx,CkCopyMsg(&ctorMsg));
1166
1167     }
1168     //        CKARRAYMAP_POPULATE_INITIAL(PE == thisPe);
1169         
1170     mgr->doneInserting();
1171     CkFreeMsg(ctorMsg);
1172   }
1173 };
1174
1175
1176 CkpvStaticDeclare(double*, rem);
1177
1178 class arrInfo {
1179  private:
1180    CkArrayIndex _nelems;
1181    std::vector<int> _map;
1182  public:
1183    arrInfo() {}
1184    arrInfo(const CkArrayIndex& n, int *speeds) : _nelems(n), _map(_nelems.getCombinedCount())
1185    {
1186      distrib(speeds);
1187    }
1188    ~arrInfo() {}
1189    int getMap(const CkArrayIndex &i);
1190    void distrib(int *speeds);
1191    void pup(PUP::er& p){
1192      p|_nelems;
1193      p|_map;
1194    }
1195 };
1196
1197 static int cmp(const void *first, const void *second)
1198 {
1199   int fi = *((const int *)first);
1200   int si = *((const int *)second);
1201   return ((CkpvAccess(rem)[fi]==CkpvAccess(rem)[si]) ?
1202           0 :
1203           ((CkpvAccess(rem)[fi]<CkpvAccess(rem)[si]) ?
1204           1 : (-1)));
1205 }
1206
1207 void
1208 arrInfo::distrib(int *speeds)
1209 {
1210   int _nelemsCount = _nelems.getCombinedCount();
1211   double total = 0.0;
1212   int npes = CkNumPes();
1213   int i,j,k;
1214   for(i=0;i<npes;i++)
1215     total += (double) speeds[i];
1216   std::vector<double> nspeeds(npes);
1217   for(i=0;i<npes;i++)
1218     nspeeds[i] = (double) speeds[i] / total;
1219   std::vector<int> cp(npes);
1220   for(i=0;i<npes;i++)
1221     cp[i] = (int) (nspeeds[i]*_nelemsCount);
1222   int nr = 0;
1223   for(i=0;i<npes;i++)
1224     nr += cp[i];
1225   nr = _nelemsCount - nr;
1226   if(nr != 0)
1227   {
1228     CkpvAccess(rem) = new double[npes];
1229     for(i=0;i<npes;i++)
1230       CkpvAccess(rem)[i] = (double)_nelemsCount*nspeeds[i] - cp[i];
1231     std::vector<int> pes(npes);
1232     for(i=0;i<npes;i++)
1233       pes[i] = i;
1234     qsort(pes.data(), npes, sizeof(int), cmp);
1235     for(i=0;i<nr;i++)
1236       cp[pes[i]]++;
1237     delete[] CkpvAccess(rem);
1238   }
1239   k = 0;
1240   for(i=0;i<npes;i++)
1241   {
1242     for(j=0;j<cp[i];j++)
1243       _map[k++] = i;
1244   }
1245 }
1246
1247 int
1248 arrInfo::getMap(const CkArrayIndex &i)
1249 {
1250   if(i.dimension == 1)
1251     return _map[i.data()[0]];
1252   else
1253     return _map[((i.hash()+739)%1280107)%_nelems.getCombinedCount()];
1254 }
1255
1256 //Speeds maps processor number to "speed" (some sort of iterations per second counter)
1257 // It is initialized by processor 0.
1258 static int* speeds;
1259
1260 #if CMK_USE_PROP_MAP
1261 typedef struct _speedmsg
1262 {
1263   char hdr[CmiMsgHeaderSizeBytes];
1264   int node;
1265   int speed;
1266 } speedMsg;
1267
1268 static void _speedHdlr(void *m)
1269 {
1270   speedMsg *msg=(speedMsg *)m;
1271   if (CmiMyRank()==0)
1272     for (int pe=0;pe<CmiNodeSize(msg->node);pe++)
1273       speeds[CmiNodeFirst(msg->node)+pe] = msg->speed;  
1274   CmiFree(m);
1275 }
1276
1277 // initnode call
1278 void _propMapInit(void)
1279 {
1280   speeds = new int[CkNumPes()];
1281   int hdlr = CkRegisterHandler(_speedHdlr);
1282   CmiPrintf("[%d]Measuring processor speed for prop. mapping...\n", CkMyPe());
1283   int s = LDProcessorSpeed();
1284   speedMsg msg;
1285   CmiSetHandler(&msg, hdlr);
1286   msg.node = CkMyNode();
1287   msg.speed = s;
1288   CmiSyncBroadcastAllAndFree(sizeof(msg), &msg);
1289   for(int i=0;i<CkNumNodes();i++)
1290     CmiDeliverSpecificMsg(hdlr);
1291 }
1292 #else
1293 void _propMapInit(void)
1294 {
1295   speeds = new int[CkNumPes()];
1296   int i;
1297   for(i=0;i<CkNumPes();i++)
1298     speeds[i] = 1;
1299 }
1300 #endif
1301 /**
1302  * A proportional map object-- tries to map more objects to
1303  * faster processors and fewer to slower processors.  Also
1304  * attempts to ensure good locality by mapping nearby elements
1305  * together.
1306  */
1307 class PropMap : public CkArrayMap
1308 {
1309 private:
1310   CkPupPtrVec<arrInfo> arrs;
1311 public:
1312   PropMap(void)
1313   {
1314     CkpvInitialize(double*, rem);
1315     DEBC((AA "Creating PropMap\n" AB));
1316   }
1317   PropMap(CkMigrateMessage *m) {}
1318   int registerArray(const CkArrayIndex& numElements, CkArrayID aid)
1319   {
1320     int idx = arrs.size();
1321     arrs.resize(idx+1);
1322     arrs[idx] = new arrInfo(numElements, speeds);
1323     return idx;
1324   }
1325   void unregisterArray(int idx)
1326   {
1327     arrs[idx].destroy();
1328   }
1329   int procNum(int arrayHdl, const CkArrayIndex &i)
1330   {
1331     return arrs[arrayHdl]->getMap(i);
1332   }
1333   void pup(PUP::er& p){
1334     int oldNumPes = -1;
1335     if(p.isPacking()){
1336       oldNumPes = CkNumPes();
1337     }
1338     p|oldNumPes;
1339     p|arrs;
1340     if(p.isUnpacking() && oldNumPes != CkNumPes()){
1341       for(int idx = 0; idx < arrs.length(); ++idx){
1342         arrs[idx]->distrib(speeds);
1343       }
1344     }
1345   }
1346 };
1347
1348 class CkMapsInit : public Chare
1349 {
1350 public:
1351         CkMapsInit(CkArgMsg *msg) {
1352                 //_defaultArrayMapID = CProxy_HilbertArrayMap::ckNew();
1353                 _defaultArrayMapID = CProxy_DefaultArrayMap::ckNew();
1354                 _fastArrayMapID = CProxy_FastArrayMap::ckNew();
1355                 delete msg;
1356         }
1357
1358         CkMapsInit(CkMigrateMessage *m) {}
1359 };
1360
1361 // given an envelope of a Charm msg, find the recipient object pointer
1362 CkMigratable * CkArrayMessageObjectPtr(envelope *env) {
1363   if (env->getMsgtype() != ForArrayEltMsg)
1364       return NULL;   // not an array msg
1365
1366   ///@todo: Delegate this to the array manager which can then deal with ForArrayEltMsg
1367   CkArray *mgr = CProxy_CkArray(env->getArrayMgr()).ckLocalBranch();
1368   return mgr ? mgr->lookup(ck::ObjID(env->getRecipientID()).getElementID()) : NULL;
1369 }
1370
1371 /****************************** Out-of-Core support ********************/
1372
1373 #if CMK_OUT_OF_CORE
1374 CooPrefetchManager CkArrayElementPrefetcher;
1375 CkpvDeclare(int,CkSaveRestorePrefetch);
1376
1377 /**
1378  * Return the out-of-core objid (from CooRegisterObject)
1379  * that this Converse message will access.  If the message
1380  * will not access an object, return -1.
1381  */
1382 int CkArrayPrefetch_msg2ObjId(void *msg) {
1383   envelope *env=(envelope *)msg;
1384   CkMigratable *elt = CkArrayMessageObjectPtr(env);
1385   return elt?elt->prefetchObjID:-1;
1386 }
1387
1388 /**
1389  * Write this object (registered with RegisterObject)
1390  * to this writable file.
1391  */
1392 void CkArrayPrefetch_writeToSwap(FILE *swapfile,void *objptr) {
1393   CkMigratable *elt=(CkMigratable *)objptr;
1394
1395   //Save the element's data to disk:
1396   PUP::toDisk p(swapfile);
1397   elt->virtual_pup(p);
1398
1399   //Call the element's destructor in-place (so pointer doesn't change)
1400   CkpvAccess(CkSaveRestorePrefetch)=1;
1401   elt->~CkMigratable(); //< because destructor is virtual, destroys user class too.
1402   CkpvAccess(CkSaveRestorePrefetch)=0;
1403 }
1404         
1405 /**
1406  * Read this object (registered with RegisterObject)
1407  * from this readable file.
1408  */
1409 void CkArrayPrefetch_readFromSwap(FILE *swapfile,void *objptr) {
1410   CkMigratable *elt=(CkMigratable *)objptr;
1411   //Call the element's migration constructor in-place
1412   CkpvAccess(CkSaveRestorePrefetch)=1;
1413   int ctorIdx=_chareTable[elt->thisChareType]->migCtor;
1414   elt->myRec->invokeEntry(elt,(CkMigrateMessage *)0,ctorIdx,true);
1415   CkpvAccess(CkSaveRestorePrefetch)=0;
1416   
1417   //Restore the element's data from disk:
1418   PUP::fromDisk p(swapfile);
1419   elt->virtual_pup(p);
1420 }
1421
1422 static void _CkMigratable_prefetchInit(void) 
1423 {
1424   CkpvExtern(int,CkSaveRestorePrefetch);
1425   CkpvAccess(CkSaveRestorePrefetch)=0;
1426   CkArrayElementPrefetcher.msg2ObjId=CkArrayPrefetch_msg2ObjId;
1427   CkArrayElementPrefetcher.writeToSwap=CkArrayPrefetch_writeToSwap;
1428   CkArrayElementPrefetcher.readFromSwap=CkArrayPrefetch_readFromSwap;
1429   CooRegisterManager(&CkArrayElementPrefetcher, _charmHandlerIdx);
1430 }
1431 #endif
1432
1433 /****************************** CkMigratable ***************************/
1434 /**
1435  * This tiny class is used to convey information to the 
1436  * newly created CkMigratable object when its constructor is called.
1437  */
1438 class CkMigratable_initInfo {
1439 public:
1440         CkLocRec *locRec;
1441         int chareType;
1442         bool forPrefetch; /* If true, this creation is only a prefetch restore-from-disk.*/
1443 };
1444
1445 CkpvStaticDeclare(CkMigratable_initInfo,mig_initInfo);
1446
1447
1448 void _CkMigratable_initInfoInit(void) {
1449   CkpvInitialize(CkMigratable_initInfo,mig_initInfo);
1450 #if CMK_OUT_OF_CORE
1451   _CkMigratable_prefetchInit();
1452 #endif
1453 }
1454
1455 void CkMigratable::commonInit(void) {
1456         CkMigratable_initInfo &i=CkpvAccess(mig_initInfo);
1457 #if CMK_OUT_OF_CORE
1458         isInCore=true;
1459         if (CkpvAccess(CkSaveRestorePrefetch))
1460                 return; /* Just restoring from disk--don't touch object */
1461         prefetchObjID=-1; //Unregistered
1462 #endif
1463         myRec=i.locRec;
1464         thisIndexMax=myRec->getIndex();
1465         thisChareType=i.chareType;
1466         usesAtSync=false;
1467         usesAutoMeasure=true;
1468         barrierRegistered=false;
1469
1470   local_state = OFF;
1471   prev_load = 0.0;
1472   can_reset = false;
1473
1474 #if CMK_LBDB_ON
1475   if (_lb_args.metaLbOn()) {
1476     atsync_iteration = myRec->getMetaBalancer()->get_iteration();
1477     myRec->getMetaBalancer()->AdjustCountForNewContributor(atsync_iteration);
1478   }
1479 #endif
1480
1481 #if CMK_FAULT_EVAC
1482         AsyncEvacuate(true);
1483 #endif
1484 }
1485
1486 CkMigratable::CkMigratable(void) {
1487         DEBC((AA "In CkMigratable constructor\n" AB));
1488         commonInit();
1489 }
1490 CkMigratable::CkMigratable(CkMigrateMessage *m): Chare(m) {
1491         commonInit();
1492 }
1493
1494 int CkMigratable::ckGetChareType(void) const {return thisChareType;}
1495
1496 void CkMigratable::pup(PUP::er &p) {
1497         DEBM((AA "In CkMigratable::pup %s\n" AB,idx2str(thisIndexMax)));
1498         Chare::pup(p);
1499         p|thisIndexMax;
1500         p(usesAtSync);
1501   p(can_reset);
1502         p(usesAutoMeasure);
1503 #if CMK_LBDB_ON 
1504         int readyMigrate = 0;
1505         if (p.isPacking()) readyMigrate = myRec->isReadyMigrate();
1506         p|readyMigrate;
1507         if (p.isUnpacking()) myRec->ReadyMigrate(readyMigrate);
1508 #endif
1509         if(p.isUnpacking()) barrierRegistered=false;
1510
1511 #if CMK_FAULT_EVAC
1512         p | asyncEvacuate;
1513         if(p.isUnpacking()){myRec->AsyncEvacuate(asyncEvacuate);}
1514 #endif
1515         
1516         ckFinishConstruction();
1517 }
1518
1519 void CkMigratable::ckDestroy(void) {}
1520 void CkMigratable::ckAboutToMigrate(void) { }
1521 void CkMigratable::ckJustMigrated(void) { }
1522 void CkMigratable::ckJustRestored(void) { }
1523
1524 CkMigratable::~CkMigratable() {
1525         DEBC((AA "In CkMigratable::~CkMigratable %s\n" AB,idx2str(thisIndexMax)));
1526 #if CMK_OUT_OF_CORE
1527         isInCore=false;
1528         if (CkpvAccess(CkSaveRestorePrefetch)) 
1529                 return; /* Just saving to disk--don't deregister anything. */
1530         /* We're really leaving or dying-- unregister from the ooc system*/
1531         if (prefetchObjID!=-1) {
1532                 CooDeregisterObject(prefetchObjID);
1533                 prefetchObjID=-1;
1534         }
1535 #endif
1536 #if CMK_LBDB_ON 
1537         if (barrierRegistered) {
1538           DEBL((AA "Removing barrier for element %s\n" AB,idx2str(thisIndexMax)));
1539           if (usesAtSync)
1540                 myRec->getLBDB()->RemoveLocalBarrierClient(ldBarrierHandle);
1541           else
1542                 myRec->getLBDB()->RemoveLocalBarrierReceiver(ldBarrierRecvHandle);
1543         }
1544
1545   if (_lb_args.metaLbOn()) {
1546     myRec->getMetaBalancer()->AdjustCountForDeadContributor(atsync_iteration);
1547   }
1548 #endif
1549         myRec->destroy(); /* Attempt to delete myRec if it's no longer in use */
1550         //To detect use-after-delete
1551         thisIndexMax.nInts=0;
1552         thisIndexMax.dimension=0;
1553 }
1554
1555 void CkMigratable::CkAbort(const char *why) const {
1556         CkError("CkMigratable '%s' aborting:\n",_chareTable[thisChareType]->name);
1557         ::CkAbort(why);
1558 }
1559
1560 void CkMigratable::ResumeFromSync(void)
1561 {
1562 //      CkAbort("::ResumeFromSync() not defined for this array element!\n");
1563 }
1564
1565 void CkMigratable::UserSetLBLoad() {
1566         CkAbort("::UserSetLBLoad() not defined for this array element!\n");
1567 }
1568
1569 #if CMK_LBDB_ON  //For load balancing:
1570 // user can call this helper function to set obj load (for model-based lb)
1571 void CkMigratable::setObjTime(double cputime) {
1572         myRec->setObjTime(cputime);
1573 }
1574 double CkMigratable::getObjTime() {
1575         return myRec->getObjTime();
1576 }
1577
1578 #if CMK_LB_USER_DATA
1579 /**
1580 * Use this method to set user specified data to the lbdatabase.
1581 *
1582 * Eg usage: 
1583 * In the application code,
1584 *   void *data = getObjUserData(CkpvAccess(_lb_obj_index));
1585 *   *(int *) data = val;
1586 *
1587 * In the loadbalancer or wherever this data is used do
1588 *   for (int i = 0; i < stats->n_objs; i++ ) {
1589 *     LDObjData &odata = stats->objData[i];
1590 *     int* udata = (int *) odata.getUserData(CkpvAccess(_lb_obj_index));
1591 *   }
1592 *
1593 * For a complete example look at tests/charm++/load_balancing/lb_userdata_test/
1594 */
1595 void *CkMigratable::getObjUserData(int idx) {
1596         return myRec->getObjUserData(idx);
1597 }
1598 #endif
1599
1600 void CkMigratable::clearMetaLBData() {
1601 //  if (can_reset) {
1602     local_state = OFF;
1603     atsync_iteration = -1;
1604     prev_load = 0.0;
1605     can_reset = false;
1606 //  }
1607 }
1608
1609 void CkMigratable::recvLBPeriod(void *data) {
1610   if (atsync_iteration < 0) {
1611     return;
1612   }
1613   int lb_period = *((int *) data);
1614  DEBAD(("\t[obj %s] Received the LB Period %d current iter %d state %d on PE %d\n",
1615      idx2str(thisIndexMax), lb_period, atsync_iteration, local_state, CkMyPe()));
1616
1617   bool is_tentative;
1618   if (local_state == LOAD_BALANCE) {
1619     CkAssert(lb_period == myRec->getMetaBalancer()->getPredictedLBPeriod(is_tentative));
1620     return;
1621   }
1622
1623   if (local_state == PAUSE) {
1624     if (atsync_iteration < lb_period) {
1625       local_state = DECIDED;
1626       ResumeFromSync();
1627       return;
1628     }
1629     local_state = LOAD_BALANCE;
1630
1631     can_reset = true;
1632     //myRec->getLBDB()->AtLocalBarrier(ldBarrierHandle);
1633     return;
1634   }
1635   local_state = DECIDED;
1636 }
1637
1638 void CkMigratable::metaLBCallLB() {
1639   if(usesAtSync)
1640     myRec->getLBDB()->AtLocalBarrier(ldBarrierHandle);
1641 }
1642
1643 void CkMigratable::ckFinishConstruction(void)
1644 {
1645 //      if ((!usesAtSync) || barrierRegistered) return;
1646         myRec->setMeasure(usesAutoMeasure);
1647         if (barrierRegistered) return;
1648         DEBL((AA "Registering barrier client for %s\n" AB,idx2str(thisIndexMax)));
1649         if (usesAtSync)
1650           ldBarrierHandle = myRec->getLBDB()->AddLocalBarrierClient(
1651                 (LDBarrierFn)staticResumeFromSync,(void*)(this));
1652         else
1653           ldBarrierRecvHandle = myRec->getLBDB()->AddLocalBarrierReceiver(
1654                 (LDBarrierFn)staticResumeFromSync,(void*)(this));
1655         barrierRegistered=true;
1656 }
1657
1658 void CkMigratable::AtSync(int waitForMigration)
1659 {
1660         if (!usesAtSync)
1661                 CkAbort("You must set usesAtSync=true in your array element constructor to use AtSync!\n");
1662 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
1663         mlogData->toResumeOrNot=1;
1664 #endif
1665         if(CkpvAccess(hasNullLB)) {
1666                 ResumeFromSync();
1667                 return;
1668         }
1669         myRec->AsyncMigrate(!waitForMigration);
1670         if (waitForMigration) ReadyMigrate(true);
1671         ckFinishConstruction();
1672   DEBL((AA "Element %s going to sync\n" AB,idx2str(thisIndexMax)));
1673   // model-based load balancing, ask user to provide cpu load
1674   if (usesAutoMeasure == false) UserSetLBLoad();
1675
1676   if(_lb_psizer_on || _lb_args.metaLbOn()){
1677     PUP::sizer ps;
1678     this->virtual_pup(ps);
1679     if(_lb_psizer_on)
1680       setPupSize(ps.size());
1681     if(_lb_args.metaLbOn())
1682       myRec->getMetaBalancer()->SetCharePupSize(ps.size());
1683   }
1684
1685   if (!_lb_args.metaLbOn()) {
1686     myRec->getLBDB()->AtLocalBarrier(ldBarrierHandle);
1687     return;
1688   }
1689
1690   // When MetaBalancer is turned on
1691
1692   if (atsync_iteration == -1) {
1693     can_reset = false;
1694     local_state = OFF;
1695     prev_load = 0.0;
1696   }
1697
1698   atsync_iteration++;
1699   //CkPrintf("[pe %s] atsync_iter %d && predicted period %d state: %d\n",
1700   //    idx2str(thisIndexMax), atsync_iteration,
1701   //    myRec->getMetaBalancer()->getPredictedLBPeriod(), local_state);
1702   double tmp = prev_load;
1703   prev_load = myRec->getObjTime();
1704   double current_load = prev_load - tmp;
1705
1706   // If the load for the chares are based on certain model, then set the
1707   // current_load to be whatever is the obj load.
1708   if (!usesAutoMeasure) {
1709     current_load = myRec->getObjTime();
1710   }
1711
1712   if (atsync_iteration <= myRec->getMetaBalancer()->get_finished_iteration()) {
1713     CkPrintf("[%d:%s] Error!! Contributing to iter %d < current iter %d\n",
1714       CkMyPe(), idx2str(thisIndexMax), atsync_iteration,
1715       myRec->getMetaBalancer()->get_finished_iteration());
1716     CkAbort("Not contributing to the right iteration\n");
1717   }
1718
1719   if (atsync_iteration != 0) {
1720     myRec->getMetaBalancer()->AddLoad(atsync_iteration, current_load);
1721   }
1722
1723   bool is_tentative;
1724   if (atsync_iteration < myRec->getMetaBalancer()->getPredictedLBPeriod(is_tentative)) {
1725     ResumeFromSync();
1726   } else if (is_tentative) {
1727     local_state = PAUSE;
1728   } else if (local_state == DECIDED) {
1729     DEBAD(("[%d:%s] Went to load balance iter %d\n", CkMyPe(), idx2str(thisIndexMax), atsync_iteration));
1730     local_state = LOAD_BALANCE;
1731     can_reset = true;
1732     //myRec->getLBDB()->AtLocalBarrier(ldBarrierHandle);
1733   } else {
1734     DEBAD(("[%d:%s] Went to pause state iter %d\n", CkMyPe(), idx2str(thisIndexMax), atsync_iteration));
1735     local_state = PAUSE;
1736   }
1737 }
1738
1739 void CkMigratable::ReadyMigrate(bool ready)
1740 {
1741         myRec->ReadyMigrate(ready);
1742 }
1743
1744 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
1745     extern int globalResumeCount;
1746 #endif
1747
1748 void CkMigratable::staticResumeFromSync(void* data)
1749 {
1750         CkMigratable *el=(CkMigratable *)data;
1751 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
1752     if(el->mlogData->toResumeOrNot ==0 || el->mlogData->resumeCount >= globalResumeCount){
1753         return;
1754     }
1755 #endif
1756         DEBL((AA "Element %s resuming from sync\n" AB,idx2str(el->thisIndexMax)));
1757 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
1758     CpvAccess(_currentObj) = el;
1759 #endif
1760
1761   if (_lb_args.metaLbOn()) {
1762         el->clearMetaLBData();
1763         }
1764         el->ResumeFromSync();
1765 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
1766     el->mlogData->resumeCount++;
1767 #endif
1768 }
1769
1770 void CkMigratable::setMigratable(int migratable) 
1771 {
1772         myRec->setMigratable(migratable);
1773 }
1774
1775 void CkMigratable::setPupSize(size_t obj_pup_size)
1776 {
1777         myRec->setPupSize(obj_pup_size);
1778 }
1779
1780 struct CkArrayThreadListener {
1781         struct CthThreadListener base;
1782         CkMigratable *mig;
1783 };
1784
1785 static void CkArrayThreadListener_suspend(struct CthThreadListener *l)
1786 {
1787         CkArrayThreadListener *a=(CkArrayThreadListener *)l;
1788         a->mig->ckStopTiming();
1789 }
1790
1791 static void CkArrayThreadListener_resume(struct CthThreadListener *l)
1792 {
1793         CkArrayThreadListener *a=(CkArrayThreadListener *)l;
1794         a->mig->ckStartTiming();
1795 }
1796
1797 static void CkArrayThreadListener_free(struct CthThreadListener *l)
1798 {
1799         CkArrayThreadListener *a=(CkArrayThreadListener *)l;
1800         delete a;
1801 }
1802
1803 void CkMigratable::CkAddThreadListeners(CthThread tid, void *msg)
1804 {
1805         Chare::CkAddThreadListeners(tid, msg);   // for trace
1806         CthSetThreadID(tid, thisIndexMax.data()[0], thisIndexMax.data()[1], 
1807                        thisIndexMax.data()[2]);
1808         CkArrayThreadListener *a=new CkArrayThreadListener;
1809         a->base.suspend=CkArrayThreadListener_suspend;
1810         a->base.resume=CkArrayThreadListener_resume;
1811         a->base.free=CkArrayThreadListener_free;
1812         a->mig=this;
1813         CthAddListener(tid,(struct CthThreadListener *)a);
1814 }
1815 #else
1816 void CkMigratable::setObjTime(double cputime) {}
1817 double CkMigratable::getObjTime() {return 0.0;}
1818
1819 #if CMK_LB_USER_DATA
1820 void *CkMigratable::getObjUserData(int idx) { return NULL; }
1821 #endif
1822
1823 /* no load balancer: need dummy implementations to prevent link error */
1824 void CkMigratable::CkAddThreadListeners(CthThread tid, void *msg)
1825 {
1826 }
1827 #endif
1828
1829
1830 /************************** Location Records: *********************************/
1831
1832
1833 /*----------------- Local:
1834 Matches up the array index with the local index, an
1835 interfaces with the load balancer on behalf of the
1836 represented array elements.
1837 */
1838 CkLocRec::CkLocRec(CkLocMgr *mgr,bool fromMigration,
1839                    bool ignoreArrival, const CkArrayIndex &idx_, CmiUInt8 id_)
1840   :myLocMgr(mgr),idx(idx_), id(id_),
1841          deletedMarker(NULL),running(false)
1842 {
1843 #if CMK_LBDB_ON
1844         DEBL((AA "Registering element %s with load balancer\n" AB,idx2str(idx)));
1845         //BIGSIM_OOC DEBUGGING
1846         //CkPrintf("LocMgr on %d: Registering element %s with load balancer\n", CkMyPe(), idx2str(idx));
1847         nextPe = -1;
1848         asyncMigrate = false;
1849         readyMigrate = true;
1850         enable_measure = true;
1851 #if CMK_FAULT_EVAC
1852         bounced  = false;
1853 #endif
1854         the_lbdb=mgr->getLBDB();
1855         if(_lb_args.metaLbOn())
1856           the_metalb=mgr->getMetaBalancer();
1857 #if CMK_GLOBAL_LOCATION_UPDATE
1858         CmiUInt8 locMgrGid = mgr->getGroupID().idx;
1859         id_ = ck::ObjID(id_).getElementID();
1860         id_ |= locMgrGid << ck::ObjID().ELEMENT_BITS;
1861 #endif        
1862         ldHandle=the_lbdb->RegisterObj(mgr->getOMHandle(),
1863                 id_, (void *)this,1);
1864         if (fromMigration) {
1865                 DEBL((AA "Element %s migrated in\n" AB,idx2str(idx)));
1866                 if (!ignoreArrival)  {
1867                         the_lbdb->Migrated(ldHandle, true);
1868                   // load balancer should ignore this objects movement
1869                 //  AsyncMigrate(true);
1870                 }
1871         }
1872 #endif
1873
1874 #if CMK_FAULT_EVAC
1875         asyncEvacuate = true;
1876 #endif
1877 }
1878 CkLocRec::~CkLocRec()
1879 {
1880         if (deletedMarker!=NULL) *deletedMarker=true;
1881 #if CMK_LBDB_ON
1882         stopTiming();
1883         DEBL((AA "Unregistering element %s from load balancer\n" AB,idx2str(idx)));
1884         the_lbdb->UnregisterObj(ldHandle);
1885 #endif
1886 }
1887 void CkLocRec::migrateMe(int toPe) //Leaving this processor
1888 {
1889         //This will pack us up, send us off, and delete us
1890 //      printf("[%d] migrating migrateMe to %d \n",CkMyPe(),toPe);
1891         myLocMgr->emigrate(this,toPe);
1892 }
1893
1894 #if CMK_LBDB_ON
1895 void CkLocRec::startTiming(int ignore_running) {
1896         if (!ignore_running) running=true;
1897         DEBL((AA "Start timing for %s at %.3fs {\n" AB,idx2str(idx),CkWallTimer()));
1898         if (enable_measure) the_lbdb->ObjectStart(ldHandle);
1899 }
1900 void CkLocRec::stopTiming(int ignore_running) {
1901         DEBL((AA "} Stop timing for %s at %.3fs\n" AB,idx2str(idx),CkWallTimer()));
1902         if ((ignore_running || running) && enable_measure) the_lbdb->ObjectStop(ldHandle);
1903         if (!ignore_running) running=false;
1904 }
1905 void CkLocRec::setObjTime(double cputime) {
1906         the_lbdb->EstObjLoad(ldHandle, cputime);
1907 }
1908 double CkLocRec::getObjTime() {
1909         LBRealType walltime, cputime;
1910         the_lbdb->GetObjLoad(ldHandle, walltime, cputime);
1911         return walltime;
1912 }
1913 #if CMK_LB_USER_DATA
1914 void* CkLocRec::getObjUserData(int idx) {
1915         return the_lbdb->GetDBObjUserData(ldHandle, idx);
1916 }
1917 #endif
1918 #endif
1919
1920 // Attempt to destroy this record. If the location manager is done with the
1921 // record (because all array elements were destroyed) then it will be deleted.
1922 void CkLocRec::destroy(void) {
1923         myLocMgr->reclaim(this);
1924 }
1925
1926 /**********Added for cosmology (inline function handling without parameter marshalling)***********/
1927
1928 LDObjHandle CkMigratable::timingBeforeCall(int* objstopped){
1929         LDObjHandle objHandle;
1930 #if CMK_LBDB_ON
1931         if (getLBDB()->RunningObject(&objHandle)) {
1932                 *objstopped = 1;
1933                 getLBDB()->ObjectStop(objHandle);
1934         }
1935         myRec->startTiming(1);
1936 #endif
1937
1938   return objHandle;
1939 }
1940
1941 void CkMigratable::timingAfterCall(LDObjHandle objHandle,int *objstopped){
1942         myRec->stopTiming(1);
1943 #if CMK_LBDB_ON
1944         if (*objstopped) {
1945                  getLBDB()->ObjectStart(objHandle);
1946         }
1947 #endif
1948
1949  return;
1950 }
1951 /****************************************************************************/
1952
1953
1954 bool CkLocRec::invokeEntry(CkMigratable *obj,void *msg,
1955         int epIdx,bool doFree) 
1956 {
1957
1958         DEBS((AA "   Invoking entry %d on element %s\n" AB,epIdx,idx2str(idx)));
1959         bool isDeleted=false; //Enables us to detect deletion during processing
1960         deletedMarker=&isDeleted;
1961         startTiming();
1962
1963
1964 #if CMK_TRACE_ENABLED
1965         if (msg) { /* Tracing: */
1966                 envelope *env=UsrToEnv(msg);
1967         //      CkPrintf("ckLocation.C beginExecuteDetailed %d %d \n",env->getEvent(),env->getsetArraySrcPe());
1968                 if (_entryTable[epIdx]->traceEnabled)
1969         {
1970             _TRACE_BEGIN_EXECUTE_DETAILED(env->getEvent(), ForChareMsg,epIdx,env->getSrcPe(), env->getTotalsize(), idx.getProjectionID(), obj);
1971             if(_entryTable[epIdx]->appWork)
1972                 _TRACE_BEGIN_APPWORK();
1973         }
1974         }
1975 #endif
1976
1977         if (doFree) 
1978            CkDeliverMessageFree(epIdx,msg,obj);
1979         else /* !doFree */
1980            CkDeliverMessageReadonly(epIdx,msg,obj);
1981
1982
1983 #if CMK_TRACE_ENABLED
1984         if (msg) { /* Tracing: */
1985                 if (_entryTable[epIdx]->traceEnabled)
1986         {
1987             if(_entryTable[epIdx]->appWork)
1988                 _TRACE_END_APPWORK();
1989                         _TRACE_END_EXECUTE();
1990         }
1991         }
1992 #endif
1993 #if CMK_LBDB_ON
1994         if (!isDeleted) checkBufferedMigration();   // check if should migrate
1995 #endif
1996         if (isDeleted) return false;//We were deleted
1997         deletedMarker=NULL;
1998         stopTiming();
1999         return true;
2000 }
2001
2002 #if CMK_LBDB_ON
2003
2004 void CkLocRec::staticMetaLBResumeWaitingChares(LDObjHandle h, int lb_ideal_period) {
2005         CkLocRec *el=(CkLocRec *)LDObjUserData(h);
2006         DEBL((AA "MetaBalancer wants to resume waiting chare %s\n" AB,idx2str(el->idx)));
2007         el->myLocMgr->informLBPeriod(el, lb_ideal_period);
2008 }
2009
2010 void CkLocRec::staticMetaLBCallLBOnChares(LDObjHandle h) {
2011         CkLocRec *el=(CkLocRec *)LDObjUserData(h);
2012         DEBL((AA "MetaBalancer wants to call LoadBalance on chare %s\n" AB,idx2str(el->idx)));
2013         el->myLocMgr->metaLBCallLB(el);
2014 }
2015
2016 void CkLocRec::staticMigrate(LDObjHandle h, int dest)
2017 {
2018         CkLocRec *el=(CkLocRec *)LDObjUserData(h);
2019         DEBL((AA "Load balancer wants to migrate %s to %d\n" AB,idx2str(el->idx),dest));
2020         el->recvMigrate(dest);
2021 }
2022
2023 void CkLocRec::recvMigrate(int toPe)
2024 {
2025         // we are in the mode of delaying actual migration
2026         // till readyMigrate()
2027         if (readyMigrate) { migrateMe(toPe); }
2028         else nextPe = toPe;
2029 }
2030
2031 void CkLocRec::AsyncMigrate(bool use)  
2032 {
2033         asyncMigrate = use; 
2034         the_lbdb->UseAsyncMigrate(ldHandle, use);
2035 }
2036
2037 bool CkLocRec::checkBufferedMigration()
2038 {
2039         // we don't migrate in user's code when calling ReadyMigrate(true)
2040         // we postphone the action to here until we exit from the user code.
2041         if (readyMigrate && nextPe != -1) {
2042             int toPe = nextPe;
2043             nextPe = -1;
2044             // don't migrate inside the object call
2045             migrateMe(toPe);
2046             // don't do anything
2047             return true;
2048         }
2049         return false;
2050 }
2051
2052 int CkLocRec::MigrateToPe()
2053 {
2054         int pe = nextPe;
2055         nextPe = -1;
2056         return pe;
2057 }
2058
2059 void CkLocRec::setMigratable(int migratable)
2060 {
2061         if (migratable)
2062           the_lbdb->Migratable(ldHandle);
2063         else
2064           the_lbdb->NonMigratable(ldHandle);
2065 }
2066
2067 void CkLocRec::setPupSize(size_t obj_pup_size) {
2068   the_lbdb->setPupSize(ldHandle, obj_pup_size);
2069 }
2070
2071 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
2072 void CkLocRec::Migrated(){
2073     the_lbdb->Migrated(ldHandle, true);
2074 }
2075 #endif
2076 #endif
2077
2078
2079 // Call ckDestroy for each record, which deletes the record, and ~CkLocRec()
2080 // removes it from the hash table, which would invalidate an iterator.
2081 void CkLocMgr::flushLocalRecs(void)
2082 {
2083   CmiImmediateLock(hashImmLock);
2084   while (hash.size()) {
2085     CkLocRec* rec = hash.begin()->second;
2086     callMethod(rec, &CkMigratable::ckDestroy);
2087   }
2088   CmiImmediateUnlock(hashImmLock);
2089 }
2090
2091 // All records are local records after the 64bit ID update
2092 void CkLocMgr::flushAllRecs(void)
2093 {
2094   flushLocalRecs();
2095 }
2096
2097
2098 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
2099 void CkLocMgr::callForAllRecords(CkLocFn fnPointer,CkArray *arr,void *data){
2100   CmiImmediateLock(hashImmLock);
2101   for (LocRecHash::iterator it = hash.begin(); it != hash.end(); it++) {
2102     fnPointer(arr,data,it->second,it->second->idx);
2103   }
2104   CmiImmediateUnlock(hashImmLock);
2105 }
2106 #endif
2107
2108 /*************************** LocMgr: CREATION *****************************/
2109 CkLocMgr::CkLocMgr(CkArrayOptions opts)
2110         :idCounter(1), thisProxy(thisgroup),
2111   thislocalproxy(thisgroup,CkMyPe())
2112         , bounds(opts.getBounds())
2113 {
2114         DEBC((AA "Creating new location manager %d\n" AB,thisgroup));
2115 // moved to _CkMigratable_initInfoInit()
2116 //      CkpvInitialize(CkMigratable_initInfo,mig_initInfo);
2117
2118         duringMigration = false;
2119
2120 //Register with the map object
2121         mapID = opts.getMap();
2122         map=(CkArrayMap *)CkLocalBranch(mapID);
2123         if (map==NULL) CkAbort("ERROR!  Local branch of array map is NULL!");
2124         mapHandle=map->registerArray(opts.getEnd(), thisgroup);
2125
2126         // Figure out the mapping from indices to object IDs if one is possible
2127         compressor = ck::FixedArrayIndexCompressor::make(bounds);
2128
2129 //Find and register with the load balancer
2130 #if CMK_LBDB_ON
2131         lbdbID = _lbdb;
2132         metalbID = _metalb;
2133 #endif
2134         initLB(lbdbID, metalbID);
2135         hashImmLock = CmiCreateImmediateLock();
2136 }
2137
2138 CkLocMgr::CkLocMgr(CkMigrateMessage* m)
2139         :IrrGroup(m),thisProxy(thisgroup),thislocalproxy(thisgroup,CkMyPe())
2140 {
2141         duringMigration = false;
2142         hashImmLock = CmiCreateImmediateLock();
2143 }
2144
2145 CkLocMgr::~CkLocMgr() {
2146 #if CMK_LBDB_ON
2147   the_lbdb->RemoveLocalBarrierClient(dummyBarrierHandle);
2148   the_lbdb->DecreaseLocalBarrier(dummyBarrierHandle, 1);
2149   the_lbdb->RemoveLocalBarrierReceiver(lbBarrierReceiver);
2150   the_lbdb->UnregisterOM(myLBHandle);
2151 #endif
2152   map->unregisterArray(mapHandle);
2153   CmiDestroyLock(hashImmLock);
2154 }
2155
2156 void CkLocMgr::pup(PUP::er &p){
2157         IrrGroup::pup(p);
2158         p|mapID;
2159         p|mapHandle;
2160         p|lbdbID;
2161         p|metalbID;
2162         p|bounds;
2163         if(p.isUnpacking()) {
2164                 thisProxy=thisgroup;
2165                 CProxyElement_CkLocMgr newlocalproxy(thisgroup,CkMyPe());
2166                 thislocalproxy=newlocalproxy;
2167                 //Register with the map object
2168                 map=(CkArrayMap *)CkLocalBranch(mapID);
2169                 if (map==NULL) CkAbort("ERROR!  Local branch of array map is NULL!");
2170                 CkArrayIndex emptyIndex;
2171                 // _lbdb is the fixed global groupID
2172                 initLB(lbdbID, metalbID);
2173                 compressor = ck::FixedArrayIndexCompressor::make(bounds);
2174 #if __FAULT__
2175         int count = 0;
2176         p | count;
2177         DEBUG(CmiPrintf("[%d] Unpacking Locmgr %d has %d home elements\n",CmiMyPe(),thisgroup.idx,count));
2178 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))    
2179         homeElementCount = count;
2180 #endif
2181         for(int i=0;i<count;i++){
2182             CkArrayIndex idx;
2183             int pe = 0;
2184             p | idx;
2185             p | pe;
2186   //          CmiPrintf("[%d] idx %s is a home element exisiting on pe %d\n",CmiMyPe(),idx2str(idx),pe);
2187             inform(idx, lookupID(idx), pe);
2188             CmiUInt8 id = lookupID(idx);
2189             CkLocRec *rec = elementNrec(id);
2190             CmiAssert(rec!=NULL);
2191             CmiAssert(lastKnown(idx) == pe);
2192         }
2193 #endif
2194                 // delay doneInserting when it is unpacking during restart.
2195                 // to prevent load balancing kicking in
2196                 if (!CkInRestarting()) 
2197                         doneInserting();
2198         }else{
2199  /**
2200  * pack the indexes of elements which have their homes on this processor
2201  * but dont exist on it.. needed for broadcast after a restart
2202  * indexes of local elements dont need to be packed
2203  * since they will be recreated later anyway
2204  */
2205 #if __FAULT__
2206         int count=0;
2207         std::vector<int> pe_list;
2208         std::vector<CmiUInt8> idx_list;
2209         for (auto itr = id2pe.begin(); itr != id2pe.end(); ++itr)
2210             if (homePe(itr->first) == CmiMyPe() && itr->second != CmiMyPe())
2211             {
2212                 idx_list.push_back(itr->first);
2213                 pe_list.push_back(itr->second);
2214                 count++;
2215             }
2216
2217         p | count;
2218         // syncft code depends on this exact arrangement:
2219         for (int i=0; i<count; i++)
2220         {
2221           p | idx_list[i];
2222           p | pe_list[i];
2223         }
2224 #endif
2225
2226         }
2227 }
2228
2229 /// Add a new local array manager to our list.
2230 void CkLocMgr::addManager(CkArrayID id,CkArray *mgr)
2231 {
2232         CK_MAGICNUMBER_CHECK
2233         DEBC((AA "Adding new array manager\n" AB));
2234         managers[id] = mgr;
2235 }
2236
2237 void CkLocMgr::deleteManager(CkArrayID id, CkArray *mgr) {
2238   CkAssert(managers[id] == mgr);
2239   managers.erase(id);
2240
2241   if (managers.size() == 0)
2242     delete this;
2243 }
2244
2245 //Tell this element's home processor it now lives "there"
2246 void CkLocMgr::informHome(const CkArrayIndex &idx,int nowOnPe)
2247 {
2248         int home=homePe(idx);
2249         if (home!=CkMyPe() && home!=nowOnPe) {
2250                 //Let this element's home Pe know it lives here now
2251                 DEBC((AA "  Telling %s's home %d that it lives on %d.\n" AB,idx2str(idx),home,nowOnPe));
2252 //#if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
2253 //#if defined(_FAULT_MLOG_)
2254 //        informLocationHome(thisgroup,idx,home,CkMyPe());
2255 //#else
2256                 thisProxy[home].updateLocation(idx, lookupID(idx), nowOnPe);
2257 //#endif
2258         }
2259 }
2260
2261 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
2262 CkLocRec *CkLocMgr::createLocal(const CkArrayIndex &idx,
2263         bool forMigration, bool ignoreArrival,
2264         bool notifyHome,int dummy)
2265 {
2266     DEBC((AA "Adding new record for element %s\n" AB,idx2str(idx)));
2267     CkLocRec *rec=new CkLocRec(this,forMigration,ignoreArrival,idx);
2268     if(!dummy){
2269         insertRec(rec,idx); //Add to global hashtable
2270         id2pe[idx] = CkMyPe();
2271         deliverAnyBufferedMsgs(idx, bufferedMsgs);
2272     }   
2273     if (notifyHome) informHome(idx,CkMyPe());
2274     return rec; 
2275 }
2276 #else
2277 CkLocRec *CkLocMgr::createLocal(const CkArrayIndex &idx, 
2278                 bool forMigration, bool ignoreArrival,
2279                 bool notifyHome)
2280 {
2281         DEBC((AA "Adding new record for element %s\n" AB,idx2str(idx)));
2282         CmiUInt8 id = lookupID(idx);
2283
2284         CkLocRec *rec=new CkLocRec(this, forMigration, ignoreArrival, idx, id);
2285         insertRec(rec, id);
2286         inform(idx, id, CkMyPe());
2287
2288         if (notifyHome) { informHome(idx,CkMyPe()); }
2289         return rec;
2290 }
2291 #endif
2292
2293
2294 void CkLocMgr::deliverAnyBufferedMsgs(CmiUInt8 id, MsgBuffer &buffer)
2295 {
2296     auto itr = buffer.find(id);
2297     // If there are no buffered msgs, don't do anything
2298     if (itr == buffer.end()) return;
2299
2300     std::vector<CkArrayMessage*> messagesToFlush;
2301     messagesToFlush.swap(itr->second);
2302
2303     // deliver all buffered messages
2304     for (int i = 0; i < messagesToFlush.size(); ++i)
2305     {
2306 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
2307         envelope *env = UsrToEnv(messagesToFlush[i]);
2308         Chare *oldObj = CpvAccess(_currentObj);
2309         CpvAccess(_currentObj) =(Chare *) env->sender.getObject();
2310         env->sender.type = TypeInvalid;
2311 #endif
2312         CkArrayMessage *m = messagesToFlush[i];
2313         deliverMsg(m, UsrToEnv(m)->getArrayMgr(), id, NULL, CkDeliver_queue);
2314 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
2315         CpvAccess(_currentObj) = oldObj;
2316 #endif
2317     }
2318
2319     CkAssert(itr->second.empty()); // Nothing should have been added, since we
2320                                    // ostensibly know where the object lives
2321
2322     // and then, delete the entry in this table of buffered msgs
2323     buffer.erase(itr);
2324 }
2325
2326 CmiUInt8 CkLocMgr::getNewObjectID(const CkArrayIndex &idx)
2327 {
2328   CmiUInt8 id;
2329   if (!lookupID(idx, id)) {
2330     id = idCounter++ + ((CmiUInt8)CkMyPe() << 24);
2331     insertID(idx,id);
2332   }
2333   return id;
2334 }
2335
2336 //Add a new local array element, calling element's constructor
2337 bool CkLocMgr::addElement(CkArrayID mgr,const CkArrayIndex &idx,
2338                 CkMigratable *elt,int ctorIdx,void *ctorMsg)
2339 {
2340         CK_MAGICNUMBER_CHECK
2341
2342         CmiUInt8 id = getNewObjectID(idx);
2343
2344         CkLocRec *rec = elementNrec(id);
2345         if (rec == NULL)
2346         { //This is the first we've heard of that element-- add new local record
2347                 rec=createLocal(idx,false,false,true);
2348 #if CMK_GLOBAL_LOCATION_UPDATE
2349                 if (homePe(idx) != CkMyPe()) {
2350                   DEBC((AA "Global location broadcast for new element idx %s "
2351                         "assigned to %d \n" AB, idx2str(idx), CkMyPe()));
2352                   thisProxy.updateLocation(id, CkMyPe());
2353                 }
2354 #endif
2355                 
2356         }
2357         //rec is *already* local-- must not be the first insertion      
2358         else
2359                 deliverAnyBufferedMsgs(id, bufferedShadowElemMsgs);
2360         if (!addElementToRec(rec, managers[mgr], elt, ctorIdx, ctorMsg)) return false;
2361         elt->ckFinishConstruction();
2362         return true;
2363 }
2364
2365 //As above, but shared with the migration code
2366 bool CkLocMgr::addElementToRec(CkLocRec *rec,CkArray *mgr,
2367                 CkMigratable *elt,int ctorIdx,void *ctorMsg)
2368 {//Insert the new element into its manager's local list
2369   CmiUInt8 id = lookupID(rec->getIndex());
2370   if (mgr->getEltFromArrMgr(id))
2371     CkAbort("Cannot insert array element twice!");
2372   mgr->putEltInArrMgr(id, elt); //Local element table
2373
2374 //Call the element's constructor
2375         DEBC((AA "Constructing element %s of array\n" AB,idx2str(rec->getIndex())));
2376         CkMigratable_initInfo &i=CkpvAccess(mig_initInfo);
2377         i.locRec=rec;
2378         i.chareType=_entryTable[ctorIdx]->chareIdx;
2379
2380 #ifndef CMK_CHARE_USE_PTR
2381   int callingChareIdx = CkpvAccess(currentChareIdx);
2382   CkpvAccess(currentChareIdx) = -1;
2383 #endif
2384
2385         if (!rec->invokeEntry(elt,ctorMsg,ctorIdx,true)) return false;
2386
2387 #ifndef CMK_CHARE_USE_PTR
2388   CkpvAccess(currentChareIdx) = callingChareIdx;
2389 #endif
2390
2391 #if CMK_OUT_OF_CORE
2392         /* Register new element with out-of-core */
2393         PUP::sizer p_getSize;
2394         elt->virtual_pup(p_getSize);
2395         elt->prefetchObjID=CooRegisterObject(&CkArrayElementPrefetcher,p_getSize.size(),elt);
2396 #endif
2397         
2398         return true;
2399 }
2400
2401 // TODO: suppressIfHere doesn't seem to be useful anymore because we return
2402 // early when peToTell == CkMyPe()
2403 void CkLocMgr::requestLocation(const CkArrayIndex &idx, const int peToTell,
2404                                bool suppressIfHere, int ifNonExistent, int chareType, CkArrayID mgr) {
2405   int onPe = -1;
2406   DEBN(("%d requestLocation for %s peToTell %d\n", CkMyPe(), idx2str(idx), peToTell));
2407
2408   if (peToTell == CkMyPe())
2409     return;
2410
2411   CmiUInt8 id;
2412   if (lookupID(idx,id)) {
2413     // We found the ID so update the location for peToTell
2414     onPe = lastKnown(idx);
2415     thisProxy[peToTell].updateLocation(idx, id, onPe);
2416   } else {
2417     // We don't know the ID so buffer the location request
2418     DEBN(("%d Buffering ID/location req for %s\n", CkMyPe(), idx2str(idx)));
2419     bufferedLocationRequests[idx].emplace_back(peToTell, suppressIfHere);
2420
2421     switch (ifNonExistent) {
2422     case CkArray_IfNotThere_createhome:
2423       demandCreateElement(idx, chareType, CkMyPe(), mgr);
2424       break;
2425     case CkArray_IfNotThere_createhere:
2426       demandCreateElement(idx, chareType, peToTell, mgr);
2427       break;
2428     default:
2429       break;
2430     }
2431   }
2432 }
2433
2434 void CkLocMgr::requestLocation(CmiUInt8 id, const int peToTell,
2435                                bool suppressIfHere) {
2436   int onPe = -1;
2437   DEBN(("%d requestLocation for %u peToTell %d\n", CkMyPe(), id, peToTell));
2438
2439   if (peToTell == CkMyPe())
2440     return;
2441
2442   onPe = lastKnown(id);
2443
2444   if (suppressIfHere && peToTell == CkMyPe())
2445     return;
2446
2447   thisProxy[peToTell].updateLocation(id, onPe);
2448 }
2449
2450 void CkLocMgr::updateLocation(const CkArrayIndex &idx, CmiUInt8 id, int nowOnPe) {
2451   DEBN(("%d updateLocation for %s on %d\n", CkMyPe(), idx2str(idx), nowOnPe));
2452   inform(idx, id, nowOnPe);
2453   deliverAnyBufferedMsgs(id, bufferedRemoteMsgs);
2454 }
2455
2456 void CkLocMgr::updateLocation(CmiUInt8 id, int nowOnPe) {
2457   DEBN(("%d updateLocation for %s on %d\n", CkMyPe(), idx2str(idx), nowOnPe));
2458   inform(id, nowOnPe);
2459   deliverAnyBufferedMsgs(id, bufferedRemoteMsgs);
2460 }
2461
2462 void CkLocMgr::inform(const CkArrayIndex &idx, CmiUInt8 id, int nowOnPe) {
2463   // On restart, conservatively determine the next 'safe' ID to
2464   // generate for new elements by the max over all of the elements with
2465   // IDs corresponding to each PE
2466   if (CkInRestarting()) {
2467     CmiUInt8 maskedID = id & ((1u << 24) - 1);
2468     CmiUInt8 origPe = id >> 24;
2469     if (origPe == CkMyPe()) {
2470       if (maskedID >= idCounter)
2471         idCounter = maskedID + 1;
2472     } else {
2473       if (origPe < CkNumPes())
2474         thisProxy[origPe].updateLocation(idx, id, nowOnPe);
2475     }
2476   }
2477
2478   insertID(idx,id);
2479   id2pe[id] = nowOnPe;
2480
2481   auto itr = bufferedLocationRequests.find(idx);
2482   if (itr != bufferedLocationRequests.end()) {
2483     for (std::vector<std::pair<int, bool> >::iterator i = itr->second.begin();
2484          i != itr->second.end(); ++i) {
2485       int peToTell = i->first;
2486       DEBN(("%d Replying to buffered ID/location req to pe %d\n", CkMyPe(), peToTell));
2487       if (peToTell != CkMyPe())
2488         thisProxy[peToTell].updateLocation(idx, id, nowOnPe);
2489     }
2490     bufferedLocationRequests.erase(itr);
2491   }
2492
2493   deliverAnyBufferedMsgs(id, bufferedMsgs);
2494
2495   auto idx_itr = bufferedIndexMsgs.find(idx);
2496   if (idx_itr != bufferedIndexMsgs.end()) {
2497     vector<CkArrayMessage*> &msgs = idx_itr->second;
2498     for (int i = 0; i < msgs.size(); ++i) {
2499       envelope *env = UsrToEnv(msgs[i]);
2500       CkGroupID mgr = ck::ObjID(env->getRecipientID()).getCollectionID();
2501       env->setRecipientID(ck::ObjID(mgr, id));
2502       deliverMsg(msgs[i], mgr, id, &idx, CkDeliver_queue);
2503     }
2504     bufferedIndexMsgs.erase(idx_itr);
2505   }
2506 }
2507
2508 void CkLocMgr::inform(CmiUInt8 id, int nowOnPe) {
2509   id2pe[id] = nowOnPe;
2510   deliverAnyBufferedMsgs(id, bufferedMsgs);
2511 }
2512
2513
2514
2515 /*************************** LocMgr: DELETION *****************************/
2516 // This index may no longer be used -- check if any of our managers are still
2517 // using it, and if not delete it and clean up all traces of it on other PEs.
2518 void CkLocMgr::reclaim(CkLocRec* rec) {
2519         CK_MAGICNUMBER_CHECK
2520         // Return early if the record is still in use by any of our arrays
2521         for (auto itr = managers.begin(); itr != managers.end(); ++itr) {
2522                 if (itr->second->lookup(rec->getID())) return;
2523         }
2524         removeFromTable(rec->getID());
2525         
2526         DEBC((AA "Destroying record for element %s\n" AB,idx2str(rec->getIndex())));
2527         if (!duringMigration) 
2528         { //This is a local element dying a natural death
2529 #if CMK_BIGSIM_CHARM
2530                 //After migration, reclaimRemote will be called through 
2531                 //the CkRemoveArrayElement in the pupping routines for those 
2532                 //objects that are not on the home processors. However,
2533                 //those remote records should not be deleted since the corresponding
2534                 //objects are not actually deleted but on disk. If deleted, msgs
2535                 //that seeking where is the object will be accumulated (a circular
2536                 //msg chain) and causes the program no progress
2537                 if(_BgOutOfCoreFlag==1) return; 
2538 #endif
2539                 int home=homePe(rec->getIndex());
2540                 if (home!=CkMyPe())
2541 #if CMK_MEM_CHECKPOINT
2542                 if (!CkInRestarting()) // all array elements are removed anyway
2543 #endif
2544                 if (!duringDestruction)
2545                     thisProxy[home].reclaimRemote(rec->getIndex(),CkMyPe());
2546         }
2547         delete rec;
2548 }
2549
2550 // The location record associated with idx has been deleted on a remote PE, so
2551 // we should free all of our caching associated with that index.
2552 void CkLocMgr::reclaimRemote(const CkArrayIndex &idx,int deletedOnPe) {
2553         DEBC((AA "Our element %s died on PE %d\n" AB,idx2str(idx),deletedOnPe));
2554
2555         CmiUInt8 id;
2556         if (!lookupID(idx, id)) CkAbort("Cannot find ID for the given index\n");
2557
2558         // Delete the id and index from our location caching
2559         id2pe.erase(id);
2560         idx2id.erase(idx);
2561
2562         // Assert that there were no undelivered messages for the dying element
2563         CkAssert(bufferedMsgs.count(id) == 0);
2564         CkAssert(bufferedRemoteMsgs.count(id) == 0);
2565         CkAssert(bufferedShadowElemMsgs.count(id) == 0);
2566         CkAssert(bufferedLocationRequests.count(idx) == 0);
2567         CkAssert(bufferedIndexMsgs.count(idx) == 0);
2568 }
2569
2570 void CkLocMgr::removeFromTable(const CmiUInt8 id) {
2571 #if CMK_ERROR_CHECKING
2572         //Make sure it's actually in the table before we delete it
2573         if (NULL==elementNrec(id))
2574                 CkAbort("CkLocMgr::removeFromTable called on invalid index!");
2575 #endif
2576                 CmiImmediateLock(hashImmLock);
2577                 hash.erase(id);
2578                 CmiImmediateUnlock(hashImmLock);
2579 #if CMK_ERROR_CHECKING
2580         //Make sure it's really gone
2581         if (NULL!=elementNrec(id))
2582                 CkAbort("CkLocMgr::removeFromTable called, but element still there!");
2583 #endif
2584 }
2585
2586 /************************** LocMgr: MESSAGING *************************/
2587 /// Deliver message to this element, going via the scheduler if local
2588 /// @return 0 if object local, 1 if not
2589 int CkLocMgr::deliverMsg(CkArrayMessage *msg, CkArrayID mgr, CmiUInt8 id, const CkArrayIndex* idx, CkDeliver_t type, int opts) {
2590   CkLocRec *rec = elementNrec(id);
2591
2592 #if CMK_LBDB_ON
2593   if ((idx || compressor) && type==CkDeliver_queue && !(opts & CK_MSG_LB_NOTRACE) && the_lbdb->CollectingCommStats())
2594   {
2595 #if CMK_GLOBAL_LOCATION_UPDATE
2596     CmiUInt8 locMgrGid = thisgroup.idx;
2597     id = ck::ObjID(id).getElementID();
2598     id |= locMgrGid << ck::ObjID().ELEMENT_BITS;
2599 #endif
2600     the_lbdb->Send(myLBHandle
2601                    , id
2602                    , UsrToEnv(msg)->getTotalsize()
2603                    , lastKnown(id)
2604                    , 1);
2605   }
2606 #endif
2607
2608   // Known, remote location or unknown location
2609   if (rec == NULL)
2610   {
2611     if (opts & CK_MSG_KEEP)
2612       msg = (CkArrayMessage *)CkCopyMsg((void **)&msg);
2613     // known location
2614     int destPE = whichPE(id);
2615     if (destPE != -1)
2616     {
2617 #if CMK_FAULT_EVAC
2618       if((!CmiNodeAlive(destPE) && destPE != allowMessagesOnly)){
2619         CkAbort("Cannot send to a chare on a dead node");
2620       }
2621 #endif
2622       msg->array_hops()++;
2623       CkArrayManagerDeliver(destPE,msg,opts);
2624       return true;
2625     }
2626     // unknown location
2627     deliverUnknown(msg,idx,type,opts);
2628     return true;
2629   }
2630
2631   // Send via the msg q
2632   if (type==CkDeliver_queue)
2633   {
2634     if (opts & CK_MSG_KEEP)
2635       msg = (CkArrayMessage *)CkCopyMsg((void **)&msg);
2636     CkArrayManagerDeliver(CkMyPe(),msg,opts);
2637     return true;
2638   }
2639
2640   CkAssert(mgr == UsrToEnv(msg)->getArrayMgr());
2641   CkArray *arr = managers[mgr];
2642   if (!arr) {
2643     bufferedShadowElemMsgs[id].push_back(msg);
2644     return true;
2645   }
2646   CkMigratable *obj = arr->lookup(id);
2647   if (obj==NULL) {//That sibling of this object isn't created yet!
2648     if (opts & CK_MSG_KEEP)
2649       msg = (CkArrayMessage *)CkCopyMsg((void **)&msg);
2650     if (msg->array_ifNotThere()!=CkArray_IfNotThere_buffer)
2651       return demandCreateElement(msg, rec->getIndex(), CkMyPe(),type);
2652     else { // BUFFERING message for nonexistent element
2653       bufferedShadowElemMsgs[id].push_back(msg);
2654       return true;
2655     }
2656   }
2657         
2658   if (msg->array_hops()>1)
2659     multiHop(msg);
2660 #if CMK_LBDB_ON
2661   // if there is a running obj being measured, stop it temporarily
2662   LDObjHandle objHandle;
2663   bool wasAnObjRunning = false;
2664   if ((wasAnObjRunning = the_lbdb->RunningObject(&objHandle)))
2665     the_lbdb->ObjectStop(objHandle);
2666 #endif
2667   // Finally, call the entry method
2668   bool result = ((CkLocRec*)rec)->invokeEntry(obj,(void *)msg,msg->array_ep(),!(opts & CK_MSG_KEEP));
2669 #if CMK_LBDB_ON
2670   if (wasAnObjRunning) the_lbdb->ObjectStart(objHandle);
2671 #endif
2672   return result;
2673 }
2674
2675 void CkLocMgr::sendMsg(CkArrayMessage *msg, CkArrayID mgr, const CkArrayIndex &idx, CkDeliver_t type, int opts) {
2676   CK_MAGICNUMBER_CHECK
2677   DEBS((AA "send %s\n" AB,idx2str(idx)));
2678   envelope *env = UsrToEnv(msg);
2679   env->setMsgtype(ForArrayEltMsg);
2680
2681   checkInBounds(idx);
2682
2683   if (type==CkDeliver_queue)
2684     _TRACE_CREATION_DETAILED(env, msg->array_ep());
2685
2686   CmiUInt8 id;
2687   if (lookupID(idx, id)) {
2688     env->setRecipientID(ck::ObjID(mgr, id));
2689     deliverMsg(msg, mgr, id, &idx, type, opts);
2690     return;
2691   }
2692
2693   env->setRecipientID(ck::ObjID(mgr, 0));
2694
2695   int home = homePe(idx);
2696   if (home != CkMyPe()) {
2697     if (bufferedIndexMsgs.find(idx) == bufferedIndexMsgs.end())
2698       thisProxy[home].requestLocation(idx, CkMyPe(), false, msg->array_ifNotThere(), _entryTable[env->getEpIdx()]->chareIdx, mgr);
2699     bufferedIndexMsgs[idx].push_back(msg);
2700
2701     return;
2702   }
2703
2704   // We are the home, and there's no ID for this index yet - i.e. its
2705   // construction hasn't reached us yet.
2706   if (managers.find(mgr) == managers.end()) {
2707     // Even the manager for this array hasn't been constructed here yet
2708     if (CkInRestarting()) {
2709       // during restarting, this message should be ignored
2710       delete msg;
2711     } else {
2712       // Eventually, the manager will be created, and the element inserted, and
2713       // it will get pulled back out
2714       // 
2715       // XXX: Is demand creation ever possible in this case? I don't see why not
2716       bufferedIndexMsgs[idx].push_back(msg);
2717     }
2718     return;
2719   }
2720
2721   // Copy the msg, if nokeep
2722   if (opts & CK_MSG_KEEP)
2723     msg = (CkArrayMessage *)CkCopyMsg((void **)&msg);
2724
2725   // Buffer the msg
2726   bufferedIndexMsgs[idx].push_back(msg);
2727
2728 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
2729   envelope *env = UsrToEnv(msg);
2730   env->sender = CpvAccess(_currentObj)->mlogData->objID;
2731 #endif
2732
2733   // If requested, demand-create the element:
2734   if (msg->array_ifNotThere()!=CkArray_IfNotThere_buffer) {
2735     demandCreateElement(msg, idx, -1, type);
2736   }
2737 }
2738
2739 /// This index is not hashed-- somehow figure out what to do.
2740 void CkLocMgr::deliverUnknown(CkArrayMessage *msg, const CkArrayIndex* idx, CkDeliver_t type, int opts)
2741 {
2742   CK_MAGICNUMBER_CHECK
2743   CmiUInt8 id = msg->array_element_id();
2744   int home;
2745   if (idx) home = homePe(*idx);
2746   else home = homePe(id);
2747
2748   if (home != CkMyPe()) {// Forward the message to its home processor
2749     id2pe[id] = home;
2750     if (UsrToEnv(msg)->getTotalsize() < _messageBufferingThreshold) {
2751       DEBM((AA "Forwarding message for unknown %u to home %d \n" AB, id, home));
2752       msg->array_hops()++;
2753       CkArrayManagerDeliver(home, msg, opts);
2754     } else {
2755       DEBM((AA "Buffering message for unknown %u, home %d \n" AB, id, home));
2756       if (bufferedRemoteMsgs.find(id) == bufferedRemoteMsgs.end())
2757         thisProxy[home].requestLocation(id, CkMyPe(), false);
2758       bufferedRemoteMsgs[id].push_back(msg);
2759     }
2760   } else { // We *are* the home processor:
2761     //Check if the element's array manager has been registered yet:
2762     //No manager yet-- postpone the message (stupidly)
2763     if (managers.find(UsrToEnv((void*)msg)->getArrayMgr()) == managers.end()) {
2764       if (CkInRestarting()) {
2765         // during restarting, this message should be ignored
2766         delete msg;
2767       } else {
2768         CkArrayManagerDeliver(CkMyPe(),msg);
2769       }
2770     } else { // Has a manager-- must buffer the message
2771       // Copy the msg, if nokeep
2772       if (opts & CK_MSG_KEEP)
2773         msg = (CkArrayMessage *)CkCopyMsg((void **)&msg);
2774       // Buffer the msg
2775       bufferedMsgs[id].push_back(msg);
2776 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
2777       envelope *env = UsrToEnv(msg);
2778       env->sender = CpvAccess(_currentObj)->mlogData->objID;
2779 #endif
2780       // If requested, demand-create the element:
2781       if (msg->array_ifNotThere()!=CkArray_IfNotThere_buffer) {
2782         CkAbort("Demand creation of elements is currently unimplemented");
2783       }
2784     }
2785   }
2786 }
2787
2788 void CkLocMgr::demandCreateElement(const CkArrayIndex &idx, int chareType, int onPe, CkArrayID mgr)
2789 {
2790   int ctor=_chareTable[chareType]->getDefaultCtor();
2791   if (ctor==-1) CkAbort("Can't create array element to handle message--\n"
2792                         "The element has no default constructor in the .ci file!\n");
2793
2794   //Find the manager and build the element
2795   DEBC((AA "Demand-creating element %s on pe %d\n" AB,idx2str(idx),onPe));
2796   inform(idx, getNewObjectID(idx), onPe);
2797   CProxy_CkArray(mgr)[onPe].demandCreateElement(idx, ctor, CkDeliver_inline);
2798 }
2799
2800 bool CkLocMgr::demandCreateElement(CkArrayMessage *msg, const CkArrayIndex &idx, int onPe,CkDeliver_t type)
2801 {
2802         CK_MAGICNUMBER_CHECK
2803         int chareType=_entryTable[msg->array_ep()]->chareIdx;
2804         int ctor=_chareTable[chareType]->getDefaultCtor();
2805         if (ctor==-1) CkAbort("Can't create array element to handle message--\n"
2806                               "The element has no default constructor in the .ci file!\n");
2807         if (onPe==-1) 
2808         { //Decide where element needs to live
2809                 if (msg->array_ifNotThere()==CkArray_IfNotThere_createhere) 
2810                         onPe=UsrToEnv(msg)->getsetArraySrcPe();
2811                 else //Createhome
2812                         onPe=homePe(idx);
2813         }
2814         
2815         //Find the manager and build the element
2816         DEBC((AA "Demand-creating element %s on pe %d\n" AB,idx2str(idx),onPe));
2817         CProxy_CkArray(UsrToEnv((void *)msg)->getArrayMgr())[onPe].demandCreateElement(idx, ctor, type);
2818         return onPe == CkMyPe();
2819 }
2820
2821 //This message took several hops to reach us-- fix it
2822 void CkLocMgr::multiHop(CkArrayMessage *msg)
2823 {
2824         CK_MAGICNUMBER_CHECK
2825         int srcPe=msg->array_getSrcPe();
2826         if (srcPe==CkMyPe())
2827           DEB((AA "Odd routing: local element %u is %d hops away!\n" AB, msg->array_element_id(),msg->array_hops()));
2828         else
2829         {//Send a routing message letting original sender know new element location
2830           DEBS((AA "Sending update back to %d for element %u\n" AB, srcPe, msg->array_element_id()));
2831           thisProxy[srcPe].updateLocation(msg->array_element_id(), CkMyPe());
2832         }
2833 }
2834
2835 void CkLocMgr::checkInBounds(const CkArrayIndex &idx)
2836 {
2837 #if CMK_ERROR_CHECKING
2838   if (bounds.nInts > 0) {
2839     CkAssert(idx.dimension == bounds.dimension);
2840     bool shorts = idx.dimension > 3;
2841
2842     for (int i = 0; i < idx.dimension; ++i) {
2843       unsigned int thisDim = shorts ? idx.indexShorts[i] : idx.index[i];
2844       unsigned int thatDim = shorts ? bounds.indexShorts[i] : bounds.index[i];
2845       CkAssert(thisDim < thatDim);
2846     }
2847   }
2848 #endif
2849 }
2850
2851 /************************** LocMgr: ITERATOR *************************/
2852 CkLocation::CkLocation(CkLocMgr *mgr_, CkLocRec *rec_)
2853         :mgr(mgr_), rec(rec_) {}
2854         
2855 const CkArrayIndex &CkLocation::getIndex(void) const {
2856         return rec->getIndex();
2857 }
2858
2859 CmiUInt8 CkLocation::getID() const {
2860         return rec->getID();
2861 }
2862
2863 void CkLocation::destroyAll() {
2864         mgr->callMethod(rec, &CkMigratable::ckDestroy);
2865 }
2866
2867 void CkLocation::pup(PUP::er &p) {
2868         mgr->pupElementsFor(p,rec,CkElementCreation_migrate);
2869 }
2870
2871 CkLocIterator::~CkLocIterator() {}
2872
2873 /// Iterate over our local elements:
2874 void CkLocMgr::iterate(CkLocIterator &dest) {
2875   //Poke through the hash table for local ArrayRecs.
2876   CmiImmediateLock(hashImmLock);
2877   for (LocRecHash::iterator it = hash.begin(); it != hash.end(); it++) {
2878     CkLocation loc(this,it->second);
2879     dest.addLocation(loc);
2880   }
2881   CmiImmediateUnlock(hashImmLock);
2882 }
2883
2884
2885
2886
2887 /************************** LocMgr: MIGRATION *************************/
2888 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
2889 void CkLocMgr::pupElementsFor(PUP::er &p,CkLocRec *rec,
2890         CkElementCreation_t type, bool create, int dummy)
2891 {
2892     p.comment("-------- Array Location --------");
2893     std::vector<CkMigratable *> dummyElts;
2894
2895     for (auto itr = managers.begin(); itr != managers.end(); ++itr) {
2896         int elCType;
2897         if (!p.isUnpacking())
2898         { //Need to find the element's existing type
2899             CkMigratable *elt = itr->second->getEltFromArrMgr(rec->getIndex());
2900             if (elt) elCType=elt->ckGetChareType();
2901             else elCType=-1; //Element hasn't been created
2902         }
2903         p(elCType);
2904         if (p.isUnpacking() && elCType!=-1) {
2905             CkMigratable *elt = itr->second->allocateMigrated(elCType,rec->getIndex(),type);
2906             int migCtorIdx=_chareTable[elCType]->getMigCtor();
2907                 if(!dummy){
2908                         if(create)
2909                                 if (!addElementToRec(rec, itr->second, elt, migCtorIdx, NULL)) return;
2910                                 }else{
2911                     CkMigratable_initInfo &i=CkpvAccess(mig_initInfo);
2912                     i.locRec=rec;
2913                     i.chareType=_entryTable[migCtorIdx]->chareIdx;
2914                     dummyElts.push_back(elt);
2915                     if (!rec->invokeEntry(elt,NULL,migCtorIdx,true)) return ;
2916                 }
2917         }
2918     }
2919     if(!dummy){
2920         for (auto itr = managers.begin(); itr != managers.end(); ++itr) {
2921             CkMigratable *elt = itr->second->getEltFromArrMgr(rec->getIndex());
2922             if (elt!=NULL)
2923                 {
2924                        elt->virtual_pup(p);
2925                 }
2926         }
2927     }else{
2928             for(int i=0;i<dummyElts.size();i++){
2929                 CkMigratable *elt = dummyElts[i];
2930                 if (elt!=NULL){
2931             elt->virtual_pup(p);
2932                         }
2933                 delete elt;
2934             }
2935             for (auto itr = managers.begin(); itr != managers.end(); ++itr) {
2936                 itr->second->eraseEltFromArrMgr(rec->getIndex());
2937             }
2938     }
2939 }
2940 #else
2941 void CkLocMgr::pupElementsFor(PUP::er &p,CkLocRec *rec,
2942                 CkElementCreation_t type,bool rebuild)
2943 {
2944         p.comment("-------- Array Location --------");
2945
2946         //First pup the element types
2947         // (A separate loop so ckLocal works even in element pup routines)
2948     for (auto itr = managers.begin(); itr != managers.end(); ++itr) {
2949                 int elCType;
2950                 CkArray *arr = itr->second;
2951                 if (!p.isUnpacking())
2952                 { //Need to find the element's existing type
2953                         CkMigratable *elt = arr->getEltFromArrMgr(rec->getID());
2954                         if (elt) elCType=elt->ckGetChareType();
2955                         else elCType=-1; //Element hasn't been created
2956                 }
2957                 p(elCType);
2958                 if (p.isUnpacking() && elCType!=-1) {
2959                         //Create the element
2960                         CkMigratable *elt = arr->allocateMigrated(elCType, type);
2961                         int migCtorIdx=_chareTable[elCType]->getMigCtor();
2962                         //Insert into our tables and call migration constructor
2963                         if (!addElementToRec(rec,arr,elt,migCtorIdx,NULL)) return;
2964                         if (type==CkElementCreation_resume)
2965                         { // HACK: Re-stamp elements on checkpoint resume--
2966                           //  this restores, e.g., reduction manager's gcount
2967                           arr->stampListenerData(elt);
2968                         }
2969                 }
2970         }
2971         //Next pup the element data
2972     for (auto itr = managers.begin(); itr != managers.end(); ++itr) {
2973                 CkMigratable *elt = itr->second->getEltFromArrMgr(rec->getID());
2974                 if (elt!=NULL)
2975                 {
2976                         elt->virtual_pup(p);
2977 #if CMK_ERROR_CHECKING
2978                         if (p.isUnpacking()) elt->sanitycheck();
2979 #endif
2980                 }
2981         }
2982 #if CMK_MEM_CHECKPOINT
2983         if(rebuild){
2984           ArrayElement *elt;
2985           std::vector<CkMigratable *> list;
2986           migratableList(rec, list);
2987           CmiAssert(!list.empty());
2988           for (int l=0; l<list.size(); l++) {
2989                 //    reset, may not needed now
2990                 // for now.
2991                 for (int i=0; i<CK_ARRAYLISTENER_MAXLEN; i++) {
2992                         ArrayElement * elt = (ArrayElement *)list[l];
2993                   contributorInfo *c=(contributorInfo *)&elt->listenerData[i];
2994                   if (c) c->redNo = 0;
2995                 }
2996           }
2997                 
2998         }
2999 #endif
3000 }
3001 #endif
3002
3003 /// Call this member function on each element of this location:
3004 void CkLocMgr::callMethod(CkLocRec *rec,CkMigratable_voidfn_t fn)
3005 {
3006     for (auto itr = managers.begin(); itr != managers.end(); ++itr) {
3007                 CkMigratable *el = itr->second->getEltFromArrMgr(rec->getID());
3008                 if (el) (el->* fn)();
3009         }
3010 }
3011
3012 /// Call this member function on each element of this location:
3013 void CkLocMgr::callMethod(CkLocRec *rec,CkMigratable_voidfn_arg_t fn,     void * data)
3014 {
3015     for (auto itr = managers.begin(); itr != managers.end(); ++itr) {
3016                 CkMigratable *el = itr->second->getEltFromArrMgr(rec->getID());
3017                 if (el) (el->* fn)(data);
3018         }
3019 }
3020
3021 /// return a list of migratables in this local record
3022 void CkLocMgr::migratableList(CkLocRec *rec, std::vector<CkMigratable *> &list)
3023 {
3024         for (auto itr = managers.begin(); itr != managers.end(); ++itr) {
3025                 CkMigratable *elt = itr->second->getEltFromArrMgr(rec->getID());
3026                 if (elt) list.push_back(elt);
3027         }
3028 }
3029
3030 /// Migrate this local element away to another processor.
3031 void CkLocMgr::emigrate(CkLocRec *rec,int toPe)
3032 {
3033         CK_MAGICNUMBER_CHECK
3034         if (toPe==CkMyPe()) return; //You're already there!
3035
3036 #if CMK_FAULT_EVAC
3037         /*
3038                 if the toProcessor is already marked as invalid, dont emigrate
3039                 Shouldn't happen but might
3040         */
3041         if(!CmiNodeAlive(toPe)){
3042                 return;
3043         }
3044 #endif
3045
3046         CkArrayIndex idx=rec->getIndex();
3047         CmiUInt8 id = rec->getID();
3048
3049 #if CMK_OUT_OF_CORE
3050         /* Load in any elements that are out-of-core */
3051     for (auto itr = managers.begin(); itr != managers.end(); ++itr) {
3052                 CkMigratable *el = itr->second->getEltFromArrMgr(rec->getIndex());
3053                 if (el) if (!el->isInCore) CooBringIn(el->prefetchObjID);
3054         }
3055 #endif
3056
3057         //Let all the elements know we're leaving
3058         callMethod(rec,&CkMigratable::ckAboutToMigrate);
3059         /*EVAC*/
3060
3061 //First pass: find size of migration message
3062         size_t bufSize;
3063         {
3064                 PUP::sizer p;
3065                 pupElementsFor(p,rec,CkElementCreation_migrate);
3066                 bufSize=p.size(); 
3067         }
3068 #if CMK_ERROR_CHECKING
3069         if (bufSize > std::numeric_limits<int>::max()) {
3070                 CmiPrintf("Cannot migrate an object with size greater than %zu bytes!\n", std::numeric_limits<int>::max());
3071                 CmiAbort("");
3072         }
3073 #endif
3074
3075 //Allocate and pack into message
3076         CkArrayElementMigrateMessage *msg = new (bufSize, 0) CkArrayElementMigrateMessage(idx, id,
3077 #if CMK_LBDB_ON
3078                 rec->isAsyncMigrate(),
3079 #else
3080                 false,
3081 #endif
3082                 bufSize, managers.size(),
3083 #if CMK_FAULT_EVAC
3084     rec->isBounced()
3085 #else
3086     false
3087 #endif
3088     );
3089
3090 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_)) 
3091     msg->gid = ckGetGroupID();
3092 #endif
3093         {
3094                 PUP::toMem p(msg->packData); 
3095                 p.becomeDeleting(); 
3096                 pupElementsFor(p,rec,CkElementCreation_migrate);
3097                 if (p.size()!=bufSize) {
3098                         CkError("ERROR! Array element claimed it was %d bytes to a "
3099                                 "sizing PUP::er, but copied %d bytes into the packing PUP::er!\n",
3100                                 bufSize,p.size());
3101                         CkAbort("Array element's pup routine has a direction mismatch.\n");
3102                 }
3103         }
3104
3105         DEBM((AA "Migrated index size %s to %d \n" AB,idx2str(idx),toPe));      
3106
3107 //#if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
3108 //#if defined(_FAULT_MLOG_)
3109 //    sendMlogLocation(toPe,UsrToEnv(msg));
3110 //#else
3111         //Send off message and delete old copy
3112         thisProxy[toPe].immigrate(msg);
3113 //#endif
3114
3115         duringMigration=true;
3116         for (auto itr = managers.begin(); itr != managers.end(); ++itr) {
3117                 itr->second->deleteElt(id);
3118         }
3119         duringMigration=false;
3120
3121         //The element now lives on another processor-- tell ourselves and its home
3122         inform(idx, id, toPe);
3123 //#if (!defined(_FAULT_MLOG_) && !defined(_FAULT_CAUSAL_))    
3124 //#if !defined(_FAULT_MLOG_)    
3125         informHome(idx,toPe);
3126 //#endif
3127
3128 #if !CMK_LBDB_ON && CMK_GLOBAL_LOCATION_UPDATE
3129         DEBM((AA "Global location update. idx %s " 
3130               "assigned to %d \n" AB,idx2str(idx),toPe));
3131         thisProxy.updateLocation(id, toPe);
3132 #endif
3133
3134         CK_MAGICNUMBER_CHECK
3135 }
3136
3137 #if CMK_LBDB_ON
3138 void CkLocMgr::informLBPeriod(CkLocRec *rec, int lb_ideal_period) {
3139         callMethod(rec,&CkMigratable::recvLBPeriod, (void *)&lb_ideal_period);
3140 }
3141
3142 void CkLocMgr::metaLBCallLB(CkLocRec *rec) {
3143         callMethod(rec, &CkMigratable::metaLBCallLB);
3144 }
3145 #endif
3146
3147 /**
3148   Migrating array element is arriving on this processor.
3149 */
3150 void CkLocMgr::immigrate(CkArrayElementMigrateMessage *msg)
3151 {
3152         const CkArrayIndex &idx=msg->idx;
3153                 
3154         PUP::fromMem p(msg->packData); 
3155         
3156         if (msg->nManagers < managers.size())
3157                 CkAbort("Array element arrived from location with fewer managers!\n");
3158         if (msg->nManagers > managers.size()) {
3159                 //Some array managers haven't registered yet-- throw it back
3160                 DEBM((AA "Busy-waiting for array registration on migrating %s\n" AB,idx2str(idx)));
3161                 thisProxy[CkMyPe()].immigrate(msg);
3162                 return;
3163         }
3164
3165         insertID(idx,msg->id);
3166
3167         //Create a record for this element
3168 //#if (!defined(_FAULT_MLOG_) && !defined(_FAULT_CAUSAL_))    
3169 //#if !defined(_FAULT_MLOG_)     
3170         CkLocRec *rec=createLocal(idx,true,msg->ignoreArrival,false /* home told on departure */ );
3171 //#else
3172 //    CkLocRec *rec=createLocal(idx,true,true,false /* home told on departure */ );
3173 //#endif
3174         
3175         //Create the new elements as we unpack the message
3176         pupElementsFor(p,rec,CkElementCreation_migrate);
3177         if (p.size()!=msg->length) {
3178                 CkError("ERROR! Array element claimed it was %d bytes to a"
3179                         "packing PUP::er, but %d bytes in the unpacking PUP::er!\n",
3180                         msg->length,p.size());
3181                 CkError("(I have %d managers; he claims %d managers)\n",
3182                         managers.size(), msg->nManagers);
3183                 
3184                 CkAbort("Array element's pup routine has a direction mismatch.\n");
3185         }
3186
3187 #if CMK_FAULT_EVAC
3188         /*
3189                         if this element came in as a result of being bounced off some other process,
3190                         then it needs to be resumed. It is assumed that it was bounced because load 
3191                         balancing caused it to move into a processor which later crashed
3192         */
3193         if(msg->bounced){
3194                 callMethod(rec,&CkMigratable::ResumeFromSync);
3195         }
3196 #endif
3197
3198         //Let all the elements know we've arrived
3199         callMethod(rec,&CkMigratable::ckJustMigrated);
3200
3201 #if CMK_FAULT_EVAC
3202         /*
3203                 If this processor has started evacuating array elements on it 
3204                 dont let new immigrants in. If they arrive send them to what
3205                 would be their correct homePE.
3206                 Leave a record here mentioning the processor where it got sent
3207         */
3208         if(CkpvAccess(startedEvac)){
3209                 int newhomePE = getNextPE(idx);
3210                 DEBM((AA "Migrated into failed processor index size %s resent to %d \n" AB,idx2str(idx),newhomePE));    
3211                 int targetPE=getNextPE(idx);
3212                 //set this flag so that load balancer is not informed when
3213                 //this element migrates
3214                 rec->AsyncMigrate(true);
3215                 rec->Bounced(true);
3216                 emigrate(rec,targetPE);
3217         }
3218 #endif
3219
3220         delete msg;
3221 }
3222
3223 void CkLocMgr::restore(const CkArrayIndex &idx, CmiUInt8 id, PUP::er &p)
3224 {
3225         insertID(idx,id);
3226
3227         //This is in broughtIntoMem during out-of-core emulation in BigSim,
3228         //informHome should not be called since such information is already
3229         //immediately updated real migration
3230 #if CMK_ERROR_CHECKING
3231         if(_BgOutOfCoreFlag!=2)
3232             CmiAbort("CkLocMgr::restore should only be used in out-of-core emulation for BigSim and be called when object is brought into memory!\n");
3233 #endif
3234         CkLocRec *rec=createLocal(idx,false,false,false);
3235         
3236         //BIGSIM_OOC DEBUGGING
3237         //CkPrintf("Proc[%d]: Registering element %s with LDB\n", CkMyPe(), idx2str(idx));
3238
3239         //Create the new elements as we unpack the message
3240         pupElementsFor(p,rec,CkElementCreation_restore);
3241
3242         callMethod(rec,&CkMigratable::ckJustRestored);
3243 }
3244
3245
3246 /// Insert and unpack this array element from this checkpoint (e.g., from CkLocation::pup)
3247 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
3248 void CkLocMgr::resume(const CkArrayIndex &idx, CmiUInt8 id, PUP::er &p, bool create, int dummy)
3249 {
3250         insertID(idx,id);
3251
3252         CkLocRec *rec;
3253
3254         if(create){
3255                 rec = createLocal(idx,false,false,true && !dummy /* home doesn't know yet */,dummy );
3256         }else{
3257                 rec = elementNrec(idx);
3258                 if(rec == NULL) 
3259                         CmiAbort("Local object not found");
3260         }
3261         
3262     pupElementsFor(p,rec,CkElementCreation_resume,create,dummy);
3263
3264     if(!dummy){
3265         callMethod(rec,&CkMigratable::ckJustMigrated);
3266     }
3267 }
3268 #else
3269 void CkLocMgr::resume(const CkArrayIndex &idx, CmiUInt8 id, PUP::er &p, bool notify,bool rebuild)
3270 {
3271         insertID(idx,id);
3272
3273         CkLocRec *rec=createLocal(idx,false,false,notify /* home doesn't know yet */ );
3274
3275         //Create the new elements as we unpack the message
3276         pupElementsFor(p,rec,CkElementCreation_resume,rebuild);
3277
3278         callMethod(rec,&CkMigratable::ckJustMigrated);
3279 }
3280 #endif
3281
3282 /********************* LocMgr: UTILITY ****************/
3283 void CkMagicNumber_impl::badMagicNumber(
3284         int expected,const char *file,int line,void *obj) const
3285 {
3286         CkError("FAILURE on pe %d, %s:%d> Expected %p's magic number "
3287                 "to be 0x%08x; but found 0x%08x!\n", CkMyPe(),file,line,obj,
3288                 expected, magic);
3289         CkAbort("Bad magic number detected!  This implies either\n"
3290                 "the heap or a message was corrupted!\n");
3291 }
3292 CkMagicNumber_impl::CkMagicNumber_impl(int m) :magic(m) { }
3293
3294 int CkLocMgr::whichPE(const CkArrayIndex &idx) const
3295 {
3296   CmiUInt8 id;
3297   if (!lookupID(idx, id))
3298     return -1;
3299
3300   IdPeMap::const_iterator itr = id2pe.find(id);
3301   return (itr != id2pe.end() ? itr->second : -1);
3302 }
3303
3304 int CkLocMgr::whichPE(const CmiUInt8 id) const
3305 {
3306   IdPeMap::const_iterator itr = id2pe.find(id);
3307   return (itr != id2pe.end() ? itr->second : -1);
3308 }
3309
3310 //"Last-known" location (returns a processor number)
3311 int CkLocMgr::lastKnown(const CkArrayIndex &idx) {
3312         CkLocMgr *vthis=(CkLocMgr *)this;//Cast away "const"
3313         int pe = whichPE(idx);
3314         if (pe==-1) return homePe(idx);
3315         else{
3316 #if CMK_FAULT_EVAC
3317                 if(!CmiNodeAlive(pe)){
3318                         CkAbort("Last known PE is no longer alive");
3319                 }
3320 #endif
3321                 return pe;
3322         }       
3323 }
3324
3325 //"Last-known" location (returns a processor number)
3326 int CkLocMgr::lastKnown(CmiUInt8 id) {
3327   int pe = whichPE(id);
3328   if (pe==-1) return homePe(id);
3329   else{
3330 #if CMK_FAULT_EVAC
3331     if(!CmiNodeAlive(pe)){
3332       CkAbort("Last known PE is no longer alive");
3333     }
3334 #endif
3335     return pe;
3336   }     
3337 }
3338
3339 /// Return true if this array element lives on another processor
3340 bool CkLocMgr::isRemote(const CkArrayIndex &idx,int *onPe) const
3341 {
3342     int pe = whichPE(idx);
3343     /* not definitely a remote element */
3344     if (pe == -1 || pe == CkMyPe())
3345         return false;
3346     // element is indeed remote
3347     *onPe = pe;
3348     return true;
3349 }
3350
3351 static const char *rec2str[]={
3352     "base (INVALID)",//Base class (invalid type)
3353     "local",//Array element that lives on this Pe
3354 };
3355
3356 #if (defined(_FAULT_MLOG_) || defined(_FAULT_CAUSAL_))
3357 void CkLocMgr::setDuringMigration(bool _duringMigration){
3358     duringMigration = _duringMigration;
3359 }
3360 #endif
3361
3362 // If we are deleting our last array manager set duringDestruction to true to
3363 // avoid sending out unneeded reclaimRemote messages.
3364 void CkLocMgr::setDuringDestruction(bool _duringDestruction) {
3365   duringDestruction = (_duringDestruction && managers.size() == 1);
3366 }
3367
3368 //Add given element array record at idx, replacing the existing record
3369 void CkLocMgr::insertRec(CkLocRec *rec, const CmiUInt8 &id) {
3370     CkLocRec *old_rec = elementNrec(id);
3371     CmiImmediateLock(hashImmLock);
3372     hash[id] = rec;
3373     CmiImmediateUnlock(hashImmLock);
3374     delete old_rec;
3375 }
3376
3377 //Call this on an unrecognized array index
3378 static void abort_out_of_bounds(const CkArrayIndex &idx)
3379 {
3380   CkPrintf("ERROR! Unknown array index: %s\n",idx2str(idx));
3381   CkAbort("Array index out of bounds\n");
3382 }
3383
3384 //Look up array element in hash table.  Index out-of-bounds if not found.
3385 // TODO: Could this take an ID instead?
3386 CkLocRec *CkLocMgr::elementRec(const CkArrayIndex &idx) {
3387 #if ! CMK_ERROR_CHECKING
3388 //Assume the element will be found
3389   return hash[lookupID(idx)];
3390 #else
3391 //Include an out-of-bounds check if the element isn't found
3392   CmiUInt8 id;
3393   CkLocRec *rec = NULL;
3394   if (lookupID(idx, id) && (rec = elementNrec(id))) {
3395         return rec;
3396   } else {
3397         if (rec==NULL) abort_out_of_bounds(idx);
3398         return NULL;
3399   }
3400 #endif
3401 }
3402
3403 //Look up array element in hash table.  Return NULL if not there.
3404 CkLocRec *CkLocMgr::elementNrec(const CmiUInt8 id) {
3405   LocRecHash::iterator it = hash.find(id);
3406   return it == hash.end() ? NULL : it->second;
3407 }
3408
3409 struct LocalElementCounter :  public CkLocIterator
3410 {
3411     unsigned int count;
3412     LocalElementCounter() : count(0) {}
3413     void addLocation(CkLocation &loc)
3414         { ++count; }
3415 };
3416
3417 unsigned int CkLocMgr::numLocalElements()
3418 {
3419     LocalElementCounter c;
3420     iterate(c);
3421     return c.count;
3422 }
3423
3424
3425 /********************* LocMgr: LOAD BALANCE ****************/
3426
3427 #if !CMK_LBDB_ON
3428 //Empty versions of all load balancer calls
3429 void CkLocMgr::initLB(CkGroupID lbdbID_, CkGroupID metalbID_) {}
3430 void CkLocMgr::startInserting(void) {}
3431 void CkLocMgr::doneInserting(void) {}
3432 void CkLocMgr::dummyAtSync(void) {}
3433 #endif
3434
3435
3436 #if CMK_LBDB_ON
3437 void CkLocMgr::initLB(CkGroupID lbdbID_, CkGroupID metalbID_)
3438 { //Find and register with the load balancer
3439         the_lbdb = (LBDatabase *)CkLocalBranch(lbdbID_);
3440         if (the_lbdb == 0)
3441                 CkAbort("LBDatabase not yet created?\n");
3442         DEBL((AA "Connected to load balancer %p\n" AB,the_lbdb));
3443         if(_lb_args.metaLbOn()){
3444           the_metalb = (MetaBalancer *)CkLocalBranch(metalbID_);
3445           if (the_metalb == 0)
3446                   CkAbort("MetaBalancer not yet created?\n");
3447         }
3448         // Register myself as an object manager
3449         LDOMid myId;
3450         myId.id = thisgroup;
3451         LDCallbacks myCallbacks;
3452         myCallbacks.migrate = (LDMigrateFn)CkLocRec::staticMigrate;
3453         myCallbacks.setStats = NULL;
3454         myCallbacks.queryEstLoad = NULL;
3455   myCallbacks.metaLBResumeWaitingChares =
3456       (LDMetaLBResumeWaitingCharesFn)CkLocRec::staticMetaLBResumeWaitingChares;
3457   myCallbacks.metaLBCallLBOnChares =
3458       (LDMetaLBCallLBOnCharesFn)CkLocRec::staticMetaLBCallLBOnChares;
3459         myLBHandle = the_lbdb->RegisterOM(myId,this,myCallbacks);
3460
3461         // Tell the lbdb that I'm registering objects
3462         the_lbdb->RegisteringObjects(myLBHandle);
3463
3464         /*Set up the dummy barrier-- the load balancer needs
3465           us to call Registering/DoneRegistering during each AtSync,
3466           and this is the only way to do so.
3467         */
3468         lbBarrierReceiver = the_lbdb->AddLocalBarrierReceiver(
3469                 (LDBarrierFn)staticRecvAtSync,(void*)(this));
3470         dummyBarrierHandle = the_lbdb->AddLocalBarrierClient(
3471                 (LDResumeFn)staticDummyResumeFromSync,(void*)(this));
3472         dummyAtSync();
3473 }
3474 void CkLocMgr::dummyAtSync(void)
3475 {
3476         DEBL((AA "dummyAtSync called\n" AB));
3477         the_lbdb->AtLocalBarrier(dummyBarrierHandle);
3478 }
3479
3480 void CkLocMgr::staticDummyResumeFromSync(void* data)
3481 {      ((CkLocMgr*)data)->dummyResumeFromSync(); }
3482 void CkLocMgr::dummyResumeFromSync()
3483 {
3484         DEBL((AA "DummyResumeFromSync called\n" AB));
3485         the_lbdb->DoneRegisteringObjects(myLBHandle);
3486         dummyAtSync();
3487 }
3488 void CkLocMgr::staticRecvAtSync(void* data)
3489 {      ((CkLocMgr*)data)->recvAtSync(); }
3490 void CkLocMgr::recvAtSync()
3491 {
3492         DEBL((AA "recvAtSync called\n" AB));
3493         the_lbdb->RegisteringObjects(myLBHandle);
3494 }
3495
3496 void CkLocMgr::startInserting(void)
3497 {
3498         the_lbdb->RegisteringObjects(myLBHandle);
3499 }
3500 void CkLocMgr::doneInserting(void)
3501 {
3502         the_lbdb->DoneRegisteringObjects(myLBHandle);
3503 }
3504 #endif
3505
3506 #include "CkLocation.def.h"
3507
3508