diff --git a/src/pmval/pmval.c b/src/pmval/pmval.c index 8c95eb8..af6fdd5 100644 --- a/src/pmval/pmval.c +++ b/src/pmval/pmval.c @@ -3,6 +3,7 @@ * * Copyright (c) 1995-2001 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2008-2009 Aconex. All Rights Reserved. + * Copyright (c) 2011 Red Hat Inc. * * 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 @@ -26,7 +27,7 @@ #define ALL_SAMPLES -1 -static char *options = "A:a:D:df:gh:i:K:n:O:p:rs:S:t:T:U:w:zZ:?"; +static char *options = "A:a:D:df:gh:i:K:n:O:p:rs:S:t:T:U:w:xzZ:?"; static char usage[] = "Usage: %s [options] metricname\n\n" "Options:\n" @@ -52,6 +53,7 @@ static char usage[] = " -U archive metrics source is a PCP log archive (do not interpolate\n" " and -t option ignored)\n" " -w width set the width of each column of output\n" + " -x expand event records\n" " -Z timezone set reporting timezone\n" " -z set reporting timezone to local time of metrics source\n"; @@ -108,6 +110,7 @@ static pmTime *pmtime; static pmTimeControls controls; static struct timeval last = {INT_MAX, 999999}; /* end time for log */ static int fixed = -1; +static int xflag; /* for -x */ /*************************************************************************** * processing fetched values @@ -370,6 +373,7 @@ howide(int type) case PM_TYPE_DOUBLE: return 21; case PM_TYPE_STRING: return 21; case PM_TYPE_AGGREGATE: return 21; + case PM_TYPE_EVENT: return 21; default: fprintf(stderr, "pmval: unknown performance metric value type %s\n", pmTypeStr(type)); exit(EXIT_FAILURE); @@ -549,6 +553,199 @@ printreal(double v, int minwidth) } } +/* + * stolen from pmval.c ... 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); + } + numinst = pmGetInDom(indom, &instlist, &namelist); + last = indom; + } + + for (i = 0; i < numinst; i++) { + if (instlist[i] == inst) + return namelist[i]; + } + + return NULL; +} + +static void myeventdump(pmValueSet *vsp); + +/* + * stolen from pmval.c ... we only ever have one metric + */ +static void +mydump(pmDesc *dp, pmValueSet *vsp, char *indent) +{ + int j; + char *p; + + if (indent != NULL) + printf("%s", indent); + if (vsp->numval == 0) { + printf("No value(s) available!\n"); + return; + } + else if (vsp->numval < 0) { + printf("Error: %s\n", pmErrStr(vsp->numval)); + return; + } + + for (j = 0; j < vsp->numval; j++) { + pmValue *vp = &vsp->vlist[j]; + if (dp->indom != PM_INDOM_NULL) { + if ((p = lookup(dp->indom, vp->inst)) == NULL) { +/* For now, always report the error and give up if the instance disappeared. */ +#if 0 + if (p_force) { + /* the instance disappeared; ignore it */ + printf(" inst [%d \"%s\"]\n", vp->inst, "DISAPPEARED"); + continue; + } + else { +#endif + /* report the error and give up */ + printf("pmNameIndom: indom=%s inst=%d: %s\n", + pmInDomStr(dp->indom), vp->inst, pmErrStr(PM_ERR_INST)); + printf(" inst [%d]", vp->inst); +#if 0 + } +#endif + } + else + printf(" inst [%d or \"%s\"]", vp->inst, p); + } + else + printf(" "); + printf(" value "); + pmPrintValue(stdout, vsp->valfmt, dp->type, vp, 1); + putchar('\n'); + if (dp->type == PM_TYPE_EVENT && xflag) + myeventdump(vsp); + } +} + +/* + * stolen from pmval.c ... + */ + +static void +myeventdump(pmValueSet *vsp) +{ + int r; /* event records */ + int p; /* event parameters */ + int nrecords; + int flags; + pmResult **res; + static pmID pmid_flags; + static pmID pmid_missed; + + nrecords = pmUnpackEventRecords(vsp, &res); + if (nrecords < 0) { + fprintf(stderr, "pmUnpackEventRecords: %s\n", pmErrStr(nrecords)); + return; + } + + 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(" --- event record [%d] timestamp ", r); + __pmPrintStamp(stdout, &res[r]->timestamp); + if (res[r]->numpmid == 0) { + printf(" ---\n"); + printf(" No parameters\n"); + continue; + } + if (res[r]->numpmid < 0) { + printf(" ---\n"); + printf(" Error: illegal number of parameters (%d)\n", + res[r]->numpmid); + continue; + } + flags = 0; + for (p = 0; p < res[r]->numpmid; p++) { + pmValueSet *xvsp = res[r]->vset[p]; + int sts; + pmDesc desc; + char *name; + + if (pmNameID(xvsp->pmid, &name) >= 0) { + if (p == 0) { + if (xvsp->pmid == pmid_flags) { + flags = xvsp->vlist[0].value.lval; + printf(" flags 0x%x", flags); + printf(" (%s) ---\n", pmEventFlagsStr(flags)); + free(name); + continue; + } + else + printf(" ---\n"); + } + if ((flags & PM_EVENT_FLAG_MISSED) && + (p == 1) && + (xvsp->pmid == pmid_missed)) { + printf(" ==> %d missed event records\n", + xvsp->vlist[0].value.lval); + free(name); + continue; + } + printf(" %s (%s)\n", name, pmIDStr(xvsp->pmid)); + free(name); + } + else + printf(" PMID: %s\n", pmIDStr(xvsp->pmid)); + if ((sts = pmLookupDesc(xvsp->pmid, &desc)) < 0) { + printf(" pmLookupDesc: %s\n", pmErrStr(sts)); + continue; + } + mydump(&desc, xvsp, " "); + } + } + if (nrecords >= 0) + pmFreeEventResult(res); +} + /* Print performance metric values */ static void printvals(Context *x, pmValueSet *vset, int cols) @@ -567,8 +764,13 @@ printvals(Context *x, pmValueSet *vset, int cols) pmExtractValue(vset->valfmt, &vset->vlist[0], x->desc.type, &av, PM_TYPE_DOUBLE); printreal(av.d, cols); } - else + else { pmPrintValue(stdout, vset->valfmt, x->desc.type, &vset->vlist[0], cols); + if (x->desc.type == PM_TYPE_EVENT && xflag) { + putchar('\n'); + myeventdump(vset); + } + } } else @@ -588,8 +790,13 @@ printvals(Context *x, pmValueSet *vset, int cols) pmExtractValue(vset->valfmt, &vset->vlist[j], x->desc.type, &av, PM_TYPE_DOUBLE); printreal(av.d, cols); } - else + else { pmPrintValue(stdout, vset->valfmt, x->desc.type, &vset->vlist[j], cols); + if (x->desc.type == PM_TYPE_EVENT && xflag) { + putchar('\n'); + myeventdump(vset); + } + } } else printf("%*s", cols, "?"); @@ -608,8 +815,13 @@ printvals(Context *x, pmValueSet *vset, int cols) pmExtractValue(vset->valfmt, &vset->vlist[j], x->desc.type, &av, PM_TYPE_DOUBLE); printreal(av.d, 1); } - else + else { pmPrintValue(stdout, vset->valfmt, x->desc.type, &vset->vlist[j], 1); + if (x->desc.type == PM_TYPE_EVENT && xflag) { + putchar('\n'); + myeventdump(vset); + } + } printf(", but instance=%d is unknown\n", vset->vlist[j].inst); } } @@ -965,6 +1177,10 @@ getargs(int argc, /* in - command line argument count */ else *cols = d; break; + case 'x': + xflag = 1; + break; + case 'z': /* timezone from host */ if (tz != NULL) { fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); @@ -1218,8 +1434,8 @@ main(int argc, char *argv[]) getargs(argc, argv, &cntxt, &now, &delta, &smpls, &cols); - if (cntxt.desc.type == PM_TYPE_EVENT) { - fprintf(stderr, "%s: Cannot display values for PM_TYPE_EVENT metrics\n", + if (cntxt.desc.type == PM_TYPE_EVENT && xflag == 0) { + fprintf(stderr, "%s: Cannot display values for PM_TYPE_EVENT metrics without -x\n", pmProgname); exit(EXIT_FAILURE); }