summaryrefslogtreecommitdiff
path: root/src/pmevent
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
downloadpcp-debian/3.9.10.tar.gz
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmevent')
-rw-r--r--src/pmevent/GNUmakefile35
-rw-r--r--src/pmevent/doargs.c517
-rw-r--r--src/pmevent/pmevent.c531
-rw-r--r--src/pmevent/pmevent.h56
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;