00001
00005
00006
00007
00008
00009 #include "charm++.h"
00010
00011 #ifdef CMK_ORIGIN2000
00012 #include "trace-counter.h"
00013 #include "ck.h"
00014 #include <inttypes.h>
00015 #include <values.h>
00016
00017 #define DEBUGF(x) // CmiPrintf x
00018 #define VER 1.0
00019
00020
00021 extern "C" int start_counters(int e0, int e1);
00022 extern "C" int read_counters(int e0, long long *c0, int e1, long long *c1);
00023
00024
00025
00026
00027
00028
00029
00030 static const int NUM_EXTRA_PERF = 6;
00031
00032 CkpvStaticDeclare(Trace*, _trace);
00033 CpvStaticDeclare(CountLogPool*, _logPool);
00034 CpvStaticDeclare(char*, _logName);
00035 CpvStaticDeclare(char**, _counterNames);
00036 CpvStaticDeclare(char**, _counterDesc);
00037 CpvStaticDeclare(int, _numCounters);
00038 CpvStaticDeclare(int, _reductionID);
00039 static int _numEvents = 0;
00040 CpvDeclare(double, version);
00041
00042
00043 CmiHandler StatTableReduction(char* msg)
00044 {
00045 DEBUGF(("StatTableReduction called\n", CmiMyPe(), CmiNumPes()));
00046 static double* reduce = NULL;
00047 static int numReduce = 0;
00048 int numCounters = CpvAccess(_numCounters);
00049 int size = 2*CpvAccess(_numCounters)+NUM_EXTRA_PERF;
00050 int i;
00051 if (reduce == NULL) {
00052
00053 reduce = new double[size];
00054 for (i=0; i<size; i++) { reduce[i] = 0.0; }
00055 DEBUGF((" allocated reduce numCounters %d size %d\n",
00056 numCounters, size));
00057 }
00058
00059
00060 double* msgResults = (double *)(msg+ALIGN8(CmiMsgHeaderSizeBytes));
00061 for (i=0; i<size; i++) {
00062 reduce[i] += msgResults[i];
00063 }
00064
00065 char** counterNames = CpvAccess(_counterNames);
00066 numReduce++;
00067 DEBUGF((" numReduce %d numPes %d\n", numReduce, CmiNumPes()));
00068 int phase = reduce[2*numCounters];
00069 if (numReduce >= CmiNumPes()) {
00070
00071 numReduce = 0;
00072 for (i=0; i<numCounters; i++) {
00073 if (reduce[2*i+1]>0.0) {
00074 if (phase >= 0) {
00075 CmiPrintf("PHASE %d %s totalCount %f totalTime (us) %f\n"
00076 "PHASE %d %s count/proc %f avgTime (us)/phase %f\n",
00077 phase, counterNames[i], reduce[2*i], reduce[2*i+1]*1e6,
00078 phase, counterNames[i], reduce[2*i]/CmiNumPes(),
00079 reduce[2*i+1]*1e6/CmiNumPes());
00080 }
00081 else {
00082 CmiPrintf("%s totalCount %f totalTime (us) %f\n"
00083 "%s count/proc %f avgTime (us)/phase %f\n",
00084 counterNames[i], reduce[2*i], reduce[2*i+1]*1e6,
00085 counterNames[i], reduce[2*i]/CmiNumPes(),
00086 reduce[2*i+1]*1e6/CmiNumPes());
00087 }
00088 }
00089 }
00090 if (phase >= 0) {
00091 CmiPrintf("PHASE %d totalIdleTime (us) %f avgIdleTime (us)/phase %f\n",
00092 phase, reduce[2*numCounters+1]*1e6,
00093 reduce[2*numCounters+1]*1e6/CmiNumPes());
00094 }
00095 else {
00096 CmiPrintf("totalIdleTime (us) %f avgIdleTime (us)/phase %f\n",
00097 reduce[2*numCounters+1]*1e6,
00098 reduce[2*numCounters+1]*1e6/CmiNumPes());
00099 }
00100 if (reduce[2*numCounters+2] > 0.0) {
00101
00102 if (phase >= 0) {
00103 CmiPrintf("PHASE %d flops/s %f flops/s/PE %f\n",
00104 phase, reduce[2*numCounters+2],
00105 reduce[2*numCounters+2]/CmiNumPes());
00106 }
00107 else {
00108 CmiPrintf("flops/s %f flops/s/PE %f\n",
00109 reduce[2*numCounters+2],
00110 reduce[2*numCounters+2]/CmiNumPes());
00111 }
00112 }
00113 char* missRate = NULL;
00114 for (i=0; i<3; i++) {
00115 switch (i) {
00116 case 0: missRate = "l1 avg miss rate (%)"; break;
00117 case 1: missRate = "l2 avg miss rate (%)"; break;
00118 case 2: missRate = "tlb avg miss rate (%)"; break;
00119 }
00120 if (reduce[2*numCounters+3+i] >= 0.0) {
00121 if (phase >= 0) {
00122 CmiPrintf("PHASE %d %s %f\n",
00123 phase, missRate, reduce[2*numCounters+3+i]/CmiNumPes()*100);
00124 }
00125 else {
00126 CmiPrintf("%s %f\n",
00127 missRate, reduce[2*numCounters+3+i]/CmiNumPes()*100);
00128 }
00129 }
00130 }
00131
00132
00133 delete [] reduce;
00134 reduce = NULL;
00135 }
00136 CmiFree(msg);
00137 }
00138
00148 static const int NUM_COUNTER_ARGS = 32;
00149 static TraceCounter::CounterArg COUNTER_ARG[NUM_COUNTER_ARGS] =
00150 { TraceCounter::CounterArg( 0, "CYCLES0", "Cycles (also see code 16)"),
00151 TraceCounter::CounterArg( 1, "INSTR", "Issued instructions"),
00152 TraceCounter::CounterArg( 2, "LOAD", "Issued loads"),
00153 TraceCounter::CounterArg( 3, "STORE", "Issued stores"),
00154 TraceCounter::CounterArg( 4, "STORE_COND", "Issued store conditionals"),
00155 TraceCounter::CounterArg( 5, "FAIL_COND", "Failed store conditionals"),
00156 TraceCounter::CounterArg( 6, "DECODE_BR", "Decoded branches. (This changes meaning in 3.x versions of R10000. It becomes resolved branches)"),
00157 TraceCounter::CounterArg( 7, "QUADWORDS2", "Quadwords written back from secondary cache"),
00158 TraceCounter::CounterArg( 8, "CACHE_ER2", "Correctable secondary cache data array ECC errors"),
00159 TraceCounter::CounterArg( 9, "L1_IMISS", "Primary (L1) instruction cache misses"),
00160 TraceCounter::CounterArg(10, "L2_IMISS", "Secondary (L2) instruction cache misses"),
00161 TraceCounter::CounterArg(11, "INSTRMISPR", "Instruction misprediction from secondary cache way prediction table"),
00162 TraceCounter::CounterArg(12, "EXT_INTERV", "External interventions"),
00163 TraceCounter::CounterArg(13, "EXT_INVAL", "External invalidations"),
00164 TraceCounter::CounterArg(14, "VIRT_COHER", "Virtual coherency conditions. (This changes meaning in 3.x versions of R10000. It becomes ALU/FPU forward progress cycles. On the R12000, this counter is always 0)."),
00165 TraceCounter::CounterArg(15, "GR_INSTR15", "Graduated instructions (also see code 17)"),
00166 TraceCounter::CounterArg(16, "CYCLES16", "Cycles (also see code 0)"),
00167 TraceCounter::CounterArg(17, "GR_INSTR17", "Graduated instructions (also see code 15)"),
00168 TraceCounter::CounterArg(18, "GR_LOAD" , "Graduated loads"),
00169 TraceCounter::CounterArg(19, "GR_STORE", "Graduated stores"),
00170 TraceCounter::CounterArg(20, "GR_ST_COND", "Graduated store conditionals"),
00171 TraceCounter::CounterArg(21, "GR_FLOPS", "Graduated floating point instructions"),
00172 TraceCounter::CounterArg(22, "QUADWORDS1", "Quadwords written back from primary data cache"),
00173 TraceCounter::CounterArg(23, "TLB_MISS", "TLB misses"),
00174 TraceCounter::CounterArg(24, "MIS_BR", "Mispredicted branches"),
00175 TraceCounter::CounterArg(25, "L1_DMISS", "Primary (L1) data cache misses"),
00176 TraceCounter::CounterArg(26, "L2_DMISS", "Primary (L2) data cache misses"),
00177 TraceCounter::CounterArg(27, "DATA_MIS", "Data misprediction from secondary cache way predicition table"),
00178 TraceCounter::CounterArg(28, "EXT_INTERV2", "External intervention hits in secondary cache (L2)"),
00179 TraceCounter::CounterArg(29, "EXT_INVAL2", "External invalidation hits in secondary cache"),
00180 TraceCounter::CounterArg(30, "CLEAN_ST_PRE", "Store/prefetch exclusive to clean block in secondary cache"),
00181 TraceCounter::CounterArg(31, "SHARE_ST_PRE", "Store/prefetch exclusive to shared block in secondary cache")
00182 };
00183
00184
00185 void _createTracecounter(char **argv)
00186 {
00187 DEBUGF(("%d/%d DEBUG: createTraceCounter\n", CmiMyPe(), CmiNumPes()));
00188 CkpvInitialize(Trace*, _trace);
00189 TraceCounter* tc = new TraceCounter(); _MEMCHECK(tc);
00190 tc->traceInit(argv);
00191 CkpvAccess(_trace) = tc;
00192 CkpvAccess(_traces)->addTrace(CkpvAccess(_trace));
00193 }
00194
00195
00196 StatTable::StatTable():
00197 stats_(NULL), numStats_(0)
00198 {
00199 DEBUGF(("%d/%d DEBUG: StatTable::StatTable %08x size %d\n",
00200 CmiMyPe(), CmiNumPes(), this));
00201
00202 DEBUGF(("%d/%d registering reductionID\n", CmiMyPe(), CmiNumPes()));
00203 CpvAccess(_reductionID) = CmiRegisterHandler((CmiHandler)StatTableReduction);
00204 }
00205
00206
00207 StatTable::~StatTable() { delete [] stats_; }
00208
00209
00210 void StatTable::init(int argc)
00211 {
00212 char** counterNames = CpvAccess(_counterNames);
00213 char** counterDesc = CpvAccess(_counterDesc);
00214
00215 if (argc > numStats_) {
00216 delete [] stats_;
00217 stats_ = new Statistics[argc]; _MEMCHECK(stats_);
00218 numStats_ = argc;
00219 }
00220 for (int i=0; i<argc; i++) {
00221 DEBUGF(("%d/%d DEBUG: %d name %s\n desc %s\n",
00222 CmiMyPe(), CmiNumPes(), i, name[i], desc[i]));
00223 stats_[i].name = counterNames[i];
00224 stats_[i].desc = counterDesc[i];
00225 }
00226 clear();
00227 }
00228
00230 void StatTable::setEp(int epidx, int stat, long long value, double time)
00231 {
00232
00233
00234
00235 CkAssert(epidx<MAX_ENTRIES);
00236 CkAssert(stat<numStats_ && stat>=0);
00237
00238 int numCalled = stats_[stat].numCalled[epidx];
00239 double avg = stats_[stat].avgCount[epidx];
00240 double stdDev = stats_[stat].stdDevCount[epidx];
00241 stats_[stat].numCalled[epidx]++;
00242 stats_[stat].avgCount[epidx] = (avg * numCalled + value) / (numCalled + 1);
00243
00244
00245 avg = stats_[stat].avgCount[epidx];
00246 stats_[stat].stdDevCount[epidx] =
00247 (stdDev * numCalled + (value-avg)*(value-avg)) / (numCalled+1);
00248
00249
00250 stats_[stat].totTime[epidx] += time;
00251 if (stats_[stat].maxCount[epidx] < value) {
00252 stats_[stat].maxCount[epidx] = value;
00253 }
00254 if (stats_[stat].minCount[epidx] > value) {
00255 stats_[stat].minCount[epidx] = value;
00256 }
00257 }
00258
00263 void StatTable::write(FILE* fp)
00264 {
00265 DEBUGF(("%d/%d DEBUG: Writing StatTable\n", CmiMyPe(), CmiNumPes()));
00266 int i, j;
00267 int _numEntries=_entryTable.size();
00268 for (i=0; i<numStats_; i++) {
00269
00270
00271 fprintf(fp, "[%s {%s}]\n", stats_[i].name, stats_[i].desc);
00272
00273 fprintf(fp, "[%s num_called] ", stats_[i].name);
00274 for (j=0; j<_numEntries+1; j++) {
00275 fprintf(fp, "%d ", stats_[i].numCalled[j]);
00276 }
00277 fprintf(fp, "\n");
00278
00279 fprintf(fp, "[%s avg_count] ", stats_[i].name);
00280 for (j=0; j<_numEntries+1; j++) {
00281 fprintf(fp, "%f ", stats_[i].avgCount[j]);
00282 }
00283 fprintf(fp, "\n");
00284
00285 fprintf(fp, "[%s std_dev_count] ", stats_[i].name);
00286 for (j=0; j<_numEntries+1; j++) {
00287 fprintf(fp, "%f ", sqrt(stats_[i].stdDevCount[j]));
00288 }
00289 fprintf(fp, "\n");
00290
00291 fprintf(fp, "[%s total_time(us)] ", stats_[i].name);
00292 for (j=0; j<_numEntries+1; j++) {
00293 fprintf(fp, "%f ", stats_[i].totTime[j]*1e6);
00294 }
00295 fprintf(fp, "\n");
00296
00297 fprintf(fp, "[%s max_count] ", stats_[i].name);
00298 for (j=0; j<_numEntries+1; j++) {
00299 fprintf(fp, "%ld ", stats_[i].maxCount[j]);
00300 }
00301 fprintf(fp, "\n");
00302
00303 fprintf(fp, "[%s min_count] ", stats_[i].name);
00304 for (j=0; j<_numEntries+1; j++) {
00305 if (stats_[i].minCount[j] == MAXLONGLONG) { stats_[i].minCount[j] = 0; }
00306 fprintf(fp, "%ld ", stats_[i].minCount[j]);
00307 }
00308 fprintf(fp, "\n");
00309 }
00310 DEBUGF(("%d/%d DEBUG: Finished writing StatTable\n", CmiMyPe(), CmiNumPes()));
00311 }
00312
00314 void StatTable::clear()
00315 {
00316 for (int i=0; i<numStats_; i++) {
00317 for (int j=0; j<MAX_ENTRIES; j++) {
00318 stats_[i].numCalled[j] = 0;
00319 stats_[i].avgCount[j] = 0.0;
00320 stats_[i].stdDevCount[j] = 0.0;
00321 stats_[i].totTime[j] = 0.0;
00322 stats_[i].maxCount[j] = 0.0;
00323 stats_[i].minCount[j] = MAXLONGLONG;
00324 }
00325 }
00326 }
00327
00331 void StatTable::doReduction(int phase, double idleTime) {
00332 DEBUGF(("%d/%d DEBUG: StatTable::doReduction()\n",
00333 CmiMyPe(), CmiNumPes(), this));
00334
00335 int msgSize =
00336 ALIGN8(CmiMsgHeaderSizeBytes)+
00337 sizeof(double)*(2*numStats_+NUM_EXTRA_PERF);
00338 char *msg = (char *)CmiAlloc(msgSize);
00339 double* reduction = (double*)(msg+ALIGN8(CmiMsgHeaderSizeBytes));
00340
00341 char** counterNames = CpvAccess(_counterNames);
00342 int GR_FLOPS = -1; double flopsRate = -1.0;
00343 int LOAD = -1; double loadRate = -1.0;
00344 int STORE = -1; double storeRate = -1.0;
00345 int L1_DMISS = -1; double l1Rate = -1.0;
00346 int L2_DMISS = -1; double l2Rate = -1.0;
00347 int TLB_MISS = -1; double tlbRate = -1.0;
00348 int i, j;
00349 for (i=0; i<2*numStats_+NUM_EXTRA_PERF; i++) { reduction[i] = 0.0; }
00350 for (i=0; i<numStats_; i++) {
00351 for (int j=0; j<MAX_ENTRIES; j++) {
00352 reduction[2*i] += stats_[i].numCalled[j]*stats_[i].avgCount[j];
00353 reduction[2*i+1] += stats_[i].totTime[j];
00354 }
00355 if (strcmp(counterNames[i], "GR_FLOPS")==0) { GR_FLOPS = i; }
00356 else if (strcmp(counterNames[i], "LOAD")==0) { LOAD = i; }
00357 else if (strcmp(counterNames[i], "STORE")==0) { STORE = i; }
00358 else if (strcmp(counterNames[i], "L1_DMISS")==0) { L1_DMISS = i; }
00359 else if (strcmp(counterNames[i], "L2_DMISS")==0) { L2_DMISS = i; }
00360 else if (strcmp(counterNames[i], "TLB_MISS")==0) { TLB_MISS = i; }
00361 }
00362 if (CmiMyPe()==0) { reduction[2*numStats_] = phase; }
00363 reduction[2*numStats_+1] = idleTime;
00364
00365 reduction[2*numStats_+2] = -1.0;
00366 reduction[2*numStats_+3] = -1.0;
00367 reduction[2*numStats_+4] = -1.0;
00368 reduction[2*numStats_+5] = -1.0;
00369
00370 double* rate = NULL;
00371 int index;
00372 for (i=0; i<6; i++) {
00373 switch (i) {
00374 case 0: rate = &flopsRate; index = GR_FLOPS; break;
00375 case 1: rate = &loadRate; index = LOAD; break;
00376 case 2: rate = &storeRate; index = STORE; break;
00377 case 3: rate = &l1Rate; index = L1_DMISS; break;
00378 case 4: rate = &l2Rate; index = L2_DMISS; break;
00379 case 5: rate = &tlbRate; index = TLB_MISS; break;
00380 }
00381 if (index >= 0 && reduction[2*index+1] > 0.0) {
00382
00383 *rate = reduction[2*index]/reduction[2*index+1];
00384 }
00385 }
00386
00387 if (GR_FLOPS >= 0) { reduction[2*numStats_+2] = flopsRate; }
00388 if (LOAD >= 0 && STORE >= 0) {
00389 double memRate = loadRate + storeRate;
00390 if (L1_DMISS >= 0 & memRate > 0) {
00391 reduction[2*numStats_+3] = l1Rate / memRate;
00392 }
00393 if (L2_DMISS >= 0 & memRate > 0) {
00394 reduction[2*numStats_+4] = l2Rate / memRate;
00395 }
00396 if (TLB_MISS >= 0 & memRate > 0) {
00397 reduction[2*numStats_+5] = tlbRate / memRate;
00398 }
00399 }
00400
00401
00402 CmiSetHandler(msg, (int)CpvAccess(_reductionID));
00403 int handlerID = CmiGetHandler(msg);
00404 DEBUGF(("%d/%d handlerID %d reductionID %d\n",
00405 CmiMyPe(), CmiNumPes(), handlerID, CpvAccess(_reductionID)));
00406 CmiSyncSendAndFree(0, msgSize, msg);
00407 }
00408
00409 CountLogPool::CountLogPool():
00410 stats_ (),
00411 lastPhase_ (-1)
00412 {
00413 DEBUGF(("%d/%d DEBUG: CountLogPool::CountLogPool() %08x\n",
00414 CmiMyPe(), CmiNumPes(), this));
00415 }
00416
00417
00418 FILE* CountLogPool::openFile(int phase) {
00419
00420
00421
00422 DEBUGF(("%d CountLogPool::openFile(%d)\n", CmiMyPe(), phase));
00423 const static int strSize = 10;
00424 char pestr[strSize+1];
00425 char phasestr[strSize+1];
00426 snprintf(pestr, strSize, "%d", CmiMyPe());
00427 pestr[strSize] = '\0';
00428 int len = strlen(CpvAccess(_logName)) + strlen("phase.count.") + 2*strSize + 1;
00429 char* fname = new char[len+1]; _MEMCHECK(fname);
00430 if (phase >= 0) {
00431 snprintf(phasestr, strSize, "%d", phase);
00432 phasestr[strSize] = '\0';
00433 sprintf(fname, "%s.phase%s.%s.count", CpvAccess(_logName), phasestr, pestr);
00434 }
00435 else { sprintf(fname, "%s.%s.count", CpvAccess(_logName), pestr); }
00436 FILE* fp = NULL;
00437 DEBUGF(("%d/%d DEBUG: TRACE: %s:%d\n", CmiMyPe(), CmiNumPes(), fname, errno));
00438 do {
00439 fp = fopen(fname, "w+");
00440 } while (!fp && errno == EINTR);
00441 delete[] fname;
00442 if(!fp) {
00443 CmiAbort("Cannot open Summary Trace File for writing...\n");
00444 }
00445 return fp;
00446 }
00447
00448 void CountLogPool::write(int phase)
00449 {
00450 if (phase >= 0) { lastPhase_ = phase; }
00451 if (phase < 0 && lastPhase_ >= 0) { lastPhase_++; phase = lastPhase_; }
00452
00453 int _numEntries=_entryTable.size();
00454 FILE* fp = (phase==-1) ? openFile() : openFile(phase);
00455 fprintf(fp, "ver:%3.1f %d/%d ep:%d counters:%d\n",
00456 CpvAccess(version), CmiMyPe(), CmiNumPes(), _numEntries+1,
00457 stats_.numStats());
00458 stats_.write(fp);
00459 fclose(fp);
00460 }
00461
00462 void CountLogPool::writeSts(int phase)
00463 {
00464
00465
00466
00467 if (phase >= 0) { lastPhase_ = phase; }
00468 DEBUGF(("%d CountLogPool::writeSts(%d)\n", CmiMyPe(), phase));
00469
00470 const static int strSize = 10;
00471 char phasestr[strSize+1];
00472 int _numEntries=_entryTable.size();
00473
00474 char *fname =
00475 new char[strlen(CpvAccess(_logName))+strlen(".count.sts")+strSize];
00476 _MEMCHECK(fname);
00477 if (phase < 0 && lastPhase_ >= 0) { phase = lastPhase_; }
00478 if (phase >= 0) {
00479 snprintf(phasestr, strSize, "%d", phase);
00480 phasestr[strSize] = '\0';
00481 sprintf(fname, "%s.phase%s.count.sts", CpvAccess(_logName), phasestr);
00482 }
00483 else { sprintf(fname, "%s.count.sts", CpvAccess(_logName)); }
00484 FILE *sts = fopen(fname, "w+");
00485
00486 if(sts==0)
00487 CmiAbort("Cannot open summary sts file for writing.\n");
00488 CmiPrintf("WRITING FILE=%s\n", fname);
00489 delete[] fname;
00490 fprintf(sts, "MACHINE %s\n",CMK_MACHINE_NAME);
00491 fprintf(sts, "PROCESSORS %d\n", CmiNumPes());
00492 fprintf(sts, "TOTAL_CHARES %d\n", _chareTable.size());
00493 fprintf(sts, "TOTAL_EPS %d\n", _numEntries+1);
00494 fprintf(sts, "TOTAL_MSGS %d\n", _msgTable.size());
00495 fprintf(sts, "TOTAL_PSEUDOS %d\n", 0);
00496 fprintf(sts, "TOTAL_EVENTS %d\n", _numEvents);
00497 int i;
00498 for(i=0;i<_chareTable.size();i++)
00499 fprintf(sts, "CHARE %d %s\n", i, _chareTable[i]->name);
00500 for(i=0;i<_numEntries;i++)
00501 fprintf(sts, "ENTRY CHARE %d %s %d %d\n", i, _entryTable[i]->name,
00502 _entryTable[i]->chareIdx, _entryTable[i]->msgIdx);
00503
00504 fprintf(sts, "ENTRY CHARE %d OVERVIEW -1 -1\n", _numEntries);
00505 for(i=0;i<_msgTable.size();i++)
00506 fprintf(sts, "MESSAGE %d %ld\n", i, _msgTable[i]->size);
00507 for(i=0;i<_numEvents;i++)
00508 fprintf(sts, "EVENT %d Event%d\n", i, i);
00509 fprintf(sts, "END\n");
00510 fclose(sts);
00511 }
00512
00513 void CountLogPool::setEp(int epidx,
00514 int index1, long long count1,
00515 int index2, long long count2,
00516 double time)
00517 {
00518
00519
00520
00521 if (epidx >= MAX_ENTRIES) {
00522 CmiAbort("CountLogPool::setEp too many entry points!\n");
00523 }
00524 stats_.setEp(epidx, index1, count1, time);
00525 stats_.setEp(epidx, index2, count2, time);
00526 }
00527
00529 TraceCounter::TraceCounter() :
00530
00531 firstArg_ (NULL),
00532 lastArg_ (NULL),
00533 argStrSize_ (0),
00534 commandLine_ (NULL),
00535 commandLineSz_ (0),
00536 counter1_ (NULL),
00537 counter2_ (NULL),
00538 counter1Sz_ (0),
00539 counter2Sz_ (0),
00540
00541 overview_ (false),
00542 switchRandom_ (false),
00543 switchByPhase_ (false),
00544 noLog_ (false),
00545 writeByPhase_ (false),
00546
00547 execEP_ (-1),
00548 startEP_ (0.0),
00549 genStart_ (-1),
00550
00551 idleTime_ (0.0),
00552 phase_ (-1),
00553 reductionPhase_(-1),
00554 traceOn_ (false),
00555 status_ (IDLE),
00556 dirty_ (false)
00557 {
00558 for (int i=0; i<NUM_COUNTER_ARGS; i++) { registerArg(&COUNTER_ARG[i]); }
00559 }
00560
00562 TraceCounter::~TraceCounter() {
00563 delete [] commandLine_;
00564 traceClose();
00565 }
00566
00568 void TraceCounter::traceInit(char **argv)
00569 {
00570 CpvInitialize(CountLogPool*, _logPool);
00571 CpvInitialize(char*, _logName);
00572 CpvInitialize(double, version);
00573 CpvInitialize(char**, _counterNames);
00574 CpvInitialize(char**, _counterDesc);
00575 CpvInitialize(int, _numCounters);
00576 CpvInitialize(int, _reductionID);
00577
00578 CpvAccess(_logName) = (char *) malloc(strlen(argv[0])+1);
00579 _MEMCHECK(CpvAccess(_logName));
00580 strcpy(CpvAccess(_logName), argv[0]);
00581 CpvAccess(version) = VER;
00582
00583 int i;
00584
00585 char* counters = NULL;
00586 commandLine_ = NULL;
00587 bool badArg = false;
00588 int numCounters = 0;
00589 if (CmiGetArgStringDesc(argv, "+counters", &counters, "Measure these performance counters")) {
00590 if (CmiMyPe()==0) { CmiPrintf("Counters: %s\n", counters); }
00591 int offset = 0;
00592 int limit = strlen(counters);
00593 char* ptr = counters;
00594 while (offset < limit &&
00595 (ptr = strtok(&counters[offset], ",")) != NULL)
00596 {
00597 offset += strlen(ptr)+1;
00598 ptr = &ptr[strlen(ptr)+1];
00599 numCounters++;
00600 }
00601 if (CmiMyPe()==0) {
00602 CmiPrintf("There are %d counters\n", numCounters);
00603 }
00604 commandLine_ = new CounterArg[numCounters];
00605 ptr = counters;
00606 for (i=0; i<numCounters; i++) {
00607 commandLine_[i].arg = ptr;
00608 if (!matchArg(&commandLine_[i])) {
00609 if (CmiMyPe()==0) { CmiPrintf("Bad arg: [%s]\n", ptr); }
00610 badArg = true;
00611 }
00612 ptr = &ptr[strlen(ptr)+1];
00613 }
00614 }
00615 commandLineSz_ = numCounters;
00616
00617
00618 if (badArg || CmiGetArgFlagDesc(argv, "+count-help", "List available performance counters")) {
00619 if (CmiMyPe() == 0) { printHelp(); }
00620 ConverseExit(); return;
00621 }
00622 else if (counters == NULL) {
00623 if (CmiMyPe() == 0) { usage(); }
00624 ConverseExit(); return;
00625 }
00626
00627
00628 overview_ = CmiGetArgFlag(argv, "+count-overview");
00629 switchRandom_ = CmiGetArgFlag(argv, "+count-switchrandom");
00630 switchByPhase_ = CmiGetArgFlag(argv, "+count-switchbyphase");
00631 noLog_ = CmiGetArgFlag(argv, "+count-nolog");
00632 writeByPhase_ = CmiGetArgFlag(argv, "+count-writebyphase");
00633 char* logName = NULL;
00634 if (CmiGetArgString(argv, "+count-logname", &logName)) {
00635 CpvAccess(_logName) = logName;
00636 if (noLog_) {
00637 if (CkMyPe()==0) {
00638 CmiPrintf("+count-logname and +count-nolog are MUTUALLY EXCLUSIVE\n");
00639 usage();
00640 CmiAbort("");
00641 }
00642 }
00643 }
00644 if (switchByPhase_ && overview_) {
00645 if (CkMyPe()==0) {
00646 CmiPrintf(
00647 "+count-switchbyphase and +count-overview are MUTUALLY EXCLUSIVE\n"
00648 "+count-overview automatically switches by phase.\n");
00649 usage();
00650 CmiAbort("");
00651 }
00652 }
00653 if (writeByPhase_ && noLog_) {
00654 if (CkMyPe()==0) {
00655 CmiPrintf("+count-writebyphase and +count-nolog are MUTUALLY EXCLUSIVE\n");
00656 usage();
00657 CmiAbort("");
00658 }
00659 }
00660
00661
00662 CounterArg* last1 = NULL;
00663 CounterArg* last2 = NULL;
00664 CounterArg* tmp = NULL;
00665 counter1Sz_ = counter2Sz_ = 0;
00666 for (i=0; i<commandLineSz_; i++) {
00667 tmp = &commandLine_[i];
00668 if (tmp->code < NUM_COUNTER_ARGS/2) {
00669 if (counter1_ == NULL) { counter1_ = tmp; last1 = counter1_; }
00670 else { last1->next = tmp; last1 = tmp; }
00671 counter1Sz_++;
00672 }
00673 else {
00674 if (counter2_ == NULL) { counter2_ = tmp; last2 = counter2_; }
00675 else { last2->next = tmp; last2 = tmp; }
00676 counter2Sz_++;
00677 }
00678 }
00679 if (counter1_ == NULL) {
00680 printHelp();
00681 if (CmiMyPe()==0) {
00682 CmiPrintf("\nMust specify some counters with code < %d\n",
00683 NUM_COUNTER_ARGS/2);
00684 }
00685 ConverseExit();
00686 }
00687 if (counter2_ == NULL) {
00688 printHelp();
00689 if (CmiMyPe()==0) {
00690 CmiPrintf("\nMust specify some counters with code >= %d\n",
00691 NUM_COUNTER_ARGS/2);
00692 }
00693 ConverseExit();
00694 }
00695 last1->next = counter1_;
00696 last2->next = counter2_;
00697
00698
00699 if (CmiMyPe() == 0) {
00700 CmiPrintf("Running with tracemode=counter and args:\n");
00701
00702 tmp = counter1_;
00703 i = 0;
00704 do {
00705 CmiPrintf(" <counter1-%d>=%d %s %s\n", i, tmp->code, tmp->arg, tmp->desc);
00706 tmp = tmp->next;
00707 i++;
00708 } while (tmp != counter1_);
00709
00710 tmp = counter2_;
00711 i = 0;
00712 do {
00713 CmiPrintf(" <counter2-%d>=%d %s %s\n", i, tmp->code, tmp->arg, tmp->desc);
00714 tmp = tmp->next;
00715 i++;
00716 } while (tmp != counter2_);
00717
00718 CmiPrintf(
00719 "+count-overview %d\n+count-switchrandom %d\n"
00720 "+count-switchbyphase %d\n+count-nolog %d\n"
00721 "+count-logname %s\n+count-writebyphase %d\n",
00722 overview_, switchRandom_, switchByPhase_, noLog_,
00723 logName, writeByPhase_);
00724 }
00725
00726
00727 CpvAccess(_logPool) = new CountLogPool();
00728
00729
00730 char** counterNames = new char*[counter1Sz_+counter2Sz_];
00731 char** counterDesc = new char*[counter1Sz_+counter2Sz_];
00732 tmp = counter1_;
00733 for (i=0; i<counter1Sz_; i++) {
00734 tmp->index = i;
00735 counterNames[i] = tmp->arg;
00736 counterDesc[i] = tmp->desc;
00737 tmp = tmp->next;
00738 }
00739 tmp = counter2_;
00740 for (i=0; i<counter2Sz_; i++) {
00741 tmp->index = counter1Sz_+i;
00742 counterNames[counter1Sz_+i] = tmp->arg;
00743 counterDesc[counter1Sz_+i] = tmp->desc;
00744 tmp = tmp->next;
00745 }
00746 CpvAccess(_counterNames) = counterNames;
00747 CpvAccess(_counterDesc) = counterDesc;
00748 CpvAccess(_numCounters) = numCounters;
00749
00750
00751
00752 _MEMCHECK(CpvAccess(_logPool));
00753 CpvAccess(_logPool)->init(numCounters);
00754 DEBUGF(("%d/%d DEBUG: Created _logPool at %08x\n",
00755 CmiMyPe(), CmiNumPes(), CpvAccess(_logPool)));
00756 }
00757
00761 void TraceCounter::traceBegin() {
00762 DEBUGF(("%d/%d traceBegin called\n", CmiMyPe(), CmiNumPes()));
00763 if (traceOn_) {
00764 static bool print = true;
00765 if (print) {
00766 print = false;
00767 if (CmiMyPe()==0) {
00768 CmiPrintf("%d/%d WARN: traceBegin called but trace already on!\n"
00769 " Sure you didn't mean to use +traceoff?\n",
00770 CmiMyPe(), CmiNumPes());
00771 }
00772 }
00773 }
00774 else {
00775 if (overview_) { beginOverview(); }
00776 idleTime_ = 0.0;
00777 if (writeByPhase_) { phase_++; }
00778 traceOn_ = true;
00779 }
00780 }
00781
00785 void TraceCounter::traceEnd() {
00786 DEBUGF(("%d/%d traceEnd called\n", CmiMyPe(), CmiNumPes()));
00787 if (!traceOn_) {
00788 static bool print = true;
00789 if (print) {
00790 print = false;
00791 if (CmiMyPe()==0) {
00792 CmiPrintf("%d/%d WARN: traceEnd called but trace not on!\n"
00793 " Sure you didn't mean to use +traceoff?\n",
00794 CmiMyPe(), CmiNumPes());
00795 }
00796 }
00797 }
00798 else {
00799 traceOn_ = false;
00800 dirty_ = false;
00801 if (overview_) { endOverview(); }
00802 else if (switchByPhase_) { switchCounters(); };
00803
00804 if (!noLog_ && writeByPhase_) {
00805 if (CmiMyPe()==0) { CpvAccess(_logPool)->writeSts(phase_); }
00806 CpvAccess(_logPool)->write(phase_);
00807 }
00808 reductionPhase_++;
00809 CpvAccess(_logPool)->doReduction(reductionPhase_, idleTime_);
00810 if (writeByPhase_) {
00811 idleTime_ = 0.0;
00812 CpvAccess(_logPool)->clearEps();
00813 }
00814
00815 DEBUGF(("%d/%d DEBUG: Created _logPool at %08x\n",
00816 CmiMyPe(), CmiNumPes(), CpvAccess(_logPool)));
00817 }
00818 }
00819
00823 void TraceCounter::beginExecute(envelope *e)
00824 {
00825
00826 if (e==NULL) { beginExecute(-1,-1,_threadEP,-1); }
00827 else { beginExecute(-1,-1,e->getEpIdx(),-1); }
00828 }
00829
00833 void TraceCounter::beginExecute
00834 (
00835 int event,
00836 int msgType,
00837 int ep,
00838 int srcPe,
00839 int mlen,
00840 CmiObjId *idx
00841 )
00842 {
00843 DEBUGF(("%d/%d DEBUG: beginExecute EP %d\n", CmiMyPe(), CmiNumPes(), ep));
00844
00845 if (!traceOn_ || overview_) { return; }
00846
00847 execEP_=ep;
00848
00849 if (status_!= IDLE) {
00850 static bool print = true;
00851 if (print) {
00852 print = false;
00853 if (CmiMyPe()==0) {
00854 CmiPrintf("WARN: %d beginExecute called when status not IDLE!\n",
00855 CmiMyPe());
00856 }
00857 }
00858 return;
00859 }
00860 else { status_=WORKING; }
00861
00862 if ((genStart_=start_counters(counter1_->code, counter2_->code))<0)
00863 {
00864 CmiPrintf("genStart=%d counter1=%d counter2=%d\n",
00865 genStart_, counter1_->code, counter2_->code);
00866 CmiAbort("ERROR: start_counters() in beginExecute\n");
00867 }
00868
00869 startEP_=TraceTimer();
00870 DEBUGF(("%d/%d DEBUG: beginExecute EP %d genStart %d\n",
00871 CmiMyPe(), CmiNumPes(), ep, genStart_));
00872 }
00873
00877 void TraceCounter::endExecute()
00878 {
00879 DEBUGF(("%d/%d DEBUG: endExecute EP %d genStart_ %d\n",
00880 CmiMyPe(), CmiNumPes(), execEP_, genStart_));
00881
00882 if (!traceOn_ || overview_) { return; }
00883
00884 if (status_!=WORKING) {
00885 static bool print = true;
00886 if (print) {
00887 print = false;
00888 if (CmiMyPe()==0) {
00889 CmiPrintf("WARN: %d endExecute called when status not WORKING!\n",
00890 CmiMyPe());
00891 }
00892 }
00893 return;
00894 }
00895 else { status_=IDLE; }
00896
00897 double t = TraceTimer();
00898
00899 long long value1 = 0, value2 = 0;
00900 int genRead;
00901 if ((genRead=read_counters(counter1_->code, &value1, counter2_->code, &value2)) < 0 ||
00902 genRead != genStart_)
00903 {
00904 CmiPrintf("genRead %d genStart_ %d counter1 %ld counter2 %ld\n",
00905 genRead, genStart_, value1, value2);
00906 traceClose();
00907 CmiAbort("ERROR: read_counters() in endExecute\n");
00908 }
00909
00910 DEBUGF((
00911 "%d/%d DEBUG: endExecute genRead %d Time %f counter1 %d counter2 %ld\n",
00912 CmiMyPe(), CmiNumPes(), genRead, t-startEP_, value1, value2));
00913 if (execEP_ != -1) {
00914 dirty_ = true;
00915 CpvAccess(_logPool)->setEp(execEP_, counter1_->index, value1,
00916 counter2_->index, value2, t-startEP_);
00917 if (!switchByPhase_) { switchCounters(); }
00918 }
00919 }
00920
00922 void TraceCounter::beginIdle(double curWallTime) {
00923 if (traceOn_) { startIdle_ = TraceTimer(curWallTime); }
00924 }
00925
00927 void TraceCounter::endIdle(double curWallTime) {
00928 if (traceOn_) { idleTime_ += TraceTimer(curWallTime)-startIdle_; }
00929 }
00930
00932 void TraceCounter::beginPack()
00933 {
00934 DEBUGF(("%d/%d DEBUG: beginPack\n", CmiMyPe(), CmiNumPes()));
00935
00936
00937
00938
00939
00940 }
00941
00943 void TraceCounter::endPack() {
00944 DEBUGF(("%d/%d DEBUG: endPack\n", CmiMyPe(), CmiNumPes()));
00945
00946
00947
00948
00949
00950 }
00951
00954 void TraceCounter::beginUnpack() {
00955 DEBUGF(("%d/%d DEBUG: beginUnpack\n", CmiMyPe(), CmiNumPes()));
00956
00957
00958
00959
00960
00961 }
00962
00965 void TraceCounter::endUnpack() {
00966 DEBUGF(("%d/%d DEBUG: endUnpack\n", CmiMyPe(), CmiNumPes()));
00967
00968
00969
00970
00971
00972 }
00973
00975 void TraceCounter::beginComputation()
00976 {
00977 }
00978
00981 void TraceCounter::endComputation() {
00982 CpvAccess(_logPool)->doReduction(-1, idleTime_);
00983 }
00984
00986 void TraceCounter::traceClearEps() {
00987 CpvAccess(_logPool)->clearEps();
00988 }
00989
00991 void TraceCounter::traceWriteSts() {
00992 if (traceOn_ && !noLog_) {
00993 if (CmiMyPe()==0) { CpvAccess(_logPool)->writeSts(); }
00994 }
00995 }
00996
00998 void TraceCounter::traceClose()
00999 {
01000 if (dirty_) {
01001 if (overview_) { endOverview(); }
01002 else {
01003 if (!noLog_) {
01004 CpvAccess(_logPool)->write();
01005 if(CmiMyPe()==0) {
01006 CpvAccess(_logPool)->writeSts();
01007 CmiPrintf("TraceCounter dirty, writing results\n");
01008 }
01009 }
01010 }
01011 dirty_ = false;
01012 }
01013 if (CpvAccess(_logPool)!=NULL) {
01014 CkpvAccess(_trace)->endComputation();
01015 delete CpvAccess(_logPool);
01016 CpvAccess(_logPool) = NULL;
01017 }
01018 }
01019
01022 void TraceCounter::beginOverview()
01023 {
01024 DEBUGF(("%d/%d DEBUG: beginOverview\n",
01025 CmiMyPe(), CmiNumPes()));
01026 if ((genStart_=start_counters(counter1_->code, counter2_->code))<0)
01027 {
01028 CmiPrintf("genStart=%d counter1=%d counter2=%d\n",
01029 genStart_, counter1_->code, counter2_->code);
01030 CmiAbort("ERROR: start_counters() in beginOverview\n");
01031 }
01032 startEP_=TraceTimer();
01033 DEBUGF(("%d/%d DEBUG: beginOverview\n", CmiMyPe(), CmiNumPes()));
01034 dirty_ = true;
01035 }
01036
01037 void TraceCounter::endOverview()
01038 {
01039 DEBUGF(("%d/%d DEBUG: endOverview\n", CmiMyPe(), CmiNumPes()));
01040
01041 double t = TraceTimer();
01042 int _numEntries=_entryTable.size();
01043
01044 long long value1 = 0, value2 = 0;
01045 int genRead;
01046 if ((genRead=read_counters(counter1_->code, &value1, counter2_->code, &value2)) < 0 ||
01047 genRead != genStart_)
01048 {
01049 CmiPrintf("genRead %d genStart_ %d counter1 %ld counter2 %ld\n",
01050 genRead, genStart_, value1, value2);
01051 traceClose();
01052 CmiAbort("ERROR: read_counters() in endOverview\n");
01053 }
01054
01055 DEBUGF((
01056 "%d/%d DEBUG: endOverview genRead %d Time %f counter1 %ld counter2 %ld\n",
01057 CmiMyPe(), CmiNumPes(), genRead, t-startEP_, value1, value2));
01058 dirty_ = false;
01059
01060 CpvAccess(_logPool)->setEp(_numEntries,
01061 counter1_->index, value1,
01062 counter2_->index, value2,
01063 t-startEP_);
01064 DEBUGF((
01065 "%d/%d OVERVIEW phase%d Time(us) %f %s %ld %s %ld Idle(us) %f"
01066 " (overflow? MAX=%ld)\n",
01067 CmiMyPe(), CmiNumPes(), phase_, (t-startEP_)*1e6, counter1_->arg, value1,
01068 counter2_->arg, value2, idleTime_*1e6, MAXLONGLONG));
01069
01070 switchCounters();
01071 }
01072
01074 void TraceCounter::switchCounters()
01075 {
01076 static bool first = true;
01077 if (switchRandom_) {
01078 int i;
01079 if (first) { first = false; srand(TraceTimer()*1e6); }
01080 int counter1Change =
01081 (int) (rand() / (double) 0x7FFF * counter1Sz_ + 0.5);
01082 int counter2Change =
01083 (int) (rand() / (double) 0x7FFF * counter2Sz_ + 0.5);
01084 if (CmiMyPe()==0) {
01085 DEBUGF(("change %d/%d %d/%d\n",
01086 counter1Change, counter1Sz_,
01087 counter2Change, counter2Sz_));
01088 }
01089 if (counter1Change > counter1Sz_) { counter1Change = counter1Sz_; }
01090 if (counter2Change > counter2Sz_) { counter2Change = counter2Sz_; }
01091 for (i=0; i<counter1Change; i++) { counter1_ = counter1_->next; }
01092 for (i=0; i<counter2Change; i++) { counter2_ = counter2_->next; }
01093 }
01094 else {
01095 counter1_ = counter1_->next;
01096 counter2_ = counter2_->next;
01097 }
01098 if (CmiMyPe()==0) {
01099 DEBUGF(("%d/%d New counters are %s %s\n",
01100 CmiMyPe(), CmiNumPes(), counter1_->arg, counter2_->arg));
01101 }
01102 }
01103
01105 void TraceCounter::registerArg(CounterArg* arg)
01106 {
01107 if (firstArg_ == NULL) {
01108 firstArg_ = lastArg_ = arg;
01109 argStrSize_ = strlen(arg->arg);
01110 }
01111 else {
01112
01113 CounterArg* check = firstArg_;
01114 while (check != NULL) {
01115 if (strcmp(check->arg, arg->arg)==0 || check->code == arg->code) {
01116 if (CmiMyPe()==0) {
01117 CmiPrintf("Two args with same name %s or code %d\n",
01118 arg->arg, arg->code);
01119 }
01120 CmiAbort("TraceCounter::registerArg()\n");
01121 }
01122 check = check->next;
01123 }
01124
01125 lastArg_->next = arg;
01126 lastArg_ = arg;
01127 int len = strlen(arg->arg);
01128 if (len > argStrSize_) { argStrSize_ = len; }
01129 }
01130 }
01131
01135 bool TraceCounter::matchArg(CounterArg* arg)
01136 {
01137 bool match = false;
01138 CounterArg* matchArg = firstArg_;
01139 int matchCode = atoi(arg->arg);
01140 if (matchCode == 0) {
01141 if (arg->arg[0] != '0' || arg->arg[1] != '\0') { matchCode = -1; }
01142 }
01143
01144 while (matchArg != NULL && !match) {
01145
01146 if (strcmp(matchArg->arg, arg->arg)==0) {
01147 match = true;
01148 arg->code = matchArg->code;
01149 arg->desc = matchArg->desc;
01150 }
01151 else if (matchArg->code == matchCode) {
01152 match = true;
01153 arg->code = matchArg->code;
01154 arg->arg = matchArg->arg;
01155 arg->desc = matchArg->desc;
01156 }
01157 matchArg = matchArg->next;
01158 }
01159
01160 return match;
01161 }
01162
01164 void TraceCounter::usage() {
01165 CmiPrintf(
01166 "ERROR: You've linked with '-tracemode counter', so you must specify\n"
01167 " the +counters <counters> option followed by any of the \n"
01168 " following optional command line options.\n"
01169 "\n"
01170 "REQUIRED: +counters <counter>\n"
01171 "\n"
01172 " +counters <counters>: Where <counters> is comma delimited list\n"
01173 " of valid counters. Type '+count-help' to\n"
01174 " get a list of valid counters.\n"
01175 "\n"
01176 "OPTIONAL: [+count-overview] [+count-switchrandom] [+switchbyphase]\n"
01177 "\n"
01178 " +count-overview: Collect counter values between start/stop\n"
01179 " of the program (or traceBegin/traceEnd if\n"
01180 " user marked events are on [see Performance\n"
01181 " Counter section of the Charm++ manual]).\n"
01182 " Normal operation collects counter values\n"
01183 " between the stop/start of Charm++ entry\n"
01184 " points.\n"
01185 " +count-switchrandom: Counters will switch randomly between\n"
01186 " each event instead of in the order\n"
01187 " specified by the <counters> arg.\n"
01188 " +count-switchbyphase: Counters will switch not every EP call,\n"
01189 " but only in between phases (between each\n"
01190 " traceBegin/traceEnd call).\n"
01191 " +count-nolog: Don't write any log files.\n"
01192 "\n"
01193 "See the Performance Counter section of the Charm++ manual for\n"
01194 "examples of different options.\n"
01195 "\n");
01196 }
01197
01199 void TraceCounter::printHelp()
01200 {
01201 CmiPrintf(
01202 "Specify one of the following (code or str) after +counters:\n\n"
01203 " code str\n"
01204 " ---- ---\n");
01205
01206
01207 char format[64];
01208 snprintf(format, 64, " %%2d %%-%ds %%s\n", argStrSize_);
01209
01210 CounterArg* help = firstArg_;
01211 while (help != NULL) {
01212 CmiPrintf(format, help->code, help->arg, help->desc);
01213 help = help->next;
01214 }
01215 }
01216
01217 #else
01218 void _createTracecounter(char **argv)
01219 {
01220 }
01221 #endif // CMK_ORIGIN2000
01222