summaryrefslogtreecommitdiff
path: root/src/pmevent/pmevent.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2014-10-26 12:33:50 +0400
committerIgor Pashev <pashev.igor@gmail.com>2014-10-26 12:33:50 +0400
commit47e6e7c84f008a53061e661f31ae96629bc694ef (patch)
tree648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/pmevent/pmevent.c
downloadpcp-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.c531
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;
+}