Added runtime option "+traceWarn" for warning messages from the tracing
[charm.git] / src / ck-perf / trace-summary.C
1 /*****************************************************************************
2  * $Source$
3  * $Author$
4  * $Date$
5  * $Revision$
6  *****************************************************************************/
7
8 /**
9  * \addtogroup CkPerf
10 */
11 /*@{*/
12
13 #include "charm++.h"
14 #include "trace-summary.h"
15 #include "trace-summaryBOC.h"
16
17 #define DEBUGF(x)  // CmiPrintf x
18
19 #define VER   4.0
20
21 #define INVALIDEP     -2
22 #define TRACEON_EP     -3
23
24 #define DefaultBinCount      10000
25
26 CkpvStaticDeclare(TraceSummary*, _trace);
27 static int _numEvents = 0;
28 #define NUM_DUMMY_EPS 9
29 CkpvDeclare(int, binCount);
30 CkpvDeclare(double, binSize);
31 CkpvDeclare(double, version);
32
33 int sumonly = 0;
34 int sumDetail = 0;
35
36 /**
37   For each TraceFoo module, _createTraceFoo() must be defined.
38   This function is called in _createTraces() generated in moduleInit.C
39 */
40 void _createTracesummary(char **argv)
41 {
42   DEBUGF(("%d createTraceSummary\n", CkMyPe()));
43   CkpvInitialize(TraceSummary*, _trace);
44   CkpvAccess(_trace) = new  TraceSummary(argv);
45   CkpvAccess(_traces)->addTrace(CkpvAccess(_trace));
46 }
47
48
49 /// function call for starting a phase in trace summary logs 
50 extern "C" 
51 void CkSummary_StartPhase(int phase)
52 {
53    CkpvAccess(_trace)->startPhase(phase);
54 }
55
56
57 /// function call for adding an event mark
58 extern "C" 
59 void CkSummary_MarkEvent(int eventType)
60 {
61    CkpvAccess(_trace)->addEventType(eventType);
62 }
63
64 static inline void writeU(FILE* fp, int u)
65 {
66   fprintf(fp, "%4d", u);
67 }
68
69 PhaseEntry::PhaseEntry() 
70 {
71   int _numEntries=_entryTable.size();
72   // FIXME: Hopes there won't be more than 10 more EP's registered from now on...
73   nEPs = _numEntries+10; 
74   count = new int[nEPs];
75   times = new double[nEPs];
76   maxtimes = new double[nEPs];
77   for (int i=0; i<nEPs; i++) {
78     count[i] = 0;
79     times[i] = 0.0;
80     maxtimes[i] = 0.;
81   }
82 }
83
84 SumLogPool::~SumLogPool() 
85 {
86   if (!sumonly) {
87     write();
88     fclose(fp);
89     if (sumDetail) fclose(sdfp);
90   }
91   // free memory for mark
92   if (markcount > 0)
93   for (int i=0; i<MAX_MARKS; i++) {
94     for (int j=0; j<events[i].length(); j++)
95       delete events[i][j];
96   }
97   delete[] pool;
98   delete[] epInfo;
99   delete[] cpuTime;
100   delete[] numExecutions;
101 }
102
103 void SumLogPool::addEventType(int eventType, double time)
104 {
105    if (eventType <0 || eventType >= MAX_MARKS) {
106        CkPrintf("Invalid event type %d!\n", eventType);
107        return;
108    }
109    MarkEntry *e = new MarkEntry;
110    e->time = time;
111    events[eventType].push_back(e);
112    markcount ++;
113 }
114
115 SumLogPool::SumLogPool(char *pgm) : numBins(0), phaseTab(MAX_PHASES) 
116 {
117    // TBD: Can this be moved to initMem?
118    poolSize = CkpvAccess(binCount);
119    if (poolSize % 2) poolSize++;        // make sure it is even
120    pool = new BinEntry[poolSize];
121    _MEMCHECK(pool);
122
123    fp = NULL;
124    sdfp = NULL;
125    //CmiPrintf("TRACE: %s:%d\n", fname, errno);
126    if (!sumonly) {
127     char pestr[10];
128     sprintf(pestr, "%d", CkMyPe());
129     int len = strlen(pgm) + strlen(".sumd.") + strlen(pestr) + 1;
130     char *fname = new char[len+1];
131
132     sprintf(fname, "%s.%s.sum", pgm, pestr);
133     do {
134       fp = fopen(fname, "w+");
135     } while (!fp && errno == EINTR);
136     if (!fp) {
137     CkPrintf("[%d] Attempting to open [%s]\n",CkMyPe(),fname);
138       CmiAbort("Cannot open Summary Trace File for writing...\n");
139     }
140
141     if (sumDetail) {
142         sprintf(fname, "%s.%s.sumd", pgm, pestr);
143         do {
144             sdfp = fopen(fname, "w+");
145         } while (!sdfp && errno == EINTR);
146         if(!sdfp) {
147             CmiAbort("Cannot open Detailed Summary Trace File for writing...\n");
148         }
149     }
150
151     delete[] fname;
152    }
153
154    // event
155    markcount = 0;
156
157    if (CkMyPe() == 0)
158    {
159     char *fname = new char[strlen(CkpvAccess(traceRoot))+strlen(".sum.sts")+1];
160     sprintf(fname, "%s.sum.sts", CkpvAccess(traceRoot));
161     stsfp = fopen(fname, "w+");
162     //CmiPrintf("File: %s \n", fname);
163     if(stsfp == 0)
164       CmiAbort("Cannot open summary sts file for writing.\n");
165     delete[] fname;
166    }
167 }
168
169 void SumLogPool::initMem()
170 {
171    int _numEntries=_entryTable.size();
172    epInfoSize = _numEntries + NUM_DUMMY_EPS + 1; // keep a spare EP
173    epInfo = new SumEntryInfo[epInfoSize];
174    _MEMCHECK(epInfo);
175
176    cpuTime = NULL;
177    numExecutions = NULL;
178    if (sumDetail) {
179        cpuTime = new double[poolSize*epInfoSize];
180        _MEMCHECK(cpuTime);
181        memset(cpuTime, 0, poolSize*epInfoSize*sizeof(double));
182        numExecutions = new int[poolSize*epInfoSize];
183        _MEMCHECK(numExecutions);
184        memset(numExecutions, 0, poolSize*epInfoSize*sizeof(int));
185
186 //         int i, e;
187 //         for(i=0; i<poolSize; i++) {
188 //             for(e=0; e< epInfoSize; e++) {
189 //                 setCPUtime(i,e,0.0);
190 //                 setNumExecutions(i,e,0);
191 //             }
192 //         }
193    }
194 }
195
196 int SumLogPool::getUtilization(int interval, int ep) {
197     return (int)(getCPUtime(interval, ep) * 100.0 / CkpvAccess(binSize)); 
198 };
199
200 void SumLogPool::write(void) 
201 {
202   int i;
203   unsigned int j;
204   int _numEntries=_entryTable.size();
205
206   fprintf(fp, "ver:%3.1f %d/%d count:%d ep:%d interval:%e", CkpvAccess(version), CkMyPe(), CkNumPes(), numBins, _numEntries, CkpvAccess(binSize));
207   if (CkpvAccess(version)>=3.0)
208   {
209     fprintf(fp, " phases:%d", phaseTab.numPhasesCalled());
210   }
211   fprintf(fp, "\n");
212
213   // write bin time
214 #if 1
215   int last=pool[0].getU();
216   writeU(fp, last);
217   int count=1;
218   for(j=1; j<numBins; j++) {
219     int u = pool[j].getU();
220     if (last == u) {
221       count++;
222     }
223     else {
224       if (count > 1) fprintf(fp, "+%d", count);
225       writeU(fp, u);
226       last = u;
227       count = 1;
228     }
229   }
230   if (count > 1) fprintf(fp, "+%d", count);
231 #else
232   for(j=0; j<numEntries; j++) 
233       pool[j].write(fp);
234 #endif
235   fprintf(fp, "\n");
236
237   // write entry execution time
238   fprintf(fp, "EPExeTime: ");
239   for (i=0; i<_numEntries; i++)
240     fprintf(fp, "%ld ", (long)(epInfo[i].epTime*1.0e6));
241   fprintf(fp, "\n");
242   // write entry function call times
243   fprintf(fp, "EPCallTime: ");
244   for (i=0; i<_numEntries; i++)
245     fprintf(fp, "%d ", epInfo[i].epCount);
246   fprintf(fp, "\n");
247   // write max entry function execute times
248   fprintf(fp, "MaxEPTime: ");
249   for (i=0; i<_numEntries; i++)
250     fprintf(fp, "%ld ", (long)(epInfo[i].epMaxTime*1.0e6));
251   fprintf(fp, "\n");
252 #if 0
253   for (i=0; i<SumEntryInfo::HIST_SIZE; i++) {
254     for (j=0; j<_numEntries; j++) 
255       fprintf(fp, "%d ", epInfo[j].hist[i]);
256     fprintf(fp, "\n");
257   }
258 #endif
259   // write marks
260   if (CkpvAccess(version)>=2.0) 
261   {
262     fprintf(fp, "NumMarks: %d ", markcount);
263     for (i=0; i<MAX_MARKS; i++) {
264       for(int j=0; j<events[i].length(); j++)
265         fprintf(fp, "%d %f ", i, events[i][j]->time);
266     }
267     fprintf(fp, "\n");
268   }
269   // write phases
270   if (CkpvAccess(version)>=3.0)
271   {
272     phaseTab.write(fp);
273   }
274
275   // write summary details
276   if (sumDetail) {
277         fprintf(sdfp, "ver:%3.1f cpu:%d/%d numIntervals:%d numEPs:%d intervalSize:%e\n",
278                 CkpvAccess(version), CkMyPe(), CkNumPes(),
279                 numBins, _numEntries, CkpvAccess(binSize));
280
281         // Write out cpuTime in microseconds
282         // Run length encoding (RLE) along EP axis
283         fprintf(sdfp, "ExeTimePerEPperInterval ");
284         unsigned int e, i;
285         long last= (long) (getCPUtime(0,0)*1.0e6);
286         int count=0;
287         fprintf(sdfp, "%ld", last);
288         for(e=0; e<_numEntries; e++) {
289             for(i=0; i<numBins; i++) {
290
291                 long u= (long) (getCPUtime(i,e)*1.0e6);
292                 if (last == u) {
293                     count++;
294                 } else {
295
296                     if (count > 1) fprintf(sdfp, "+%d", count);
297                     fprintf(sdfp, " %ld", u);
298                     last = u;
299                     count = 1;
300                 }
301             }
302         }
303         if (count > 1) fprintf(sdfp, "+%d", count);
304         fprintf(sdfp, "\n");
305
306         // Write out numExecutions
307         // Run length encoding (RLE) along EP axis
308         fprintf(sdfp, "EPCallTimePerInterval ");
309         last= getNumExecutions(0,0);
310         count=0;
311         fprintf(sdfp, "%d", last);
312         for(e=0; e<_numEntries; e++) {
313             for(i=0; i<numBins; i++) {
314
315                 long u= getNumExecutions(i, e);
316                 if (last == u) {
317                     count++;
318                 } else {
319
320                     if (count > 1) fprintf(sdfp, "+%d", count);
321                     fprintf(sdfp, " %d", u);
322                     last = u;
323                     count = 1;
324                 }
325             }
326         }
327         if (count > 1) fprintf(sdfp, "+%d", count);
328         fprintf(sdfp, "\n");
329   }
330 }
331
332 void SumLogPool::writeSts(void)
333 {
334   traceWriteSTS(stsfp,_numEvents);
335   for(int i=0;i<_numEvents;i++)
336     fprintf(stsfp, "EVENT %d Event%d\n", i, i);
337   fprintf(stsfp, "END\n");
338   fclose(stsfp);
339 }
340
341 // Called once per interval
342 void SumLogPool::add(double time, int pe) 
343 {
344   new (&pool[numBins++]) BinEntry(time);
345   if(poolSize==numBins) shrink();
346 }
347
348 // Called once per run of an EP
349 // adds 'time' to EP's time, increments epCount
350 void SumLogPool::setEp(int epidx, double time) 
351 {
352   if (epidx >= epInfoSize) {
353         CmiAbort("Invalid entry point!!\n");
354   }
355   //CmiPrintf("set EP: %d %e \n", epidx, time);
356   epInfo[epidx].setTime(time);
357   // set phase table counter
358   phaseTab.setEp(epidx, time);
359 }
360
361 // Called once from endExecute, endPack, etc. this function updates
362 // the sumDetail intervals.
363 void SumLogPool::updateSummaryDetail(int epIdx, double startTime, double endTime)
364 {
365         if (epIdx >= epInfoSize) {
366             CmiAbort("Too many entry points!!\n");
367         }
368
369         double binSz = CkpvAccess(binSize);
370         int startingBinIdx, endingBinIdx;
371         startingBinIdx = (int)(startTime/binSz);
372         endingBinIdx = (int)(endTime/binSz);
373         // shrink if needed
374         while (endingBinIdx >= poolSize) {
375           shrink();
376           CmiAssert(CkpvAccess(binSize) > binSz);
377           binSz = CkpvAccess(binSize);
378           startingBinIdx = (int)(startTime/binSz);
379           endingBinIdx = (int)(endTime/binSz);
380         }
381
382         if (startingBinIdx == endingBinIdx) {
383             addToCPUtime(startingBinIdx, epIdx, endTime - startTime);
384         } else if (startingBinIdx < endingBinIdx) { // EP spans intervals
385             addToCPUtime(startingBinIdx, epIdx, (startingBinIdx+1)*binSz - startTime);
386             while(++startingBinIdx < endingBinIdx)
387                 addToCPUtime(startingBinIdx, epIdx, binSz);
388             addToCPUtime(endingBinIdx, epIdx, endTime - endingBinIdx*binSz);
389         } else {
390           CkPrintf("[%d] EP:%d Start:%lf End:%lf\n",CkMyPe(),epIdx,
391                    startTime, endTime);
392             CmiAbort("Error: end time of EP is less than start time\n");
393         }
394
395         incNumExecutions(startingBinIdx, epIdx);
396 };
397
398 // Shrinks pool[], cpuTime[], and numExecutions[]
399 void SumLogPool::shrink(void)
400 {
401 //  double t = CmiWallTimer();
402
403   // We ensured earlier that poolSize is even; therefore now numBins
404   // == poolSize == even.
405   int entries = numBins/2;
406   for (int i=0; i<entries; i++)
407   {
408      pool[i].time() = pool[i*2].time() + pool[i*2+1].time();
409      if (sumDetail)
410      for (int e=0; e < epInfoSize; e++) {
411          setCPUtime(i, e, getCPUtime(i*2, e) + getCPUtime(i*2+1, e));
412          setNumExecutions(i, e, getNumExecutions(i*2, e) + getNumExecutions(i*2+1, e));
413      }
414   }
415   // zero out the remaining intervals
416   if (sumDetail) {
417     memset(&cpuTime[entries*epInfoSize], 0, (numBins-entries)*epInfoSize*sizeof(double));
418     memset(&numExecutions[entries*epInfoSize], 0, (numBins-entries)*epInfoSize*sizeof(int));
419   }
420   numBins = entries;
421   CkpvAccess(binSize) *= 2;
422
423 //CkPrintf("Shrinked binsize: %f entries:%d takes %fs!!!!\n", CkpvAccess(binSize), numEntries, CmiWallTimer()-t);
424 }
425
426 int  BinEntry::getU() 
427
428   return (int)(_time * 100.0 / CkpvAccess(binSize)); 
429 }
430
431 void BinEntry::write(FILE* fp)
432 {
433   writeU(fp, getU());
434 }
435
436 TraceSummary::TraceSummary(char **argv):binStart(0.0),bin(0.0),msgNum(0)
437 {
438   if (CkpvAccess(traceOnPe) == 0) return;
439
440   CkpvInitialize(int, binCount);
441   CkpvInitialize(double, binSize);
442   CkpvInitialize(double, version);
443   CkpvAccess(binSize) = BIN_SIZE;
444   CkpvAccess(version) = VER;
445   CkpvAccess(binCount) = DefaultBinCount;
446   if (CmiGetArgIntDesc(argv,"+bincount",&CkpvAccess(binCount), "Total number of summary bins"))
447     if (CkMyPe() == 0) 
448       CmiPrintf("Trace: bincount: %d\n", CkpvAccess(binCount));
449   CmiGetArgDoubleDesc(argv,"+binsize",&CkpvAccess(binSize),
450         "CPU usage log time resolution");
451   CmiGetArgDoubleDesc(argv,"+version",&CkpvAccess(version),
452         "Write this .sum file version");
453
454   epThreshold = 0.001; 
455   CmiGetArgDoubleDesc(argv,"+epThreshold",&epThreshold,
456         "Execution time histogram lower bound");
457   epInterval = 0.001; 
458   CmiGetArgDoubleDesc(argv,"+epInterval",&epInterval,
459         "Execution time histogram bin size");
460
461   sumonly = CmiGetArgFlagDesc(argv, "+sumonly", "merge histogram bins on processor 0");
462   // +sumonly overrides +sumDetail
463   if (!sumonly)
464       sumDetail = CmiGetArgFlagDesc(argv, "+sumDetail", "more detailed summary info");
465
466   _logPool = new SumLogPool(CkpvAccess(traceRoot));
467   // assume invalid entry point on start
468   execEp=INVALIDEP;
469 }
470
471 void TraceSummary::traceClearEps(void)
472 {
473   _logPool->clearEps();
474 }
475
476 void TraceSummary::traceWriteSts(void)
477 {
478   if(CkMyPe()==0)
479       _logPool->writeSts();
480 }
481
482 void TraceSummary::traceClose(void)
483 {
484   if(CkMyPe()==0)
485       _logPool->writeSts();
486   CkpvAccess(_trace)->endComputation();
487   // destructor call the write()
488   delete _logPool;
489   // remove myself from traceArray so that no tracing will be called.
490   CkpvAccess(_traces)->removeTrace(this);
491 }
492
493 void TraceSummary::beginExecute(CmiObjId *tid)
494 {
495   beginExecute(-1,-1,_threadEP,-1);
496 }
497
498 void TraceSummary::beginExecute(envelope *e)
499 {
500   // no message means thread execution
501   if (e==NULL) {
502     beginExecute(-1,-1,_threadEP,-1);
503   }
504   else {
505     beginExecute(-1,-1,e->getEpIdx(),-1);
506   }  
507 }
508
509 void TraceSummary::beginExecute(int event,int msgType,int ep,int srcPe, int mlen, CmiObjId *idx)
510 {
511   if (execEp != INVALIDEP) {
512     TRACE_WARN("Warning: TraceSummary two consecutive BEGIN_PROCESSING!\n");
513     return;
514   }
515   
516   execEp=ep;
517   double t = TraceTimer();
518   //CmiPrintf("start: %f \n", start);
519   
520   start = t;
521   double ts = binStart;
522   // fill gaps
523   while ((ts = ts + CkpvAccess(binSize)) < t) {
524      _logPool->add(bin, CkMyPe());
525      bin=0.0;
526      binStart = ts;
527   }
528 }
529
530 void TraceSummary::endExecute(void)
531 {
532 //  if (!flag) return;
533   double t = TraceTimer();
534   double ts = start;
535   double nts = binStart;
536
537   if (execEp == TRACEON_EP) {
538     // if trace just got turned on, then one expects to see this
539     // END_PROCESSING event without seeing a preceeding BEGIN_PROCESSING
540     return;
541   }
542
543   if (execEp == INVALIDEP) {
544     TRACE_WARN("Warning: TraceSummary END_PROCESSING without BEGIN_PROCESSING!\n");
545     return;
546   }
547
548   if (execEp != -1)
549   {
550     _logPool->setEp(execEp, t-ts);
551   }
552
553   while ((nts = nts + CkpvAccess(binSize)) < t)
554   {
555      bin += nts-ts;
556      binStart  = nts;
557      _logPool->add(bin, CkMyPe()); // This calls shrink() if needed
558      bin = 0;
559      ts = nts;
560   }
561   bin += t - ts;
562
563   if (sumDetail)
564       _logPool->updateSummaryDetail(execEp, start, t);
565
566   execEp = INVALIDEP;
567 }
568
569 void TraceSummary::beginPack(void)
570 {
571     packstart = CmiWallTimer();
572 }
573
574 void TraceSummary::endPack(void)
575 {
576     _logPool->setEp(_packEP, CmiWallTimer() - packstart);
577     if (sumDetail)
578         _logPool->updateSummaryDetail(_packEP,  TraceTimer(packstart), TraceTimer(CmiWallTimer()));
579 }
580
581 void TraceSummary::beginUnpack(void)
582 {
583     unpackstart = CmiWallTimer();
584 }
585
586 void TraceSummary::endUnpack(void)
587 {
588     _logPool->setEp(_unpackEP, CmiWallTimer()-unpackstart);
589     if (sumDetail)
590         _logPool->updateSummaryDetail(_unpackEP,  TraceTimer(unpackstart), TraceTimer(CmiWallTimer()));
591 }
592
593 void TraceSummary::beginComputation(void)
594 {
595   // initialze arrays because now the number of entries is known.
596   _logPool->initMem();
597 }
598
599 void TraceSummary::endComputation(void)
600 {
601   static int done = 0;
602   if (done) return;
603   done = 1;
604   if (msgNum==0) {
605 //CmiPrintf("Add at last: %d pe:%d time:%f msg:%d\n", index, CkMyPe(), bin, msgNum);
606      _logPool->add(bin, CkMyPe());
607      bin = 0.0;
608      msgNum ++;
609
610      binStart  += CkpvAccess(binSize);
611      double t = TraceTimer();
612      double ts = binStart;
613      while (ts < t)
614      {
615        _logPool->add(bin, CkMyPe());
616        bin=0.0;
617        ts += CkpvAccess(binSize);
618      }
619
620   }
621 }
622
623 void TraceSummary::addEventType(int eventType)
624 {
625   _logPool->addEventType(eventType, TraceTimer());
626 }
627
628 void TraceSummary::startPhase(int phase)
629 {
630    _logPool->startPhase(phase);
631 }
632
633
634 /// for TraceSummaryBOC
635
636 CkGroupID traceSummaryGID;
637
638 void TraceSummaryBOC::startSumOnly()
639 {
640   CmiAssert(CkMyPe() == 0);
641
642   CProxy_TraceSummaryBOC p(traceSummaryGID);
643   int size = CkpvAccess(_trace)->pool()->getNumEntries();
644   p.askSummary(size);
645 }
646
647 void TraceSummaryBOC::askSummary(int size)
648 {
649   if (CkpvAccess(_trace) == NULL) return;
650
651   int traced = CkpvAccess(_trace)->traceOnPE();
652
653   BinEntry *bins = new BinEntry[size+1];
654   bins[size] = traced;          // last element is the traced pe count
655   if (traced) {
656     CkpvAccess(_trace)->endComputation();
657     int n = CkpvAccess(_trace)->pool()->getNumEntries();
658     BinEntry *localBins = CkpvAccess(_trace)->pool()->bins();
659 #if 0
660   CmiPrintf("askSummary on [%d] numEntried=%d\n", CkMyPe(), n);
661 #if 1
662   for (int i=0; i<n; i++) CmiPrintf("%4d", localBins[i].getU());
663   CmiPrintf("\n");
664 #endif
665 #endif
666     if (n>size) n=size;
667     for (int i=0; i<n; i++) bins[i] = localBins[i];
668   }
669
670   contribute(sizeof(BinEntry)*(size+1), bins, CkReduction::sum_double);
671   delete [] bins;
672 }
673
674 extern "C" void _CkExit();
675
676 void TraceSummaryBOC::sendSummaryBOC(CkReductionMsg *msg)
677 {
678   if (CkpvAccess(_trace) == NULL) return;
679
680   CkAssert(CkMyPe() == 0);
681
682   int n = msg->getSize()/sizeof(BinEntry);
683   nBins = n-1;
684   bins = (BinEntry *)msg->getData();
685   nTracedPEs = (int)bins[n-1].time();
686   //CmiPrintf("traced: %d entry:%d\n", nTracedPEs, nBins);
687
688   write();
689
690   delete msg;
691
692   _CkExit();
693 }
694
695 void TraceSummaryBOC::write(void) 
696 {
697   int i;
698   unsigned int j;
699
700   char *fname = new char[strlen(CkpvAccess(traceRoot))+strlen(".sum")+1];
701   sprintf(fname, "%s.sum", CkpvAccess(traceRoot));
702   FILE *sumfp = fopen(fname, "w+");
703   //CmiPrintf("File: %s \n", fname);
704   if(sumfp == 0)
705       CmiAbort("Cannot open summary sts file for writing.\n");
706   delete[] fname;
707
708   int _numEntries=_entryTable.size();
709   fprintf(sumfp, "ver:%3.1f %d/%d count:%d ep:%d interval:%e numTracedPE:%d", CkpvAccess(version), CkMyPe(), CkNumPes(), nBins, _numEntries, CkpvAccess(binSize), nTracedPEs);
710   fprintf(sumfp, "\n");
711
712   // write bin time
713 #if 0
714   int last=pool[0].getU();
715   writeU(fp, last);
716   int count=1;
717   for(j=1; j<numEntries; j++) {
718     int u = pool[j].getU();
719     if (last == u) {
720       count++;
721     }
722     else {
723       if (count > 1) fprintf(fp, "+%d", count);
724       writeU(fp, u);
725       last = u;
726       count = 1;
727     }
728   }
729   if (count > 1) fprintf(fp, "+%d", count);
730 #else
731   for(j=0; j<nBins; j++) {
732     bins[j].time() /= nTracedPEs;
733     bins[j].write(sumfp);
734   }
735 #endif
736   fprintf(sumfp, "\n");
737   fclose(sumfp);
738
739 }
740
741 extern "C" void CombineSummary()
742 {
743 #ifndef CMK_OPTIMIZE
744   CmiPrintf("[%d] CombineSummary called!\n", CkMyPe());
745   if (sumonly) {
746     CmiPrintf("[%d] Sum Only start!\n", CkMyPe());
747       // pe 0 start the sumonly process
748     CProxy_TraceSummaryBOC sumProxy(traceSummaryGID);
749     sumProxy[0].startSumOnly();
750   }
751   else CkExit();
752 #else
753   CkExit();
754 #endif
755 }
756
757 void initTraceSummaryBOC()
758 {
759 #ifdef __BLUEGENE__
760   if(BgNodeRank()==0) {
761 #else
762   if (CkMyRank() == 0) {
763 #endif
764     registerExitFn(CombineSummary);
765   }
766 }
767
768 #include "TraceSummary.def.h"
769
770
771 /*@}*/