// // Received a Set or a VCRMode requiring us to adjust our state // and possibly rethink everything. This can result from a time // control position change, delta change, direction change, etc. // void GroupControl::adjustWorldView(QmcTime::Packet *packet, bool vcrMode) { my.delta = packet->delta; my.position = packet->position; my.realDelta = __pmtimevalToReal(&packet->delta); my.realPosition = __pmtimevalToReal(&packet->position); console->post("GroupControl::adjustWorldView: " "sh=%d vh=%d delta=%.2f position=%.2f (%s) state=%s", my.samples, my.visible, my.realDelta, my.realPosition, timeString(my.realPosition), timeState()); QmcTime::State state = packet->state; if (isArchiveSource()) { if (packet->state == QmcTime::ForwardState) adjustArchiveWorldViewForward(packet, vcrMode); else if (packet->state == QmcTime::BackwardState) adjustArchiveWorldViewBackward(packet, vcrMode); else adjustArchiveWorldViewStopped(packet, vcrMode); } else if (state != QmcTime::StoppedState) adjustLiveWorldViewForward(packet); else adjustLiveWorldViewStopped(packet); }
/* Print performance metric rates */ static void printrates(Context *x, pmValueSet *vset1, struct timeval stamp1, /* current values */ pmValueSet *vset2, struct timeval stamp2, /* previous values */ int cols) { int i, j; double delta; /* compute delta from timestamps and convert units */ delta = x->scale * (__pmtimevalToReal(&stamp1) - __pmtimevalToReal(&stamp2)); /* null instance domain */ if (x->desc.indom == PM_INDOM_NULL) { if ((vset1->numval == 1) && (vset2->numval == 1)) printrate(vset1->valfmt, x->desc.type, &vset1->vlist[0], &vset2->vlist[0], delta, cols); else printf("%*s", cols, "?"); putchar('\n'); } /* non-null instance domain */ else { for (i = 0; i < x->inum; i++) { for (j = 0; j < vset1->numval; j++) { if (vset1->vlist[j].inst == x->ipairs[i].id) break; } if ((j < vset1->numval) && (j < vset2->numval) && (vset1->vlist[j].inst == vset2->vlist[j].inst)) printrate(vset1->valfmt, x->desc.type, &vset1->vlist[j], &vset2->vlist[j], delta, cols); else printf("%*s", cols, "?"); putchar(' '); } putchar('\n'); for (j = 0; j < vset1->numval; j++) { for (i = 0; i < x->inum; i++) { if (vset1->vlist[j].inst == x->ipairs[i].id) break; } if (x->iall == 1 && i == x->inum && j < vset2->numval && vset1->vlist[j].inst == vset2->vlist[j].inst) { printf("Warning: value="); printrate(vset1->valfmt, x->desc.type, &vset1->vlist[j], &vset2->vlist[j], delta, 1); printf(", but instance=%d is unknown\n", vset1->vlist[j].inst); } } } }
/* Print parameter values as output header. */ static void printhdr(Context *x) { pmUnits units; char tbfr[26]; const char *u; printf("metric: %s\n", x->metric); if (opts.context != PM_CONTEXT_ARCHIVE) printf("host: %s\n", x->hostname); else { printf("archive: %s\n", source); printf("host: %s\n", x->hostname); printf("start: %s", pmCtime(&opts.origin.tv_sec, tbfr)); if (opts.finish.tv_sec != INT_MAX) printf("end: %s", pmCtime(&opts.finish.tv_sec, tbfr)); } printf("semantics: "); switch (x->desc.sem) { case PM_SEM_COUNTER: printf("cumulative counter"); if (! rawCounter) printf(" (converting to rate)"); break; case PM_SEM_INSTANT: printf("instantaneous value"); break; case PM_SEM_DISCRETE: printf("discrete instantaneous value"); break; default: printf("unknown"); } putchar('\n'); units = x->desc.units; u = pmUnitsStr(&units); printf("units: %s", *u == '\0' ? "none" : u); if ((! rawCounter) && (x->desc.sem == PM_SEM_COUNTER)) { printf(" (converting to "); if (units.dimTime == 0) units.scaleTime = PM_TIME_SEC; units.dimTime--; if ((units.dimSpace == 0) && (units.dimTime == 0) && (units.dimCount == 0)) printf("time utilization)"); else { u = pmUnitsStr(&units); printf("%s)", *u == '\0' ? "none" : u); } } putchar('\n'); /* sample count and interval */ if (opts.samples < 0) printf("samples: all\n"); else printf("samples: %d\n", opts.samples); if ((opts.samples > 1) && (opts.context != PM_CONTEXT_ARCHIVE || amode == PM_MODE_INTERP)) printf("interval: %1.2f sec\n", __pmtimevalToReal(&opts.interval)); }
/* return real time */ RealTime getReal(void) { struct timeval t; __pmtimevalNow(&t); return __pmtimevalToReal(&t); }
void QmcGroup::updateBounds() { double newStart = DBL_MAX; double newEnd = 0.0; double startReal; double endReal; struct timeval startTv; struct timeval endTv; my.timeStart.tv_sec = 0; my.timeStart.tv_usec = 0; my.timeEnd = my.timeStart; for (unsigned int i = 0; i < numContexts(); i++) { if (my.contexts[i]->handle() >= 0 && my.contexts[i]->source().type() == PM_CONTEXT_ARCHIVE) { startTv = my.contexts[i]->source().start(); endTv = my.contexts[i]->source().end(); startReal = __pmtimevalToReal(&startTv); endReal = __pmtimevalToReal(&endTv); if (startReal < newStart) newStart = startReal; if (endReal > newEnd) newEnd = endReal; } } __pmtimevalFromReal(newStart, &my.timeStart); __pmtimevalFromReal(newEnd, &my.timeEnd); my.timeEndReal = newEnd; if (pmDebug & DBG_TRACE_PMC) { QTextStream cerr(stderr); cerr << "QmcGroup::updateBounds: start = " << my.timeStart.tv_sec << '.' << my.timeStart.tv_usec << ", end = " << my.timeEnd.tv_sec << '.' << my.timeEnd.tv_usec << endl; } }
void GroupControl::init(int samples, int visible, struct timeval *interval, struct timeval *position) { my.samples = samples; my.visible = visible; if (isArchiveSource()) { my.pmtimeState = QmcTime::StoppedState; my.buttonState = QedTimeButton::StoppedArchive; } else { my.pmtimeState = QmcTime::ForwardState; my.buttonState = QedTimeButton::ForwardLive; } my.delta = *interval; my.position = *position; my.realDelta = __pmtimevalToReal(interval); my.realPosition = __pmtimevalToReal(position); my.timeData = (double *)malloc(samples * sizeof(double)); for (int i = 0; i < samples; i++) my.timeData[i] = my.realPosition - (i * my.realDelta); }
// // Fetch all metric values across all gadgets, and also update the // unified time axis. // void GroupControl::step(QmcTime::Packet *packet) { double stepPosition = __pmtimevalToReal(&packet->position); console->post(PmChart::DebugProtocol, "GroupControl::step: stepping to time %.2f, delta=%.2f, state=%s", stepPosition, my.realDelta, timeState()); if ((packet->source == QmcTime::ArchiveSource && ((packet->state == QmcTime::ForwardState && my.timeState != ForwardState) || (packet->state == QmcTime::BackwardState && my.timeState != BackwardState))) || sideStep(stepPosition, my.realPosition, my.realDelta)) return adjustWorldView(packet, false); my.pmtimeState = packet->state; my.position = packet->position; my.realPosition = stepPosition; int last = my.samples - 1; if (packet->state == QmcTime::ForwardState) { // left-to-right (all but 1st) if (my.samples > 1) memmove(&my.timeData[1], &my.timeData[0], sizeof(double) * last); my.timeData[0] = my.realPosition; } else if (packet->state == QmcTime::BackwardState) { // right-to-left if (my.samples > 1) memmove(&my.timeData[0], &my.timeData[1], sizeof(double) * last); my.timeData[last] = my.realPosition - torange(my.delta, last); } fetch(); bool active = isActive(packet); if (isActive(packet)) newButtonState(packet->state, packet->mode, pmchart->isTabRecording()); refreshGadgets(active); }
/* Fetch metric values. */ static int getvals(Context *x, /* in - full pm description */ pmResult **vs) /* alloc - pm values */ { pmResult *r; int e; int i; if (rawArchive) { /* * for -U mode, read until we find either a pmResult with the * pmid we are after, or a mark record */ for ( ; ; ) { e = pmFetchArchive(&r); if (e < 0) break; if (r->numpmid == 0) { if (opts.guiflag || opts.context == PM_CONTEXT_ARCHIVE) __pmPrintStamp(stdout, &r->timestamp); printf(" Archive logging suspended\n"); pmFreeResult(r); return -1; } for (i = 0; i < r->numpmid; i++) { if (r->vset[i]->pmid == x->pmid) break; } if (i != r->numpmid) break; pmFreeResult(r); } } else { e = pmFetch(1, &(x->pmid), &r); i = 0; } if (e < 0) { if (e == PM_ERR_EOL && opts.guiflag) { pmTimeStateBounds(&controls, pmtime); return -1; } if (rawArchive) fprintf(stderr, "\n%s: pmFetchArchive: %s\n", pmProgname, pmErrStr(e)); else fprintf(stderr, "\n%s: pmFetch: %s\n", pmProgname, pmErrStr(e)); exit(EXIT_FAILURE); } if (opts.guiflag) pmTimeStateAck(&controls, pmtime); if (__pmtimevalToReal(&r->timestamp) > __pmtimevalToReal(&opts.finish)) { pmFreeResult(r); return -2; } if (r->vset[i]->numval == 0) { if (opts.guiflag || opts.context == PM_CONTEXT_ARCHIVE) { __pmPrintStamp(stdout, &r->timestamp); printf(" "); } printf("No values available\n"); pmFreeResult(r); return -1; } else if (r->vset[i]->numval < 0) { if (rawArchive) fprintf(stderr, "\n%s: pmFetchArchive: %s\n", pmProgname, pmErrStr(r->vset[i]->numval)); else fprintf(stderr, "\n%s: pmFetch: %s\n", pmProgname, pmErrStr(r->vset[i]->numval)); pmFreeResult(r); return -1; } *vs = r; qsort(r->vset[i]->vlist, (size_t)r->vset[i]->numval, sizeof(pmValue), compare); return i; }
// convert timeval to seconds double QedApp::timevalToSeconds(struct timeval t) { return __pmtimevalToReal(&t); }
/* ** The engine() drives the main-loop of the program */ void engine(void) { int i, j; struct sigaction sigact; double timed, delta; void getusr1(int), getusr2(int); /* ** reserve space for system-level statistics */ static struct sstat *cursstat; /* current */ static struct sstat *presstat; /* previous */ static struct sstat *devsstat; /* deviation */ static struct sstat *hlpsstat; /* ** reserve space for task-level statistics */ static struct tstat *curtpres; /* current present list */ static int curtlen; /* size of present list */ struct tstat *curpexit; /* exited process list */ struct tstat *devtstat; /* deviation list */ struct tstat **devpstat; /* pointers to processes */ /* in deviation list */ unsigned int ntaskpres; /* number of tasks present */ unsigned int nprocexit; /* number of exited procs */ unsigned int nprocexitnet; /* number of exited procs */ /* via netatopd daemon */ unsigned int ntaskdev; /* nr of tasks deviated */ unsigned int nprocdev; /* nr of procs deviated */ int nprocpres; /* nr of procs present */ int totrun, totslpi, totslpu, totzombie; unsigned int noverflow; /* ** initialization: allocate required memory dynamically */ cursstat = sstat_alloc("current sysstats"); presstat = sstat_alloc("prev sysstats"); devsstat = sstat_alloc("deviate sysstats"); curtlen = PROCMIN * 3 / 2; /* add 50% for threads */ curtpres = calloc(curtlen, sizeof(struct tstat)); ptrverify(curtpres, "Malloc failed for %d procstats\n", curtlen); /* ** install the signal-handler for ALARM, USR1 and USR2 (triggers ** for the next sample) */ memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getusr1; sigaction(SIGUSR1, &sigact, (struct sigaction *)0); memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getusr2; sigaction(SIGUSR2, &sigact, (struct sigaction *)0); memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getalarm; sigaction(SIGALRM, &sigact, (struct sigaction *)0); if (interval.tv_sec || interval.tv_usec) setalarm(&interval); /* ** MAIN-LOOP: ** - Wait for the requested number of seconds or for other trigger ** ** - System-level counters ** get current counters ** calculate the differences with the previous sample ** ** - Process-level counters ** get current counters from running & exited processes ** calculate the differences with the previous sample ** ** - Call the print-function to visualize the differences */ for (sampcnt=0; sampcnt < nsamples; sampcnt++) { char lastcmd; /* ** wait for alarm-signal to arrive (except first sample) ** or wait for SIGUSR1/SIGUSR2 */ if (sampcnt > 0 && awaittrigger && !rawreadflag) pause(); awaittrigger = 1; /* ** take a snapshot of the current system-level statistics */ hlpsstat = cursstat; /* swap current/prev. stats */ cursstat = presstat; presstat = hlpsstat; photosyst(cursstat); /* obtain new counters */ /* ** take a snapshot of the current task-level statistics ** ** first register active tasks ** --> atop malloc's a minimal amount of space which is ** only extended when needed */ memset(curtpres, 0, curtlen * sizeof(struct tstat)); ntaskpres = photoproc(&curtpres, &curtlen); /* ** register processes that exited during last sample; ** first determine how many processes exited ** ** the number of exited processes is limited to avoid ** that atop explodes in memory and introduces OOM killing */ nprocexit = acctprocnt(); /* number of exited processes */ if (nprocexit > MAXACCTPROCS) { noverflow = nprocexit - MAXACCTPROCS; nprocexit = MAXACCTPROCS; } else noverflow = 0; /* ** determine how many processes have been exited ** for the netatop module (only processes that have ** used the network) */ if (nprocexit > 0 && (supportflags & NETATOPD)) nprocexitnet = netatop_exitstore(); else nprocexitnet = 0; /* ** reserve space for the exited processes and read them */ if (nprocexit > 0) { curpexit = malloc(nprocexit * sizeof(struct tstat)); ptrverify(curpexit, "Malloc failed for %d exited processes\n", nprocexit); memset(curpexit, 0, nprocexit * sizeof(struct tstat)); nprocexit = acctphotoproc(curpexit, nprocexit); /* ** reposition offset in accounting file when not ** all exited processes have been read (i.e. skip ** those processes) */ if (noverflow) acctrepos(noverflow); } else { curpexit = NULL; } /* ** calculate the deviations (i.e. calculate the activity ** during the last sample). Note for PMAPI calls we had ** to delay changing curtime until after sampling due to ** the way pmSetMode(3) works. */ pretime = curtime; /* timestamp for previous sample */ curtime = cursstat->stamp; /* timestamp for this sample */ timed = __pmtimevalToReal(&curtime); delta = timed - __pmtimevalToReal(&pretime); deviatsyst(cursstat, presstat, devsstat, delta); devtstat = malloc((ntaskpres+nprocexit) * sizeof(struct tstat)); ptrverify(devtstat, "Malloc failed for %d modified tasks\n", ntaskpres+nprocexit); ntaskdev = deviattask(curtpres, ntaskpres, curpexit, nprocexit, deviatonly, devtstat, devsstat, &nprocdev, &nprocpres, &totrun, &totslpi, &totslpu, &totzombie); /* ** create list of pointers specifically to the process entries ** in the task list */ devpstat = malloc(sizeof (struct tstat *) * nprocdev); ptrverify(devpstat, "Malloc failed for %d process ptrs\n", nprocdev); for (i=0, j=0; i < ntaskdev; i++) { if ( (devtstat+i)->gen.isproc) devpstat[j++] = devtstat+i; } /* ** activate the installed print-function to visualize ** the deviations */ lastcmd = (vis.show_samp)(timed, delta > 1.0 ? delta : 1.0, devsstat, devtstat, devpstat, ntaskdev, ntaskpres, nprocdev, nprocpres, totrun, totslpi, totslpu, totzombie, nprocexit, noverflow, sampcnt==0); if (rawreadflag) __pmtimevalInc(&curtime, &interval); /* ** release dynamically allocated memory */ if (nprocexit > 0) free(curpexit); if (nprocexitnet > 0) netatop_exiterase(); free(devtstat); free(devpstat); if (lastcmd == 'r') /* reset requested ? */ { sampcnt = -1; curtime = origin; /* set current (will be 'previous') counters to 0 */ memset(curtpres, 0, curtlen * sizeof(struct tstat)); sstat_reset(cursstat); /* remove all tasks in database */ pdb_makeresidue(); pdb_cleanresidue(); } } /* end of main-loop */ }
void rawwrite(pmOptions *opts, const char *name, struct timeval *delta, unsigned int nsamples, char midnightflag) { pmRecordHost *record; struct timeval elapsed; double duration; double interval; char args[MAXPATHLEN]; char *host; int sts; host = (opts->nhosts > 0) ? opts->hosts[0] : "local:"; interval = __pmtimevalToReal(delta); duration = interval * nsamples; if (midnightflag) { time_t now = time(NULL); struct tm *tp; tp = localtime(&now); tp->tm_hour = 23; tp->tm_min = 59; tp->tm_sec = 59; duration = (double) (mktime(tp) - now); } if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "%s: start recording, %.2fsec duration [%s].\n", pmProgname, duration, name); } if (__pmMakePath(name, S_IRWXU|S_IRWXG|S_IROTH|S_IXOTH) < 0) { fprintf(stderr, "%s: making folio path %s for recording: %s\n", pmProgname, name, osstrerror()); cleanstop(1); } if (chdir(name) < 0) { fprintf(stderr, "%s: entering folio %s for recording: %s\n", pmProgname, name, strerror(oserror())); cleanstop(1); } /* ** Non-graphical application using libpcp_gui services - never want ** to see popup dialogs from pmlogger(1) here, so force the issue. */ putenv("PCP_XCONFIRM_PROG=/bin/true"); snprintf(args, sizeof(args), "%s.folio", basename((char *)name)); args[sizeof(args)-1] = '\0'; if (pmRecordSetup(args, pmProgname, 1) == NULL) { fprintf(stderr, "%s: cannot setup recording to %s: %s\n", pmProgname, name, osstrerror()); cleanstop(1); } if ((sts = pmRecordAddHost(host, 1, &record)) < 0) { fprintf(stderr, "%s: adding host %s to recording: %s\n", pmProgname, host, pmErrStr(sts)); cleanstop(1); } rawconfig(record->f_config, interval); /* ** start pmlogger with a deadhand timer, ensuring it will stop */ snprintf(args, sizeof(args), "-T%.3fseconds", duration); args[sizeof(args)-1] = '\0'; if ((sts = pmRecordControl(record, PM_REC_SETARG, args)) < 0) { fprintf(stderr, "%s: setting loggers arguments: %s\n", pmProgname, pmErrStr(sts)); cleanstop(1); } if ((sts = pmRecordControl(NULL, PM_REC_ON, "")) < 0) { fprintf(stderr, "%s: failed to start recording: %s\n", pmProgname, pmErrStr(sts)); cleanstop(1); } __pmtimevalFromReal(duration, &elapsed); __pmtimevalSleep(elapsed); if ((sts = pmRecordControl(NULL, PM_REC_OFF, "")) < 0) { fprintf(stderr, "%s: failed to stop recording: %s\n", pmProgname, pmErrStr(sts)); cleanstop(1); } if (pmDebug & DBG_TRACE_APPL1) { fprintf(stderr, "%s: cleanly stopped recording.\n", pmProgname); } }
int pass3(__pmContext *ctxp, char *archname, pmOptions *opts) { struct timeval timespan; int sts; pmResult *result; struct timeval last_stamp; struct timeval delta_stamp; l_ctxp = ctxp; l_archname = archname; if (vflag) fprintf(stderr, "%s: start pass3\n", archname); if ((sts = pmSetMode(PM_MODE_FORW, &opts->start, 0)) < 0) { fprintf(stderr, "%s: pmSetMode failed: %s\n", l_archname, pmErrStr(sts)); return STS_FATAL; } /* check which timestamp print format we should be using */ timespan = opts->finish; tsub(×pan, &opts->start); if (timespan.tv_sec > 86400) /* seconds per day: 60*60*24 */ dayflag = 1; sts = 0; last_stamp = opts->start; for ( ; ; ) { /* * we need the next record with no fancy checks or record * skipping in libpcp, so use __pmLogRead() in preference * to pmFetchArchive() */ if ((sts = __pmLogRead(l_ctxp->c_archctl->ac_log, l_ctxp->c_mode, NULL, &result, PMLOGREAD_NEXT)) < 0) break; result_count++; delta_stamp = result->timestamp; tsub(&delta_stamp, &last_stamp); #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL0) { int i; int sum_val = 0; int cnt_noval = 0; int cnt_err = 0; pmValueSet *vsp; fprintf(stderr, "%s.%d:[", l_archname, l_ctxp->c_archctl->ac_vol); print_stamp(stderr, &result->timestamp); for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; if (vsp->numval > 0) sum_val += vsp->numval; else if (vsp->numval == 0) cnt_noval++; else cnt_err++; } fprintf(stderr, "] delta(stamp)=%.3fsec", __pmtimevalToReal(&delta_stamp)); fprintf(stderr, " numpmid=%d sum(numval)=%d", result->numpmid, sum_val); if (cnt_noval > 0) fprintf(stderr, " count(numval=0)=%d", cnt_noval); if (cnt_err > 0) fprintf(stderr, " count(numval<0)=%d", cnt_err); fputc('\n', stderr); } #endif if (delta_stamp.tv_sec < 0) { /* time went backwards! */ fprintf(stderr, "%s.%d:[", l_archname, l_ctxp->c_archctl->ac_vol); print_stamp(stderr, &result->timestamp); fprintf(stderr, "]: timestamp went backwards, prior timestamp: "); print_stamp(stderr, &last_stamp); fprintf(stderr, "\n"); } last_stamp = result->timestamp; if ((opts->finish.tv_sec > result->timestamp.tv_sec) || ((opts->finish.tv_sec == result->timestamp.tv_sec) && (opts->finish.tv_usec >= result->timestamp.tv_usec))) { if (result->numpmid == 0) { /* * MARK record ... make sure wrap check is not done * at next fetch (mimic interp.c from libpcp) */ __pmHashNode *hptr; checkData *checkdata; int k; for (hptr = __pmHashWalk(&hashlist, PM_HASH_WALK_START); hptr != NULL; hptr = __pmHashWalk(&hashlist, PM_HASH_WALK_NEXT)) { checkdata = (checkData *)hptr->data; for (k = 0; k < checkdata->listsize; k++) { checkdata->instlist[k]->lasttime.tv_sec = 0; } } mark_count++; } else docheck(result); pmFreeResult(result); } else { pmFreeResult(result); sts = PM_ERR_EOL; break; } } if (sts != PM_ERR_EOL) { fprintf(stderr, "[after "); print_stamp(stderr, &last_stamp); fprintf(stderr, "]: pmFetch: error: %s\n", pmErrStr(sts)); return STS_FATAL; } return STS_OK; }
static void docheck(pmResult *result) { int i, j, k; int sts; pmDesc desc; pmAtomValue av; pmValue *vp; pmValueSet *vsp; __pmHashNode *hptr = NULL; checkData *checkdata = NULL; double diff; struct timeval timediff; for (i = 0; i < result->numpmid; i++) { vsp = result->vset[i]; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL1) { if (vsp->numval == 0) { fprintf(stderr, "%s.%d:[", l_archname, l_ctxp->c_archctl->ac_vol); print_stamp(stderr, &result->timestamp); fprintf(stderr, "] "); print_metric(stderr, vsp->pmid); fprintf(stderr, ": no values returned\n"); continue; } else if (vsp->numval < 0) { fprintf(stderr, "%s.%d:[", l_archname, l_ctxp->c_archctl->ac_vol); print_stamp(stderr, &result->timestamp); fprintf(stderr, "] "); print_metric(stderr, vsp->pmid); fprintf(stderr, ": error from numval: %s\n", pmErrStr(vsp->numval)); continue; } } #endif if (vsp->numval <= 0) continue; /* check if pmid already in hash list */ if ((hptr = __pmHashSearch(vsp->pmid, &hashlist)) == NULL) { if ((sts = pmLookupDesc(vsp->pmid, &desc)) < 0) { fprintf(stderr, "%s.%d:[", l_archname, l_ctxp->c_archctl->ac_vol); print_stamp(stderr, &result->timestamp); fprintf(stderr, "] "); print_metric(stderr, vsp->pmid); fprintf(stderr, ": pmLookupDesc failed: %s\n", pmErrStr(sts)); continue; } if (desc.type != PM_TYPE_32 && desc.type != PM_TYPE_U32 && desc.type != PM_TYPE_64 && desc.type != PM_TYPE_U64 && desc.type != PM_TYPE_FLOAT && desc.type != PM_TYPE_DOUBLE) { continue; /* no checks for non-numeric metrics */ } /* create a new one & add to list */ checkdata = (checkData*) malloc(sizeof(checkData)); newHashItem(vsp, &desc, checkdata, &result->timestamp); if (__pmHashAdd(checkdata->desc.pmid, (void*)checkdata, &hashlist) < 0) { fprintf(stderr, "%s.%d:[", l_archname, l_ctxp->c_archctl->ac_vol); print_stamp(stderr, &result->timestamp); fprintf(stderr, "] "); print_metric(stderr, vsp->pmid); fprintf(stderr, ": __pmHashAdd failed (internal pmlogcheck error)\n"); /* free memory allocated above on insert failure */ for (j = 0; j < vsp->numval; j++) { if (checkdata->instlist[j] != NULL) free(checkdata->instlist[j]); } if (checkdata->instlist != NULL) free(checkdata->instlist); continue; } } else { /* pmid exists - update statistics */ checkdata = (checkData *)hptr->data; for (j = 0; j < vsp->numval; j++) { /* iterate thro result values */ vp = &vsp->vlist[j]; k = j; /* index into stored inst list, result may differ */ if ((vsp->numval > 1) || (checkdata->desc.indom != PM_INDOM_NULL)) { /* must store values using correct inst - probably in correct order already */ if ((k < checkdata->listsize) && (checkdata->instlist[k]->inst != vp->inst)) { for (k = 0; k < checkdata->listsize; k++) { if (vp->inst == checkdata->instlist[k]->inst) { break; /* k now correct */ } } if (k == checkdata->listsize) { /* no matching inst was found */ newHashInst(vp, checkdata, vsp->valfmt, &result->timestamp, k); continue; } } else if (k >= checkdata->listsize) { k = checkdata->listsize; newHashInst(vp, checkdata, vsp->valfmt, &result->timestamp, k); continue; } } if (k >= checkdata->listsize) { /* only error values observed so far */ k = checkdata->listsize; newHashInst(vp, checkdata, vsp->valfmt, &result->timestamp, k); continue; } timediff = result->timestamp; tsub(&timediff, &(checkdata->instlist[k]->lasttime)); if (timediff.tv_sec < 0) { /* clip negative values at zero */ timediff.tv_sec = 0; timediff.tv_usec = 0; } diff = __pmtimevalToReal(&timediff); if ((sts = pmExtractValue(vsp->valfmt, vp, checkdata->desc.type, &av, PM_TYPE_DOUBLE)) < 0) { fprintf(stderr, "%s.%d:[", l_archname, l_ctxp->c_archctl->ac_vol); print_stamp(stderr, &result->timestamp); fprintf(stderr, "] "); print_metric(stderr, vsp->pmid); fprintf(stderr, ": pmExtractValue failed: %s\n", pmErrStr(sts)); continue; } if (checkdata->desc.sem == PM_SEM_COUNTER) { if (diff == 0.0) continue; diff *= checkdata->scale; #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_APPL2) { fprintf(stderr, "%s.%d:[", l_archname, l_ctxp->c_archctl->ac_vol); print_stamp(stderr, &result->timestamp); fprintf(stderr, "] "); print_metric(stderr, checkdata->desc.pmid); fprintf(stderr, ": current counter value is %.0f\n", av.d); } #endif unwrap(av.d, &(result->timestamp), checkdata, k); } checkdata->instlist[k]->lastval = av.d; checkdata->instlist[k]->lasttime = result->timestamp; } } } }
/* initialize access to archive */ int initArchive(Archive *a) { pmLogLabel label; struct timeval tv; int sts; int handle; Archive *b; const char *tmp; /* setup temorary context for the archive */ if ((sts = pmNewContext(PM_CONTEXT_ARCHIVE, a->fname)) < 0) { fprintf(stderr, "%s: cannot open archive %s\n" "pmNewContext failed: %s\n", pmProgname, a->fname, pmErrStr(sts)); return 0; } handle = sts; tmp = pmGetContextHostName(handle); if (strlen(tmp) == 0) { fprintf(stderr, "%s: pmGetContextHostName(%d) failed\n", pmProgname, handle); return 0; } if ((a->hname = strdup(tmp)) == NULL) __pmNoMem("host name copy", strlen(tmp)+1, PM_FATAL_ERR); /* get the goodies from archive label */ if ((sts = pmGetArchiveLabel(&label)) < 0) { fprintf(stderr, "%s: cannot read label from archive %s\n" "pmGetArchiveLabel failed: %s\n", pmProgname, a->fname, pmErrStr(sts)); pmDestroyContext(handle); return 0; } a->first = __pmtimevalToReal(&label.ll_start); if ((sts = pmGetArchiveEnd(&tv)) < 0) { fprintf(stderr, "%s: archive %s is corrupted\n" "pmGetArchiveEnd failed: %s\n", pmProgname, a->fname, pmErrStr(sts)); pmDestroyContext(handle); return 0; } a->last = __pmtimevalToReal(&tv); /* check for duplicate host */ b = archives; while (b) { if (strcmp(a->hname, b->hname) == 0) { fprintf(stderr, "%s: Error: archive %s not legal - archive %s is already open " "for host %s\n", pmProgname, a->fname, b->fname, b->hname); pmDestroyContext(handle); return 0; } b = b->next; } /* put archive record on the archives list */ a->next = archives; archives = a; /* update first and last available data points */ if (first == -1 || a->first < first) first = a->first; if (a->last > last) last = a->last; pmDestroyContext(handle); return 1; }
/* execute fetches for given Task */ void taskFetch(Task *t) { Host *h; Fetch *f; Profile *p; Metric *m; pmResult *r; pmValueSet **v; int i; int sts; /* do all fetches, quick as you can */ h = t->hosts; while (h) { f = h->fetches; while (f) { if (f->result) pmFreeResult(f->result); if (! h->down) { pmUseContext(f->handle); if ((sts = pmFetch(f->npmids, f->pmids, &f->result)) < 0) { if (! archives) { __pmNotifyErr(LOG_ERR, "pmFetch from %s failed: %s\n", symName(f->host->name), pmErrStr(sts)); host_state_changed(symName(f->host->name), STATE_LOSTCONN); h->down = 1; mark_all(h); } f->result = NULL; } } else f->result = NULL; f = f->next; } h = h->next; } /* sort and distribute pmValueSets to requesting Metrics */ h = t->hosts; while (h) { if (! h->down) { f = h->fetches; while (f && (r = f->result)) { /* sort all vlists in result r */ v = r->vset; for (i = 0; i < r->numpmid; i++) { if ((*v)->numval > 0) { qsort((*v)->vlist, (size_t)(*v)->numval, sizeof(pmValue), compair); } v++; } /* distribute pmValueSets to Metrics */ p = f->profiles; while (p) { m = p->metrics; while (m) { for (i = 0; i < r->numpmid; i++) { if (m->desc.pmid == r->vset[i]->pmid) { if (r->vset[i]->numval > 0) { m->vset = r->vset[i]; m->stamp = __pmtimevalToReal(&r->timestamp); } break; } } m = m->next; } p = p->next; } f = f->next; } } h = h->next; } }
/* * Walk an expression tree, filling in operand values from the * pmResult at the leaf nodes and propagating the computed values * towards the root node of the tree. */ static int eval_expr(node_t *np, pmResult *rp, int level) { int sts; int i; int j; int k; size_t need; assert(np != NULL); if (np->left != NULL) { sts = eval_expr(np->left, rp, level+1); if (sts < 0) return sts; } if (np->right != NULL) { sts = eval_expr(np->right, rp, level+1); if (sts < 0) return sts; } /* mostly, np->left is not NULL ... */ assert (np->type == L_NUMBER || np->type == L_NAME || np->left != NULL); switch (np->type) { case L_NUMBER: if (np->info->numval == 0) { /* initialize ivlist[] for singular instance first time through */ np->info->numval = 1; if ((np->info->ivlist = (val_t *)malloc(sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: number ivlist", sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } np->info->ivlist[0].inst = PM_INDOM_NULL; /* don't need error checking, done in the lexical scanner */ np->info->ivlist[0].value.l = atoi(np->value); } return 1; break; case L_DELTA: case L_RATE: /* * this and the last values are in the left expr */ np->info->last_stamp = np->info->stamp; np->info->stamp = rp->timestamp; free_ivlist(np); np->info->numval = np->left->info->numval <= np->left->info->last_numval ? np->left->info->numval : np->left->info->last_numval; if (np->info->numval <= 0) return np->info->numval; if ((np->info->ivlist = (val_t *)malloc(np->info->numval*sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: delta()/rate() ivlist", np->info->numval*sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } /* * delta() * ivlist[k] = left->ivlist[i] - left->last_ivlist[j] * rate() * ivlist[k] = (left->ivlist[i] - left->last_ivlist[j]) / * (timestamp - left->last_stamp) */ for (i = k = 0; i < np->left->info->numval; i++) { j = i; if (j >= np->left->info->last_numval) j = 0; if (np->left->info->ivlist[i].inst != np->left->info->last_ivlist[j].inst) { /* current ith inst != last jth inst ... search in last */ #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { fprintf(stderr, "eval_expr: inst[%d] mismatch left [%d]=%d last [%d]=%d\n", k, i, np->left->info->ivlist[i].inst, j, np->left->info->last_ivlist[j].inst); } #endif for (j = 0; j < np->left->info->last_numval; j++) { if (np->left->info->ivlist[i].inst == np->left->info->last_ivlist[j].inst) break; } if (j == np->left->info->last_numval) { /* no match, skip this instance from this result */ continue; } #ifdef PCP_DEBUG else { if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { fprintf(stderr, "eval_expr: recover @ last [%d]=%d\n", j, np->left->info->last_ivlist[j].inst); } } #endif } np->info->ivlist[k].inst = np->left->info->ivlist[i].inst; if (np->type == L_DELTA) { /* for delta() result type == operand type */ switch (np->left->desc.type) { case PM_TYPE_32: np->info->ivlist[k].value.l = np->left->info->ivlist[i].value.l - np->left->info->last_ivlist[j].value.l; break; case PM_TYPE_U32: np->info->ivlist[k].value.ul = np->left->info->ivlist[i].value.ul - np->left->info->last_ivlist[j].value.ul; break; case PM_TYPE_64: np->info->ivlist[k].value.ll = np->left->info->ivlist[i].value.ll - np->left->info->last_ivlist[j].value.ll; break; case PM_TYPE_U64: np->info->ivlist[k].value.ull = np->left->info->ivlist[i].value.ull - np->left->info->last_ivlist[j].value.ull; break; case PM_TYPE_FLOAT: np->info->ivlist[k].value.f = np->left->info->ivlist[i].value.f - np->left->info->last_ivlist[j].value.f; break; case PM_TYPE_DOUBLE: np->info->ivlist[k].value.d = np->left->info->ivlist[i].value.d - np->left->info->last_ivlist[j].value.d; break; default: /* * Nothing should end up here as check_expr() checks * for numeric data type at bind time */ return PM_ERR_CONV; } } else { /* rate() conversion, type will be DOUBLE */ struct timeval stampdiff; stampdiff = np->info->stamp; __pmtimevalDec(&stampdiff, &np->info->last_stamp); switch (np->left->desc.type) { case PM_TYPE_32: np->info->ivlist[k].value.d = (double)(np->left->info->ivlist[i].value.l - np->left->info->last_ivlist[j].value.l); break; case PM_TYPE_U32: np->info->ivlist[k].value.d = (double)(np->left->info->ivlist[i].value.ul - np->left->info->last_ivlist[j].value.ul); break; case PM_TYPE_64: np->info->ivlist[k].value.d = (double)(np->left->info->ivlist[i].value.ll - np->left->info->last_ivlist[j].value.ll); break; case PM_TYPE_U64: np->info->ivlist[k].value.d = (double)(np->left->info->ivlist[i].value.ull - np->left->info->last_ivlist[j].value.ull); break; case PM_TYPE_FLOAT: np->info->ivlist[k].value.d = (double)(np->left->info->ivlist[i].value.f - np->left->info->last_ivlist[j].value.f); break; case PM_TYPE_DOUBLE: np->info->ivlist[k].value.d = np->left->info->ivlist[i].value.d - np->left->info->last_ivlist[j].value.d; break; default: /* * Nothing should end up here as check_expr() checks * for numeric data type at bind time */ return PM_ERR_CONV; } np->info->ivlist[k].value.d /= __pmtimevalToReal(&stampdiff); /* * check_expr() ensures dimTime is 0 or 1 at bind time */ if (np->left->desc.units.dimTime == 1) { /* scale rate(time counter) -> time utilization */ if (np->info->time_scale < 0) { /* * one trip initialization for time utilization * scaling factor (to scale metric from counter * units into seconds) */ int i; np->info->time_scale = 1; if (np->left->desc.units.scaleTime > PM_TIME_SEC) { for (i = PM_TIME_SEC; i < np->left->desc.units.scaleTime; i++) np->info->time_scale *= 60; } else { for (i = np->left->desc.units.scaleTime; i < PM_TIME_SEC; i++) np->info->time_scale /= 1000; } } np->info->ivlist[k].value.d *= np->info->time_scale; } } k++; } np->info->numval = k; return np->info->numval; break; case L_INSTANT: /* * values are in the left expr */ np->info->last_stamp = np->info->stamp; np->info->stamp = rp->timestamp; np->info->numval = np->left->info->numval; if (np->info->numval > 0) np->info->ivlist = np->left->info->ivlist; return np->info->numval; break; case L_AVG: case L_COUNT: case L_SUM: case L_MAX: case L_MIN: if (np->info->ivlist == NULL) { /* initialize ivlist[] for singular instance first time through */ if ((np->info->ivlist = (val_t *)malloc(sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: aggr ivlist", sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } np->info->ivlist[0].inst = PM_IN_NULL; } /* * values are in the left expr */ if (np->type == L_COUNT) { np->info->numval = 1; np->info->ivlist[0].value.l = np->left->info->numval; } else { np->info->numval = 1; if (np->type == L_AVG) np->info->ivlist[0].value.f = 0; else if (np->type == L_SUM) { switch (np->desc.type) { case PM_TYPE_32: np->info->ivlist[0].value.l = 0; break; case PM_TYPE_U32: np->info->ivlist[0].value.ul = 0; break; case PM_TYPE_64: np->info->ivlist[0].value.ll = 0; break; case PM_TYPE_U64: np->info->ivlist[0].value.ull = 0; break; case PM_TYPE_FLOAT: np->info->ivlist[0].value.f = 0; break; case PM_TYPE_DOUBLE: np->info->ivlist[0].value.d = 0; break; } } for (i = 0; i < np->left->info->numval; i++) { switch (np->type) { case L_AVG: switch (np->left->desc.type) { case PM_TYPE_32: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.l / np->left->info->numval; break; case PM_TYPE_U32: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.ul / np->left->info->numval; break; case PM_TYPE_64: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.ll / np->left->info->numval; break; case PM_TYPE_U64: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.ull / np->left->info->numval; break; case PM_TYPE_FLOAT: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.f / np->left->info->numval; break; case PM_TYPE_DOUBLE: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.d / np->left->info->numval; break; default: /* * check_expr() checks for numeric data * type at bind time ... if here, botch! */ return PM_ERR_CONV; } break; case L_MAX: switch (np->desc.type) { case PM_TYPE_32: if (i == 0 || np->info->ivlist[0].value.l < np->left->info->ivlist[i].value.l) np->info->ivlist[0].value.l = np->left->info->ivlist[i].value.l; break; case PM_TYPE_U32: if (i == 0 || np->info->ivlist[0].value.ul < np->left->info->ivlist[i].value.ul) np->info->ivlist[0].value.ul = np->left->info->ivlist[i].value.ul; break; case PM_TYPE_64: if (i == 0 || np->info->ivlist[0].value.ll < np->left->info->ivlist[i].value.ll) np->info->ivlist[0].value.ll = np->left->info->ivlist[i].value.ll; break; case PM_TYPE_U64: if (i == 0 || np->info->ivlist[0].value.ull < np->left->info->ivlist[i].value.ull) np->info->ivlist[0].value.ull = np->left->info->ivlist[i].value.ull; break; case PM_TYPE_FLOAT: if (i == 0 || np->info->ivlist[0].value.f < np->left->info->ivlist[i].value.f) np->info->ivlist[0].value.f = np->left->info->ivlist[i].value.f; break; case PM_TYPE_DOUBLE: if (i == 0 || np->info->ivlist[0].value.d < np->left->info->ivlist[i].value.d) np->info->ivlist[0].value.d = np->left->info->ivlist[i].value.d; break; default: /* * check_expr() checks for numeric data * type at bind time ... if here, botch! */ return PM_ERR_CONV; } break; case L_MIN: switch (np->desc.type) { case PM_TYPE_32: if (i == 0 || np->info->ivlist[0].value.l > np->left->info->ivlist[i].value.l) np->info->ivlist[0].value.l = np->left->info->ivlist[i].value.l; break; case PM_TYPE_U32: if (i == 0 || np->info->ivlist[0].value.ul > np->left->info->ivlist[i].value.ul) np->info->ivlist[0].value.ul = np->left->info->ivlist[i].value.ul; break; case PM_TYPE_64: if (i == 0 || np->info->ivlist[0].value.ll > np->left->info->ivlist[i].value.ll) np->info->ivlist[0].value.ll = np->left->info->ivlist[i].value.ll; break; case PM_TYPE_U64: if (i == 0 || np->info->ivlist[0].value.ull > np->left->info->ivlist[i].value.ull) np->info->ivlist[0].value.ull = np->left->info->ivlist[i].value.ull; break; case PM_TYPE_FLOAT: if (i == 0 || np->info->ivlist[0].value.f > np->left->info->ivlist[i].value.f) np->info->ivlist[0].value.f = np->left->info->ivlist[i].value.f; break; case PM_TYPE_DOUBLE: if (i == 0 || np->info->ivlist[0].value.d > np->left->info->ivlist[i].value.d) np->info->ivlist[0].value.d = np->left->info->ivlist[i].value.d; break; default: /* * check_expr() checks for numeric data * type at bind time ... if here, botch! */ return PM_ERR_CONV; } break; case L_SUM: switch (np->desc.type) { case PM_TYPE_32: np->info->ivlist[0].value.l += np->left->info->ivlist[i].value.l; break; case PM_TYPE_U32: np->info->ivlist[0].value.ul += np->left->info->ivlist[i].value.ul; break; case PM_TYPE_64: np->info->ivlist[0].value.ll += np->left->info->ivlist[i].value.ll; break; case PM_TYPE_U64: np->info->ivlist[0].value.ull += np->left->info->ivlist[i].value.ull; break; case PM_TYPE_FLOAT: np->info->ivlist[0].value.f += np->left->info->ivlist[i].value.f; break; case PM_TYPE_DOUBLE: np->info->ivlist[0].value.d += np->left->info->ivlist[i].value.d; break; default: /* * check_expr() checks for numeric data * type at bind time ... if here, botch! */ return PM_ERR_CONV; } break; } } } return np->info->numval; break; case L_NAME: /* * Extract instance-values from pmResult and store them in * ivlist[] as <int, pmAtomValue> pairs */ for (j = 0; j < rp->numpmid; j++) { if (np->info->pmid == rp->vset[j]->pmid) { free_ivlist(np); np->info->numval = rp->vset[j]->numval; if (np->info->numval <= 0) return np->info->numval; if ((np->info->ivlist = (val_t *)malloc(np->info->numval*sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: metric ivlist", np->info->numval*sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } for (i = 0; i < np->info->numval; i++) { np->info->ivlist[i].inst = rp->vset[j]->vlist[i].inst; switch (np->desc.type) { case PM_TYPE_32: case PM_TYPE_U32: np->info->ivlist[i].value.l = rp->vset[j]->vlist[i].value.lval; break; case PM_TYPE_64: case PM_TYPE_U64: memcpy((void *)&np->info->ivlist[i].value.ll, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, sizeof(__int64_t)); break; case PM_TYPE_FLOAT: if (rp->vset[j]->valfmt == PM_VAL_INSITU) { /* old style insitu float */ np->info->ivlist[i].value.l = rp->vset[j]->vlist[i].value.lval; } else { assert(rp->vset[j]->vlist[i].value.pval->vtype == PM_TYPE_FLOAT); memcpy((void *)&np->info->ivlist[i].value.f, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, sizeof(float)); } break; case PM_TYPE_DOUBLE: memcpy((void *)&np->info->ivlist[i].value.d, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, sizeof(double)); break; case PM_TYPE_STRING: need = rp->vset[j]->vlist[i].value.pval->vlen-PM_VAL_HDR_SIZE; if ((np->info->ivlist[i].value.cp = (char *)malloc(need)) == NULL) { __pmNoMem("eval_expr: string value", rp->vset[j]->vlist[i].value.pval->vlen, PM_FATAL_ERR); /*NOTREACHED*/ } memcpy((void *)np->info->ivlist[i].value.cp, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, need); np->info->ivlist[i].vlen = need; break; case PM_TYPE_AGGREGATE: case PM_TYPE_AGGREGATE_STATIC: case PM_TYPE_EVENT: case PM_TYPE_HIGHRES_EVENT: if ((np->info->ivlist[i].value.vbp = (pmValueBlock *)malloc(rp->vset[j]->vlist[i].value.pval->vlen)) == NULL) { __pmNoMem("eval_expr: aggregate value", rp->vset[j]->vlist[i].value.pval->vlen, PM_FATAL_ERR); /*NOTREACHED*/ } memcpy(np->info->ivlist[i].value.vbp, (void *)rp->vset[j]->vlist[i].value.pval, rp->vset[j]->vlist[i].value.pval->vlen); np->info->ivlist[i].vlen = rp->vset[j]->vlist[i].value.pval->vlen; break; default: /* * really only PM_TYPE_NOSUPPORT should * end up here */ return PM_ERR_TYPE; } } return np->info->numval; } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DERIVE) { char strbuf[20]; fprintf(stderr, "eval_expr: botch: operand %s not in the extended pmResult\n", pmIDStr_r(np->info->pmid, strbuf, sizeof(strbuf))); __pmDumpResult(stderr, rp); } #endif return PM_ERR_PMID; case L_ANON: /* no values available for anonymous metrics */ return 0; default: /* * binary operator cases ... always have a left and right * operand and no errors (these are caught earlier when the * recursive call on each of the operands would may have * returned an error */ assert(np->left != NULL); assert(np->right != NULL); free_ivlist(np); /* * empty result cases first */ if (np->left->info->numval == 0) { np->info->numval = 0; return np->info->numval; } if (np->right->info->numval == 0) { np->info->numval = 0; return np->info->numval; } /* * really got some work to do ... */ if (np->left->desc.indom == PM_INDOM_NULL) np->info->numval = np->right->info->numval; else if (np->right->desc.indom == PM_INDOM_NULL) np->info->numval = np->left->info->numval; else { /* * Generally have the same number of instances because * both operands are over the same instance domain, * fetched with the same profile. When not the case, * the result can contain no more instances than in * the smaller of the operands. */ if (np->left->info->numval <= np->right->info->numval) np->info->numval = np->left->info->numval; else np->info->numval = np->right->info->numval; } if ((np->info->ivlist = (val_t *)malloc(np->info->numval*sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: expr ivlist", np->info->numval*sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } /* * ivlist[k] = left-ivlist[i] <op> right-ivlist[j] */ for (i = j = k = 0; k < np->info->numval; ) { if (i >= np->left->info->numval || j >= np->right->info->numval) { /* run out of operand instances, quit */ np->info->numval = k; break; } if (np->left->desc.indom != PM_INDOM_NULL && np->right->desc.indom != PM_INDOM_NULL) { if (np->left->info->ivlist[i].inst != np->right->info->ivlist[j].inst) { /* left ith inst != right jth inst ... search in right */ #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { fprintf(stderr, "eval_expr: inst[%d] mismatch left [%d]=%d right [%d]=%d\n", k, i, np->left->info->ivlist[i].inst, j, np->right->info->ivlist[j].inst); } #endif for (j = 0; j < np->right->info->numval; j++) { if (np->left->info->ivlist[i].inst == np->right->info->ivlist[j].inst) break; } if (j == np->right->info->numval) { /* * no match, so next instance on left operand, * and reset to start from first instance of * right operand */ i++; j = 0; continue; } #ifdef PCP_DEBUG else { if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { fprintf(stderr, "eval_expr: recover @ right [%d]=%d\n", j, np->right->info->ivlist[j].inst); } } #endif } } np->info->ivlist[k].value = bin_op(np->desc.type, np->type, np->left->info->ivlist[i].value, np->left->desc.type, np->left->info->mul_scale, np->left->info->div_scale, np->right->info->ivlist[j].value, np->right->desc.type, np->right->info->mul_scale, np->right->info->div_scale); if (np->left->desc.indom != PM_INDOM_NULL) np->info->ivlist[k].inst = np->left->info->ivlist[i].inst; else np->info->ivlist[k].inst = np->right->info->ivlist[j].inst; k++; if (np->left->desc.indom != PM_INDOM_NULL) { i++; if (np->right->desc.indom != PM_INDOM_NULL) { j++; if (j >= np->right->info->numval) { /* rescan if need be */ j = 0; } } } else if (np->right->desc.indom != PM_INDOM_NULL) { j++; } } return np->info->numval; } /*NOTREACHED*/ }