00001
00002
00003
00004
00005 #include "charm++.h"
00006 #include "collidecharm_impl.h"
00007
00008 #define COLLIDE_TRACE 0
00009 #if COLLIDE_TRACE
00010
00011 # define SRM_STATUS(x) ckout<<"["<<CkMyPe()<<"] C.Sync> "<<x<<endl;
00012 # define CM_STATUS(x) ckout<<"["<<CkMyPe()<<"] C.Mgr> "<<x<<endl;
00013 # define CC_STATUS(x) { \
00014 char buf[100]; \
00015 voxName(thisIndex,buf); \
00016 ckout<<"["<<CkMyPe()<<"] "<<buf<<" Voxel> "<<x<<endl; \
00017 }
00018
00019 # define COL_STATUS(x) ckout<<"["<<CkMyPe()<<"] Collide> "<<x<<endl;
00020 #else
00021
00022 # define SRM_STATUS(x)
00023 # define CM_STATUS(x)
00024 # define CC_STATUS(x)
00025 # define COL_STATUS(x)
00026 #endif
00027
00028
00029
00030
00031
00035 CkGroupID CollideSerialClient(CollisionClientFn clientFn,void *clientParam)
00036 {
00037 CProxy_serialCollideClient cl=CProxy_serialCollideClient::ckNew();
00038 cl.ckLocalBranch()->setClient(clientFn,clientParam);
00039 return cl;
00040 }
00041
00042
00045 CollideHandle CollideCreate(const CollideGrid3d &gridMap,
00046 CkGroupID clientGroupID)
00047 {
00048 CProxy_collideVoxel voxels=CProxy_collideVoxel::ckNew();
00049 voxels.doneInserting();
00050 CProxy_collideClient client(clientGroupID);
00051 return CProxy_collideMgr::ckNew(gridMap,client,voxels);
00052 }
00053
00055 void CollideRegister(CollideHandle h,int chunkNo) {
00056 CProxy_collideMgr mgr(h);
00057 mgr.ckLocalBranch()->registerContributor(chunkNo);
00058 }
00060 void CollideUnregister(CollideHandle h,int chunkNo) {
00061 CProxy_collideMgr mgr(h);
00062 mgr.ckLocalBranch()->unregisterContributor(chunkNo);
00063 }
00064
00068 void CollideBoxesPrio(CollideHandle h,int chunkNo,
00069 int nBox,const bbox3d *boxes,const int *prio)
00070 {
00071 CProxy_collideMgr mgr(h);
00072 mgr.ckLocalBranch()->contribute(chunkNo,nBox,boxes,prio);
00073 }
00074
00075
00076 objListMsg::objListMsg(
00077 int n_,CollideObjRec *obj_,
00078 const returnReceipt &receipt_)
00079 :isHeapAllocated(true),receipt(receipt_),
00080 n(n_),obj(obj_)
00081 {}
00082
00083 void objListMsg::freeHeapAllocated()
00084 {
00085 if (!isHeapAllocated) return;
00086 free(obj);obj=NULL;
00087 }
00088
00089
00090 #define objListMsg_OFFSETS \
00091 int offM=0; \
00092 int cntM=sizeof(objListMsg); \
00093 int offB=offM+ALIGN8(cntM); \
00094 int cntB=sizeof(CollideObjRec)*m->n;\
00095
00096 void *objListMsg::pack(objListMsg *m)
00097 {
00098 objListMsg_OFFSETS
00099 int offEnd=offB+cntB;
00100
00101 void *buf = CkAllocBuffer(m, offEnd);
00102 char *cbuf=(char *)buf;
00103 memcpy(cbuf+offM,m,cntM);
00104 memcpy(cbuf+offB,m->obj,cntB);
00105 delete m;
00106 return buf;
00107 }
00108
00109 objListMsg *objListMsg::unpack(void *buf)
00110 {
00111
00112
00113 objListMsg *m = new (buf) objListMsg;
00114 char *cbuf=(char *)buf;
00115 objListMsg_OFFSETS
00116 m->obj=(CollideObjRec *)(cbuf+offB);
00117 return m;
00118 }
00119
00120
00121
00122
00123 #if 0 //A 2-element cache is actually slower than the 1-element case below
00124
00125 template <int n>
00126 class hashCache {
00127 typedef CollideLoc3d KEY;
00128 typedef cellAggregator *OBJ;
00129 KEY keys[n];
00130 OBJ objs[n];
00131 int lastFound;
00132 public:
00133 hashCache(const KEY &invalidKey) {
00134 for (int i=0;i<n;i++) keys[i]=invalidKey;
00135 lastFound=0;
00136 }
00137 inline OBJ lookup(const KEY &k) {
00138 if (k.compare(keys[lastFound]))
00139 return objs[lastFound];
00140 for (int i=0;i<n;i++)
00141 if (i!=lastFound)
00142 if (k.compare(keys[i]))
00143 {
00144 lastFound=i;
00145 return objs[i];
00146 }
00147 return OBJ(0);
00148 }
00149 void add(const KEY &k,const OBJ &o) {
00150 int doomed=lastFound+1;
00151 if (doomed>=n) doomed-=n;
00152 keys[doomed]=k;
00153 objs[doomed]=o;
00154 }
00155 };
00156 #endif
00157
00158
00159
00160 template <class KEY,class OBJ>
00161 class hashCache1 {
00162 KEY key;
00163 OBJ obj;
00164 public:
00165 hashCache1(const KEY &invalidKey) {
00166 key=invalidKey;
00167 }
00168 inline OBJ lookup(const KEY &k) {
00169 if (k.compare(key)) return obj;
00170 else return OBJ(0);
00171 }
00172 inline void add(const KEY &k,const OBJ &o) {
00173 key=k;
00174 obj=o;
00175 }
00176 };
00177
00178
00179
00180
00181
00182 class voxelAggregator {
00183 private:
00184
00185 growableBufferT<CollideObjRec> obj;
00186 CollideLoc3d destination;
00187 collideMgr *mgr;
00188 public:
00189 voxelAggregator(const CollideLoc3d &dest,collideMgr *mgr_)
00190 :destination(dest),mgr(mgr_) { }
00191
00192
00193 inline void add(const CollideObjRec &o) {
00194 obj.push_back(o);
00195 }
00196
00197
00198 void send(void);
00199 };
00200
00201
00202 void voxelAggregator::send(void) {
00203 if (obj.length()>0) {
00204
00205 CollideObjRec *o=obj.getData(); int n=obj.length();
00206 obj.detachBuffer();
00207 mgr->sendVoxelMessage(destination,n,o);
00208 }
00209 }
00210
00211
00212
00213
00214
00215
00216
00217
00218 CollisionAggregator::CollisionAggregator(const CollideGrid3d &gridMap_,collideMgr *mgr_)
00219 :gridMap(gridMap_),voxels(17,0.25),mgr(mgr_)
00220 {}
00221 CollisionAggregator::~CollisionAggregator()
00222 {
00223 compact();
00224 }
00225
00226
00227 voxelAggregator *CollisionAggregator::addAccum(const CollideLoc3d &dest)
00228 {
00229 voxelAggregator *ret=new voxelAggregator(dest,mgr);
00230 voxels.put(dest)=ret;
00231 return ret;
00232 }
00233
00234
00235 void CollisionAggregator::aggregate(int pe, int chunk, int n,
00236 const bbox3d *boxes, const int *prio)
00237 {
00238 hashCache1<CollideLoc3d,voxelAggregator *>
00239 cache(CollideLoc3d(-1000000000,-1000000000,-1000000000));
00240
00241
00242 for (int i=0;i<n;i++) {
00243
00244 const bbox3d &bbox=boxes[i];
00245 int oPrio=chunk;
00246 if (prio!=NULL) oPrio=prio[i];
00247 CollideObjRec obj(CollideObjID(chunk,i,oPrio,pe),bbox);
00248
00249 iSeg1d sx(gridMap.world2grid(0,bbox.axis(0))),
00250 sy(gridMap.world2grid(1,bbox.axis(1))),
00251 sz(gridMap.world2grid(2,bbox.axis(2)));
00252 STATS(objects++)
00253 STATS(gridSizes[0]+=sx.getMax()-sx.getMin())
00254 STATS(gridSizes[1]+=sy.getMax()-sy.getMin())
00255 STATS(gridSizes[2]+=sz.getMax()-sz.getMin())
00256
00257
00258 CollideLoc3d g;
00259 g.z=sz.getMin();
00260 do {
00261 g.y=sy.getMin();
00262 do {
00263 g.x=sx.getMin();
00264 do {
00265 voxelAggregator *c=cache.lookup(g);
00266 if (c==NULL) {
00267 c=voxels.get(g);
00268 if (c==NULL) c=addAccum(g);
00269 cache.add(g,c);
00270 }
00271 c->add(obj);
00272 } while (++g.x<sx.getMax());
00273 } while (++g.y<sy.getMax());
00274 } while (++g.z<sz.getMax());
00275 }
00276 }
00277
00278
00279 void CollisionAggregator::send(void)
00280 {
00281 CkHashtableIterator *it=voxels.iterator();
00282 void *c;
00283 while (NULL!=(c=it->next())) (*(voxelAggregator **)c)->send();
00284 delete it;
00285 }
00286
00287
00288 void CollisionAggregator::compact(void)
00289 {
00290 CkHashtableIterator *it=voxels.iterator();
00291 void *c;
00292 while (NULL!=(c=it->next())) delete *(voxelAggregator **)c;
00293 delete it;
00294 voxels.empty();
00295 }
00296
00297
00298 syncReductionMgr::syncReductionMgr()
00299 :thisproxy(thisgroup)
00300 {
00301 stepCount=-1;
00302 stepFinished=true;
00303 localFinished=false;
00304
00305
00306 onPE=CkMyPe();
00307 if (onPE==0) treeParent=-1;
00308 else treeParent=(onPE-1)/TREE_WID;
00309 treeChildStart=(onPE*TREE_WID)+1;
00310 treeChildEnd=treeChildStart+TREE_WID;
00311 if (treeChildStart>CkNumPes()) treeChildStart=CkNumPes();
00312 if (treeChildEnd>CkNumPes()) treeChildEnd=CkNumPes();
00313 nChildren=treeChildEnd-treeChildStart;
00314 }
00315 void syncReductionMgr::startStep(int stepNo,bool withProd)
00316 {
00317 SRM_STATUS("syncReductionMgr::startStep");
00318 if (stepNo<1+stepCount) return;
00319 if (stepNo>1+stepCount) CkAbort("Tried to start SRMgr step from future\n");
00320 stepCount++;
00321 stepFinished=false;
00322 localFinished=false;
00323 childrenCount=0;
00324 if (nChildren>0)
00325 for (int i=0;i<TREE_WID;i++)
00326 if (treeChildStart+i<CkNumPes())
00327 thisproxy[treeChildStart+i].childProd(stepCount);
00328 if (withProd)
00329 pleaseAdvance();
00330 }
00331
00332 void syncReductionMgr::advance(void)
00333 {
00334 SRM_STATUS("syncReductionMgr::advance");
00335 if (stepFinished) startStep(stepCount+1,false);
00336 localFinished=true;
00337 tryFinish();
00338 }
00339
00340 void syncReductionMgr::pleaseAdvance(void)
00341 { }
00342
00343
00344 void syncReductionMgr::reductionFinished(void)
00345 { }
00346
00347 void syncReductionMgr::tryFinish(void)
00348 {
00349 SRM_STATUS("syncReductionMgr::tryFinish");
00350 if (localFinished && (!stepFinished) && childrenCount==nChildren)
00351 {
00352 stepFinished=true;
00353 if (treeParent!=-1)
00354 thisproxy[treeParent].childDone(stepCount);
00355 else
00356 reductionFinished();
00357 }
00358 }
00359
00360 void syncReductionMgr::childProd(int stepCount)
00361 {
00362 SRM_STATUS("syncReductionMgr::childProd");
00363 if (stepFinished) startStep(stepCount,true);
00364 tryFinish();
00365 }
00366
00367 void syncReductionMgr::childDone(int stepCount)
00368 {
00369 SRM_STATUS("syncReductionMgr::childDone");
00370 if (stepFinished) startStep(stepCount,true);
00371 childrenCount++;
00372 tryFinish();
00373 }
00374
00375
00376
00377
00378
00379 static int low23(unsigned int src)
00380 {
00381 unsigned int loMask=0x007fFFffu;
00382 unsigned int offset=0x00400000u;
00383 return (src&loMask)-offset;
00384 }
00385 static const char * voxName(int ix,int iy,int iz,char *buf) {
00386 int x=low23(ix);
00387 int y=low23(iy);
00388 int z=low23(iz);
00389 sprintf(buf,"(%d,%d,%d)",x,y,z);
00390 return buf;
00391 }
00392 static const char * voxName(const CkIndex3D &idx,char *buf) {
00393 return voxName(idx.x,idx.y,idx.z,buf);
00394 }
00395
00396
00397 collideMgr::collideMgr(const CollideGrid3d &gridMap_,
00398 const CProxy_collideClient &client_,
00399 const CProxy_collideVoxel &voxels)
00400 :thisproxy(thisgroup), voxelProxy(voxels),
00401 gridMap(gridMap_), client(client_), aggregator(gridMap,this)
00402 {
00403 steps=0;
00404 nContrib=0;
00405 contribCount=0;
00406 msgsSent=msgsRecvd=0;
00407 }
00408
00409
00410 void collideMgr::registerContributor(int chunkNo)
00411 {
00412 nContrib++;
00413 CM_STATUS("Contributor register: now "<<nContrib);
00414 }
00415 void collideMgr::unregisterContributor(int chunkNo)
00416 {
00417 nContrib--;
00418 CM_STATUS("Contributor unregister: now "<<nContrib);
00419 }
00420
00421
00422 void collideMgr::contribute(int chunkNo,
00423 int n,const bbox3d *boxes,const int *prio)
00424 {
00425
00426 CM_STATUS("collideMgr::contribute "<<n<<" boxes from "<<chunkNo);
00427 aggregator.aggregate(CkMyPe(),chunkNo,n,boxes,prio);
00428 aggregator.send();
00429 if (++contribCount==nContrib) {
00430
00431
00432 aggregator.compact();
00433 tryAdvance();
00434 }
00435
00436 }
00437
00438 inline CkArrayIndex3D buildIndex(const CollideLoc3d &l)
00439 {return CkArrayIndex3D(l.x,l.y,l.z);}
00440
00441
00442 void collideMgr::sendVoxelMessage(const CollideLoc3d &dest,
00443 int n,CollideObjRec *obj)
00444 {
00445 char destName[200];
00446 CM_STATUS("collideMgr::sendVoxelMessage to "<<voxName(dest.x,dest.y,dest.z,destName));
00447 msgsSent++;
00448 objListMsg *msg=new objListMsg(n,obj,
00449 objListMsg::returnReceipt(thisgroup,CkMyPe()));
00450 voxelProxy[buildIndex(dest)].add(msg);
00451 }
00452
00453 void objListMsg::returnReceipt::send(void)
00454 {
00455 CProxy_collideMgr p(gid);
00456 if (onPE==CkMyPe())
00457 p.ckLocalBranch()->voxelMessageRecvd();
00458 else
00459 p[onPE].voxelMessageRecvd();
00460 }
00461
00462
00463 void collideMgr::voxelMessageRecvd(void)
00464 {
00465 msgsRecvd++;
00466 CM_STATUS("collideMgr::voxelMessageRecvd: "<<msgsRecvd<<" of "<<msgsSent);
00467
00468 tryAdvance();
00469 }
00470
00471
00472 void collideMgr::pleaseAdvance(void)
00473 {
00474 CM_STATUS("collideMgr::pleaseAdvance");
00475 tryAdvance();
00476 }
00477
00478
00479 void collideMgr::tryAdvance(void)
00480 {
00481 CM_STATUS("tryAdvance: "<<nContrib-contribCount<<" contrib, "<<msgsSent-msgsRecvd<<" msg")
00482 if ((contribCount==nContrib) && (msgsSent==msgsRecvd)) {
00483 CM_STATUS("advancing");
00484 advance();
00485 steps++;
00486 contribCount=0;
00487 msgsSent=msgsRecvd=0;
00488 }
00489 }
00490
00491
00492 void collideMgr::reductionFinished(void)
00493 {
00494 CM_STATUS("collideMgr::reductionFinished");
00495
00496 voxelProxy.startCollision(steps,gridMap,client);
00497 }
00498
00499
00500
00501
00502 iSeg1d collideVoxel_extents[3]={
00503 iSeg1d(100,-100),iSeg1d(100,-100),iSeg1d(100,-100)};
00504
00505
00506
00507 void collideVoxel::status(const char *msg)
00508 {
00509 int x=low23(thisIndex.x);
00510 int y=low23(thisIndex.y);
00511 int z=low23(thisIndex.z);
00512 CkPrintf("Pe %d, voxel (%d,%d,%d)> %s\n",CkMyPe(),x,y,z,msg);
00513 }
00514 void collideVoxel::emptyMessages()
00515 {
00516 for (int i=0;i<msgs.length();i++) delete msgs[i];
00517 msgs.length()=0;
00518 }
00519
00520
00521
00522 collideVoxel::collideVoxel(void)
00523 {
00524 CC_STATUS("created");
00525 collideVoxel_extents[0].add(low23(thisIndex.x));
00526 collideVoxel_extents[1].add(low23(thisIndex.y));
00527 collideVoxel_extents[2].add(low23(thisIndex.z));
00528 }
00529 collideVoxel::collideVoxel(CkMigrateMessage *m)
00530 {
00531 CC_STATUS("arrived from migration");
00532 }
00533 collideVoxel::~collideVoxel()
00534 {
00535 emptyMessages();
00536 CC_STATUS("deleted. (migration depart)");
00537 }
00538 void collideVoxel::pup(PUP::er &p) {
00539 if (msgs.length()!=0) {
00540 status("Error! Cannot migrate voxels with messages in tow!\n");
00541 CkAbort("collideVoxel::pup cannot handle message case");
00542 }
00543 }
00544 void collideVoxel::add(objListMsg *msg)
00545 {
00546 CC_STATUS("add message from "<<msg->getSource());
00547 msg->sendReceipt();
00548 msgs.push_back(msg);
00549 }
00550
00551 void collideVoxel::collide(const bbox3d &territory,CollisionList &dest)
00552 {
00553 int m;
00554
00555 #if 0 //Check if all the priorities are identical-- early exit if so
00556 CC_STATUS(" early-exit (all prio. identical) test");
00557 int firstPrio=msgs[0]->tri(0).id.prio;
00558 bool allIdentical=true;
00559 for (m=0;allIdentical && m<msgs.length();m++)
00560 for (int i=0;i<msgs[m]->getNtris();i++)
00561 if (msgs[m]->tri(i).id.prio!=firstPrio)
00562 { allIdentical=false; break;}
00563 if (allIdentical) {CC_STATUS(" early-exit used!");return;}
00564 #endif
00565
00566 int n=0;
00567 for (m=0;m<msgs.length();m++) n+=msgs[m]->getObjects();
00568 CollideOctant o(n,territory);
00569 o.length()=0;
00570 bbox3d big;big.infinity();
00571 o.setBbox(big);
00572
00573 CC_STATUS(" creating bbox, etc. for polys");
00574 #if COLLIDE_TRACE
00575 bbox3d oBox; oBox.empty();
00576 #endif
00577
00578 for (m=0;m<msgs.length();m++) {
00579 const objListMsg &msg=*(msgs[m]);
00580 for (int i=0;i<msg.getObjects();i++) {
00581 o.push_fast(&msg.getObj(i));
00582 #if COLLIDE_TRACE
00583 oBox.add(msg.getObj(i).getBbox());
00584 #endif
00585 }
00586 }
00587 o.markHome(o.length());
00588 COL_STATUS(" colliding polys");
00589 COL_STATUS("\t\t\tXXX "<<o.length()<<" polys, "<<msgs.length()<<" msgs")
00590 #if COLLIDE_TRACE
00591 territory.print("Voxel territory: ");
00592 oBox.print(" Voxel objects: ");
00593 CkPrintf("\n");
00594 #endif
00595 o.findCollisions(dest);
00596 }
00597
00598
00599 void collideVoxel::startCollision(int step,
00600 const CollideGrid3d &gridMap,
00601 const CProxy_collideClient &client)
00602 {
00603 CC_STATUS("startCollision "<<step<<" on "<<msgs.length()<<" messages {");
00604
00605 bbox3d territory(gridMap.grid2world(0,rSeg1d(thisIndex.x,thisIndex.x+1)),
00606 gridMap.grid2world(1,rSeg1d(thisIndex.y,thisIndex.y+1)),
00607 gridMap.grid2world(2,rSeg1d(thisIndex.z,thisIndex.z+1))
00608 );
00609 CollisionList colls;
00610 collide(territory,colls);
00611 client.ckLocalBranch()->collisions(this,step,colls);
00612
00613 emptyMessages();
00614 CC_STATUS("} startCollision");
00615 }
00616
00617 collideClient::~collideClient() {}
00618
00619
00620 serialCollideClient::serialCollideClient(void) {
00621 clientFn=NULL;
00622 clientParam=NULL;
00623 }
00624
00626 void serialCollideClient::setClient(CollisionClientFn clientFn_,void *clientParam_) {
00627 clientFn=clientFn_;
00628 clientParam=clientParam_;
00629 }
00630
00631 void serialCollideClient::collisions(ArrayElement *src,
00632 int step,CollisionList &colls)
00633 {
00634 CkCallback cb(CkIndex_serialCollideClient::reductionDone(0),0,thisgroup);
00635 src->contribute(colls.length()*sizeof(Collision),colls.getData(),
00636 CkReduction::concat,cb);
00637 }
00638
00639
00640 void serialCollideClient::reductionDone(CkReductionMsg *msg)
00641 {
00642 int nColl=msg->getSize()/sizeof(Collision);
00643 CM_STATUS("serialCollideClient with "<<nColl<<" collisions");
00644 if (clientFn!=NULL)
00645 (clientFn)(clientParam,nColl,(Collision *)msg->getData());
00646 else
00647 CkAbort("Forgot to call serialCollideClient::setClient!\n");
00648 delete msg;
00649 }
00650
00651
00652
00653 #include "collidecharm.def.h"