00001
00022
00023 #include "RecBipartLB.h"
00024 #include "ckgraph.h"
00025 #include <limits>
00026 #include <queue>
00027 #include <vector>
00028
00029 using std::vector;
00030
00031 extern int quietModeRequested;
00032
00036 class Vertex_helper {
00037 public:
00038 inline int getPartition(){ return partition; }
00039 inline void setPartition(int p){partition=p; }
00040 inline bool getMarked(){ return marked; }
00041 inline void setMarked(bool v){ marked=v;}
00042 inline bool getBoundaryline(){return boundaryline;}
00043 inline void setBoundaryline(bool v){ boundaryline=v;}
00044 inline int getEdgestopart1(){return edgestopart1;}
00045 inline int getEdgestopart2(){return edgestopart2;}
00046 inline void setEdgestopart1(int v){edgestopart1=v;}
00047 inline void setEdgestopart2(int v){edgestopart2=v;}
00048 inline void incEdgestopart1(int v){edgestopart1+=v ;}
00049 inline void incEdgestopart2(int v){edgestopart2+=v;}
00050 inline void decEdgestopart1(int v){edgestopart1-=v;}
00051 inline void decEdgestopart2(int v){edgestopart2-=v;}
00052 inline void setLevel(int l){level=l;}
00053 inline int getLevel(){return level;}
00054 inline int getGain(){return gain;}
00055 inline void setGain(int v){gain=v;};
00056
00057 private:
00058 int partition;
00059 bool marked;
00060 bool boundaryline;
00061 int edgestopart1;
00062 int edgestopart2;
00063 int gain;
00064 int level;
00065 };
00066
00070 class BQueue {
00071 public:
00072 vector<int> q;
00073
00074 BQueue(short b){
00075 forboundary=b;
00076 }
00077
00078 inline int getMingain(){return mingain;}
00079 inline void setMingain(int v){mingain=v;}
00080 inline int getVertextoswap(){return vertextoswap;}
00081 inline void setVertextoswap(int v){vertextoswap=v;}
00082 inline int getSwapid(){return swapid;}
00083 inline void setSwapid(int v){swapid=v;}
00084 inline short getBoundary(){return forboundary;}
00085 void push(Vertex *);
00086 void removeComplete(Vertex *);
00087 void removeToSwap(Vertex *);
00088
00089 private:
00090 int mingain;
00091 int vertextoswap;
00092 int swapid;
00093 short forboundary;
00094 };
00095
00096 void RecursiveBiPart(ObjGraph *, vector<Vertex *> & ,int, int);
00097 void adjustqueues(ObjGraph *, BQueue *, BQueue *, vector<Vertex *> &, vector<Vertex *> &,int *, int);
00098 void adjustgain(ObjGraph *,vector<Vertex *> &,BQueue *);
00099 void RefineBoundary(ObjGraph *, vector<Vertex *> &, vector<Vertex *> &,BQueue *, BQueue *, int, int, int, double, double, double);
00100 int modifypartitions(ObjGraph *,vector<Vertex *> &, vector<Vertex *> &, BQueue *, BQueue *, int, int);
00101 void swapQ1toQ2(ObjGraph *, BQueue *, BQueue *, int);
00102 Vertex * removeinSwap(ObjGraph *,BQueue *, BQueue *, int);
00103 Vertex * removePtr(vector<Vertex *> &,int);
00104
00105 int level;
00106 double TOTALLOAD;
00107 vector<Vertex_helper *> vhelpers;
00108 int numparts, peno;
00109 ProcArray *parray;
00110
00111 CreateLBFunc_Def(RecBipartLB, "Algorithm for load balacing based on recursive bipartitioning of object graph")
00112
00113
00114 void BQueue::removeToSwap(Vertex *vert)
00115 {
00116 int i;
00117 int v=vert->getVertexId();
00118 for(i=0;i<q.size();i++)
00119 {
00120 if(q[i]==v)
00121 {
00122
00123 q[i]=q.back();
00124 q.pop_back();
00125 return;
00126 }
00127 }
00128 }
00129
00130
00131 void BQueue::removeComplete(Vertex *vert)
00132 {
00133 int i;
00134 int v=vert->getVertexId();
00135 for(i=0;i<q.size();i++)
00136 {
00137 if(q[i]==v)
00138 {
00139 vhelpers[v]->setBoundaryline(false);
00140 vhelpers[v]->setEdgestopart1(0);
00141 vhelpers[v]->setEdgestopart2(0);
00142 q[i]=q.back();
00143 q.pop_back();
00144 return;
00145 }
00146 }
00147 }
00148
00149 void BQueue::push(Vertex *vert)
00150 {
00151 int v=vert->getVertexId();
00152 q.push_back(v);
00153 vhelpers[v]->setBoundaryline(true);
00154 }
00155
00156
00157 RecBipartLB::RecBipartLB(const CkLBOptions &opt) : CBase_RecBipartLB(opt) {
00158 lbname = "RecBipartLB";
00159 if(CkMyPe() == 0 && !quietModeRequested)
00160 CkPrintf("CharmLB> RecBipartLB created.\n");
00161 }
00162
00163 bool RecBipartLB::QueryBalanceNow(int _step) {
00164 return true;
00165 }
00166
00167 void RecBipartLB::work(LDStats *stats) {
00168 vector<Vertex *> ptrvector;
00170 ProcArray *parr = new ProcArray(stats);
00171 ObjGraph *ogr = new ObjGraph(stats);
00172
00173
00175 level=0;
00176 peno=0;
00177 TOTALLOAD=0;
00178 numparts=CkNumPes();
00179 parray=parr;
00180
00181 double avgLoad = parr->getAverageLoad();
00182 int numPes = parr->procs.size();
00183
00184 parr->resetTotalLoad();
00185 for(int i=0;i<ogr->vertices.size();i++)
00186 {
00187 Vertex_helper *helper = new Vertex_helper();
00188 vhelpers.push_back(helper);
00189 ptrvector.push_back((Vertex *)&(ogr->vertices[i]));
00190
00191 }
00192
00193 RecursiveBiPart(ogr,ptrvector,1,numparts);
00194
00196 ogr->convertDecisions(stats);
00197 }
00198
00199
00200 void RecursiveBiPart(ObjGraph *ogr, vector<Vertex *> &pvertices, int parent, int nump)
00201 {
00202
00203 if(nump==1)
00204 {
00205 parray->procs[peno].totalLoad() = 0.0;
00206 for(int i=0;i<pvertices.size();i++)
00207 {
00208 pvertices[i]->setNewPe(peno);
00209 parray->procs[peno].totalLoad() += pvertices[i]->getVertexLoad();
00210 }
00211 peno++;
00212
00213 return;
00214 }
00215
00216 int numerator=nump/2;
00217 double ratio = ((double)numerator/nump);
00218
00219
00220 if(pvertices.size()==1)
00221 {
00222 level++;
00223 RecursiveBiPart(ogr,pvertices,2*parent-1,numerator);
00224 level--;
00225 return;
00226 }
00227
00228
00229 vector<Vertex *> partition1;
00230 vector<Vertex *> partition2;
00231 vector<bool> taken(vhelpers.size(), false);
00232
00233 int start = pvertices[0]->getVertexId();
00234 int count=0;
00235 double loadseen=0;
00236 double pload=0;
00237 bool getout=false;
00238 std::queue<int> que2;
00239 std::queue<int> que1;
00240 int KLFMruns=pvertices.size()/5;
00241
00242
00243 for(int i=0;i<pvertices.size();i++){
00244 int id=pvertices[i]->getVertexId();
00245 vhelpers[id]->setPartition(2*parent);
00246 vhelpers[id]->setMarked(false);
00247 vhelpers[id]->setBoundaryline(false);
00248 vhelpers[id]->setEdgestopart2(0);
00249 vhelpers[id]->setEdgestopart1(0);
00250 vhelpers[id]->setLevel(level);
00251 pload+=ogr->vertices[id].getVertexLoad();
00252 }
00253
00254
00255 que2.push(start);
00256 vhelpers[start]->setMarked(true);
00257
00258 int i, nbr, lastforced=0;
00259 int visitcount=0;
00260
00261 bool swap=true;
00262 int ei=-1;
00263
00264 while(!que2.empty() && !getout) {
00265 int n = que2.front();
00266 que2.pop();
00267 count++;
00268
00269 Vertex *v=(Vertex *)&(ogr->vertices[n]);
00270 loadseen+=v->getVertexLoad();
00271
00272 vhelpers[v->getVertexId()]->setPartition(2*parent-1);
00273
00274 partition1.push_back(v);
00275 taken[v->getVertexId()]=true;
00276
00277
00278 if(count==pvertices.size()-1)
00279 break;
00280
00281
00282 while(1) {
00283 ei++;
00284 if(swap==true && ei==v->sendToList.size())
00285 { swap=false; ei=0;}
00286
00287 if(swap==false && ei==v->recvFromList.size())
00288 {swap=true; ei=-1; break;}
00289
00290 if(swap)
00291 nbr = v->sendToList[ei].getNeighborId();
00292 else
00293 nbr=v->recvFromList[ei].getNeighborId();
00294
00295 Vertex_helper *u=(vhelpers[nbr]);
00296 visitcount++;
00297
00298
00299 if((u->getMarked()==false) && (u->getPartition()==2*parent) && (u->getLevel()==level)){
00300 que2.push(nbr);
00301 u->setMarked(true);
00302
00303 }
00304 }
00305
00306
00307 if(loadseen>=(ratio*pload))
00308 {
00309 getout=true;
00310 }
00311 else{
00312
00313 if(que2.empty())
00314 {
00315 for(int i=lastforced;i<pvertices.size();i++)
00316 {
00317 Vertex *w=pvertices[i];
00318 if(taken[w->getVertexId()]==false)
00319 {
00320 que2.push(w->getVertexId());
00321 vhelpers[w->getVertexId()]->setMarked(true);
00322 lastforced=i+1;
00323 break;
00324 }
00325 }
00326 }
00327 }
00328 }
00329
00330
00331 for(int i=0;i<pvertices.size();i++){
00332 Vertex *v=pvertices[i];
00333 if(taken[v->getVertexId()]==false)
00334 partition2.push_back(v);
00335 }
00336
00337 int initialedgecut;
00338
00339
00340 BQueue *q1=new BQueue(1);
00341 BQueue *q2=new BQueue(2);
00342 int tempsize=que2.size();
00343
00344 for(i=0;i<tempsize;i++)
00345 {
00346 q2->push((Vertex *)&(ogr->vertices[que2.front()]));
00347 que2.pop();
00348 }
00349 adjustqueues(ogr,q1,q2,partition1, partition2, &initialedgecut,parent);
00350
00351 RefineBoundary(ogr,partition1,partition2,q1,q2,KLFMruns,initialedgecut,parent,loadseen,pload-loadseen,ratio);
00352
00353
00354 level++;
00355 RecursiveBiPart(ogr,partition1,vhelpers[partition1[0]->getVertexId()]->getPartition(),numerator);
00356 RecursiveBiPart(ogr,partition2,vhelpers[partition2[0]->getVertexId()]->getPartition(), nump-numerator);
00357 level--;
00358 }
00359
00360
00361 void adjustqueues(ObjGraph *ogr, BQueue *que1, BQueue *que2, vector <Vertex *> &partition1, vector<Vertex *> &partition2, int *initialedgecut, int parent)
00362 {
00363 int i,uid,wid;
00364 bool swap=true;
00365 int ei=-1;
00366 Edge *edge;
00367 int edgecut=0;
00368 que2->setMingain(std::numeric_limits<int>::max());
00369 que2->setVertextoswap(-1);
00370 que2->setSwapid(-1);
00371
00372
00373 for(i=0;i<que2->q.size();i++)
00374 {
00375 int vid=que2->q[i];
00376 Vertex *v=((Vertex *)&(ogr->vertices[vid]));
00377
00378 while(1) {
00379 ei++;
00380 if(swap==true && ei==v->sendToList.size())
00381 { swap=false; ei=0;}
00382
00383 if(swap==false && ei==v->recvFromList.size())
00384 { swap=true; ei=-1; break;}
00385
00386 if(swap)
00387 {
00388 uid = v->sendToList[ei].getNeighborId();
00389 edge=(Edge *)&(v->sendToList[ei]);
00390 }
00391 else
00392 {
00393 uid = v->recvFromList[ei].getNeighborId();
00394 edge = (Edge *)&(v->recvFromList[ei]);
00395 }
00396
00397 Vertex *u =(Vertex *)&(ogr->vertices[uid]);
00398
00399 if((vhelpers[uid]->getPartition())==(2*parent-1) && (vhelpers[uid]->getLevel())==level)
00400 {
00401
00402 if(vhelpers[uid]->getBoundaryline()==false)
00403 {
00404 que1->push(u);
00405 }
00406
00407
00408 edgecut+=edge->getNumBytes();
00409 vhelpers[vid]->incEdgestopart1(edge->getNumBytes());
00410 vhelpers[uid]->incEdgestopart2(edge->getNumBytes());
00411 }
00412 if(vhelpers[uid]->getPartition()==2*parent && vhelpers[uid]->getLevel()==level)
00413 {
00414 vhelpers[vid]->incEdgestopart2(edge->getNumBytes());
00415 }
00416 }
00417
00418
00419
00420 vhelpers[vid]->setGain(vhelpers[vid]->getEdgestopart2() - vhelpers[vid]->getEdgestopart1());
00421 if(vhelpers[vid]->getGain() < que2->getMingain())
00422 {
00423 que2->setMingain(vhelpers[vid]->getGain());
00424 que2->setVertextoswap(v->getVertexId());
00425 que2->setSwapid(i);
00426 }
00427 }
00428
00429 for(i=0;i<que1->q.size();i++)
00430 {
00431 int uid=que1->q[i];
00432 swap = true; ei=-1;
00433 Vertex *u=(Vertex *)&(ogr->vertices[uid]);
00434
00435 while(1) {
00436 ei++;
00437 if(swap==true && ei==u->sendToList.size())
00438 { swap=false; ei=0;}
00439
00440 if(swap==false && ei==u->recvFromList.size())
00441 { swap=true; ei=-1; break;}
00442
00443 if(swap)
00444 {
00445 wid=u->sendToList[ei].getNeighborId();
00446 edge = (Edge *)&(u->sendToList[ei]);
00447 }
00448 else
00449 {
00450 wid=u->recvFromList[ei].getNeighborId();
00451 edge = (Edge *)&(u->recvFromList[ei]);
00452 }
00453
00454 Vertex *w=(Vertex *)&(ogr->vertices[wid]);
00455 if(vhelpers[wid]->getLevel()==level && vhelpers[wid]->getPartition()==(2*parent-1))
00456 vhelpers[uid]->incEdgestopart1(edge->getNumBytes());
00457 }
00458
00459 }
00460 *initialedgecut=edgecut;
00461
00462
00463 adjustgain(ogr,partition1, que1);
00464 }
00465
00466
00467 void adjustgain(ObjGraph *ogr,vector<Vertex *> &partition, BQueue *que)
00468 {
00469 int i;
00470 int bdry=que->getBoundary();
00471 que->setMingain(std::numeric_limits<int>::max());
00472 que->setVertextoswap(-1);
00473 que->setSwapid(-1);
00474
00475 for (i=0;i<que->q.size();i++)
00476 {
00477 int uid=que->q[i];
00478 Vertex *u =(Vertex *)&(ogr->vertices[uid]);
00479
00480 if(bdry==1)
00481 {
00482 vhelpers[uid]->setGain(vhelpers[uid]->getEdgestopart1() - vhelpers[uid]->getEdgestopart2());
00483 }
00484 else if(bdry==2)
00485 {
00486 vhelpers[uid]->setGain(vhelpers[uid]->getEdgestopart2() - vhelpers[uid]->getEdgestopart1());
00487 }
00488 if(vhelpers[uid]->getGain() < que->getMingain())
00489 {
00490 que->setMingain(vhelpers[uid]->getGain());
00491 que->setVertextoswap(u->getVertexId());
00492 que->setSwapid(i);
00493 }
00494 }
00495 }
00496
00497
00498 void RefineBoundary(ObjGraph *ogr,vector<Vertex *> &partition1, vector<Vertex *> &partition2, BQueue *que1, BQueue *que2, int runs, int initialedgecut, int parent, double part1load, double part2load, double ratio)
00499 {
00500 int r=runs;
00501 int t;
00502 if(que1->q.size()<que2->q.size())
00503 t=que1->q.size();
00504 else t=que2->q.size();
00505 if(t<r) r=t;
00506 if(r==0) return;
00507
00508 int newedgecut=initialedgecut;
00509
00510 for(int i=0;i<r;i++)
00511 {
00512 if((part1load/(part1load+part2load))>ratio)
00513 {
00514 if(partition1.size()>1 && que1->q.size()>0)
00515 {
00516 double xfer=(ogr->vertices[que1->getVertextoswap()]).getVertexLoad();
00517 part1load-=xfer;
00518 part2load+=xfer;
00519 newedgecut=modifypartitions(ogr, partition1, partition2, que1, que2, newedgecut, parent);
00520 }
00521 }
00522 else{
00523 if(partition2.size()>1 && que2->q.size()>0)
00524 {
00525 double xfer=(ogr->vertices[que2->getVertextoswap()]).getVertexLoad();
00526 part2load-=xfer;
00527 part1load+=xfer;
00528 newedgecut=modifypartitions(ogr, partition1, partition2, que2, que1, newedgecut, parent);
00529 }
00530 }
00531
00532 }
00533 }
00534
00535
00536 int modifypartitions(ObjGraph *ogr,vector<Vertex *> &partition1, vector<Vertex *> &partition2, BQueue *q1, BQueue *q2,int ec, int parent)
00537 {
00538 int newedgecut = 0;
00539 if(q1->getBoundary()==1)
00540 {
00541 int e2=vhelpers[q1->getVertextoswap()]->getEdgestopart2();
00542 int e1=vhelpers[q1->getVertextoswap()]->getEdgestopart1();
00543 newedgecut=ec-(e2)+(e1);
00544 vhelpers[q1->getVertextoswap()]->setPartition(2*parent);
00545 Vertex *ptr=removePtr(partition1,q1->getVertextoswap());
00546 partition2.push_back(ptr);
00547
00548 }
00549 else if(q1->getBoundary()==2)
00550 {
00551 int e1=vhelpers[q1->getVertextoswap()]->getEdgestopart1();
00552 int e2=vhelpers[q1->getVertextoswap()]->getEdgestopart2();
00553 newedgecut=ec-(e1)+(e2);
00554 vhelpers[q1->getVertextoswap()]->setPartition(2*parent-1);
00555 Vertex *ptr=removePtr(partition2,q1->getVertextoswap());
00556 partition1.push_back(ptr);
00557
00558 }
00559
00560 swapQ1toQ2(ogr,q1,q2,parent);
00561 adjustgain(ogr,partition1,q1);
00562 adjustgain(ogr,partition2,q2);
00563 return newedgecut;
00564 }
00565
00566 void swapQ1toQ2(ObjGraph *ogr, BQueue *q1, BQueue *q2, int parent)
00567 {
00568 Vertex *vert=removeinSwap(ogr,q1,q2,parent);
00569
00570 q2->push(vert);
00571 }
00572
00573 Vertex * removeinSwap(ObjGraph *ogr,BQueue *q1, BQueue *q2, int parent)
00574 {
00575 int ei=-1, uid, wid, einested=-1;
00576 Edge *edge, *edgenested;
00577 bool swap=true, swapnested=true;
00578 Vertex *v=(Vertex *)&(ogr->vertices[q1->getVertextoswap()]);
00579
00580
00581
00582 while(1) {
00583 ei++;
00584 if(swap==true && ei==v->sendToList.size())
00585 { swap=false; ei=0;}
00586 if(swap==false && ei==v->recvFromList.size())
00587 { swap=true; ei=-1; break;}
00588 if(swap)
00589 {
00590 uid=v->sendToList[ei].getNeighborId();
00591 edge=(Edge *)&(v->sendToList[ei]);
00592 }
00593 else
00594 {
00595 uid=v->recvFromList[ei].getNeighborId();
00596 edge=(Edge *)&(v->recvFromList[ei]);
00597 }
00598
00599 Vertex *u=(Vertex *)&(ogr->vertices[uid]);
00600
00601 if(q1->getBoundary()==1)
00602 {
00603 if((vhelpers[uid]->getBoundaryline()==true) && vhelpers[uid]->getLevel()==level)
00604 {
00605 vhelpers[uid]->incEdgestopart2(edge->getNumBytes());
00606 vhelpers[uid]->decEdgestopart1(edge->getNumBytes());
00607 }
00608 else if(vhelpers[uid]->getPartition()==(2*parent-1) && vhelpers[uid]->getLevel()==level && vhelpers[uid]->getBoundaryline()==false)
00609
00610 {
00611
00612 vhelpers[uid]->setEdgestopart2(edge->getNumBytes());
00613 vhelpers[uid]->setEdgestopart1(0);
00614
00615 while(1) {
00616 einested++;
00617 if(swapnested==true && einested==u->sendToList.size())
00618 { swapnested=false; einested=0;}
00619 if(swapnested==false && einested==u->recvFromList.size())
00620 { swapnested=true; einested=-1; break;}
00621 if(swapnested)
00622 {
00623 wid=u->sendToList[einested].getNeighborId();
00624 edgenested=(Edge *)&(u->sendToList[einested]);
00625 }
00626 else
00627 {
00628 wid=u->recvFromList[einested].getNeighborId();
00629 edgenested = (Edge *)&(u->recvFromList[einested]);
00630 }
00631 Vertex *w=(Vertex *)&(ogr->vertices[wid]);
00632 if(vhelpers[wid]->getLevel()==level && vhelpers[wid]->getPartition()==(2*parent-1))
00633 vhelpers[uid]->incEdgestopart1(edgenested->getNumBytes());
00634 }
00635 q1->push(u);
00636 }
00637 if(vhelpers[uid]->getPartition()==2*parent && vhelpers[uid]->getLevel()==level && vhelpers[uid]->getBoundaryline()==true && vhelpers[uid]->getEdgestopart1()==0)
00638
00639 {
00640 q2->removeComplete(u);
00641 }
00642 }
00643 else if(q1->getBoundary()==2)
00644 {
00645 if(vhelpers[uid]->getBoundaryline()==true && vhelpers[uid]->getLevel()==level)
00646 {
00647 vhelpers[uid]->incEdgestopart1(edge->getNumBytes());
00648 vhelpers[uid]->decEdgestopart2(edge->getNumBytes());
00649 }
00650 else if(vhelpers[uid]->getPartition()==2*parent && vhelpers[uid]->getLevel()==level && vhelpers[uid]->getBoundaryline()==false)
00651
00652 {
00653
00654 vhelpers[uid]->setEdgestopart1(edge->getNumBytes());
00655 vhelpers[uid]->setEdgestopart2(0);
00656
00657 while(1) {
00658 einested++;
00659 if(swapnested==true && einested==u->sendToList.size())
00660 { swapnested=false; einested=0;}
00661 if(swapnested==false && einested==u->recvFromList.size())
00662 { swapnested=true; einested=-1; break;}
00663 if(swapnested)
00664 {
00665 wid=u->sendToList[einested].getNeighborId();
00666 edgenested = (Edge *)&(u->sendToList[einested]);
00667 }
00668 else
00669 {
00670 wid=u->recvFromList[einested].getNeighborId();
00671 edgenested= (Edge *)&(u->recvFromList[einested]);
00672 }
00673
00674 Vertex *w=(Vertex *)&(ogr->vertices[wid]);
00675 if(vhelpers[wid]->getLevel()==level && vhelpers[wid]->getPartition()==(2*parent))
00676 vhelpers[uid]->incEdgestopart2(edgenested->getNumBytes());
00677 }
00678
00679 q1->push(u);
00680 }
00681 if(vhelpers[uid]->getPartition()==(2*parent-1) && vhelpers[uid]->getLevel()==level && vhelpers[uid]->getBoundaryline()==true && vhelpers[uid]->getEdgestopart2()==0)
00682
00683 {
00684 q2->removeComplete(u);
00685 }
00686 }
00687 }
00688
00689
00690
00691 q1->removeComplete(v);
00692 return v;
00693 }
00694
00695 Vertex * removePtr(vector<Vertex *> &vec,int id)
00696 {
00697 int i;
00698 for(i=0;i<vec.size();i++)
00699 {
00700 if(vec[i]->getVertexId()==id)
00701 {
00702 Vertex *ptr=vec[i];
00703 vec[i]=vec.back();
00704 vec.pop_back();
00705 return ptr;
00706 }
00707 }
00708 return NULL;
00709 }
00710
00711 #include "RecBipartLB.def.h"