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