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 | |
download | pcp-debian/3.9.10.tar.gz |
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmevent')
-rw-r--r-- | src/pmevent/GNUmakefile | 35 | ||||
-rw-r--r-- | src/pmevent/doargs.c | 517 | ||||
-rw-r--r-- | src/pmevent/pmevent.c | 531 | ||||
-rw-r--r-- | src/pmevent/pmevent.h | 56 |
4 files changed, 1139 insertions, 0 deletions
diff --git a/src/pmevent/GNUmakefile b/src/pmevent/GNUmakefile new file mode 100644 index 0000000..8efc8b4 --- /dev/null +++ b/src/pmevent/GNUmakefile @@ -0,0 +1,35 @@ +# +# Copyright (c) 2000,2004 Silicon Graphics, Inc. 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. +# + +TOPDIR = ../.. +include $(TOPDIR)/src/include/builddefs + +CFILES = pmevent.c doargs.c +HFILES = pmevent.h +LLDFLAGS = -L$(TOPDIR)/src/libpcp_gui/src +LLDLIBS = $(PCP_GUILIB) $(LIB_FOR_MATH) + +CMDTARGET = pmevent$(EXECSUFFIX) + +default: $(CMDTARGET) + +include $(BUILDRULES) + +install: $(CMDTARGET) + $(INSTALL) -m 755 $(CMDTARGET) $(PCP_BIN_DIR)/$(CMDTARGET) + +default_pcp: default + +install_pcp: install + diff --git a/src/pmevent/doargs.c b/src/pmevent/doargs.c new file mode 100644 index 0000000..0692c31 --- /dev/null +++ b/src/pmevent/doargs.c @@ -0,0 +1,517 @@ +/* + * 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. + */ + +#include "pmevent.h" + +static int setupEventTrace(int, char **, int, char *); +static char *options = "a:D:gh:K:LO:p:S:s:T:t:vx:zZ:?"; +static char usage[] = + "Usage: %s [options] metricname ...\n\n" + "Options:\n" + " -a archive metrics source is a PCP archive\n" + " -g start in GUI mode with new time control\n" + " -h host metrics source is PMCD on host\n" + " -K spec optional additional PMDA spec for local connection\n" + " spec is of the form op,domain,dso-path,init-routine\n" + " -L metrics source is a local context\n" + " -O offset initial offset into the reporting time window\n" + " -p port port number for connection to existing time control\n" + " -S starttime start of the reporting time window\n" + " -s samples terminate after this many samples\n" + " -T endtime end of the reporting time window\n" + " -t interval sample interval [default 1 second]\n" + " -v increase diagnostic output\n" + " -x filter optionally enable and filter the event stream\n" + " -Z timezone set reporting timezone\n" + " -z set reporting timezone to local timezone of metrics source\n"; + +/* process command line options and flags - exits on error */ +void +doargs(int argc, char **argv) +{ + int c; + long d; + int errflag = 0; + int m; + int src = 0; + int have_context = 0; + int sts; + char *endnum; + char *errmsg; + char *Sflag = NULL; /* argument of -S flag */ + char *Tflag = NULL; /* argument of -T flag */ + char *Oflag = NULL; /* argument of -O flag */ + char *xflag = NULL; /* argument of -x flag */ + int zflag = 0; /* for -z */ + char *tz = NULL; /* for -Z timezone */ + int tzh; /* initial timezone handle */ + struct timeval logStart; + metric_t *mp; + pmMetricSpec *msp; + char *msg; + static pmLogLabel label; + static char *default_host_conn = "local:"; + char *host_conn = default_host_conn; /* argument of -h */ + const char *tmp; + + delta.tv_sec = 1; + delta.tv_usec = 0; + samples = ALL_SAMPLES; + + /* extract command-line arguments */ + while ((c = getopt(argc, argv, options)) != EOF) { + switch (c) { + + case 'a': /* archive */ + if (++src > 1) { + fprintf(stderr, "%s: at most one of -a/-h/-L allowed\n", pmProgname); + errflag++; + } + ahtype = PM_CONTEXT_ARCHIVE; + archive = optarg; + break; + + case 'D': /* debug flag */ + sts = __pmParseDebug(optarg); + if (sts < 0) { + fprintf(stderr, "%s: unrecognized debug flag specification (%s)\n", + pmProgname, optarg); + errflag++; + } + else + pmDebug |= sts; + break; + + case 'g': /* use "gui" mode */ + if (port != -1) { + fprintf(stderr, "%s: at most one of -g and -p allowed\n", pmProgname); + errflag++; + } + else + gui = 1; + break; + + case 'h': /* host name */ + if (++src > 1) { + fprintf(stderr, "%s: at most one of -a/-h/-L allowed\n", pmProgname); + errflag++; + } + ahtype = PM_CONTEXT_HOST; + host_conn = optarg; + break; + + case 'K': /* update local PMDA table */ + if ((errmsg = __pmSpecLocalPMDA(optarg)) != NULL) { + fprintf(stderr, "%s: illegal -K argument\n", pmProgname); + fputs(errmsg, stderr); + fputc('\n', stderr); + errflag++; + } + break; + + case 'L': /* use local context */ + if (++src > 1) { + fprintf(stderr, "%s: at most one of -a/-h/-L allowed\n", pmProgname); + errflag++; + } + ahtype = PM_CONTEXT_LOCAL; + break; + + case 'O': /* start report time offset */ + Oflag = optarg; + break; + + case 'p': /* port for slave of existing time control */ + if (gui == 1) { + fprintf(stderr, "%s: at most one of -g and -p allowed\n", pmProgname); + errflag++; + } + else { + port = (int)strtol(optarg, &endnum, 10); + if (*endnum != '\0' || port < 0) { + fprintf(stderr, "%s: -p requires a positive numeric argument\n", pmProgname); + port = -1; + errflag++; + } + } + break; + + case 's': /* sample count */ + d = (int)strtol(optarg, &endnum, 10); + if (Tflag) { + fprintf(stderr, "%s: at most one of -s and -T allowed\n", pmProgname); + errflag++; + } + else if (*endnum != '\0' || d < 0) { + fprintf(stderr, "%s: -s requires a positive numeric argument\n", pmProgname); + errflag++; + } + else + samples = d; + break; + + case 'S': /* start report time */ + Sflag = optarg; + break; + + case 't': /* sampling interval */ + if (pmParseInterval(optarg, &delta, &msg) < 0) { + fprintf(stderr, "%s: illegal -t argument\n", pmProgname); + fputs(msg, stderr); + free(msg); + errflag++; + } + break; + + case 'T': /* end reporting time */ + if (samples != ALL_SAMPLES) { + fprintf(stderr, "%s: at most one of -s and -T allowed\n", pmProgname); + errflag++; + } + Tflag = optarg; + break; + + case 'v': + verbose++; + break; + + case 'x': + xflag = optarg; + break; + + case 'z': /* timezone from metrics source */ + if (tz != NULL) { + fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); + errflag++; + } + zflag++; + break; + + case 'Z': /* $TZ timezone */ + if (zflag) { + fprintf(stderr, "%s: at most one of -Z and/or -z allowed\n", pmProgname); + errflag++; + } + tz = optarg; + break; + + case '?': + fprintf(stderr, usage, pmProgname); + exit(EXIT_FAILURE); + + default: + errflag++; + } + } + + if (errflag) { + fprintf(stderr, usage, pmProgname); + exit(EXIT_FAILURE); + } + + if (optind >= argc) { + fprintf(stderr, "Error: no metricname specified\n"); + exit(EXIT_FAILURE); + } + + /* parse uniform metric spec */ + for ( ; optind < argc; optind++) { + if (ahtype == PM_CONTEXT_ARCHIVE) + sts = pmParseMetricSpec(argv[optind], 1, archive, &msp, &msg); + else + sts = pmParseMetricSpec(argv[optind], 0, host_conn, &msp, &msg); + if (sts < 0) { + fprintf(stderr, "%s: bad metric specification\n", pmProgname); + fputs(msg, stderr); + free(msg); + exit(EXIT_FAILURE); + } + + if (msp->isarch == 0) { + if (ahtype == -1) { + ahtype = PM_CONTEXT_HOST; + host_conn = msp->source; + } + else if ((ahtype == PM_CONTEXT_ARCHIVE) || + (ahtype == PM_CONTEXT_LOCAL && + (strcmp(msp->source, default_host_conn)))) { + fprintf(stderr, "%s: %s: only one type of metric source allowed\n", pmProgname, argv[optind]); + exit(EXIT_FAILURE); + } + else if (strcmp(host_conn, msp->source) != 0) { + fprintf(stderr, "%s: %s: only one metric source allowed, found hosts %s and %s\n", pmProgname, argv[optind], host_conn, msp->source); + exit(EXIT_FAILURE); + } + } + else if (msp->isarch == 1) { + if (ahtype == -1) { + ahtype = PM_CONTEXT_ARCHIVE; + archive = msp->source; + } + else if (ahtype != PM_CONTEXT_ARCHIVE) { + fprintf(stderr, "%s: %s: only one type of metric source allowed\n", pmProgname, argv[optind]); + exit(EXIT_FAILURE); + } + else if (strcmp(archive, msp->source) != 0) { + fprintf(stderr, "%s: %s: only one metric source allowed, found archives %s and %s\n", pmProgname, argv[optind], archive, msp->source); + exit(EXIT_FAILURE); + } + } + else if (msp->isarch == 2) { + if (ahtype == -1) { + ahtype = PM_CONTEXT_LOCAL; + } + else if (ahtype != PM_CONTEXT_LOCAL) { + fprintf(stderr, "%s: %s: only one type of metric source allowed\n", pmProgname, argv[optind]); + exit(EXIT_FAILURE); + } + } + + if (!have_context) { + if (ahtype == PM_CONTEXT_ARCHIVE) { + /* open connection to archive */ + if ((sts = pmNewContext(PM_CONTEXT_ARCHIVE, archive)) < 0) { + fprintf(stderr, "%s: Cannot open archive \"%s\": %s\n", + pmProgname, msp->source, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + ctxhandle = sts; + if ((sts = pmGetArchiveLabel(&label)) < 0) { + fprintf(stderr, "%s: Cannot get archive label record: %s\n", + pmProgname, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + have_context = 1; + logStart = label.ll_start; + host = label.ll_hostname; + if ((sts = pmGetArchiveEnd(&last)) < 0) { + fprintf(stderr, "%s: Cannot determine end of archive: %s", + pmProgname, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + } + else { + /* open connection to host or local context */ + if ((sts = pmNewContext(ahtype, host_conn)) < 0) { + if (ahtype == PM_CONTEXT_HOST) + fprintf(stderr, "%s: Cannot connect to PMCD on host \"%s\": %s\n", + pmProgname, msp->source, pmErrStr(sts)); + else + fprintf(stderr, "%s: Cannot establish local context: %s\n", + pmProgname, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + ctxhandle = sts; + have_context = 1; + __pmtimevalNow(&logStart); + } + } + + /* Look up the host name according to the pmcd or the archive. */ + tmp = pmGetContextHostName(ctxhandle); + if (strlen(tmp) == 0) { + fprintf(stderr, "%s: pmGetContextHostName(%d) failed\n", + pmProgname, ctxhandle); + exit(EXIT_FAILURE); + } + if ((host = strdup(tmp)) == NULL) + __pmNoMem("host name copy", strlen(tmp)+1, PM_FATAL_ERR); + + for (m = 0; m < nmetric; m++) { + if (strcmp(msp->metric, metrictab[m].name) == 0) + break; + } + if (m < nmetric) + mp = &metrictab[m]; + else { + nmetric++; + metrictab = (metric_t *)realloc(metrictab, nmetric*sizeof(metrictab[0])); + if (metrictab == NULL) { + __pmNoMem("metrictab", nmetric*sizeof(metrictab[0]), PM_FATAL_ERR); + /*NOTREACHED*/ + } + mp = &metrictab[nmetric-1]; + mp->name = msp->metric; + if ((sts = pmLookupName(1, &mp->name, &mp->pmid)) < 0) { + fprintf(stderr, "%s: pmLookupName: %s: %s\n", pmProgname, mp->name, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + if ((sts = pmLookupDesc(mp->pmid, &mp->desc)) < 0) { + fprintf(stderr, "%s: pmLookupDesc: %s: %s\n", pmProgname, mp->name, pmErrStr(sts)); + exit(EXIT_FAILURE); + } + if (mp->desc.type != PM_TYPE_EVENT && + mp->desc.type != PM_TYPE_HIGHRES_EVENT) { + fprintf(stderr, "%s: %s: metrics must be of event type\n", pmProgname, mp->name); + exit(EXIT_FAILURE); + } + mp->ninst = 0; + mp->iname = NULL; + mp->inst = NULL; + mp->ihash.nodes = 0; + mp->ihash.hsize = 0; + mp->ihash.hash = NULL; + } + + if (msp->ninst > 0) { + int i; + int j; + if (mp->desc.indom == PM_INDOM_NULL) { + fprintf(stderr, "%s: %s: singular metrics do not have instances\n", pmProgname, argv[optind]); + exit(EXIT_FAILURE); + } + i = mp->ninst; + mp->ninst += msp->ninst; + mp->iname = (char **)realloc(mp->iname, mp->ninst*sizeof(mp->iname[0])); + if (mp->iname == NULL) { + __pmNoMem("iname[]", mp->ninst*sizeof(mp->iname[0]), PM_FATAL_ERR); + /*NOTREACHED*/ + } + mp->inst = (int *)realloc(mp->inst, mp->ninst*sizeof(mp->inst[0])); + if (mp->inst == NULL) { + __pmNoMem("inst[]", mp->ninst*sizeof(mp->inst[0]), PM_FATAL_ERR); + /*NOTREACHED*/ + } + for (j = 0; j < msp->ninst; j++, i++) { + mp->iname[i] = msp->inst[j]; + if (ahtype == PM_CONTEXT_ARCHIVE) + sts = pmLookupInDomArchive(mp->desc.indom, mp->iname[i]); + else + sts = pmLookupInDom(mp->desc.indom, mp->iname[i]); + if (sts < 0) { + fprintf(stderr, "%s: pmLookupInDom: %s[%s]: %s\n", pmProgname, mp->name, mp->iname[i], pmErrStr(sts)); + exit(EXIT_FAILURE); + } + mp->inst[i] = sts; + } + } + + /* + * don't call pmFreeMetricSpec(msp) because we retain pointers into + * the structure + */ + } + + if (zflag) { + if ((tzh = pmNewContextZone()) < 0) { + fprintf(stderr, "%s: Cannot set context timezone: %s\n", + pmProgname, pmErrStr(tzh)); + exit(EXIT_FAILURE); + } + if (ahtype == PM_CONTEXT_ARCHIVE) { + printf("Note: timezone set to local timezone of host \"%s\" from archive\n\n", + host); + } + else { + printf("Note: timezone set to local timezone of host \"%s\"\n\n", host); + } + } + else if (tz != NULL) { + if ((tzh = pmNewZone(tz)) < 0) { + fprintf(stderr, "%s: Cannot set timezone to \"%s\": %s\n", + pmProgname, tz, pmErrStr(tzh)); + exit(EXIT_FAILURE); + } + printf("Note: timezone set to \"TZ=%s\"\n\n", tz); + } + + if (pmParseTimeWindow(Sflag, Tflag, NULL, Oflag, + &logStart, &last, &first, &last, &now, &msg) < 0) { + fprintf(stderr, "%s", msg); + exit(EXIT_FAILURE); + } + + if (setupEventTrace(argc, argv, ahtype, xflag) < 0) + exit(EXIT_FAILURE); + + if (pmDebug & DBG_TRACE_APPL0) { + char timebuf[26]; + char *tp; + int i; + fprintf(stderr, "first=%.6f", __pmtimevalToReal(&first)); + tp = pmCtime(&first.tv_sec, timebuf); + /* + * tp -> Ddd Mmm DD HH:MM:SS YYYY\n + * 0 4 8 1 1 2 2 2 + * 1 8 0 3 4 + */ + fprintf(stderr, " [%24.24s]\n", tp); + fprintf(stderr, "now=%.6f", __pmtimevalToReal(&now)); + tp = pmCtime(&now.tv_sec, timebuf); + fprintf(stderr, " [%24.24s]\n", tp); + fprintf(stderr, "last=%.6f", __pmtimevalToReal(&last)); + tp = pmCtime(&last.tv_sec, timebuf); + fprintf(stderr, " [%24.24s]\n", tp); + fprintf(stderr, "delta=%.6f\n", __pmtimevalToReal(&delta)); + if (samples != ALL_SAMPLES) + fprintf(stderr, "samples=%ld\n", samples); + for (m = 0; m < nmetric; m++) { + fprintf(stderr, "[%d] metric: %s", m, metrictab[m].name); + if (metrictab[m].ninst > 0) { + fprintf(stderr, " instance:"); + for (i = 0; i < metrictab[m].ninst; i++) { + if (i == 0) + fputc(' ', stderr); + else + fprintf(stderr, ", "); + fprintf(stderr, "%s (%d)", metrictab[m].iname[i], metrictab[m].inst[i]); + } + fputc('\n', stderr); + } + } + } +} + +int +setupEventTrace(int argc, char **argv, int ahtype, char *xflag) +{ + pmValueSet pmvs; + pmValueBlock *pmvbp; + pmResult store = { .numpmid = 1 }; + int m, vlen; + + if (ahtype == PM_CONTEXT_ARCHIVE) + return 0; /* nothing to do at this stage */ + + if (ahtype == PM_CONTEXT_HOST) + __pmSetClientIdArgv(argc, argv); + + /* build pmResult for pmStore call if we're explicitly enabling events */ + if (xflag != NULL) { + vlen = PM_VAL_HDR_SIZE + strlen(xflag) + 1; + pmvbp = (pmValueBlock *)malloc(vlen); + if (!pmvbp) + __pmNoMem("store", vlen, PM_FATAL_ERR); + pmvbp->vtype = PM_TYPE_STRING; + pmvbp->vlen = vlen; + strcpy(pmvbp->vbuf, xflag); + + store.vset[0] = &pmvs; + for (m = 0; m < nmetric; m++) { + pmvs.pmid = metrictab[m].pmid; + pmvs.numval = 1; + pmvs.valfmt = PM_VAL_SPTR; + pmvs.vlist[0].inst = PM_IN_NULL; + pmvs.vlist[0].value.pval = pmvbp; + + pmStore(&store); + } + + free(pmvbp); + } + return 0; +} 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; +} diff --git a/src/pmevent/pmevent.h b/src/pmevent/pmevent.h new file mode 100644 index 0000000..c0d234a --- /dev/null +++ b/src/pmevent/pmevent.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +#include "pmapi.h" +#include "impl.h" +#include "pmtime.h" + +#define ALL_SAMPLES -1 + +/* performance metrics from the command line */ +typedef struct { + char *name; /* name of metric */ + pmID pmid; /* metric identifier */ + pmDesc desc; /* metric description */ + int ninst; /* number of instances, 0 for all instances */ + char **iname; /* instance names */ + int *inst; /* instance ids */ + __pmHashCtl ihash; /* mapping when all instances requested */ +} metric_t; + +void doargs(int, char **); + +/* + * globals ... see declarations in pmevent.c for explanations + */ +extern char *host; /* as per pmGetContextHostName */ +extern char *archive; +extern int ahtype; +extern int ctxhandle; +extern int verbose; +extern struct timeval now; +extern struct timeval first; +extern struct timeval last; +extern struct timeval delta; +extern long samples; +extern int gui; +extern int port; +extern pmTimeControls controls; + +extern metric_t *metrictab; +extern int nmetric; +extern pmID *pmidlist; |