diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
commit | 47e6e7c84f008a53061e661f31ae96629bc694ef (patch) | |
tree | 648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/pmevent/pmevent.c | |
download | pcp-debian/3.9.10.tar.gz |
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmevent/pmevent.c')
-rw-r--r-- | src/pmevent/pmevent.c | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/src/pmevent/pmevent.c b/src/pmevent/pmevent.c new file mode 100644 index 0000000..d8221b3 --- /dev/null +++ b/src/pmevent/pmevent.c @@ -0,0 +1,531 @@ +/* + * pmevent - event record dumper + * (based on pmval) + * + * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) 2008-2009 Aconex. All Rights Reserved. + * Copyright (c) 2011 Red Hat Inc. + * Copyright (c) 2011 Ken McDonell. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * TODO + * + -g and -p - nothing has been checked + */ + +#include "pmevent.h" + +static int amode = PM_MODE_FORW; /* archive scan mode */ +static pmTime *pmtime; + +char *host; /* hostname according to pmGetContextHostName */ +char *archive; /* archive source */ +int ahtype = -1; /* archive or host or local context */ +int ctxhandle = -1; /* handle for the active context */ +int verbose; /* verbose diagnostic output */ +struct timeval now; /* current reporting time */ +struct timeval first; /* start reporting time */ +struct timeval last = {INT_MAX, 999999}; /* end reporting time */ +struct timeval delta; /* sample interval */ +long samples; /* number of samples */ +int gui; /* set if -g */ +int port = -1; /* pmtime port number from -p */ +pmTimeControls controls; + +metric_t *metrictab; /* metrics from cmd line */ +int nmetric; +pmID *pmidlist; +static pmID pmid_flags; +static pmID pmid_missed; + +/* performance metrics in the hash list */ +typedef struct { + char *name; /* name of metric */ + pmDesc desc; /* metric description */ +} hash_t; + +/* Fetch metric values. */ +static int +getvals(pmResult **result) +{ + pmResult *rp = NULL; + int sts; + int i; + int m; + + if (archive != NULL) { + /* + * for archives read until we find a pmResult with at least + * one of the pmids we are after + */ + for ( ; ; ) { + sts = pmFetchArchive(&rp); + if (sts < 0) + break; + + if (rp->numpmid == 0) + /* skip mark records */ + continue; + + /* + * scan for any of the metrics of interest ... keep skipping + * archive records until one found + */ + for (i = 0; i < rp->numpmid; i++) { + for (m = 0; m < nmetric; m++) { + if (rp->vset[i]->pmid == metrictab[m].pmid) { + /* match */ + goto done; + } + } + } + pmFreeResult(rp); + rp = NULL; + } + } + else + sts = pmFetch(nmetric, pmidlist, &rp); + +done: + if (sts >= 0) + *result = rp; + else if (rp) + pmFreeResult(rp); + + return sts; +} + +static void +timestep(struct timeval newdelta) +{ + /* time moved, may need to wait for previous value again */ + // TODO ? +} + + +/*************************************************************************** + * output + ***************************************************************************/ + +/* Print parameter values as output header. */ +static void +printhdr(void) +{ + char timebuf[26]; + + if (archive == NULL) { + printf("host: %s\n", host); + } else { + printf("archive: %s\n", archive); + printf("host: %s\n", host); + printf("start: %s", pmCtime(&first.tv_sec, timebuf)); + if (last.tv_sec != INT_MAX) + printf("end: %s", pmCtime(&last.tv_sec, timebuf)); + } + + /* sample count and interval */ + if (samples == ALL_SAMPLES) printf("samples: all\n"); + else printf("samples: %ld\n", samples); + if (samples != ALL_SAMPLES && samples > 1 && ahtype != PM_CONTEXT_ARCHIVE) + printf("interval: %1.2f sec\n", __pmtimevalToReal(&delta)); +} + +/* + * cache all of the most recently requested + * pmInDom ... + */ +static char * +lookup(pmInDom indom, int inst) +{ + static pmInDom last = PM_INDOM_NULL; + static int numinst = -1; + static int *instlist; + static char **namelist; + int i; + + if (indom != last) { + if (numinst > 0) { + free(instlist); + free(namelist); + } + if (archive == NULL) + numinst = pmGetInDom(indom, &instlist, &namelist); + else + numinst = pmGetInDomArchive(indom, &instlist, &namelist); + last = indom; + } + + for (i = 0; i < numinst; i++) { + if (instlist[i] == inst) + return namelist[i]; + } + + return NULL; +} + +static void myeventdump(pmValueSet *, int, int); + +static void +mydump(const char *name, pmDesc *dp, pmValueSet *vsp) +{ + int j; + char *p; + + if (vsp->numval == 0) { + if (verbose) + printf("%s: No value(s) available!\n", name); + return; + } + else if (vsp->numval < 0) { + printf("%s: Error: %s\n", name, pmErrStr(vsp->numval)); + return; + } + + printf(" %s", name); + for (j = 0; j < vsp->numval; j++) { + pmValue *vp = &vsp->vlist[j]; + if (dp->indom != PM_INDOM_NULL) { + if (vsp->numval > 1) + printf("\n "); + if ((p = lookup(dp->indom, vp->inst)) == NULL) + printf("[%d]", vp->inst); + else + printf("[\"%s\"]", p); + } + putchar(' '); + + switch (dp->type) { + case PM_TYPE_AGGREGATE: + case PM_TYPE_AGGREGATE_STATIC: { + /* + * pinched from pmPrintValue, just without the preamble of + * floating point values + */ + char *p; + int i; + putchar('['); + p = &vp->value.pval->vbuf[0]; + for (i = 0; i < vp->value.pval->vlen - PM_VAL_HDR_SIZE; i++, p++) + printf("%02x", *p & 0xff); + putchar(']'); + putchar('\n'); + break; + } + case PM_TYPE_EVENT: + case PM_TYPE_HIGHRES_EVENT: + /* odd, nested event type! */ + myeventdump(vsp, j, dp->type != PM_TYPE_EVENT); + break; + default: + pmPrintValue(stdout, vsp->valfmt, dp->type, vp, 1); + putchar('\n'); + } + } +} + +static void +myvaluesetdump(pmValueSet *xvsp, int idx, int *flagsp) +{ + int sts, flags = *flagsp; + hash_t *hp; + __pmHashNode *hnp; + static __pmHashCtl hash = { 0, 0, NULL }; + + if ((hnp = __pmHashSearch((unsigned int)xvsp->pmid, &hash)) == NULL) { + /* first time for this pmid */ + hp = (hash_t *)malloc(sizeof(hash_t)); + if (hp == NULL) { + __pmNoMem("hash_t", sizeof(hash_t), PM_FATAL_ERR); + /*NOTREACHED*/ + } + if ((sts = pmNameID(xvsp->pmid, &hp->name)) < 0) { + printf(" %s: pmNameID: %s\n", pmIDStr(xvsp->pmid), pmErrStr(sts)); + free(hp); + return; + } + else { + if (xvsp->pmid != pmid_flags && + xvsp->pmid != pmid_missed && + (sts = pmLookupDesc(xvsp->pmid, &hp->desc)) < 0) { + printf(" %s: pmLookupDesc: %s\n", hp->name, pmErrStr(sts)); + free(hp->name); + free(hp); + return; + } + if ((sts = __pmHashAdd((unsigned int)xvsp->pmid, (void *)hp, &hash)) < 0) { + printf(" %s: __pmHashAdd: %s\n", hp->name, pmErrStr(sts)); + free(hp->name); + free(hp); + return; + } + } + } + else + hp = (hash_t *)hnp->data; + + if (idx == 0) { + if (xvsp->pmid == pmid_flags) { + flags = *flagsp = xvsp->vlist[0].value.lval; + printf(" flags 0x%x", flags); + printf(" (%s) ---\n", pmEventFlagsStr(flags)); + return; + } + else + printf(" ---\n"); + } + if ((flags & PM_EVENT_FLAG_MISSED) && + (idx == 1) && + (xvsp->pmid == pmid_missed)) { + printf(" ==> %d missed event records\n", + xvsp->vlist[0].value.lval); + return; + } + mydump(hp->name, &hp->desc, xvsp); +} + +static void +myeventdump(pmValueSet *vsp, int idx, int highres) +{ + int r; /* event records */ + int p; /* event parameters */ + int flags; + int numpmid; + int nrecords; + pmResult **res = NULL; + pmHighResResult **hres = NULL; + + if (highres) { + if ((nrecords = pmUnpackHighResEventRecords(vsp, idx, &hres)) < 0) { + printf(" pmUnpackEventRecords: %s\n", pmErrStr(nrecords)); + return; + } + } + else { + if ((nrecords = pmUnpackEventRecords(vsp, idx, &res)) < 0) { + printf(" pmUnpackEventRecords: %s\n", pmErrStr(nrecords)); + return; + } + } + printf(" %d event records\n", nrecords); + + if (pmid_flags == 0) { + /* + * get PMID for event.flags and event.missed + * note that pmUnpackEventRecords() will have called + * __pmRegisterAnon(), so the anonymous metrics + * should now be in the PMNS + */ + char *name_flags = "event.flags"; + char *name_missed = "event.missed"; + int sts; + + sts = pmLookupName(1, &name_flags, &pmid_flags); + if (sts < 0) { + /* should not happen! */ + fprintf(stderr, "Warning: cannot get PMID for %s: %s\n", + name_flags, pmErrStr(sts)); + /* avoid subsequent warnings ... */ + __pmid_int(&pmid_flags)->item = 1; + } + sts = pmLookupName(1, &name_missed, &pmid_missed); + if (sts < 0) { + /* should not happen! */ + fprintf(stderr, "Warning: cannot get PMID for %s: %s\n", + name_missed, pmErrStr(sts)); + /* avoid subsequent warnings ... */ + __pmid_int(&pmid_missed)->item = 1; + } + } + + for (r = 0; r < nrecords; r++) { + printf(" "); + if (highres) { + numpmid = hres[r]->numpmid; + __pmPrintHighResStamp(stdout, &hres[r]->timestamp); + } + else { + numpmid = res[r]->numpmid; + __pmPrintStamp(stdout, &res[r]->timestamp); + } + + printf(" --- event record [%d]", r); + if (numpmid == 0) { + printf(" ---\n"); + printf(" ==> No parameters\n"); + continue; + } + if (numpmid < 0) { + printf(" ---\n"); + printf(" Error: illegal number of parameters (%d)\n", numpmid); + continue; + } + flags = 0; + if (highres) { + for (p = 0; p < numpmid; p++) + myvaluesetdump(hres[r]->vset[p], p, &flags); + } + else { + for (p = 0; p < numpmid; p++) + myvaluesetdump(res[r]->vset[p], p, &flags); + } + } + if (highres) + pmFreeHighResEventResult(hres); + if (res) + pmFreeEventResult(res); +} + + +/*************************************************************************** + * main + ***************************************************************************/ +int +main(int argc, char **argv) +{ + pmResult *rp = NULL; /* current values */ + int forever; + int sts; + int j; + int m; + + __pmSetProgname(argv[0]); + setlinebuf(stdout); + + doargs(argc, argv); + + pmidlist = (pmID *)malloc(nmetric*sizeof(pmidlist[0])); + if (pmidlist == NULL) { + __pmNoMem("metrictab", nmetric*sizeof(pmidlist[0]), PM_FATAL_ERR); + /*NOTREACHED*/ + } + for (m = 0 ; m < nmetric; m++) + pmidlist[m] = metrictab[m].pmid; + + if (gui || port != -1) { + char *rpt_tz; + /* set up pmtime control */ + pmWhichZone(&rpt_tz); + pmtime = pmTimeStateSetup(&controls, ahtype, port, delta, now, + first, last, rpt_tz, host); + controls.stepped = timestep; + gui = 1; /* we're using pmtime control from here on */ + } + else if (ahtype == PM_CONTEXT_ARCHIVE) /* no time control, go it alone */ + pmTimeStateMode(amode, delta, &now); + + forever = (samples == ALL_SAMPLES || gui); + + printhdr(); + + /* wait till time for first sample */ + if (archive == NULL) + __pmtimevalPause(now); + + /* main loop fetching and printing sample values */ + while (forever || (samples-- > 0)) { + if (gui) + pmTimeStateVector(&controls, pmtime); + + /* wait till time for sample */ + if (!gui && archive == NULL) + __pmtimevalSleep(delta); + + /* next sample */ + sts = getvals(&rp); + if (gui) + pmTimeStateAck(&controls, pmtime); + + if (sts < 0) { + if (sts == PM_ERR_EOL && gui) { + pmTimeStateBounds(&controls, pmtime); + continue; + } + if (sts == PM_ERR_EOL) + break; + if (archive == NULL) + fprintf(stderr, "\n%s: pmFetch: %s\n", pmProgname, pmErrStr(sts)); + else + fprintf(stderr, "\n%s: pmFetchArchive: %s\n", pmProgname, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + + if ((double)rp->timestamp.tv_sec + (double)rp->timestamp.tv_usec/1000000 > + (double)last.tv_sec + (double)last.tv_usec/1000000) + break; + + for (j = 0; j < rp->numpmid; j++) { + for (m = 0; m < nmetric; m++) { + metric_t *mp = &metrictab[m]; + if (rp->vset[j]->pmid == mp->pmid) { + if (gui || archive != NULL) { + __pmPrintStamp(stdout, &rp->timestamp); + printf(" "); + } + if (rp->vset[j]->numval == 0) { + if (verbose) + printf("%s: No values available\n", mp->name); + } else if (rp->vset[j]->numval < 0) { + printf("%s: Error: %s\n", mp->name, pmErrStr(rp->vset[j]->numval)); + } else { + int highres = (mp->desc.type != PM_TYPE_EVENT); + int i; + + for (i = 0; i < rp->vset[j]->numval; i++) { + if (rp->vset[j]->vlist[i].inst == PM_IN_NULL) + printf("%s:", mp->name); + else { + int k; + char *iname = NULL; + if (mp->ninst > 0) { + for (k = 0; k < mp->ninst; k++) { + if (mp->inst[k] == rp->vset[j]->vlist[i].inst) { + iname = mp->iname[k]; + break; + } + } + } + else { + /* all instances selected */ + __pmHashNode *hnp; + hnp = __pmHashSearch((unsigned int)rp->vset[j]->vlist[i].inst, &mp->ihash); + if (hnp == NULL) { + if (archive != NULL) + sts = pmNameInDomArchive(mp->desc.indom, rp->vset[j]->vlist[i].inst, &iname); + else + sts = pmNameInDom(mp->desc.indom, rp->vset[j]->vlist[i].inst, &iname); + if (sts < 0) { + fprintf(stderr, "%s: pmNameInDom: %s[%d]: %s\n", pmProgname, mp->name, rp->vset[j]->vlist[i].inst, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + if ((sts = __pmHashAdd((unsigned int)rp->vset[j]->vlist[i].inst, (void *)iname, &mp->ihash)) < 0) { + printf("%s: __pmHashAdd: %s[%s (%d)]: %s\n", pmProgname, mp->name, iname, rp->vset[j]->vlist[i].inst, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + } + else + iname = (char *)hnp->data; + } + if (iname == NULL) + continue; + printf("%s[%s]:", mp->name, iname); + } + myeventdump(rp->vset[j], i, highres); + } + } + break; + } + } + } + pmFreeResult(rp); + } + + return 0; +} |