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/pmlc/util.c | |
download | pcp-debian/3.9.10.tar.gz |
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmlc/util.c')
-rw-r--r-- | src/pmlc/util.c | 546 |
1 files changed, 546 insertions, 0 deletions
diff --git a/src/pmlc/util.c b/src/pmlc/util.c new file mode 100644 index 0000000..30e3881 --- /dev/null +++ b/src/pmlc/util.c @@ -0,0 +1,546 @@ +/* + * Copyright (c) 1995-2002 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "pmapi.h" +#include "impl.h" +#include "pmlc.h" + +/* this pmResult is built after parsing the current statement. The action + * routines (Status, LogReq) send it to the logger as a request. + */ +pmResult *logreq = NULL; +int sz_logreq = 0; +int n_logreq = 0; + +int n_metrics = 0; +int sz_metrics = 0; +metric_t *metric = NULL; + +int n_indoms = 0; +int sz_indoms = 0; +indom_t *indom = NULL; + +void +freemetrics(void) +{ + int i; + metric_t *mp; + + for (i = 0, mp = metric; i < n_metrics; i++, mp++) { + free(mp->name); + if (mp->status.has_insts && mp->inst != NULL) + free(mp->inst); + } + n_metrics = 0; + /* keep the array around for re-use */ +} + +void +freeindoms(void) +{ + int i; + indom_t *ip; + + for (i = 0, ip = indom; i < n_indoms; i++, ip++) { + free(ip->inst); + free(ip->name); + } + free(indom); + sz_indoms = n_indoms = 0; + indom = NULL; +} + +/* Return a pointer to the specified instance domain, adding it to the list if + * it is not already present. Returns < 0 on error. + */ +int +addindom(pmInDom newindom, int *resptr) +{ + int i; + indom_t *ip; + + for (i = 0; i < n_indoms; i++) + if (newindom == indom[i].indom) { + *resptr = i; + return 0; + } + + *resptr = -1; /* in case of errors */ + if (n_indoms >= sz_indoms) { + sz_indoms += 4; + i = sz_indoms * sizeof(indom_t); + if ((indom = (indom_t *)realloc(indom, i)) == NULL) { + __pmNoMem("expanding instance domain array", i, PM_FATAL_ERR); + } + } + ip = &indom[n_indoms]; + ip->inst = NULL; + ip->name = NULL; + + if ((i = pmGetInDom(newindom, &ip->inst, &ip->name)) < 0) { + *resptr = -1; + return i; + } + ip->indom = newindom; + ip->n_insts = i; + *resptr = n_indoms; + n_indoms++; + return 0; +} + +int metric_cnt; /* status of addmetric operation(s) */ +static int had_insts; /* new metric(s) had instances specified */ +static int n_selected; /* number of metrics selected */ +static int first_inst; /* check consistency of new metrics' InDoms */ + +void +beginmetrics(void) +{ + metric_cnt = 0; + fflush(stdout); + fflush(stderr); + freemetrics(); +} + +void +beginmetgrp(void) +{ + int i; + metric_t *mp; + + had_insts = 0; + n_selected = 0; + first_inst = 1; + for (i = 0, mp = metric; i < n_metrics; i++, mp++) { + mp->status.selected = 0; + mp->status.new = 0; + } +} + +/* Perform any instance domain fixups and error checks required for the latest + * metrics added. + */ +void +endmetgrp(void) +{ + int i; + metric_t *mp; + + if (n_metrics <= 0) { + if (metric_cnt >= 0) + metric_cnt = PM_ERR_PMID; + return; + } + + for (i = 0, mp = metric; i < n_metrics; i++, mp++) { + if (!mp->status.selected) + continue; + + /* just added metric, no instances => use all instances */ + if (mp->status.new) { + if (mp->indom != -1 && !had_insts) { + mp->n_insts = indom[mp->indom].n_insts; + mp->inst = indom[mp->indom].inst; + mp->status.has_insts = 0; + } + } + /* metric was there already */ + else + if (mp->indom == -1) + fprintf(stderr, "Warning: %s has already been specified\n", mp->name); + else + /* if metric had specific instances */ + if (mp->status.has_insts) { + if (!had_insts) { + fprintf(stderr, + "Warning: %s had instance(s) specified previously.\n" + " Using all instances since none specified this time\n", + mp->name); + if (mp->inst != NULL) + free(mp->inst); + mp->n_insts = indom[mp->indom].n_insts; + mp->inst = indom[mp->indom].inst; + mp->status.has_insts = 0; + } + } + /* metric had "use all instances" */ + else + if (!had_insts) + fprintf(stderr, + "Warning: already using all instances for %s\n", + mp->name); + else + fprintf(stderr, + "Warning: instance(s) specified for %s\n" + " (already using all instances)\n", + mp->name); + } +} + +void +endmetrics(void) +{ + int i, j, need; + metric_t *mp; + pmValueSet *vsp; + + if (metric_cnt < 0) { + if (connected()) + fputs("Logging statement ignored due to error(s)\n", stderr); + goto done; + } + +#ifdef PCP_DEBUG + if (pmDebug & DBG_TRACE_APPL0) + dumpmetrics(stdout); +#endif + + /* free any old values in the reusable pmResult skeleton */ + if (n_logreq) { + for (i = 0; i < n_logreq; i++) + free(logreq->vset[i]); + n_logreq = 0; + } + + /* build a result from the metrics and instances in the metric array */ + if (n_metrics > sz_logreq) { + if (sz_logreq) + free(logreq); + need = sizeof(pmResult) + (n_metrics - 1) * sizeof(pmValueSet *); + /* - 1 because a pmResult already contains one pmValueSet ptr */ + if ((logreq = (pmResult *)malloc(need)) == NULL) { + __pmNoMem("building result to send", need, PM_FATAL_ERR); + } + sz_logreq = n_metrics; + } + for (i = 0, mp = metric; i < n_metrics; i++, mp++) { + need = sizeof(pmValueSet); + /* pmValueSet contains one pmValue, allow for more if > 1 inst */ + if (mp->status.has_insts && mp->n_insts > 1) + need += (mp->n_insts - 1) * sizeof(pmValue); + if ((vsp = (pmValueSet *)malloc(need)) == NULL) { + __pmNoMem("building result value set", need , PM_FATAL_ERR); + } + logreq->vset[i] = vsp; + vsp->pmid = mp->pmid; + if (mp->indom == -1) + vsp->numval = 1; + else + vsp->numval = mp->status.has_insts ? mp->n_insts : 0; + vsp->valfmt = PM_VAL_INSITU; + if (mp->status.has_insts) + for (j = 0; j < vsp->numval; j++) + vsp->vlist[j].inst = mp->inst[j]; + else + vsp->vlist[0].inst = PM_IN_NULL; + } + logreq->numpmid = n_metrics; + n_logreq = n_metrics; + +done: + fflush(stderr); + fflush(stdout); +} + +/* Add a metric to the metric list. Sets metric_cnt to < 0 on fatal error. */ + +void +addmetric(const char *name) +{ + int i; + pmID pmid; + int need; + metric_t *mp; + pmDesc desc; + int sts; + + if (metric_cnt < 0) + return; + + /* Cast const away as pmLookUpName should not modify name */ + if ((sts = pmLookupName(1, (char **)&name, &pmid)) < 0) { + metric_cnt = sts; + return; + } + + for (i = 0, mp = metric; i < n_metrics; i++, mp++) + if (pmid == mp->pmid) + break; + + if (i >= n_metrics) { + /* expand metric array if necessary */ + if (n_metrics >= sz_metrics) { + sz_metrics += 4; + need = sz_metrics * sizeof(metric_t); + if ((metric = (metric_t *)realloc(metric, need)) == NULL) { + __pmNoMem("expanding metric array", need, PM_FATAL_ERR); + } + } + mp = &metric[i]; + mp->status.new = 1; + } + mp->status.selected = 1; + n_selected++; + if (i < n_metrics) /* already have this metric */ + return; + + if ((sts = pmLookupDesc(pmid, &desc)) == PM_ERR_PMID + || desc.type == PM_TYPE_NOSUPPORT) { + /* + * Name is bad or descriptor is not available ... + * this is not fatal, but need to back off a little + */ + n_selected--; + return; + } + if (sts < 0) { + /* other errors are more serious */ + metric_cnt = sts; + return; + } + if (desc.indom == PM_INDOM_NULL) + i = -1; + else + if ((metric_cnt = addindom(desc.indom, &i)) < 0) + return; + + mp->name = strdup(name); + mp->pmid = pmid; + mp->indom = i; + mp->n_insts = 0; + mp->inst = NULL; + mp->status.has_insts = 0; + metric_cnt = ++n_metrics; + return; +} + +/* Add an instance to the selected metric(s) on the metric list. + * If name is NULL, use instance number in inst. + * Check that + * - the last group of metrics added have the same pmInDom + * - the specified instance exists in the metrics' instance domain. + */ +void +addinst(char *name, int instid) +{ + metric_t *mp, *first_mp; + indom_t *ip; + int m, i, j, need; + int inst; + static int done_inst_msg = 0; + + /* don't try to add instances if one more metrics were erroneous */ + if (metric_cnt < 0) + return; + + had_insts = 1; + + /* Find the first selected metric */ + for (m = 0, mp = metric; m < n_metrics; m++, mp++) + if (mp->status.selected) + break; +#ifdef PCP_DEBUG + if (m >= n_metrics) { + fprintf(stderr, "Ark! No metrics selected for addinst(%s)\n", name); + abort(); + } +#endif + first_mp = mp; + + if (first_inst) { + /* check that the first metric doesn't have PM_INDOM_NULL */ + if (mp->indom == -1) { + metric_cnt = PM_ERR_INDOM; + fprintf(stderr, "%s has no instance domain but an instance was specified\n", + mp->name); + return; + } + + /* check that all of the metrics have the same instance domain */ + if (n_selected > 1) { + i = 0; + for (i++, mp++; m < n_metrics; m++, mp++) { + if (!mp->status.selected) + continue; + + /* check pointers to indoms; PM_INDOM_NULL has -1 */ + if (first_mp->indom != mp->indom) { + if (i++ == 0) { + fprintf(stderr, + "The instance domains for the following metrics clash with %s:\n", + first_mp->name); + metric_cnt = PM_ERR_INDOM; + } + if (i < 5) { /* elide any domain errors after this */ + fputs(mp->name, stderr); + putc('\n', stderr); + } + else { + fputs("(etc.)\n", stderr); + break; + } + } + } + if (i) + return; + } + first_inst = 0; + } + + mp = first_mp; /* go back to first selected metric */ + ip = &indom[mp->indom]; + for (i = 0; i < ip->n_insts; i++) + if (name != NULL) { + if (strcasecmp(name, ip->name[i]) == 0) + break; + } + else + if (instid == ip->inst[i]) + break; + + for ( ; m < n_metrics; m++, mp++) { + if (!mp->status.selected) + continue; + + /* check that metric with explicit instances has the specified inst. + * For those metrics that specify "all instances" an instance not there yet + * is OK (but generates a warning) since we don't need to give pmlogger any + * instance ids. + * For metrics with specific instances, an unknown instance is an error + * since the instance id can't be given to pmlogger. + */ + if (i >= ip->n_insts) { + if (mp->status.has_insts || mp->status.new) { + metric_cnt = PM_ERR_INST; + if (name != NULL) + fprintf(stderr, "%s currently has no instance named %s\n", mp->name, name); + else + fprintf(stderr, "%s currently has no instance number %d\n", mp->name, instid); + if (!done_inst_msg) { + fputs(" - you may only specify metric instances active now. However if no\n" + " instances are specified, pmlogger will use all of the instances\n" + " available at the time the metric is logged\n", + stderr); + done_inst_msg = 1; + } + } + /* for an old metric specifying all instances warn if the specified + * instance is not currently in the instance domain. + */ + else { + if (name != NULL) + fprintf(stderr, + "Warning: instance %s not currently in %s's instance domain\n", + name, mp->name); + else + fprintf(stderr, + "Warning: instance %d not currently in %s's instance domain\n", + instid, mp->name); + fputs(" (getting all instances anyway)\n", stderr); + } + continue; + } + inst = ip->inst[i]; + + /* check that we don't already have the same instance */ + for (j = 0; j < mp->n_insts; j++) + if (inst == mp->inst[j]) + break; + + if (j < mp->n_insts) { /* already have inst */ + if (mp->status.has_insts) { + if (name != NULL) { + fprintf(stderr, + "Warning: instance %s already specified for %s\n", + name, mp->name); + } + else { + fprintf(stderr, + "Warning: instance %d already specified for %s\n", + instid, mp->name); + } + } + + /* if the metric had no insts of its own, (it specifies all insts) + * just do nothing. endmetgrp() will print a single message which + * is better than having, one printed for each instance specified. + */ + continue; + } + + else { /* don't have this inst */ + /* add inst for new metric or old metric with explicit insts */ + if (mp->status.new || mp->status.has_insts) { + j = mp->n_insts++; + if (j == 0) + mp->status.has_insts = 1; + need = mp->n_insts * sizeof(int); + if ((mp->inst = (int *)realloc(mp->inst, need)) == NULL) { + if (name != NULL) + fprintf(stderr, "%s inst %s: ", mp->name, name); + else + fprintf(stderr, "%s inst %d: ", mp->name, instid); + __pmNoMem("expanding instance array", need, PM_FATAL_ERR); + } + mp->inst[j] = inst; + } + } + } +} + +#ifdef PCP_DEBUG +void +dumpmetrics(FILE *f) +{ + int i, j, k; + metric_t *mp; + + fprintf(f, " Inst Inst Name\n"); + fprintf(f, " ====== =========\n"); + + for (i = 0, mp = metric; i < n_metrics; i++, mp++) { + fprintf(f, "%s\n", mp->name); + if (mp->indom == -1) + fprintf(f, " singular instance\n"); + else { + indom_t *ip = &indom[mp->indom]; + int *inst = ip->inst; + char **name = ip->name; + int n_insts = ip->n_insts; + + /* No instances specified, use them all */ + if (mp->n_insts == 0) + for (j = 0; j < n_insts; j++) + fprintf(f, " %6d %s\n", inst[j], name[j]); + else + for (j = 0; j < mp->n_insts; j++) { + int m_inst = mp->inst[j];; + + for (k = 0; k < n_insts; k++) + if (m_inst == inst[k]) + break; + if (k < n_insts) + fprintf(f, " %6d %s\n", inst[k], name[k]); + else + fprintf(f, " KAPOWIE! inst %d not found\n", m_inst); + } + } + putc('\n', f); + } +} +#endif |