00001
00002 #include "pose.h"
00003 #include "srtable.h"
00004 #include "gvt.def.h"
00005 #include "qd.h"
00006
00007 CkGroupID ThePVT;
00008 CkGroupID TheGVT;
00009 CpvExtern(int, stateRecovery);
00010 CpvExtern(eventID, theEventID);
00012 PVT::PVT()
00013 {
00014 #ifdef VERBOSE_DEBUG
00015 CkPrintf("[%d] constructing PVT\n",CkMyPe());
00016 #endif
00017 CpvInitialize(int, stateRecovery);
00018 CpvAccess(stateRecovery) = 0;
00019 CpvInitialize(eventID, theEventID);
00020 CpvAccess(theEventID)=eventID();
00021
00022 LBTurnInstrumentOff();
00023 optGVT = POSE_UnsetTS; conGVT = POSE_UnsetTS;
00024 rdone=0;
00025 SRs=NULL;
00026 #ifdef POSE_COMM_ON
00027
00028 #endif
00029 #ifndef CMK_OPTIMIZE
00030 localStats = (localStat *)CkLocalBranch(theLocalStats);
00031 if(pose_config.stats)
00032 {
00033 localStats->TimerStart(GVT_TIMER);
00034 }
00035 #endif
00036 #ifdef MEM_TEMPORAL
00037 localTimePool = (TimePool *)CkLocalBranch(TempMemID);
00038 CkPrintf("NOTE: Temporal memory manager is ON!\n");
00039 #endif
00040 optPVT = conPVT = estGVT = POSE_UnsetTS;
00041 startPhaseActive = gvtTurn = simdone = 0;
00042 SendsAndRecvs = new SRtable();
00043 SendsAndRecvs->Initialize();
00044 specEventCount = eventCount = waitForFirst = 0;
00045 iterMin = POSE_UnsetTS;
00046 int P=CkNumPes(), N=CkMyPe();
00047 reportReduceTo = -1;
00048 if ((N < P-2) && (N%2 == 1)) {
00049 reportTo = N-1;
00050 reportsExpected = reportEnd = 0;
00051 }
00052 else if (N < P-2) {
00053 reportTo = N;
00054 reportsExpected = 2;
00055 if (N == P-3)
00056 reportsExpected = 1;
00057 reportEnd = 0;
00058 if (N < (P-2)/2)
00059 reportReduceTo = P-2;
00060 else reportReduceTo = P-1;
00061 }
00062 if (N == P-2) {
00063 reportTo = N;
00064 reportEnd = 1;
00065 reportsExpected = 1 + (P-2)/4 + ((P-2)%4)/2;
00066 }
00067 else if (N == P-1) {
00068 reportTo = N;
00069 reportEnd = 1;
00070 if (P==1) reportsExpected = 1;
00071 else reportsExpected = 1 + (P-2)/4 + (P-2)%2;
00072 }
00073
00074 #ifndef CMK_OPTIMIZE
00075 if(pose_config.stats)
00076 localStats->TimerStop();
00077 #endif
00078 }
00079
00080 void PVT::startPhaseExp(prioBcMsg *m) {
00081 startPhase(m);
00082 }
00083
00085 void PVT::startPhase(prioBcMsg *m)
00086 {
00087 CProxy_GVT g(TheGVT);
00088 CProxy_PVT p(ThePVT);
00089 register int i;
00090
00091 if (startPhaseActive) return;
00092 #ifndef CMK_OPTIMIZE
00093 if(pose_config.stats)
00094 localStats->TimerStart(GVT_TIMER);
00095 #endif
00096 startPhaseActive = 1;
00097 if (m->bc) {
00098 prioBcMsg *startMsg = new (8*sizeof(POSE_TimeType)) prioBcMsg;
00099 startMsg->bc = 0;
00100 *((POSE_TimeType *)CkPriorityPtr(startMsg)) = 1-POSE_TimeMax;
00101 CkSetQueueing(startMsg, CK_QUEUEING_IFIFO);
00102 p.startPhaseExp(startMsg);
00103 }
00104
00105 objs.Wake();
00106
00107 optPVT = conPVT = POSE_UnsetTS;
00108 int end = objs.getNumSpaces();
00109 for (i=0; i<end; i++)
00110 if (objs.objs[i].isPresent()) {
00111 if (objs.objs[i].isOptimistic()) {
00112 if ((optPVT < 0) || ((objs.objs[i].getOVT() < optPVT) &&
00113 (objs.objs[i].getOVT() > POSE_UnsetTS))) {
00114 optPVT = objs.objs[i].getOVT();
00115 CkAssert(simdone>0 || ((objs.objs[i].getOVT() >= estGVT) ||
00116 (objs.objs[i].getOVT() == POSE_UnsetTS)));
00117 }
00118 }
00119 else if (objs.objs[i].isConservative()) {
00120 if ((conPVT < 0) || ((objs.objs[i].getOVT() < conPVT) &&
00121 (objs.objs[i].getOVT() > POSE_UnsetTS)))
00122 conPVT = objs.objs[i].getOVT();
00123 }
00124 CkAssert(simdone>0 || (optPVT >= estGVT)||(optPVT == POSE_UnsetTS)||(estGVT == POSE_UnsetTS));
00125 CkAssert(simdone>0 || (conPVT >= estGVT)||(conPVT == POSE_UnsetTS)||(estGVT == POSE_UnsetTS));
00126 }
00127
00128
00129 POSE_TimeType pvt = optPVT;
00130 if ((conPVT < pvt) && (conPVT > POSE_UnsetTS)) pvt = conPVT;
00131 if ((iterMin < pvt) && (iterMin > POSE_UnsetTS)) pvt = iterMin;
00132 if (waitForFirst) {
00133 waitForFirst = 0;
00134 if (pvt == POSE_UnsetTS)
00135 SendsAndRecvs->Restructure(estGVT, estGVT, POSE_UnsetTS);
00136 else
00137 SendsAndRecvs->Restructure(estGVT, pvt, POSE_UnsetTS);
00138 }
00139
00140
00141 POSE_TimeType xt;
00142 if (pvt == POSE_UnsetTS) {
00143 POSE_TimeType maxOVT = POSE_UnsetTS;
00144 for (i=0; i<end; i++)
00145 if (objs.objs[i].isPresent()) {
00146 xt = objs.objs[i].getOVT2();
00147 if (xt > maxOVT)
00148 maxOVT = xt;
00149 }
00150 if (maxOVT > estGVT)
00151 pvt = maxOVT;
00152 }
00153
00154
00155 POSE_TimeType maxSR;
00156 UpdateMsg *um = SendsAndRecvs->PackTable(pvt, &maxSR);
00157
00158 um->optPVT = pvt;
00159 um->conPVT = conPVT;
00160 um->maxSR = maxSR;
00161 um->runGVTflag = 0;
00162
00163 if (um->numEntries > 0) {
00164
00165 }
00166
00167 p[reportTo].reportReduce(um);
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177 objs.SetIdle();
00178 iterMin = POSE_UnsetTS;
00179 #ifndef CMK_OPTIMIZE
00180 if(pose_config.stats)
00181 localStats->TimerStop();
00182 #endif
00183 }
00184
00186 void PVT::setGVT(GVTMsg *m)
00187 {
00188 #ifndef CMK_OPTIMIZE
00189 if(pose_config.stats)
00190 localStats->TimerStart(GVT_TIMER);
00191 #endif
00192 CProxy_PVT p(ThePVT);
00193 CkAssert(m->estGVT >= estGVT);
00194 estGVT = m->estGVT;
00195 int i, end = objs.getNumSpaces();
00196 #ifdef POSE_COMM_ON
00197
00198
00199
00200 #endif
00201 simdone = m->done;
00202 CkFreeMsg(m);
00203 waitForFirst = 1;
00204 objs.Commit();
00205 #ifdef MEM_TEMPORAL
00206 localTimePool->set_min_time(estGVT);
00207 #endif
00208 startPhaseActive = 0;
00209 prioBcMsg *startMsg = new (8*sizeof(int)) prioBcMsg;
00210 startMsg->bc = 1;
00211 *((int *)CkPriorityPtr(startMsg)) = 0;
00212 CkSetQueueing(startMsg, CK_QUEUEING_IFIFO);
00213 p[CkMyPe()].startPhase(startMsg);
00214 #ifndef CMK_OPTIMIZE
00215 if(pose_config.stats)
00216 localStats->TimerStop();
00217 #endif
00218 }
00219
00221 int PVT::objRegister(int arrIdx, POSE_TimeType safeTime, int sync, sim *myPtr)
00222 {
00223 int i = objs.Insert(arrIdx, POSE_UnsetTS, sync, myPtr);
00224 return(i*1000 + CkMyPe());
00225 }
00226
00227
00228 void PVT::objRemove(int pvtIdx)
00229 {
00230 int idx = (pvtIdx-CkMyPe())/1000;
00231 objs.Delete(idx);
00232 }
00233
00235 void PVT::objUpdate(POSE_TimeType timestamp, int sr)
00236 {
00237 #ifndef CMK_OPTIMIZE
00238 int tstat = localStats->TimerRunning();
00239 if(pose_config.stats){
00240 if (tstat)
00241 localStats->SwitchTimer(GVT_TIMER);
00242 else
00243 localStats->TimerStart(GVT_TIMER);
00244 }
00245 #endif
00246
00247
00248
00249 CkAssert(simdone>0 || (timestamp >= estGVT) || (estGVT == POSE_UnsetTS));
00250 CkAssert((sr == SEND) || (sr == RECV));
00251 if ((estGVT > POSE_UnsetTS) &&
00252 ((timestamp < iterMin) || (iterMin == POSE_UnsetTS)))
00253 iterMin = timestamp;
00254 if (waitForFirst) {
00255 waitForFirst = 0;
00256 SendsAndRecvs->Restructure(estGVT, timestamp, sr);
00257 }
00258 else SendsAndRecvs->Insert(timestamp, sr);
00259 #ifndef CMK_OPTIMIZE
00260 if(pose_config.stats){
00261 if (tstat)
00262 localStats->SwitchTimer(tstat);
00263 else
00264 localStats->TimerStop();
00265 }
00266 #endif
00267
00268 }
00269
00271 void PVT::objUpdateOVT(int pvtIdx, POSE_TimeType safeTime, POSE_TimeType ovt)
00272 {
00273 int index = (pvtIdx-CkMyPe())/1000;
00274
00275
00276
00277 CkAssert(simdone>0 || (safeTime >= estGVT) || (safeTime == POSE_UnsetTS));
00278 if ((safeTime == POSE_UnsetTS) && (objs.objs[index].getOVT2() < ovt))
00279 objs.objs[index].setOVT2(ovt);
00280 else if ((safeTime > POSE_UnsetTS) &&
00281 ((objs.objs[index].getOVT() > safeTime) || (objs.objs[index].getOVT() == POSE_UnsetTS)))
00282 objs.objs[index].setOVT(safeTime);
00283 }
00284
00286 void PVT::reportReduce(UpdateMsg *m)
00287 {
00288 #ifndef CMK_OPTIMIZE
00289 if(pose_config.stats)
00290 localStats->TimerStart(GVT_TIMER);
00291 #endif
00292 CProxy_PVT p(ThePVT);
00293 CProxy_GVT g(TheGVT);
00294 POSE_TimeType lastGVT = 0, maxSR=0;
00295
00296
00297 if ((optGVT < 0) || ((m->optPVT > POSE_UnsetTS) && (m->optPVT < optGVT)))
00298 optGVT = m->optPVT;
00299 if (m->maxSR > 0)
00300 maxSR = m->maxSR;
00301 addSR(&SRs, m->SRs, optGVT, m->numEntries);
00302 rdone++;
00303 CkFreeMsg(m);
00304
00305 if (rdone == reportsExpected) {
00306 UpdateMsg *um;
00307 int entryCount = 0;
00308
00309 SRentry *tmp = SRs;
00310 while (tmp && ((tmp->timestamp <= optGVT) || (optGVT == POSE_UnsetTS))
00311 && (tmp->sends != tmp->recvs)) {
00312 entryCount++;
00313 tmp = tmp->next;
00314 }
00315 um = new (entryCount * sizeof(SRentry), 0) UpdateMsg;
00316 tmp = SRs;
00317 int i=0;
00318 while (tmp && ((tmp->timestamp <= optGVT) || (optGVT == POSE_UnsetTS))
00319 && (tmp->sends != tmp->recvs)) {
00320 um->SRs[i] = *tmp;
00321 tmp = tmp->next;
00322 i++;
00323 }
00324 um->numEntries = entryCount;
00325 um->optPVT = optGVT;
00326 um->conPVT = conGVT;
00327 um->maxSR = maxSR;
00328 um->runGVTflag = 0;
00329
00330 if (reportEnd) {
00331 if (simdone>0)
00332 g[0].computeGVT(um);
00333 else {
00334 g[gvtTurn].computeGVT(um);
00335 gvtTurn = (gvtTurn + 1) % CkNumPes();
00336 }
00337 }
00338 else {
00339 p[reportReduceTo].reportReduce(um);
00340 }
00341
00342
00343 optGVT = conGVT = POSE_UnsetTS;
00344 SRentry *cur = SRs;
00345 SRs = NULL;
00346 while (cur) {
00347 tmp = cur->next;
00348 delete cur;
00349 cur = tmp;
00350 }
00351 rdone = 0;
00352 }
00353 #ifndef CMK_OPTIMIZE
00354 if(pose_config.stats)
00355 localStats->TimerStop();
00356 #endif
00357 }
00358
00360 GVT::GVT()
00361 {
00362 #ifdef VERBOSE_DEBUG
00363 CkPrintf("[%d] constructing GVT\n",CkMyPe());
00364 #endif
00365
00366 optGVT = POSE_UnsetTS, conGVT = POSE_UnsetTS;
00367 done=0;
00368 SRs = NULL;
00369 startOffset = 0;
00370
00371 #ifndef CMK_OPTIMIZE
00372 localStats = (localStat *)CkLocalBranch(theLocalStats);
00373 #endif
00374 #ifndef SEQUENTIAL_POSE
00375 if(pose_config.lb_on)
00376 nextLBstart = pose_config.lb_skip - 1;
00377 #endif
00378 estGVT = lastEarliest = inactiveTime = POSE_UnsetTS;
00379 lastSends = lastRecvs = inactive = 0;
00380 reportsExpected = 1;
00381 if (CkNumPes() >= 2) reportsExpected = 2;
00382
00383
00384 if (CkMyPe() == 0) {
00385 CProxy_PVT p(ThePVT);
00386 prioBcMsg *startMsg = new (8*sizeof(int)) prioBcMsg;
00387 startMsg->bc = 1;
00388 *((int *)CkPriorityPtr(startMsg)) = 0;
00389 CkSetQueueing(startMsg, CK_QUEUEING_IFIFO);
00390 p.startPhase(startMsg);
00391 }
00392 }
00393
00394
00395
00396
00397
00398
00399
00400
00402 void GVT::runGVT(UpdateMsg *m)
00403 {
00404 #ifndef CMK_OPTIMIZE
00405 if(pose_config.stats)
00406 localStats->TimerStart(GVT_TIMER);
00407 #endif
00408 estGVT = m->optPVT;
00409 inactive = m->inactive;
00410 inactiveTime = m->inactiveTime;
00411 nextLBstart = m->nextLB;
00412 CProxy_GVT g(TheGVT);
00413 m->runGVTflag = 1;
00414 g[CkMyPe()].computeGVT(m);
00415 #ifndef CMK_OPTIMIZE
00416 if(pose_config.stats)
00417 localStats->TimerStop();
00418 #endif
00419 }
00420
00422 void GVT::computeGVT(UpdateMsg *m)
00423 {
00424 #ifndef CMK_OPTIMIZE
00425 if(pose_config.stats)
00426 localStats->TimerStart(GVT_TIMER);
00427 #endif
00428 CProxy_PVT p(ThePVT);
00429 CProxy_GVT g(TheGVT);
00430 GVTMsg *gmsg = new GVTMsg;
00431 POSE_TimeType lastGVT = 0, earliestMsg = POSE_UnsetTS,
00432 earlyAny = POSE_UnsetTS;
00433
00434 if (CkMyPe() != 0) startOffset = 1;
00435 if (m->runGVTflag == 1) done++;
00436 else {
00437
00438 if ((optGVT < 0) || ((m->optPVT > POSE_UnsetTS) && (m->optPVT < optGVT)))
00439 optGVT = m->optPVT;
00440 if ((conGVT < 0) || ((m->conPVT > POSE_UnsetTS) && (m->conPVT < conGVT)))
00441 conGVT = m->conPVT;
00442 if (m->maxSR > earlyAny)
00443 earlyAny = m->maxSR;
00444
00445
00446
00447
00448 addSR(&SRs, m->SRs, optGVT, m->numEntries);
00449 done++;
00450 }
00451 CkFreeMsg(m);
00452
00453 if (done == reportsExpected+startOffset) {
00454 #ifndef CMK_OPTIMIZE
00455 if(pose_config.stats)
00456 localStats->GvtInc();
00457 #endif
00458 done = 0;
00459 startOffset = 1;
00460 lastGVT = estGVT;
00461 if (lastGVT < 0) lastGVT = 0;
00462 estGVT = POSE_UnsetTS;
00463
00464
00465 estGVT = optGVT;
00466 if ((conGVT > POSE_UnsetTS) && (estGVT > POSE_UnsetTS) && (conGVT < estGVT)) estGVT = conGVT;
00467
00468
00469
00470
00471 SRentry *tmp = SRs;
00472 POSE_TimeType lastSR = POSE_UnsetTS;
00473 while (tmp && ((tmp->timestamp <= estGVT) || (estGVT == POSE_UnsetTS))) {
00474 lastSR = tmp->timestamp;
00475 if (tmp->sends != tmp->recvs) {
00476 earliestMsg = tmp->timestamp;
00477 break;
00478 }
00479 tmp = tmp->next;
00480 }
00481
00482
00483 if (((earliestMsg < estGVT) && (earliestMsg != POSE_UnsetTS)) ||
00484 (estGVT == POSE_UnsetTS))
00485 estGVT = earliestMsg;
00486 if ((lastSR != POSE_UnsetTS) && (estGVT == POSE_UnsetTS) &&
00487 (lastSR > lastGVT))
00488 estGVT = lastSR;
00489
00490
00491 if ((optGVT == POSE_UnsetTS) && (earliestMsg == POSE_UnsetTS)) {
00492 inactive++;
00493
00494
00495
00496
00497
00498
00499
00500 estGVT = lastGVT;
00501 if (inactive == 1) inactiveTime = lastGVT;
00502 }
00503 else if (estGVT < 0) {
00504 estGVT = lastGVT;
00505 inactive = 0;
00506 }
00507 else inactive = 0;
00508
00509
00510
00511 CmiAssert(estGVT >= lastGVT);
00512
00513
00514
00515
00516
00517 int term = 0;
00518 if ((estGVT >= POSE_endtime) && (POSE_endtime > POSE_UnsetTS)) {
00519 #if USE_LONG_TIMESTAMPS
00520 CkPrintf("At endtime: %lld\n", POSE_endtime);
00521 #else
00522 CkPrintf("At endtime: %d\n", POSE_endtime);
00523 #endif
00524 term = 1;
00525 }
00526 else if (inactive > 2) {
00527 #if USE_LONG_TIMESTAMPS
00528 CkPrintf("Simulation inactive at time: %lld\n", inactiveTime);
00529 #else
00530 CkPrintf("Simulation inactive at time: %d\n", inactiveTime);
00531 #endif
00532 term = 1;
00533 }
00534
00535
00536 gmsg->estGVT = estGVT;
00537 gmsg->done = term;
00538 if (term) {
00539
00540
00541 #if USE_LONG_TIMESTAMPS
00542 CkPrintf("Final GVT = %lld\n", gmsg->estGVT);
00543 #else
00544 CkPrintf("Final GVT = %d\n", gmsg->estGVT);
00545 #endif
00546 p.setGVT(gmsg);
00547 POSE_stop();
00548 }
00549 else {
00550 p.setGVT(gmsg);
00551
00552 if(pose_config.lb_on)
00553 {
00554
00555 #ifndef CMK_OPTIMIZE
00556 if(pose_config.stats)
00557 localStats->SwitchTimer(LB_TIMER);
00558 #endif
00559
00560 if (CkNumPes() > 1) {
00561 nextLBstart++;
00562 if (pose_config.lb_skip == nextLBstart) {
00563 TheLBG.calculateLocalLoad();
00564 nextLBstart = 0;
00565 }
00566 }
00567 #ifndef CMK_OPTIMIZE
00568 if(pose_config.stats)
00569 localStats->SwitchTimer(GVT_TIMER);
00570 #endif
00571 }
00572
00573
00574 UpdateMsg *umsg = new UpdateMsg;
00575 umsg->maxSR=0;
00576 umsg->optPVT = estGVT;
00577 umsg->inactive = inactive;
00578 umsg->inactiveTime = inactiveTime;
00579 umsg->nextLB = nextLBstart;
00580 umsg->runGVTflag = 0;
00581 g[(CkMyPe()+1) % CkNumPes()].runGVT(umsg);
00582 }
00583
00584
00585 optGVT = conGVT = POSE_UnsetTS;
00586 SRentry *cur = SRs;
00587 SRs = NULL;
00588 while (cur) {
00589 tmp = cur->next;
00590 delete cur;
00591 cur = tmp;
00592 }
00593 }
00594 #ifndef CMK_OPTIMIZE
00595 if(pose_config.stats)
00596 localStats->TimerStop();
00597 #endif
00598 }
00599
00600 void GVT::addSR(SRentry **SRs, SRentry *e, POSE_TimeType og, int ne)
00601 {
00602 register int i;
00603 SRentry *tab = (*SRs);
00604 SRentry *tmp = tab;
00605
00606 for (i=0; i<ne; i++) {
00607 if ((e[i].timestamp < og) || (og == POSE_UnsetTS)) {
00608 if (!tmp) {
00609 tab = new SRentry(e[i].timestamp, (SRentry *)NULL);
00610 tab->sends = e[i].sends;
00611 tab->recvs = e[i].recvs;
00612 tmp = tab;
00613 *SRs = tmp;
00614 }
00615 else {
00616 if (e[i].timestamp < tmp->timestamp) {
00617 CkAssert(tmp == *SRs);
00618 tab = new SRentry(e[i].timestamp, tmp);
00619 tab->sends = e[i].sends;
00620 tab->recvs = e[i].recvs;
00621 tmp = tab;
00622 *SRs = tmp;
00623 }
00624 else if (e[i].timestamp == tmp->timestamp) {
00625 tmp->sends = tmp->sends + e[i].sends;
00626 tmp->recvs = tmp->recvs + e[i].recvs;
00627 }
00628 else {
00629 while (tmp->next && (e[i].timestamp > tmp->next->timestamp))
00630 tmp = tmp->next;
00631 if (!tmp->next) {
00632 tmp->next = new SRentry(e[i].timestamp, (SRentry *)NULL);
00633 tmp->next->sends = tmp->next->sends + e[i].sends;
00634 tmp->next->recvs = tmp->next->recvs + e[i].recvs;
00635 tmp = tmp->next;
00636 }
00637 else if (e[i].timestamp == tmp->next->timestamp) {
00638 tmp->next->sends = tmp->next->sends + e[i].sends;
00639 tmp->next->recvs = tmp->next->recvs + e[i].recvs;
00640 tmp = tmp->next;
00641 }
00642 else {
00643 tmp->next = new SRentry(e[i].timestamp, tmp->next);
00644 tmp->next->sends = tmp->next->sends + e[i].sends;
00645 tmp->next->recvs = tmp->next->recvs + e[i].recvs;
00646 tmp = tmp->next;
00647 }
00648 }
00649 }
00650 }
00651 else break;
00652 }
00653 }
00654
00655 void PVT::addSR(SRentry **SRs, SRentry *e, POSE_TimeType og, int ne)
00656 {
00657 register int i;
00658 SRentry *tab = (*SRs);
00659 SRentry *tmp = tab;
00660
00661 for (i=0; i<ne; i++) {
00662 if ((e[i].timestamp < og) || (og == POSE_UnsetTS)) {
00663 if (!tmp) {
00664 tab = new SRentry(e[i].timestamp, (SRentry *)NULL);
00665 tab->sends = e[i].sends;
00666 tab->recvs = e[i].recvs;
00667 tmp = tab;
00668 *SRs = tmp;
00669 }
00670 else {
00671 if (e[i].timestamp < tmp->timestamp) {
00672 CkAssert(tmp == *SRs);
00673 tab = new SRentry(e[i].timestamp, tmp);
00674 tab->sends = e[i].sends;
00675 tab->recvs = e[i].recvs;
00676 tmp = tab;
00677 *SRs = tmp;
00678 }
00679 else if (e[i].timestamp == tmp->timestamp) {
00680 tmp->sends = tmp->sends + e[i].sends;
00681 tmp->recvs = tmp->recvs + e[i].recvs;
00682 }
00683 else {
00684 while (tmp->next && (e[i].timestamp > tmp->next->timestamp))
00685 tmp = tmp->next;
00686 if (!tmp->next) {
00687 tmp->next = new SRentry(e[i].timestamp, (SRentry *)NULL);
00688 tmp->next->sends = tmp->next->sends + e[i].sends;
00689 tmp->next->recvs = tmp->next->recvs + e[i].recvs;
00690 tmp = tmp->next;
00691 }
00692 else if (e[i].timestamp == tmp->next->timestamp) {
00693 tmp->next->sends = tmp->next->sends + e[i].sends;
00694 tmp->next->recvs = tmp->next->recvs + e[i].recvs;
00695 tmp = tmp->next;
00696 }
00697 else {
00698 tmp->next = new SRentry(e[i].timestamp, tmp->next);
00699 tmp->next->sends = tmp->next->sends + e[i].sends;
00700 tmp->next->recvs = tmp->next->recvs + e[i].recvs;
00701 tmp = tmp->next;
00702 }
00703 }
00704 }
00705 }
00706 else break;
00707 }
00708 }