16cf5d460c5a5fafc44c8f6b1e4b50d091c5e9f9
[namd.git] / src / NamdHybridLB.C
1 /*****************************************************************************
2  * $Source: /home/cvs/namd/cvsroot/namd2/src/NamdHybridLB.C,v $
3  * $Author: jim $
4  * $Date: 2017/03/30 20:06:17 $
5  * $Revision: 1.40 $
6  *****************************************************************************/
7
8 #if !defined(WIN32) || defined(__CYGWIN__)
9 #include <unistd.h>
10 #endif
11 #include <fcntl.h>
12
13 #include "InfoStream.h"
14 #include "NamdHybridLB.h"
15 #include "Node.h"
16 #include "PatchMap.h"
17 #include "ComputeMap.h"
18 #include "LdbCoordinator.h"
19
20 class SplitComputesMsg : public CMessage_SplitComputesMsg {
21 public:
22   double maxUnsplit;
23   double averageLoad;
24   double avgCompute;
25   double maxCompute;
26   int maxComputeId;
27   int nMoveableComputes;
28   int numPesAvailable;
29   int n;
30   int *cid;
31   float *load;
32 };
33
34 #include "NamdHybridLB.def.h"
35
36 // #define DUMP_LDBDATA 1
37 // #define LOAD_LDBDATA 1
38
39 extern int isPmeProcessor(int); 
40 #ifdef MEM_OPT_VERSION
41 extern int isOutputProcessor(int); 
42 #endif
43 // Load array defined in NamdCentLB.C
44 extern double *cpuloads;
45
46 /**
47  * Creates the chare array for the hybrid load balancer.
48  */ 
49 void CreateNamdHybridLB() {
50         CProxy_NamdHybridLB::ckNew();
51
52         // creating an array to store the loads of all processors
53         // to be used with proxy spanning tree
54         if (CkMyPe() == 0 && cpuloads == NULL) {
55                 cpuloads = new double[CkNumPes()];
56                 CmiAssert(cpuloads != NULL);
57                 for (int i=0; i<CkNumPes(); i++) cpuloads[i] = 0.0;
58         }
59 }
60
61 /**
62  * @brief Default constructor.
63  */
64 NamdHybridLB::NamdHybridLB(): HybridBaseLB(CkLBOptions(-1))
65 {
66   // setting the name
67   lbname = (char *)"NamdHybridLB";
68
69   delete tree;        // delete the tree built from the base class
70   const SimParameters* simParams = Node::Object()->simParameters;
71   if (CkNumPes() <= simParams->hybridGroupSize)  {
72     tree = new TwoLevelTree;   // similar to centralized load balancing
73   }
74   else {
75     tree = new ThreeLevelTree(simParams->hybridGroupSize);
76     initTree();
77     // can only do shrink strategy on levels > 1
78     statsStrategy = SHRINK_NULL;
79   }
80
81   // initializing thisProxy
82   thisProxy = CProxy_NamdHybridLB(thisgroup);
83   
84   // initializing the central LB
85   centralLB = AllocateNamdCentLB();
86
87   // initializing the dummy LB
88   dummyLB = AllocateNamdDummyLB();
89
90   // assigning initial values to variables
91   from_procs = NULL;
92   computeArray = NULL;
93   patchArray = NULL;
94   processorArray = NULL;
95   updateCount = 0;
96   splitCount = 0;
97   splitComputesMsgs = 0;
98   updateFlag = false;
99   collectFlag = false;
100
101 }
102
103 /**
104  * @brief Function used to discover if load balancer can be run at that point.
105  *
106  * It is called from HybridBase every time AtSync method is called.
107  */
108 bool NamdHybridLB::QueryBalanceNow(int _step){ 
109   if ( LdbCoordinator::Object()->takingLdbData ) {
110           return true;
111   } else {
112           return false;
113   } 
114 }
115
116 bool NamdHybridLB::QueryDumpData() {
117 #if 0                                                                                             
118   if (LdbCoordinator::Object()->ldbCycleNum == 1)  return true;                                
119   if (LdbCoordinator::Object()->ldbCycleNum == 2)  return true;                                
120 #endif                                                                                            
121   return false;                                                                                
122 }
123
124 #if 0
125 /**
126  *  Runs the load balancing strategy with shrinking the load information.
127  *  Note: now, it is just calling the Strategy, but eventually will have
128  *  its own code.
129  */
130 LBVectorMigrateMsg* NamdHybridLB::VectorStrategy(LDStats* stats){
131   CkPrintf("[%d] Using Vector Strategy to balance the load\n",CkMyPe());
132   LBVectorMigrateMsg* msg = new(0,0) LBVectorMigrateMsg;
133   msg->n_moves = 0;
134   msg->level = currentLevel;
135   return msg;
136 }
137 #endif
138
139 /*
140  * Runs the load balancing strategy
141  */
142 CLBMigrateMsg* NamdHybridLB::Strategy(LDStats* stats)
143 {
144         int i;
145         // CkPrintf("[%d] NamdHybridLB at Strategy\n",CkMyPe());
146         
147         // calling the centralLB for level 1            
148         if(currentLevel == 1){
149                 LevelData *lData = levelData[currentLevel];
150                 CLBMigrateMsg *msg;
151                 LocalLBInfoMsg *newMsg;
152                 msg = GrpLevelStrategy(stats);
153
154                 // creating a new message to send to its parent
155                 newMsg = new(msg->n_moves,endPE-startPE+1) LocalLBInfoMsg;
156                 newMsg->n_moves = msg->n_moves;
157                 newMsg->startPE = startPE;
158                 newMsg->endPE = endPE;
159                 for(i=0; i<msg->n_moves; i++){
160                         newMsg->moves[i] = msg->moves[i];
161                 }
162                 for(i=0; i<endPE-startPE+1; i++){
163                         newMsg->cpuloads[i] = peLoads[i];
164                 }
165                 delete [] peLoads;
166                 thisProxy[0].UpdateLocalLBInfo(newMsg);
167                 return msg;
168         }else{
169                 dummyLB->work(stats);
170                 return createMigrateMsg(stats);
171         }
172 }
173
174 /**
175  * Updates the compute map with the migration information from its children.
176  */
177 void NamdHybridLB::UpdateLocalLBInfo(LocalLBInfoMsg *msg){
178         int children;
179         int i;
180
181         // getting the number of children
182         children = tree->numNodes(currentLevel);
183         // CkPrintf("[%d] Updating compute map, total %d\n",CkMyPe(),siblings);
184
185         // getting the compute map to insert the changes coming from the children
186         ComputeMap *computeMap = ComputeMap::Object();
187
188         // traversing the set of moves in msg
189         for(i=0; i<msg->n_moves; i++){
190             if (msg->moves[i].to_pe != -1)
191                 computeMap->setNewNode(msg->moves[i].obj.id.id[0],msg->moves[i].to_pe); 
192         }
193
194         // CODING
195         // updating cpuloads array
196         for(i=msg->startPE; i<=msg->endPE; i++){
197                 cpuloads[i] = msg->cpuloads[i-msg->startPE];
198         }
199
200         // checking if all children have sent the update
201         updateCount++;
202         if(updateCount == children){
203                 updateCount = 0;
204                 updateFlag = true;
205                  // CkPrintf("[%d] UPDATE READY\n",CkMyPe());           
206         }
207
208         // checking if the collect info is ready
209         if(updateFlag && collectFlag){
210                 updateFlag = false;
211                 collectFlag = false;    
212                 thisProxy[parent_backup].CollectInfo(loc_backup, n_backup, fromlevel_backup);
213         }
214
215         delete msg;
216 }
217
218 void NamdHybridLB::splitComputes(SplitComputesMsg *msg) {
219   const int children = tree->numNodes(1);
220
221   if ( ! splitComputesMsgs ) {
222     splitComputesMsgs = new SplitComputesMsg*[children];
223   }
224   
225   splitComputesMsgs[splitCount] = msg;
226
227   if ( ++splitCount == children ) {
228     splitCount = 0;
229
230     const SimParameters* simParams = Node::Object()->simParameters;
231     ComputeMap *computeMap = ComputeMap::Object();
232
233     double maxUnsplit = 0.;
234     double averageLoad = 0.;
235     double avgCompute = 0.;
236     double maxCompute = 0.;
237     int maxComputeId = -1;
238     int nMoveableComputes = 0;
239     int numPesAvailable = 0;
240     int nToSplit = 0;
241
242     for ( int j=0; j < children; ++j ) {
243       SplitComputesMsg *msg = splitComputesMsgs[j];
244       if ( msg->maxUnsplit > maxUnsplit ) { maxUnsplit = msg->maxUnsplit; }
245       if ( msg->maxCompute > maxCompute ) { maxCompute = msg->maxCompute; maxComputeId = msg->maxComputeId; }
246       averageLoad += msg->averageLoad * msg->numPesAvailable;
247       numPesAvailable += msg->numPesAvailable;
248       avgCompute += msg->avgCompute * msg->nMoveableComputes;
249       nMoveableComputes += msg->nMoveableComputes;
250       nToSplit += msg->n;
251     }
252     
253     averageLoad /= numPesAvailable;
254     if ( nMoveableComputes ) avgCompute /= nMoveableComputes; else avgCompute = 0.;
255
256     CkPrintf("LDB: Largest compute %d load %f is %.1f%% of average load %f\n",
257             maxComputeId, maxCompute, 100. * maxCompute / averageLoad, averageLoad);
258     CkPrintf("LDB: Average compute %f is %.1f%% of average load %f\n",
259             avgCompute, 100. * avgCompute / averageLoad, averageLoad);
260
261     if ( ! nToSplit ) {
262       for ( int j=0; j < children; ++j ) {
263         delete splitComputesMsgs[j];
264       }
265     } else {
266       // partitions are stored as char but mostly limited by
267       // high load noise at low outer-loop iteration counts
268       int maxParts = 10;
269 #ifdef NAMD_CUDA
270 //split LCPO compute very small, else CUDA compute is delayed
271       if (simParams->LCPOOn) {
272         maxParts = 20;
273       }
274 #endif
275       int totalAddedParts = 0;
276       maxCompute = averageLoad / 10.;
277       if ( maxCompute < 2. * avgCompute ) maxCompute = 2. * avgCompute;
278       if ( simParams->ldbRelativeGrainsize > 0. ) {
279         maxCompute = averageLoad * simParams->ldbRelativeGrainsize;
280       }
281       CkPrintf("LDB: Partitioning computes with target load %f\n", maxCompute);
282
283       for ( int j=0; j < children; ++j ) {
284         SplitComputesMsg *msg = splitComputesMsgs[j];
285         for (int i=0; i < msg->n; ++i) {
286           int nparts = (int) ceil(msg->load[i] / maxCompute);
287           if ( nparts > maxParts ) nparts = maxParts;
288           if ( nparts < 1 ) nparts = 1;
289           computeMap->setNewNumPartitions(msg->cid[i],nparts);
290           totalAddedParts += nparts - 1;
291         }
292         delete msg;
293       }
294
295       CkPrintf("LDB: Increased migratable compute count from %d to %d\n",
296               nMoveableComputes,nMoveableComputes+totalAddedParts);
297       CkPrintf("LDB: Largest unpartitionable compute is %f\n", maxUnsplit);
298     }
299   }
300 }
301
302
303 /**
304  * This function implements a strategy similar to the one used in the 
305  * centralized case in NamdCentLB.
306  */
307 CLBMigrateMsg* NamdHybridLB::GrpLevelStrategy(LDStats* stats) {
308   int numProcessors = stats->nprocs();  // number of processors at group level
309   int numPatches = PatchMap::Object()->numPatches();
310   ComputeMap *computeMap = ComputeMap::Object();
311   const int numComputes = computeMap->numComputes();
312   const int numGroupComputes = stats->n_migrateobjs;
313   const SimParameters* simParams = Node::Object()->simParameters;
314
315   if ( ! processorArray ) processorArray = new processorInfo[numProcessors];
316   // these data structures are global and need to be distributed
317   if ( ! patchArray ) patchArray = new patchInfo[numPatches];
318   if ( ! computeArray ) computeArray = new computeInfo[numGroupComputes];
319   if ( ! from_procs ) from_procs = new int[numGroupComputes];
320
321   int nMoveableComputes = buildData(stats);
322   CmiAssert(nMoveableComputes <= numGroupComputes);
323
324
325 #if LDB_DEBUG
326 #define DUMP_LDBDATA 1
327 #define LOAD_LDBDATA 1
328 #endif
329
330 #if DUMP_LDBDATA 
331   dumpDataASCII("ldbd_before", numProcessors, numPatches, nMoveableComputes);
332 #elif LOAD_LDBDATA
333   loadDataASCII("ldbd_before.5", numProcessors, numPatches, nMoveableComputes);
334   // CkExit();
335 #endif
336
337   double averageLoad = 0.;
338   double avgCompute;
339   double maxCompute;
340   int maxComputeId;
341   int numPesAvailable;
342   {
343    int i;
344    double total = 0.;
345    maxCompute = 0.;
346    int maxi = 0;
347    for (i=0; i<nMoveableComputes; i++) {
348       double load = computeArray[i].load;
349       total += load;
350       if ( load > maxCompute ) { maxCompute = load;  maxi = i; }
351    }
352    avgCompute = total / nMoveableComputes;
353    maxComputeId = computeArray[maxi].handle.id.id[0];
354
355     int P = stats->nprocs();
356    numPesAvailable = 0;
357    for (i=0; i<P; i++) {
358       if (processorArray[i].available) {
359         ++numPesAvailable;
360         total += processorArray[i].backgroundLoad;
361       }
362    }
363    if (numPesAvailable == 0)
364      NAMD_die("No processors available for load balancing!\n");
365
366    averageLoad = total/numPesAvailable;
367   }
368
369   int i_split = 0;
370   double maxUnsplit = 0.;
371
372   if ( step() == 1 ) {
373     for (int i=0; i<nMoveableComputes; i++) {
374       const int cid = computeArray[i].handle.id.id[0];
375       if ( computeMap->numPartitions(cid) == 0 ) {
376         const double load = computeArray[i].load;
377         if ( load > maxUnsplit ) maxUnsplit = load;
378         continue;
379       }
380       ++i_split;
381     }
382   }
383
384   {
385     SplitComputesMsg *msg = new(i_split,i_split) SplitComputesMsg;
386     msg->maxUnsplit = maxUnsplit;
387     msg->averageLoad = averageLoad;
388     msg->avgCompute = avgCompute;
389     msg->maxCompute = maxCompute;
390     msg->maxComputeId = maxComputeId;
391     msg->nMoveableComputes = nMoveableComputes;
392     msg->numPesAvailable = numPesAvailable;
393     msg->n = i_split;
394
395     if ( step() == 1 ) {
396       i_split = 0;
397       for (int i=0; i<nMoveableComputes; i++) {
398         computeArray[i].processor = computeArray[i].oldProcessor;
399         const int cid = computeArray[i].handle.id.id[0];
400         if ( computeMap->numPartitions(cid) == 0 ) {
401           continue;
402         }
403         msg->cid[i_split] = cid;
404         msg->load[i_split] = computeArray[i].load;
405         ++i_split;
406       }
407     }
408
409     thisProxy[0].splitComputes(msg);
410   }
411
412   if ( step() == 1 ) {
413     // compute splitting only
414   } else if (simParams->ldbStrategy == LDBSTRAT_DEFAULT) { // default
415     if (step() < 4)
416       TorusLB(computeArray, patchArray, processorArray,
417                   nMoveableComputes, numPatches, numProcessors);
418     else
419       RefineTorusLB(computeArray, patchArray, processorArray,
420                   nMoveableComputes, numPatches, numProcessors, 1);
421   } else if (simParams->ldbStrategy == LDBSTRAT_COMPREHENSIVE) {
422     TorusLB(computeArray, patchArray, processorArray,
423                   nMoveableComputes, numPatches, numProcessors);
424   } else if (simParams->ldbStrategy == LDBSTRAT_REFINEONLY) {
425     RefineTorusLB(computeArray, patchArray, processorArray,
426                   nMoveableComputes, numPatches, numProcessors, 1);
427   } else if (simParams->ldbStrategy == LDBSTRAT_OLD) {
428     NAMD_die("Old load balancer strategy is not compatible with hybrid balancer.");
429     if (step() < 4)
430       Alg7(computeArray, patchArray, processorArray,
431                   nMoveableComputes, numPatches, numProcessors);
432     else
433       RefineOnly(computeArray, patchArray, processorArray,
434                   nMoveableComputes, numPatches, numProcessors);
435   }
436
437 #if LDB_DEBUG && USE_TOPOMAP
438   TopoManager tmgr;
439   int pe1, pe2, pe3, hops=0;
440   /* This is double counting the hops
441   for(int i=0; i<nMoveableComputes; i++)
442   {
443     pe1 = computeArray[i].processor;
444     pe2 = patchArray[computeArray[i].patch1].processor;
445     pe3 = patchArray[computeArray[i].patch2].processor;
446     hops += tmgr.getHopsBetweenRanks(pe1, pe2);
447     if(computeArray[i].patch1 != computeArray[i].patch2)
448       hops += tmgr.getHopsBetweenRanks(pe1, pe3);  
449   }*/
450   for (int i=0; i<numPatches; i++)  {
451     //int num = patchArray[i].proxiesOn.numElements();
452     pe1 = patchArray[i].processor;
453     Iterator nextProc;
454     processorInfo *p = (processorInfo *)patchArray[i].proxiesOn.iterator((Iterator *)&nextProc);
455     while (p) {
456       pe2 = p->Id;
457       hops += tmgr.getHopsBetweenRanks(pe1, pe2);
458       p = (processorInfo *)patchArray[i].proxiesOn.next((Iterator*)&nextProc);
459     }
460   }
461   CkPrintf("Load Balancing: Number of Hops: %d\n", hops);
462 #endif
463
464 #if DUMP_LDBDATA
465   dumpDataASCII("ldbd_after", numProcessors, numPatches, nMoveableComputes);
466 #elif LOAD_LDBDATA
467   dumpDataASCII("ldbd_after.5", numProcessors, numPatches, nMoveableComputes);
468   // loadDataASCII("ldbd_after", numProcessors, numPatches, nMoveableComputes);
469   // CkExit();
470 #endif
471
472   // For error checking:
473   // Count up computes, to see if somebody doesn't have any computes
474   int i;
475 #if 0
476   int* computeCount = new int[numProcessors];
477   for(i=0; i<numProcessors; i++)
478     computeCount[i]=0;
479   for(i=0; i<nMoveableComputes; i++)
480     computeCount[computeArray[i].processor]++;
481   for(i=0; i<numProcessors; i++) {
482     if (computeCount[i]==0)
483       iout << iINFO <<"Warning: Processor " << i 
484            << " has NO moveable computes.\n" << endi;
485   }
486   delete [] computeCount;
487 #endif
488   
489   CkVec<MigrateInfo *> migrateInfo;
490   for(i=0;i<nMoveableComputes;i++) {
491     if (computeArray[i].processor != from_procs[i]+stats->procs[0].pe) {
492       /* CkPrintf("[%d] Obj %d migrating from %d (%d) to %d\n",
493                      CkMyPe(),computeArray[i].handle.id.id[0],
494                          from_procs[i], computeArray[i].oldProcessor, computeArray[i].processor); */
495       MigrateInfo *migrateMe = new MigrateInfo;
496       migrateMe->obj = computeArray[i].handle;
497       //migrateMe->from_pe = computeArray[i].oldProcessor;
498       int frompe = from_procs[i];
499       if (frompe == numProcessors)
500         frompe = -1;
501       else
502         frompe = frompe + stats->procs[0].pe;
503       migrateMe->from_pe = frompe;
504       migrateMe->to_pe = computeArray[i].processor;
505       if (frompe == -1) {
506           // don't know yet which processor this compute belongs to, but
507           // inform receiver
508         LDObjData obj;
509         obj.handle = computeArray[i].handle;
510         thisProxy[computeArray[i].processor].ObjMigrated(obj, NULL, 0, currentLevel-1);
511       } 
512       migrateInfo.insertAtEnd(migrateMe);
513
514       // sneak in updates to ComputeMap
515       //ERASE CkPrintf("%d setting %d to processor %d\n",CkMyPe(),computeArray[i].handle.id.id[0],computeArray[i].processor);
516       computeMap->setNewNode(computeArray[i].handle.id.id[0],
517                                 computeArray[i].processor);
518     }
519   }
520   // CkPrintf("LOAD BALANCING READY %d\n",CkMyPe()); 
521
522   LBMigrateMsg* msg;
523   msg = createMigrateMsg(migrateInfo, numProcessors);
524
525   peLoads = new double [numProcessors]; 
526   startPE = processorArray[0].Id;
527   endPE = processorArray[numProcessors-1].Id;
528   // CkPrintf("[%d] numProcessors=%d, %d to %d\n",CkMyPe(),numProcessors,processorArray[0].Id,processorArray[numProcessors-1].Id);
529   for (i=0; i<numProcessors; i++) {
530         peLoads[i] = processorArray[i].load;
531   }
532
533
534   delete [] from_procs;
535   delete [] processorArray;
536   delete [] patchArray;
537   delete [] computeArray;
538
539   from_procs = NULL;
540   processorArray = NULL;
541   patchArray = NULL;
542   computeArray = NULL;
543   
544   return msg;
545
546 }
547
548 void NamdHybridLB::dumpDataASCII(char *file, int numProcessors,
549                                int numPatches, int numComputes)
550 {
551   char filename[128];
552   sprintf(filename, "%s_%d.%d", file, CkMyPe(), step());
553   FILE* fp = fopen(filename,"w");
554   if (fp == NULL){
555      perror("dumpLDStatsASCII");
556      return;
557   }
558   // CkPrintf("***** DUMP data to file: %s ***** \n", filename);
559   fprintf(fp,"%d %d %d\n",numProcessors,numPatches,numComputes);
560
561   int i;
562   for(i=0;i<numProcessors;i++) {
563     processorInfo* p = processorArray + i;
564     fprintf(fp,"%d %e %e %e %e\n",p->Id,p->load,p->backgroundLoad,p->computeLoad,p->idleTime);
565   }
566
567   for(i=0;i < numPatches; i++) {
568     patchInfo* p = patchArray + i;
569     fprintf(fp,"%d %e %d %d\n",p->Id,p->load,p->processor,p->numAtoms);
570   }
571
572   for(i=0; i < numComputes; i++) {
573     computeInfo* c = computeArray + i;
574     fprintf(fp,"%d %e %d %d %d %d",c->Id,c->load,c->patch1,c->patch2,
575             c->processor,c->oldProcessor);
576     fprintf(fp, "\n");
577   }
578
579   // dump patchSet
580   for (i=0; i< numProcessors; i++) {
581       int num = processorArray[i].proxies.numElements();
582       fprintf(fp, "%d %d: ", i, num);
583       Iterator nextProxy;
584       patchInfo *p = (patchInfo *)processorArray[i].proxies.
585         iterator((Iterator *)&nextProxy);
586       while (p) {
587           fprintf(fp, "%d ", p->Id);
588           p = (patchInfo *)processorArray[i].proxies.
589             next((Iterator*)&nextProxy);
590       }
591       fprintf(fp, "\n");
592   }
593   // dump proxiesOn
594   for (i=0; i<numPatches; i++)  {
595     int num = patchArray[i].proxiesOn.numElements();
596     fprintf(fp, "%d %d: ", i, num);
597       Iterator nextProc;
598       processorInfo *p = (processorInfo *)patchArray[i].proxiesOn.
599         iterator((Iterator *)&nextProc);
600       while (p) {
601         fprintf(fp, "%d ", p->Id);
602         p = (processorInfo *)patchArray[i].proxiesOn.
603           next((Iterator*)&nextProc);
604       }
605       fprintf(fp, "\n");
606   }
607
608   fclose(fp);
609   //CkExit();
610 }
611
612
613 /**
614  * @brief Builds the data structures required for the load balancing strategies in NAMD.
615  */ 
616 int NamdHybridLB::buildData(LDStats* stats) {
617   int n_pes = stats->nprocs();
618
619   PatchMap* patchMap = PatchMap::Object();
620   ComputeMap* computeMap = ComputeMap::Object();
621   const SimParameters* simParams = Node::Object()->simParameters;
622
623   BigReal bgfactor = simParams->ldbBackgroundScaling;
624   BigReal pmebgfactor = simParams->ldbPMEBackgroundScaling;
625   BigReal homebgfactor = simParams->ldbHomeBackgroundScaling;
626   int pmeOn = simParams->PMEOn;
627   int unLoadPme = simParams->ldbUnloadPME;
628   int pmeBarrier = simParams->PMEBarrier;
629   int unLoadZero = simParams->ldbUnloadZero;
630   int unLoadOne = simParams->ldbUnloadOne;
631   int unLoadIO= simParams->ldbUnloadOutputPEs;
632   // traversing the list of processors and getting their load information
633   int i, pe_no;
634   for (i=0; i<n_pes; ++i) {
635     pe_no = stats->procs[i].pe;
636
637     // BACKUP processorArray[i].Id = i; 
638     processorArray[i].Id = pe_no;               // absolute pe number
639     processorArray[i].available = true;
640     // BACKUP if ( pmeOn && isPmeProcessor(i) )
641     if ( pmeOn && isPmeProcessor(pe_no) ) {
642       processorArray[i].backgroundLoad = pmebgfactor * stats->procs[i].bg_walltime;
643     // BACKUP } else if (patchMap->numPatchesOnNode(i) > 0) {
644     } else if (patchMap->numPatchesOnNode(pe_no) > 0) {
645       processorArray[i].backgroundLoad = homebgfactor * stats->procs[i].bg_walltime;
646     } else {
647       processorArray[i].backgroundLoad = bgfactor * stats->procs[i].bg_walltime;
648     }
649     processorArray[i].idleTime = stats->procs[i].idletime;
650     processorArray[i].load = processorArray[i].computeLoad = 0.0;
651   }
652
653   // If I am group zero, then offload processor 0 and 1 in my group
654   if(stats->procs[0].pe == 0) {
655     if(unLoadZero) processorArray[0].available = false;
656     if(unLoadOne) processorArray[1].available = false;
657   }
658
659   // if all pes are Pme, disable this flag
660   if (pmeOn && unLoadPme) {
661     for (i=0; i<n_pes; i++) {
662       if(!isPmeProcessor(stats->procs[i].pe))  break;
663     }
664     if (i == n_pes) {
665       iout << iINFO << "Turned off unLoadPme flag!\n"  << endi;
666       unLoadPme = 0;
667     }
668   }
669
670   if (pmeOn && unLoadPme) {
671     for (i=0; i<n_pes; i++) {
672       if ((pmeBarrier && i==0) || isPmeProcessor(stats->procs[i].pe)) 
673         processorArray[i].available = false;
674     }
675   }
676
677   // if all pes are output, disable this flag
678 #ifdef MEM_OPT_VERSION
679   if (unLoadIO) {
680       if (simParams->numoutputprocs == n_pes) {
681           iout << iINFO << "Turned off unLoadIO flag!\n"  << endi;
682           unLoadIO = 0;
683       }
684   }
685   if (unLoadIO){
686       for (i=0; i<n_pes; i++) {
687           if (isOutputProcessor(stats->procs[i].pe)) 
688               processorArray[i].available = false;
689       }
690   }
691 #endif
692
693   // need to go over all patches to get all required proxies
694   int numPatches = patchMap->numPatches();
695   int totalLocalProxies = 0;
696   int totalProxies = 0;
697   for ( int pid=0; pid<numPatches; ++pid ) {
698         int neighborNodes[PatchMap::MaxOneAway + PatchMap::MaxTwoAway];
699
700         patchArray[pid].Id = pid;
701         patchArray[pid].numAtoms = 0;
702         patchArray[pid].processor = patchMap->node(pid);
703
704         const int numProxies = 
705 #if 0 // USE_TOPOMAP - this function needs to be there for the hybrid case
706         requiredProxiesOnProcGrid(pid,neighborNodes);
707 #else
708         requiredProxies(pid, neighborNodes);
709 #endif
710
711         int numLocalProxies = 0;
712         for (int k=0; k<numProxies; k++) {
713                 if( (neighborNodes[k] >= stats->procs[0].pe) && (neighborNodes[k] <= stats->procs[n_pes-1].pe) ){
714                         ++numLocalProxies;
715                         int index = neighborNodes[k] - stats->procs[0].pe;
716                         processorArray[index].proxies.unchecked_insert(&patchArray[pid]);
717                         patchArray[pid].proxiesOn.unchecked_insert(&processorArray[index]);
718                 }
719         }
720 #if 0
721         if ( numLocalProxies ) {
722             CkPrintf("LDB Pe %d patch %d has %d local of %d total proxies\n",
723                 CkMyPe(), pid, numLocalProxies, numProxies);
724         }
725 #endif
726         totalLocalProxies += numLocalProxies;
727         totalProxies += numProxies;
728   }
729 #if 0
730   CkPrintf("LDB Pe %d has %d local of %d total proxies\n",
731                 CkMyPe(), totalLocalProxies, totalProxies);
732 #endif
733   
734   int nMoveableComputes=0;
735   int index;
736
737   int j;
738
739   // this loop goes over only the objects in this group
740   for(j=0; j < stats->n_objs; j++) {
741         const LDObjData &this_obj = stats->objData[j];
742         int frompe = stats->from_proc[j];
743
744         // filter out non-NAMD managed objects (like PME array)
745         if (this_obj.omID().id.idx != 1) {
746                 // CmiAssert(frompe>=0 && frompe<n_pes);
747                 // CkPrintf("non-NAMD object %d on pe %d with walltime %lf\n",
748                 // this_obj.id().id[0], frompe + stats->procs[0].pe, this_obj.wallTime);
749                 processorArray[frompe].backgroundLoad += this_obj.wallTime;
750                 continue;
751         }
752
753         if (this_obj.id().id[1] == -2) { // Its a patch
754                 // handled above to get required proxies from all patches
755                 processorArray[frompe].backgroundLoad += this_obj.wallTime;
756         } else if (this_obj.id().id[1] == -3) { // Its a bonded compute
757                 processorArray[frompe].backgroundLoad += this_obj.wallTime;
758         } else if (this_obj.migratable && this_obj.wallTime != 0.) { // Its a compute
759
760                 const int cid = this_obj.id().id[0];
761                 const int p0 = computeMap->pid(cid,0);
762
763                 // For self-interactions, just return the same pid twice
764                 int p1;
765                 if (computeMap->numPids(cid) > 1)
766                         p1 = computeMap->pid(cid,1);
767                         else p1 = p0;
768                         computeArray[nMoveableComputes].Id = cid;
769                         //BACKUP computeArray[nMoveableComputes].oldProcessor = stats->from_proc[j];
770                         if (frompe >= n_pes) {  // from outside
771 CkPrintf("assigning random old processor...this looks broken\n");
772                           computeArray[nMoveableComputes].oldProcessor = CrnRand()%n_pes + stats->procs[0].pe;     // random
773                         }
774                         else {
775                           computeArray[nMoveableComputes].oldProcessor = frompe + stats->procs[0].pe;
776                         }
777                         from_procs[nMoveableComputes] = frompe;
778
779                         //BACKUP2 index = stats->from_proc[j] - stats->procs[0].pe;
780                         //BACKUP processorArray[stats->from_proc[j]].computeLoad += this_obj.wallTime;
781                         int index = computeArray[nMoveableComputes].oldProcessor - stats->procs[0].pe; 
782                         processorArray[index].computeLoad += this_obj.wallTime;
783                         computeArray[nMoveableComputes].processor = -1;
784                         computeArray[nMoveableComputes].patch1 = p0;
785                         computeArray[nMoveableComputes].patch2 = p1;
786                         computeArray[nMoveableComputes].handle = this_obj.handle;
787                         computeArray[nMoveableComputes].load = this_obj.wallTime;
788                         nMoveableComputes++;
789         }
790   }
791
792         for (i=0; i<n_pes; i++) {
793           processorArray[i].load = processorArray[i].backgroundLoad + processorArray[i].computeLoad;
794         }
795         stats->clear();
796         return nMoveableComputes;
797 }
798
799
800 int NamdHybridLB::requiredProxies(PatchID id, int neighborNodes[])
801 {
802   PatchMap* patchMap = PatchMap::Object();
803   int myNode = patchMap->node(id);
804   int nProxyNodes = 0;
805
806 #define IF_NEW_NODE \
807     int j; \
808     for ( j=0; j<nProxyNodes && neighborNodes[j] != proxyNode; ++j ); \
809     if ( j == nProxyNodes )
810
811   PatchID neighbors[1 + PatchMap::MaxOneAway + PatchMap::MaxTwoAway];
812   neighbors[0] = id;
813   int numNeighbors = 1 + patchMap->downstreamNeighbors(id,neighbors+1);
814   for ( int i = 0; i < numNeighbors; ++i ) {
815     const int proxyNode = patchMap->basenode(neighbors[i]);
816     if ( proxyNode != myNode ) {
817       IF_NEW_NODE {
818         neighborNodes[nProxyNodes] = proxyNode;
819         nProxyNodes++;
820       }
821     }
822   }
823
824   // Distribute initial default proxies across empty processors.
825   // This shouldn't be necessary, but may constrain the load balancer
826   // and avoid placing too many proxies on a single processor.  -JCP
827   
828   // This code needs to be turned off when the creation of ST is
829   // shifted to the load balancers -ASB
830
831 #if 1
832   int numNodes = CkNumPes();
833   int numPatches = patchMap->numPatches();
834   int emptyNodes = numNodes - numPatches;
835   if ( emptyNodes > numPatches ) {
836     int nodesPerPatch = nProxyNodes + 1 + (emptyNodes-1) / numPatches;
837     int maxNodesPerPatch = PatchMap::MaxOneAway + PatchMap::MaxTwoAway;
838     if ( nodesPerPatch > maxNodesPerPatch ) nodesPerPatch = maxNodesPerPatch;
839     int proxyNode = (myNode + 1) % numNodes;
840     while ( nProxyNodes < nodesPerPatch &&
841                         ! patchMap->numPatchesOnNode(proxyNode) ) {
842       if ( proxyNode != myNode ) {
843         IF_NEW_NODE {
844           neighborNodes[nProxyNodes] = proxyNode;
845           nProxyNodes++;
846         }
847       }
848       proxyNode = (proxyNode + 1) % numNodes;
849     }
850     proxyNode = (myNode - 1 + numNodes) % numNodes;
851     while ( nProxyNodes < nodesPerPatch &&
852                         ! patchMap->numPatchesOnNode(proxyNode) ) {
853       if ( proxyNode != myNode ) {
854         IF_NEW_NODE {
855           neighborNodes[nProxyNodes] = proxyNode;
856           nProxyNodes++;
857         }
858       }
859       proxyNode = (proxyNode - 1 + numNodes) % numNodes;
860     }
861     proxyNode = (myNode + 1) % numNodes;
862     int count = 0;
863     while ( nProxyNodes < nodesPerPatch ) {
864       if ( ! patchMap->numPatchesOnNode(proxyNode) && proxyNode != myNode ) {
865         IF_NEW_NODE {
866           neighborNodes[nProxyNodes] = proxyNode;
867           nProxyNodes++;
868         }
869       }
870       proxyNode = (proxyNode + 1) % numNodes;
871       count ++; if (count == numNodes) break;   // we looped all
872     }
873   } else {
874     int proxyNode = myNode - 1;
875     if ( proxyNode >= 0 && ! patchMap->numPatchesOnNode(proxyNode) ) {
876       if ( proxyNode != myNode ) {
877         IF_NEW_NODE {
878           neighborNodes[nProxyNodes] = proxyNode;
879           nProxyNodes++;
880         }
881       }
882     }
883     proxyNode = myNode + 1;
884     if ( proxyNode < numNodes && ! patchMap->numPatchesOnNode(proxyNode) ) {
885       if ( proxyNode != myNode ) {
886         IF_NEW_NODE {
887           neighborNodes[nProxyNodes] = proxyNode;
888           nProxyNodes++;
889         }
890       }
891     }
892   }
893 #endif
894
895   return nProxyNodes;
896 }
897
898 #if 0
899 void NamdHybridLB::CollectInfo(Location *loc, int n, int fromlevel)
900 {
901    int atlevel = fromlevel + 1;
902    LevelData *lData = levelData[atlevel];
903    lData->info_recved++;
904
905    CkVec<Location> &matchedObjs = lData->matchedObjs;
906 CmiAssert(0);
907
908    // sort into mactched and unmatched list
909    std::map<LDObjKey, int> &unmatchedObjs = lData->unmatchedObjs;
910    for (int i=0; i<n; i++) {
911      std::map<LDObjKey, int>::iterator iter = unmatchedObjs.find(loc[i].key);
912      if (iter != unmatchedObjs.end()) {
913        CmiAssert(iter->second != -1 || loc[i].loc != -1);
914        if (loc[i].loc == -1) loc[i].loc = iter->second;
915        matchedObjs.push_back(loc[i]);
916        unmatchedObjs.erase(iter);
917      }
918      else
919        unmatchedObjs[loc[i].key] = loc[i].loc;
920    }
921
922 //  DEBUGF(("[%d] level %d has %d unmatched and %d matched. \n", CkMyPe(), atlevel, unmatchedObjs.size(), matchedObjs.size()));
923
924    if (lData->info_recved == lData->nChildren) {
925      lData->info_recved = 0;
926      if (_lb_args.debug() > 1)
927          CkPrintf("[%d] CollectInfo at level %d started at %f\n",
928                 CkMyPe(), atlevel, CkWallTimer());
929      if (lData->parent != -1) {
930
931                 // NAMD specific
932                 CkVec<Location> unmatchedbuf;
933                 for(std::map<LDObjKey, int>::const_iterator it = unmatchedObjs.begin(); it != unmatchedObjs.end(); ++it){
934                 unmatchedbuf.push_back(Location(it->first, it->second));
935                 }
936                 // checking if update of ComputeMap is ready before calling parent
937                 if(CkMyPe() == 0){
938                         if(updateFlag){
939                                 updateFlag = false;
940                                 collectFlag = false;
941                                 thisProxy[lData->parent].CollectInfo(unmatchedbuf.getVec(), unmatchedbuf.size(), atlevel);
942                         }else{
943                                 CkPrintf("[%d] COMPUTEMAP UPDATE NOT READY\n",CkMyPe());
944                                 collectFlag = true;
945                                 parent_backup = lData->parent;
946                                 loc_backup = unmatchedbuf.getVec();
947                                 n_backup = unmatchedbuf.size();
948                                 fromlevel_backup = atlevel;
949                         }
950                 }else{
951                         // send only unmatched ones up the tree
952                         thisProxy[lData->parent].CollectInfo(unmatchedbuf.getVec(), unmatchedbuf.size(), atlevel);
953                 }
954
955      }
956      else { // root
957        // we should have all answers now
958        CmiAssert(unmatchedObjs.size() == 0);
959        // start send match list down
960        thisProxy.PropagateInfo(matchedObjs.getVec(), matchedObjs.size(), atlevel, lData->nChildren, lData->children);
961        lData->statsData->clear();
962      }
963    }
964 }
965 #endif