char * __pmLabelIdentString(int ident, int type, char *buf, size_t buflen) { char *p, id[32]; switch (type) { case PM_LABEL_DOMAIN: pmsprintf(buf, buflen, "Domain %u", ident); break; case PM_LABEL_INDOM: case PM_LABEL_INSTANCES: pmsprintf(buf, buflen, "InDom %s", pmInDomStr_r(ident, id, sizeof(id))); break; case PM_LABEL_CLUSTER: pmIDStr_r(ident, id, sizeof(id)); p = rindex(id, '.'); *p = '\0'; pmsprintf(buf, buflen, "Cluster %s", id); break; case PM_LABEL_ITEM: pmsprintf(buf, buflen, "PMID %s", pmIDStr_r(ident, id, sizeof(id))); break; case PM_LABEL_CONTEXT: pmsprintf(buf, buflen, "Context"); break; default: buf[0] = '\0'; break; } return buf; }
static void foo(FILE *f, char *fn, int i) { pmDesc desc; char strbuf[60]; int sts; sts = pmLookupDesc(pmidlist[i], &desc); if (sts < 0) { fprintf(f, "%s: pmLookupDesc[%s] -> %s\n", fn, pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf)), pmErrStr(sts)); pthread_exit("botch"); } else if (pmidlist[i] != desc.pmid) { fprintf(f, "%s: pmLookupDesc: Expecting PMID: %s", fn, pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf))); fprintf(f, " got: %s\n", pmIDStr_r(desc.pmid, strbuf, sizeof(strbuf))); pthread_exit("botch"); } else { fprintf(f, "%s: %s (%s) ->", fn, namelist[i], pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf))); fprintf(f, " %s", pmTypeStr_r(desc.type, strbuf, sizeof(strbuf))); fprintf(f, " %s", pmInDomStr_r(desc.indom, strbuf, sizeof(strbuf))); if (desc.sem == PM_SEM_COUNTER) fprintf(f, " counter"); else if (desc.sem == PM_SEM_INSTANT) fprintf(f, " instant"); else if (desc.sem == PM_SEM_DISCRETE) fprintf(f, " discrete"); else fprintf(f, " sem-%d", desc.sem); fprintf(f, " %s\n", pmUnitsStr_r(&desc.units, strbuf, sizeof(strbuf))); } }
int pmdaDesc(pmID pmid, pmDesc *desc, pmdaExt *pmda) { e_ext_t *extp = (e_ext_t *)pmda->e_ext; pmdaMetric *metric; char strbuf[32]; if (extp->dispatch->comm.pmda_interface >= PMDA_INTERFACE_5) __pmdaSetContext(pmda->e_context); if (pmda->e_flags & PMDA_EXT_FLAG_HASHED) metric = __pmdaHashedSearch(pmid, &extp->hashpmids); else if (pmda->e_direct) metric = __pmdaDirectSearch(pmid, pmda); else metric = __pmdaLinearSearch(pmid, pmda); if (metric) { *desc = metric->m_desc; return 0; } __pmNotifyErr(LOG_ERR, "pmdaDesc: Requested metric %s is not defined", pmIDStr_r(pmid, strbuf, sizeof(strbuf))); return PM_ERR_PMID; }
char * strcluster(pmID pmid) { static char buffer[32]; char *p; pmIDStr_r(pmid, buffer, sizeof(buffer)); p = rindex(buffer, '.'); *p = '\0'; return buffer; }
int __pmSendDescReq(int fd, int from, pmID pmid) { desc_req_t *pp; int sts; if ((pp = (desc_req_t *)__pmFindPDUBuf(sizeof(desc_req_t))) == NULL) return -oserror(); pp->hdr.len = sizeof(desc_req_t); pp->hdr.type = PDU_DESC_REQ; pp->hdr.from = from; pp->pmid = __htonpmID(pmid); #ifdef DESPERATE { char strbuf[20]; fprintf(stderr, "__pmSendDescReq: converted 0x%08x (%s) to 0x%08x\n", pmid, pmIDStr_r(pmid, strbuf, sizeof(strbuf)), pp->pmid); } #endif sts = __pmXmitPDU(fd, (__pmPDU *)pp); __pmUnpinPDUBuf(pp); return sts; }
void pmiDump(void) { FILE *f = stderr; fprintf(f, "pmiDump: context %ld of %d", (long)(current - context_tab), ncontext); if (current == NULL) { fprintf(f, " Error: current context is not defined.\n"); return; } else { fprintf(f, " archive: %s\n", current->archive == NULL ? "<undefined>" : current->archive); } fprintf(f, " state: %d ", current->state); switch (current->state) { case CONTEXT_START: fprintf(f, "(start)"); break; case CONTEXT_ACTIVE: fprintf(f, "(active)"); break; case CONTEXT_END: fprintf(f, "(end)"); break; default: fprintf(f, "(BAD)"); break; } fprintf(f, " hostname: %s timezone: %s\n", current->hostname == NULL ? "<undefined>" : current->hostname, current->timezone == NULL ? "<undefined>" : current->timezone); if (current->nmetric == 0) fprintf(f, " No metrics.\n"); else { int m; char strbuf[20]; for (m = 0; m < current->nmetric; m++) { fprintf(f, " metric[%d] name=%s pmid=%s\n", m, current->metric[m].name, pmIDStr_r(current->metric[m].pmid, strbuf, sizeof(strbuf))); __pmPrintDesc(f, ¤t->metric[m].desc); } } if (current->nindom == 0) fprintf(f, " No indoms.\n"); else { int i; char strbuf[20]; for (i = 0; i < current->nindom; i++) { fprintf(f, " indom[%d] indom=%s", i, pmInDomStr_r(current->indom[i].indom, strbuf, sizeof(strbuf))); if (current->indom[i].ninstance == 0) { fprintf(f, " No instances.\n"); } else { int j; fputc('\n', f); for (j = 0; j < current->indom[i].ninstance; j++) { fprintf(f, " instance[%d] %s (%d)\n", j, current->indom[i].name[j], current->indom[i].inst[j]); } } } } if (current->nhandle == 0) fprintf(f, " No handles.\n"); else { int h; char strbuf[20]; for (h = 0; h < current->nhandle; h++) { fprintf(f, " handle[%d] metric=%s (%s) instance=%d\n", h, current->metric[current->handle[h].midx].name, pmIDStr_r(current->metric[current->handle[h].midx].pmid, strbuf, sizeof(strbuf)), current->handle[h].inst); } } if (current->result == NULL) fprintf(f, " No pmResult.\n"); else __pmDumpResult(f, current->result); }
int pmdaFetch(int numpmid, pmID pmidlist[], pmResult **resp, pmdaExt *pmda) { int i; /* over pmidlist[] */ int j; /* over metatab and vset->vlist[] */ int sts; int need; int inst; int numval; pmValueSet *vset; pmDesc *dp; pmdaMetric metaBuf; pmdaMetric *metap; pmAtomValue atom; int type; e_ext_t *extp = (e_ext_t *)pmda->e_ext; if (extp->dispatch->version.any.ext != pmda) fprintf(stderr, "Botch: pmdaFetch: PMDA domain=%d pmda=%p extp=%p backpointer=%p pmda-via-backpointer %p NOT EQUAL to pmda\n", pmda->e_domain, pmda, extp, extp->dispatch, extp->dispatch->version.any.ext); if (extp->dispatch->comm.pmda_interface >= PMDA_INTERFACE_5) __pmdaSetContext(pmda->e_context); if (numpmid > extp->maxnpmids) { if (extp->res != NULL) free(extp->res); /* (numpmid - 1) because there's room for one valueSet in a pmResult */ need = (int)sizeof(pmResult) + (numpmid - 1) * (int)sizeof(pmValueSet *); if ((extp->res = (pmResult *) malloc(need)) == NULL) return -oserror(); extp->maxnpmids = numpmid; } extp->res->timestamp.tv_sec = 0; extp->res->timestamp.tv_usec = 0; extp->res->numpmid = numpmid; /* Look up the pmDesc for the incoming pmids in our pmdaMetrics tables, if present. Fall back to .desc callback if not found (for highly dynamic pmdas). */ for (i = 0; i < numpmid; i++) { dp = NULL; if (pmda->e_flags & PMDA_EXT_FLAG_HASHED) metap = __pmdaHashedSearch(pmidlist[i], &extp->hashpmids); else if (pmda->e_direct) metap = __pmdaDirectSearch(pmidlist[i], pmda); else metap = __pmdaLinearSearch(pmidlist[i], pmda); if (metap != NULL) dp = &(metap->m_desc); else { /* possibly a highly dynamic metric with null metrictab[] */ if (extp->dispatch->version.any.desc != NULL) { /* may need a temporary pmdaMetric for passing to e_fetchCallBack */ sts = (*(extp->dispatch->version.any.desc))(pmidlist[i], &metaBuf.m_desc, pmda); if (sts >= 0) { metaBuf.m_user = NULL; metap = &metaBuf; dp = &metaBuf.m_desc; } } } if (dp != NULL) { if (dp->indom != PM_INDOM_NULL) { /* count instances in the profile */ numval = 0; /* count instances in indom */ __pmdaStartInst(dp->indom, pmda); while (__pmdaNextInst(&inst, pmda)) { numval++; } } else { /* singular instance domains */ numval = 1; } } else { /* dynamic name metrics may often vanish, avoid log spam */ if (extp->dispatch->comm.pmda_interface < PMDA_INTERFACE_4) { char strbuf[20]; __pmNotifyErr(LOG_ERR, "pmdaFetch: Requested metric %s is not defined", pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf))); } numval = PM_ERR_PMID; } /* Must use individual malloc()s because of pmFreeResult() */ if (numval >= 1) extp->res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue)); else extp->res->vset[i] = vset = (pmValueSet *)malloc(sizeof(pmValueSet) - sizeof(pmValue)); if (vset == NULL) { sts = -oserror(); goto error; } vset->pmid = pmidlist[i]; vset->numval = numval; vset->valfmt = PM_VAL_INSITU; if (vset->numval <= 0) continue; if (dp->indom == PM_INDOM_NULL) inst = PM_IN_NULL; else { __pmdaStartInst(dp->indom, pmda); __pmdaNextInst(&inst, pmda); } type = dp->type; j = 0; do { if (j == numval) { /* more instances than expected! */ numval++; extp->res->vset[i] = vset = (pmValueSet *)realloc(vset, sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue)); if (vset == NULL) { sts = -oserror(); goto error; } } vset->vlist[j].inst = inst; if ((sts = (*(pmda->e_fetchCallBack))(metap, inst, &atom)) < 0) { char strbuf[20]; pmIDStr_r(dp->pmid, strbuf, sizeof(strbuf)); if (sts == PM_ERR_PMID) { __pmNotifyErr(LOG_ERR, "pmdaFetch: PMID %s not handled by fetch callback\n", strbuf); } else if (sts == PM_ERR_INST) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) { __pmNotifyErr(LOG_ERR, "pmdaFetch: Instance %d of PMID %s not handled by fetch callback\n", inst, strbuf); } #endif } else if (sts == PM_ERR_APPVERSION || sts == PM_ERR_PERMISSION || sts == PM_ERR_AGAIN || sts == PM_ERR_NYI) { #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_LIBPMDA) { __pmNotifyErr(LOG_ERR, "pmdaFetch: Unavailable metric PMID %s[%d]\n", strbuf, inst); } #endif } else { __pmNotifyErr(LOG_ERR, "pmdaFetch: Fetch callback error from metric PMID %s[%d]: %s\n", strbuf, inst, pmErrStr(sts)); } } else { /* * PMDA_INTERFACE_2 * >= 0 => OK * PMDA_INTERFACE_3 or PMDA_INTERFACE_4 * == 0 => no values * > 0 => OK * PMDA_INTERFACE_5 or later * == 0 (PMDA_FETCH_NOVALUES) => no values * == 1 (PMDA_FETCH_STATIC) or > 2 => OK * == 2 (PMDA_FETCH_DYNAMIC) => OK and free(atom.vp) * after __pmStuffValue() called */ if (extp->dispatch->comm.pmda_interface == PMDA_INTERFACE_2 || (extp->dispatch->comm.pmda_interface >= PMDA_INTERFACE_3 && sts > 0)) { int lsts; if ((lsts = __pmStuffValue(&atom, &vset->vlist[j], type)) == PM_ERR_TYPE) { char strbuf[20]; char st2buf[20]; __pmNotifyErr(LOG_ERR, "pmdaFetch: Descriptor type (%s) for metric %s is bad", pmTypeStr_r(type, strbuf, sizeof(strbuf)), pmIDStr_r(dp->pmid, st2buf, sizeof(st2buf))); } else if (lsts >= 0) { vset->valfmt = lsts; j++; } if (extp->dispatch->comm.pmda_interface >= PMDA_INTERFACE_5 && sts == PMDA_FETCH_DYNAMIC) { if (type == PM_TYPE_STRING) free(atom.cp); else if (type == PM_TYPE_AGGREGATE) free(atom.vbp); else { char strbuf[20]; char st2buf[20]; __pmNotifyErr(LOG_WARNING, "pmdaFetch: Attempt to free value for metric %s of wrong type %s\n", pmIDStr_r(dp->pmid, strbuf, sizeof(strbuf)), pmTypeStr_r(type, st2buf, sizeof(st2buf))); } } if (lsts < 0) sts = lsts; } } } while (dp->indom != PM_INDOM_NULL && __pmdaNextInst(&inst, pmda)); if (j == 0) vset->numval = sts; else vset->numval = j; } *resp = extp->res; return 0; error: if (i) { extp->res->numpmid = i; __pmFreeResultValues(extp->res); } return sts; }
static void foo(FILE *f, char *fn, int i, void *closure) { int sts; int numnames; int j; int leaf; pmID pmids[NMETRIC]; char **names; char *name; int *stsset; char strbuf[20]; if ((sts = pmLookupName(NMETRIC-i, &namelist[i], pmids)) < 0) { if (sts != PM_ERR_NONLEAF) { fprintf(f, "%s: %s ...: pmLookupName Error: %s\n", fn, namelist[i], pmErrStr(sts)); pthread_exit("botch"); } } for (j = i; j < NMETRIC; j++) { if (pmids[j-i] != pmidlist[j]) { fprintf(f, "%s: %s: Botch: expecting %s", fn, namelist[j], pmIDStr_r(pmidlist[j], strbuf, sizeof(strbuf))); fprintf(f, ", got %s\n", pmIDStr_r(pmids[j-i], strbuf, sizeof(strbuf))); pthread_exit("botch"); } } fprintf(f, "%s: %s ... pmLookupName OK\n", fn, namelist[i]); fprintf(f, "%s: %s", fn, namelist[i]); if (pmidlist[i] != PM_ID_NULL) { /* leaf node in PMNS */ if ((numnames = pmNameAll(pmidlist[i], &names)) < 0) { fprintf(f, "\n%s: %s ...: pmNameAll Error: %s\n", fn, namelist[i], pmErrStr(numnames)); pthread_exit("botch"); } for (j = 0; j < numnames; j++) { if (strcmp(names[j], namelist[i]) == 0) break; } if (j == numnames) { fprintf(f, "\n%s: %s: Botch: expecting %s, got {", fn, pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf)), namelist[i]); __pmPrintMetricNames(f, numnames, names, ","); fprintf(f, "}\n"); pthread_exit("botch"); } fprintf(f, " pmNameAll OK"); if ((sts = pmNameID(pmidlist[i], &name)) < 0) { fprintf(f, "\n%s: %s ...: pmNameID Error: %s\n", fn, namelist[i], pmErrStr(sts)); pthread_exit("botch"); } for (j = 0; j < numnames; j++) { if (strcmp(name, names[j]) == 0) break; } if (j == numnames) { fprintf(f, "\n%s: %s: Botch: expecting one of {", fn, pmIDStr_r(pmidlist[i], strbuf, sizeof(strbuf))); __pmPrintMetricNames(f, numnames, names, ","); fprintf(f, "}, got %s\n", name); pthread_exit("botch"); } free(names); free(name); fprintf(f, " pmNameID OK"); } else { /* non-leaf node in PMNS */ int keep = 0; if ((sts = pmGetChildrenStatus(namelist[i], &names, &stsset)) < 0) { fprintf(f, "\n%s: %s ...: pmGetChildrenStatus Error: %s\n", fn, namelist[i], pmErrStr(sts)); pthread_exit("botch"); } leaf = 0; for (j = 0; j < sts; j++) { if (stsset[j] == PMNS_LEAF_STATUS) leaf++; } PM_LOCK(chn_lock); if (leaf_chn[i] == -1) { leaf_chn[i] = leaf; nonleaf_chn[i] = sts - leaf; chn[i] = names; keep = 1; } else { if (leaf != leaf_chn[i] || sts - leaf != nonleaf_chn[i]) { fprintf(f, "\n%s: %s: Botch: expecting %d leaf & %d non-leaf, got %d leaf & %d non-leaf\n", fn, namelist[i], leaf_chn[i], nonleaf_chn[i], leaf, sts - leaf); pthread_exit("botch"); } for (j = 0; j < sts; j++) { if (strcmp(chn[i][j], names[j]) != 0) { fprintf(f, "\n%s: %s: Botch: child[%d] expecting %s, got %s\n", fn, namelist[i], j, chn[i][j], names[j]); PM_UNLOCK(chn_lock); pthread_exit("botch"); } } } if (keep == 0) { free(names); names = NULL; /* silence coverity */ } free(stsset); fprintf(f, " pmGetChildrenStatus OK"); if ((sts = pmGetChildren(namelist[i], &names)) < 0) { fprintf(f, "\n%s: %s ...: pmGetChildren Error: %s\n", fn, namelist[i], pmErrStr(sts)); PM_UNLOCK(chn_lock); pthread_exit("botch"); } if (sts != leaf_chn[i] + nonleaf_chn[i]) { fprintf(f, "\n%s: %s: Botch: expecting %d children, got %d\n", fn, namelist[i], leaf_chn[i] + nonleaf_chn[i], sts); PM_UNLOCK(chn_lock); pthread_exit("botch"); } for (j = 0; j < sts; j++) { if (strcmp(chn[i][j], names[j]) != 0) { fprintf(f, "\n%s: %s: Botch: child[%d] expecting %s, got %s\n", fn, namelist[i], j, chn[i][j], names[j]); PM_UNLOCK(chn_lock); pthread_exit("botch"); } } PM_UNLOCK(chn_lock); free(names); fprintf(f, " pmGetChildren OK"); *((int *)closure) = 0; if ((sts = pmTraversePMNS_r(namelist[i], dometric, closure)) < 0) { fprintf(f, "\n%s: %s ...: pmTraversePMNS_r Error: %s\n", fn, namelist[i], pmErrStr(sts)); pthread_exit("botch"); } if (sum_traverse[i] != *((int *)closure)) { fprintf(f, "\n%s: %s: Botch: sum strlen(descendent names) expecting %d, got %d\n", fn, namelist[i], sum_traverse[i], *((int *)closure)); pthread_exit("botch"); } fprintf(f, " pmTraversePMNS_r OK"); } fputc('\n', f); }
/* * Called when an error PDU containing PMCD_ADD_AGENT is received. * This function checks all of the configured metrics to make sure that * they have not changed. For example due to a PMDA being replaced by an * updated version */ void validate_metrics(void) { const task_t *tp; pmID *new_pmids; const pmDesc *old_desc; pmDesc new_desc; int index; int error; int sts; time_t now; char buf1[20], buf2[20]; time(&now); fprintf(stderr, "%s: Validating metrics after PMCD state changed at %s", pmProgname, ctime(&now)); /* * Check each metric in each element of the task list, whether it is * active or not. */ error = 0; for (tp = tasklist; tp != NULL; tp = tp->t_next) { /* We need at least one metric to look up. */ if (tp->t_numpmid < 1) continue; /* * Perform a bulk lookup and then check for consistency. * Lookup the metrics by name, since that's the way they are * specified in the pmlogger config file. * We need a temporary array for the new pmIDs */ new_pmids = malloc(tp->t_numpmid * sizeof(*tp->t_pmidlist)); if (new_pmids == NULL) { __pmNoMem("allocating pmID array for validating metrice", tp->t_numpmid * sizeof(*tp->t_pmidlist), PM_FATAL_ERR); } if ((sts = pmLookupName(tp->t_numpmid, tp->t_namelist, new_pmids)) < 0) { fprintf(stderr, "Error looking up metrics: Reason: %s\n", pmErrStr(sts)); exit(1); } /* Now check the individual metrics for problems. */ for (index = 0; index < tp->t_numpmid; ++index) { /* If there was an error looking up this metric, try again in order * to obtain the reason. If there is no error the second time * (possible), then the needed pmID will be fetched. */ if (new_pmids[index] == PM_ID_NULL) { if ((sts = pmLookupName(1, &tp->t_namelist[index], &new_pmids[index])) < 0) { /* The lookup of the metric is still in error. */ fprintf(stderr, "Error looking up %s: Reason: %s\n", tp->t_namelist[index], pmErrStr(sts)); ++error; continue; } /* No error the second time. Fall through */ } /* * Check that the pmid, type, semantics, instance domain and units * of the metric have not changed. */ if (new_pmids[index] != tp->t_pmidlist[index]) { fprintf(stderr, "PMID of metric \"%s\" has changed from %s to %s\n", tp->t_namelist[index], pmIDStr_r(tp->t_pmidlist[index], buf1, sizeof(buf1)), pmIDStr_r(new_pmids[index], buf2, sizeof(buf2))); ++error; } if ((sts = pmLookupDesc(new_pmids[index], &new_desc)) < 0) { fprintf(stderr, "Description unavailable for metric \"%s\": %s\n", tp->t_namelist[index], pmErrStr(sts)); ++error; continue; } old_desc = &tp->t_desclist[index]; if (new_desc.type != old_desc->type) { fprintf(stderr, "Type of metric \"%s\" has changed from %s to %s\n", tp->t_namelist[index], pmTypeStr_r(old_desc->type, buf1, sizeof(buf1)), pmTypeStr_r(new_desc.type, buf2, sizeof(buf2))); ++error; } if (new_desc.sem != old_desc->sem) { fprintf(stderr, "Semantics of metric \"%s\" have changed from %s to %s\n", tp->t_namelist[index], pmSemStr_r(old_desc->sem, buf1, sizeof(buf1)), pmSemStr_r(new_desc.sem, buf2, sizeof(buf2))); ++error; } if (new_desc.indom != old_desc->indom) { fprintf(stderr, "Instance domain of metric \"%s\" has changed from %s to %s\n", tp->t_namelist[index], pmInDomStr_r(old_desc->indom, buf1, sizeof(buf1)), pmInDomStr_r(new_desc.indom, buf2, sizeof(buf2))); ++error; } if (new_desc.units.dimSpace != old_desc->units.dimSpace || new_desc.units.dimTime != old_desc->units.dimTime || new_desc.units.dimCount != old_desc->units.dimCount || new_desc.units.scaleSpace != old_desc->units.scaleSpace || new_desc.units.scaleTime != old_desc->units.scaleTime || new_desc.units.scaleCount != old_desc->units.scaleCount) { ++error; fprintf(stderr, "Units of metric \"%s\" has changed from %s to %s\n", tp->t_namelist[index], pmUnitsStr_r(&old_desc->units, buf1, sizeof(buf1)), pmUnitsStr_r(&new_desc.units, buf2, sizeof(buf2))); } } /* loop over metrics */ free(new_pmids); } /* Loop over task list */ /* We cannot continue, if any of the metrics have changed. */ if (error) { fprintf(stderr, "One or more configured metrics have changed after pmcd state change. Exiting\n"); exit(1); } }
/* * Called with valid context locked ... */ int __pmFetchLocal(__pmContext *ctxp, int numpmid, pmID pmidlist[], pmResult **result) { int sts; int ctx; int j; int k; int n; pmResult *ans; pmResult *tmp_ans; __pmDSO *dp; int need; static pmID * splitlist=NULL; static int splitmax=0; if (PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) /* Local context requires single-threaded applications */ return PM_ERR_THREAD; if (numpmid < 1) return PM_ERR_TOOSMALL; ctx = __pmPtrToHandle(ctxp); /* * this is very ugly ... the DSOs have a high-water mark * allocation algorithm for the result skeleton, but the * code that calls us assumes it has freedom to retain * this result structure for as long as it wishes, and * then to call pmFreeResult * * we make another skeleton, selectively copy and return that * * (numpmid - 1) because there's room for one valueSet * in a pmResult */ need = (int)sizeof(pmResult) + (numpmid - 1) * (int)sizeof(pmValueSet *); if ((ans = (pmResult *)malloc(need)) == NULL) return -oserror(); /* * Check if we have enough space to accomodate "best" case scenario - * all pmids are from the same domain */ if (splitmax < numpmid) { splitmax = numpmid; pmID *tmp_list = (pmID *)realloc(splitlist, sizeof(pmID)*splitmax); if (tmp_list == NULL) { free(splitlist); splitmax = 0; free(ans); return -oserror(); } splitlist = tmp_list; } ans->numpmid = numpmid; __pmtimevalNow(&ans->timestamp); for (j = 0; j < numpmid; j++) ans->vset[j] = NULL; for (j = 0; j < numpmid; j++) { int cnt; if (ans->vset[j] != NULL) /* picked up in a previous fetch */ continue; sts = 0; if ((dp = __pmLookupDSO(((__pmID_int *)&pmidlist[j])->domain)) == NULL) /* based on domain, unknown PMDA */ sts = PM_ERR_NOAGENT; else { if (ctxp->c_sent != dp->domain) { /* * current profile is _not_ already cached at other end of * IPC, so send get current profile ... * Note: trickier than the non-local case, as no per-PMDA * caching at the PMCD end, so need to remember the * last domain to receive a profile */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_FETCH) fprintf(stderr, "__pmFetchLocal: calling ???_profile(domain: %d), " "context: %d\n", dp->domain, ctx); #endif if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; sts = dp->dispatch.version.any.profile(ctxp->c_instprof, dp->dispatch.version.any.ext); if (sts >= 0) ctxp->c_sent = dp->domain; } } /* Copy all pmID for the current domain into the temp. list */ for (cnt=0, k=j; k < numpmid; k++ ) { if (((__pmID_int*)(pmidlist+k))->domain == ((__pmID_int*)(pmidlist+j))->domain) splitlist[cnt++] = pmidlist[k]; } if (sts >= 0) { if (dp->dispatch.comm.pmda_interface >= PMDA_INTERFACE_5) dp->dispatch.version.four.ext->e_context = ctx; sts = dp->dispatch.version.any.fetch(cnt, splitlist, &tmp_ans, dp->dispatch.version.any.ext); } /* Copy results back * * Note: We DO NOT have to free tmp_ans since DSO PMDA would * ALWAYS return a pointer to the static area. */ for (n = 0, k = j; k < numpmid && n < cnt; k++) { if (pmidlist[k] == splitlist[n]) { if (sts < 0) { ans->vset[k] = (pmValueSet *)malloc(sizeof(pmValueSet)); if (ans->vset[k] == NULL) { /* cleanup all partial allocations for ans->vset[] */ for (k--; k >=0; k--) free(ans->vset[k]); free(ans); return -oserror(); } ans->vset[k]->numval = sts; ans->vset[k]->pmid = pmidlist[k]; } else { ans->vset[k] = tmp_ans->vset[n]; } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_FETCH) { char strbuf[20]; char errmsg[PM_MAXERRMSGLEN]; fprintf(stderr, "__pmFetchLocal: [%d] PMID=%s nval=", k, pmIDStr_r(pmidlist[k], strbuf, sizeof(strbuf))); if (ans->vset[k]->numval < 0) fprintf(stderr, "%s\n", pmErrStr_r(ans->vset[k]->numval, errmsg, sizeof(errmsg))); else fprintf(stderr, "%d\n", ans->vset[k]->numval); } #endif n++; } } } *result = ans; return 0; }
/* * Walk the pmidlist[] from pmFetch. * For each derived metric found in the list add all the operand metrics, * and build a combined pmID list (newlist). * * Return 0 if no derived metrics in the list, else the number of pmIDs * in the combined list. * * The derived metric pmIDs are left in the combined list (they will * return PM_ERR_NOAGENT from the fetch) to simplify the post-processing * of the pmResult in __dmpostfetch() */ int __dmprefetch(__pmContext *ctxp, int numpmid, const pmID *pmidlist, pmID **newlist) { int i; int j; int m; int xtracnt = 0; pmID *xtralist = NULL; pmID *list; ctl_t *cp = (ctl_t *)ctxp->c_dm; /* if needed, init() called in __dmopencontext beforehand */ if (cp == NULL) return 0; /* * save numpmid to be used in __dmpostfetch() ... works because calls * to pmFetch cannot be nested (at all, but certainly for the same * context). * Ditto for the fast path flag (fetch_has_dm). */ cp->numpmid = numpmid; cp->fetch_has_dm = 0; for (m = 0; m < numpmid; m++) { if (!IS_DERIVED(pmidlist[m])) continue; for (i = 0; i < cp->nmetric; i++) { if (pmidlist[m] == cp->mlist[i].pmid) { if (cp->mlist[i].expr != NULL) { get_pmids(cp->mlist[i].expr, &xtracnt, &xtralist); cp->fetch_has_dm = 1; } break; } } } if (xtracnt == 0) { if (cp->fetch_has_dm) return numpmid; else return 0; } /* * Some of the "extra" ones, may already be in the caller's pmFetch * list, or repeated in xtralist[] (if the same metric operand appears * more than once as a leaf node in the expression tree. * Remove these duplicates */ j = 0; for (i = 0; i < xtracnt; i++) { for (m = 0; m < numpmid; m++) { if (xtralist[i] == pmidlist[m]) /* already in pmFetch list */ break; } if (m < numpmid) continue; for (m = 0; m < j; m++) { if (xtralist[i] == xtralist[m]) /* already in xtralist[] */ break; } if (m == j) xtralist[j++] = xtralist[i]; } xtracnt = j; if (xtracnt == 0) { free(xtralist); return numpmid; } #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { char strbuf[20]; fprintf(stderr, "derived metrics prefetch added %d metrics:", xtracnt); for (i = 0; i < xtracnt; i++) fprintf(stderr, " %s", pmIDStr_r(xtralist[i], strbuf, sizeof(strbuf))); fputc('\n', stderr); } #endif if ((list = (pmID *)malloc((numpmid+xtracnt)*sizeof(pmID))) == NULL) { __pmNoMem("__dmprefetch: alloc list", (numpmid+xtracnt)*sizeof(pmID), PM_FATAL_ERR); /*NOTREACHED*/ } for (m = 0; m < numpmid; m++) { list[m] = pmidlist[m]; } for (i = 0; i < xtracnt; i++) { list[m++] = xtralist[i]; } free(xtralist); *newlist = list; return m; }
/* * Walk an expression tree, filling in operand values from the * pmResult at the leaf nodes and propagating the computed values * towards the root node of the tree. */ static int eval_expr(node_t *np, pmResult *rp, int level) { int sts; int i; int j; int k; size_t need; assert(np != NULL); if (np->left != NULL) { sts = eval_expr(np->left, rp, level+1); if (sts < 0) return sts; } if (np->right != NULL) { sts = eval_expr(np->right, rp, level+1); if (sts < 0) return sts; } /* mostly, np->left is not NULL ... */ assert (np->type == L_NUMBER || np->type == L_NAME || np->left != NULL); switch (np->type) { case L_NUMBER: if (np->info->numval == 0) { /* initialize ivlist[] for singular instance first time through */ np->info->numval = 1; if ((np->info->ivlist = (val_t *)malloc(sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: number ivlist", sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } np->info->ivlist[0].inst = PM_INDOM_NULL; /* don't need error checking, done in the lexical scanner */ np->info->ivlist[0].value.l = atoi(np->value); } return 1; break; case L_DELTA: case L_RATE: /* * this and the last values are in the left expr */ np->info->last_stamp = np->info->stamp; np->info->stamp = rp->timestamp; free_ivlist(np); np->info->numval = np->left->info->numval <= np->left->info->last_numval ? np->left->info->numval : np->left->info->last_numval; if (np->info->numval <= 0) return np->info->numval; if ((np->info->ivlist = (val_t *)malloc(np->info->numval*sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: delta()/rate() ivlist", np->info->numval*sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } /* * delta() * ivlist[k] = left->ivlist[i] - left->last_ivlist[j] * rate() * ivlist[k] = (left->ivlist[i] - left->last_ivlist[j]) / * (timestamp - left->last_stamp) */ for (i = k = 0; i < np->left->info->numval; i++) { j = i; if (j >= np->left->info->last_numval) j = 0; if (np->left->info->ivlist[i].inst != np->left->info->last_ivlist[j].inst) { /* current ith inst != last jth inst ... search in last */ #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { fprintf(stderr, "eval_expr: inst[%d] mismatch left [%d]=%d last [%d]=%d\n", k, i, np->left->info->ivlist[i].inst, j, np->left->info->last_ivlist[j].inst); } #endif for (j = 0; j < np->left->info->last_numval; j++) { if (np->left->info->ivlist[i].inst == np->left->info->last_ivlist[j].inst) break; } if (j == np->left->info->last_numval) { /* no match, skip this instance from this result */ continue; } #ifdef PCP_DEBUG else { if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { fprintf(stderr, "eval_expr: recover @ last [%d]=%d\n", j, np->left->info->last_ivlist[j].inst); } } #endif } np->info->ivlist[k].inst = np->left->info->ivlist[i].inst; if (np->type == L_DELTA) { /* for delta() result type == operand type */ switch (np->left->desc.type) { case PM_TYPE_32: np->info->ivlist[k].value.l = np->left->info->ivlist[i].value.l - np->left->info->last_ivlist[j].value.l; break; case PM_TYPE_U32: np->info->ivlist[k].value.ul = np->left->info->ivlist[i].value.ul - np->left->info->last_ivlist[j].value.ul; break; case PM_TYPE_64: np->info->ivlist[k].value.ll = np->left->info->ivlist[i].value.ll - np->left->info->last_ivlist[j].value.ll; break; case PM_TYPE_U64: np->info->ivlist[k].value.ull = np->left->info->ivlist[i].value.ull - np->left->info->last_ivlist[j].value.ull; break; case PM_TYPE_FLOAT: np->info->ivlist[k].value.f = np->left->info->ivlist[i].value.f - np->left->info->last_ivlist[j].value.f; break; case PM_TYPE_DOUBLE: np->info->ivlist[k].value.d = np->left->info->ivlist[i].value.d - np->left->info->last_ivlist[j].value.d; break; default: /* * Nothing should end up here as check_expr() checks * for numeric data type at bind time */ return PM_ERR_CONV; } } else { /* rate() conversion, type will be DOUBLE */ struct timeval stampdiff; stampdiff = np->info->stamp; __pmtimevalDec(&stampdiff, &np->info->last_stamp); switch (np->left->desc.type) { case PM_TYPE_32: np->info->ivlist[k].value.d = (double)(np->left->info->ivlist[i].value.l - np->left->info->last_ivlist[j].value.l); break; case PM_TYPE_U32: np->info->ivlist[k].value.d = (double)(np->left->info->ivlist[i].value.ul - np->left->info->last_ivlist[j].value.ul); break; case PM_TYPE_64: np->info->ivlist[k].value.d = (double)(np->left->info->ivlist[i].value.ll - np->left->info->last_ivlist[j].value.ll); break; case PM_TYPE_U64: np->info->ivlist[k].value.d = (double)(np->left->info->ivlist[i].value.ull - np->left->info->last_ivlist[j].value.ull); break; case PM_TYPE_FLOAT: np->info->ivlist[k].value.d = (double)(np->left->info->ivlist[i].value.f - np->left->info->last_ivlist[j].value.f); break; case PM_TYPE_DOUBLE: np->info->ivlist[k].value.d = np->left->info->ivlist[i].value.d - np->left->info->last_ivlist[j].value.d; break; default: /* * Nothing should end up here as check_expr() checks * for numeric data type at bind time */ return PM_ERR_CONV; } np->info->ivlist[k].value.d /= __pmtimevalToReal(&stampdiff); /* * check_expr() ensures dimTime is 0 or 1 at bind time */ if (np->left->desc.units.dimTime == 1) { /* scale rate(time counter) -> time utilization */ if (np->info->time_scale < 0) { /* * one trip initialization for time utilization * scaling factor (to scale metric from counter * units into seconds) */ int i; np->info->time_scale = 1; if (np->left->desc.units.scaleTime > PM_TIME_SEC) { for (i = PM_TIME_SEC; i < np->left->desc.units.scaleTime; i++) np->info->time_scale *= 60; } else { for (i = np->left->desc.units.scaleTime; i < PM_TIME_SEC; i++) np->info->time_scale /= 1000; } } np->info->ivlist[k].value.d *= np->info->time_scale; } } k++; } np->info->numval = k; return np->info->numval; break; case L_INSTANT: /* * values are in the left expr */ np->info->last_stamp = np->info->stamp; np->info->stamp = rp->timestamp; np->info->numval = np->left->info->numval; if (np->info->numval > 0) np->info->ivlist = np->left->info->ivlist; return np->info->numval; break; case L_AVG: case L_COUNT: case L_SUM: case L_MAX: case L_MIN: if (np->info->ivlist == NULL) { /* initialize ivlist[] for singular instance first time through */ if ((np->info->ivlist = (val_t *)malloc(sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: aggr ivlist", sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } np->info->ivlist[0].inst = PM_IN_NULL; } /* * values are in the left expr */ if (np->type == L_COUNT) { np->info->numval = 1; np->info->ivlist[0].value.l = np->left->info->numval; } else { np->info->numval = 1; if (np->type == L_AVG) np->info->ivlist[0].value.f = 0; else if (np->type == L_SUM) { switch (np->desc.type) { case PM_TYPE_32: np->info->ivlist[0].value.l = 0; break; case PM_TYPE_U32: np->info->ivlist[0].value.ul = 0; break; case PM_TYPE_64: np->info->ivlist[0].value.ll = 0; break; case PM_TYPE_U64: np->info->ivlist[0].value.ull = 0; break; case PM_TYPE_FLOAT: np->info->ivlist[0].value.f = 0; break; case PM_TYPE_DOUBLE: np->info->ivlist[0].value.d = 0; break; } } for (i = 0; i < np->left->info->numval; i++) { switch (np->type) { case L_AVG: switch (np->left->desc.type) { case PM_TYPE_32: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.l / np->left->info->numval; break; case PM_TYPE_U32: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.ul / np->left->info->numval; break; case PM_TYPE_64: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.ll / np->left->info->numval; break; case PM_TYPE_U64: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.ull / np->left->info->numval; break; case PM_TYPE_FLOAT: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.f / np->left->info->numval; break; case PM_TYPE_DOUBLE: np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.d / np->left->info->numval; break; default: /* * check_expr() checks for numeric data * type at bind time ... if here, botch! */ return PM_ERR_CONV; } break; case L_MAX: switch (np->desc.type) { case PM_TYPE_32: if (i == 0 || np->info->ivlist[0].value.l < np->left->info->ivlist[i].value.l) np->info->ivlist[0].value.l = np->left->info->ivlist[i].value.l; break; case PM_TYPE_U32: if (i == 0 || np->info->ivlist[0].value.ul < np->left->info->ivlist[i].value.ul) np->info->ivlist[0].value.ul = np->left->info->ivlist[i].value.ul; break; case PM_TYPE_64: if (i == 0 || np->info->ivlist[0].value.ll < np->left->info->ivlist[i].value.ll) np->info->ivlist[0].value.ll = np->left->info->ivlist[i].value.ll; break; case PM_TYPE_U64: if (i == 0 || np->info->ivlist[0].value.ull < np->left->info->ivlist[i].value.ull) np->info->ivlist[0].value.ull = np->left->info->ivlist[i].value.ull; break; case PM_TYPE_FLOAT: if (i == 0 || np->info->ivlist[0].value.f < np->left->info->ivlist[i].value.f) np->info->ivlist[0].value.f = np->left->info->ivlist[i].value.f; break; case PM_TYPE_DOUBLE: if (i == 0 || np->info->ivlist[0].value.d < np->left->info->ivlist[i].value.d) np->info->ivlist[0].value.d = np->left->info->ivlist[i].value.d; break; default: /* * check_expr() checks for numeric data * type at bind time ... if here, botch! */ return PM_ERR_CONV; } break; case L_MIN: switch (np->desc.type) { case PM_TYPE_32: if (i == 0 || np->info->ivlist[0].value.l > np->left->info->ivlist[i].value.l) np->info->ivlist[0].value.l = np->left->info->ivlist[i].value.l; break; case PM_TYPE_U32: if (i == 0 || np->info->ivlist[0].value.ul > np->left->info->ivlist[i].value.ul) np->info->ivlist[0].value.ul = np->left->info->ivlist[i].value.ul; break; case PM_TYPE_64: if (i == 0 || np->info->ivlist[0].value.ll > np->left->info->ivlist[i].value.ll) np->info->ivlist[0].value.ll = np->left->info->ivlist[i].value.ll; break; case PM_TYPE_U64: if (i == 0 || np->info->ivlist[0].value.ull > np->left->info->ivlist[i].value.ull) np->info->ivlist[0].value.ull = np->left->info->ivlist[i].value.ull; break; case PM_TYPE_FLOAT: if (i == 0 || np->info->ivlist[0].value.f > np->left->info->ivlist[i].value.f) np->info->ivlist[0].value.f = np->left->info->ivlist[i].value.f; break; case PM_TYPE_DOUBLE: if (i == 0 || np->info->ivlist[0].value.d > np->left->info->ivlist[i].value.d) np->info->ivlist[0].value.d = np->left->info->ivlist[i].value.d; break; default: /* * check_expr() checks for numeric data * type at bind time ... if here, botch! */ return PM_ERR_CONV; } break; case L_SUM: switch (np->desc.type) { case PM_TYPE_32: np->info->ivlist[0].value.l += np->left->info->ivlist[i].value.l; break; case PM_TYPE_U32: np->info->ivlist[0].value.ul += np->left->info->ivlist[i].value.ul; break; case PM_TYPE_64: np->info->ivlist[0].value.ll += np->left->info->ivlist[i].value.ll; break; case PM_TYPE_U64: np->info->ivlist[0].value.ull += np->left->info->ivlist[i].value.ull; break; case PM_TYPE_FLOAT: np->info->ivlist[0].value.f += np->left->info->ivlist[i].value.f; break; case PM_TYPE_DOUBLE: np->info->ivlist[0].value.d += np->left->info->ivlist[i].value.d; break; default: /* * check_expr() checks for numeric data * type at bind time ... if here, botch! */ return PM_ERR_CONV; } break; } } } return np->info->numval; break; case L_NAME: /* * Extract instance-values from pmResult and store them in * ivlist[] as <int, pmAtomValue> pairs */ for (j = 0; j < rp->numpmid; j++) { if (np->info->pmid == rp->vset[j]->pmid) { free_ivlist(np); np->info->numval = rp->vset[j]->numval; if (np->info->numval <= 0) return np->info->numval; if ((np->info->ivlist = (val_t *)malloc(np->info->numval*sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: metric ivlist", np->info->numval*sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } for (i = 0; i < np->info->numval; i++) { np->info->ivlist[i].inst = rp->vset[j]->vlist[i].inst; switch (np->desc.type) { case PM_TYPE_32: case PM_TYPE_U32: np->info->ivlist[i].value.l = rp->vset[j]->vlist[i].value.lval; break; case PM_TYPE_64: case PM_TYPE_U64: memcpy((void *)&np->info->ivlist[i].value.ll, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, sizeof(__int64_t)); break; case PM_TYPE_FLOAT: if (rp->vset[j]->valfmt == PM_VAL_INSITU) { /* old style insitu float */ np->info->ivlist[i].value.l = rp->vset[j]->vlist[i].value.lval; } else { assert(rp->vset[j]->vlist[i].value.pval->vtype == PM_TYPE_FLOAT); memcpy((void *)&np->info->ivlist[i].value.f, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, sizeof(float)); } break; case PM_TYPE_DOUBLE: memcpy((void *)&np->info->ivlist[i].value.d, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, sizeof(double)); break; case PM_TYPE_STRING: need = rp->vset[j]->vlist[i].value.pval->vlen-PM_VAL_HDR_SIZE; if ((np->info->ivlist[i].value.cp = (char *)malloc(need)) == NULL) { __pmNoMem("eval_expr: string value", rp->vset[j]->vlist[i].value.pval->vlen, PM_FATAL_ERR); /*NOTREACHED*/ } memcpy((void *)np->info->ivlist[i].value.cp, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, need); np->info->ivlist[i].vlen = need; break; case PM_TYPE_AGGREGATE: case PM_TYPE_AGGREGATE_STATIC: case PM_TYPE_EVENT: case PM_TYPE_HIGHRES_EVENT: if ((np->info->ivlist[i].value.vbp = (pmValueBlock *)malloc(rp->vset[j]->vlist[i].value.pval->vlen)) == NULL) { __pmNoMem("eval_expr: aggregate value", rp->vset[j]->vlist[i].value.pval->vlen, PM_FATAL_ERR); /*NOTREACHED*/ } memcpy(np->info->ivlist[i].value.vbp, (void *)rp->vset[j]->vlist[i].value.pval, rp->vset[j]->vlist[i].value.pval->vlen); np->info->ivlist[i].vlen = rp->vset[j]->vlist[i].value.pval->vlen; break; default: /* * really only PM_TYPE_NOSUPPORT should * end up here */ return PM_ERR_TYPE; } } return np->info->numval; } } #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DERIVE) { char strbuf[20]; fprintf(stderr, "eval_expr: botch: operand %s not in the extended pmResult\n", pmIDStr_r(np->info->pmid, strbuf, sizeof(strbuf))); __pmDumpResult(stderr, rp); } #endif return PM_ERR_PMID; case L_ANON: /* no values available for anonymous metrics */ return 0; default: /* * binary operator cases ... always have a left and right * operand and no errors (these are caught earlier when the * recursive call on each of the operands would may have * returned an error */ assert(np->left != NULL); assert(np->right != NULL); free_ivlist(np); /* * empty result cases first */ if (np->left->info->numval == 0) { np->info->numval = 0; return np->info->numval; } if (np->right->info->numval == 0) { np->info->numval = 0; return np->info->numval; } /* * really got some work to do ... */ if (np->left->desc.indom == PM_INDOM_NULL) np->info->numval = np->right->info->numval; else if (np->right->desc.indom == PM_INDOM_NULL) np->info->numval = np->left->info->numval; else { /* * Generally have the same number of instances because * both operands are over the same instance domain, * fetched with the same profile. When not the case, * the result can contain no more instances than in * the smaller of the operands. */ if (np->left->info->numval <= np->right->info->numval) np->info->numval = np->left->info->numval; else np->info->numval = np->right->info->numval; } if ((np->info->ivlist = (val_t *)malloc(np->info->numval*sizeof(val_t))) == NULL) { __pmNoMem("eval_expr: expr ivlist", np->info->numval*sizeof(val_t), PM_FATAL_ERR); /*NOTREACHED*/ } /* * ivlist[k] = left-ivlist[i] <op> right-ivlist[j] */ for (i = j = k = 0; k < np->info->numval; ) { if (i >= np->left->info->numval || j >= np->right->info->numval) { /* run out of operand instances, quit */ np->info->numval = k; break; } if (np->left->desc.indom != PM_INDOM_NULL && np->right->desc.indom != PM_INDOM_NULL) { if (np->left->info->ivlist[i].inst != np->right->info->ivlist[j].inst) { /* left ith inst != right jth inst ... search in right */ #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { fprintf(stderr, "eval_expr: inst[%d] mismatch left [%d]=%d right [%d]=%d\n", k, i, np->left->info->ivlist[i].inst, j, np->right->info->ivlist[j].inst); } #endif for (j = 0; j < np->right->info->numval; j++) { if (np->left->info->ivlist[i].inst == np->right->info->ivlist[j].inst) break; } if (j == np->right->info->numval) { /* * no match, so next instance on left operand, * and reset to start from first instance of * right operand */ i++; j = 0; continue; } #ifdef PCP_DEBUG else { if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { fprintf(stderr, "eval_expr: recover @ right [%d]=%d\n", j, np->right->info->ivlist[j].inst); } } #endif } } np->info->ivlist[k].value = bin_op(np->desc.type, np->type, np->left->info->ivlist[i].value, np->left->desc.type, np->left->info->mul_scale, np->left->info->div_scale, np->right->info->ivlist[j].value, np->right->desc.type, np->right->info->mul_scale, np->right->info->div_scale); if (np->left->desc.indom != PM_INDOM_NULL) np->info->ivlist[k].inst = np->left->info->ivlist[i].inst; else np->info->ivlist[k].inst = np->right->info->ivlist[j].inst; k++; if (np->left->desc.indom != PM_INDOM_NULL) { i++; if (np->right->desc.indom != PM_INDOM_NULL) { j++; if (j >= np->right->info->numval) { /* rescan if need be */ j = 0; } } } else if (np->right->desc.indom != PM_INDOM_NULL) { j++; } } return np->info->numval; } /*NOTREACHED*/ }
/* * Algorithm here is complicated by trying to re-write the pmResult. * * On entry the pmResult is likely to be built over a pinned PDU buffer, * which means individual pmValueSets cannot be selectively replaced * (this would come to tears badly in pmFreeResult() where as soon as * one pmValueSet is found to be in a pinned PDU buffer it is assumed * they are all so ... leaving a memory leak for any ones we'd modified * here). * * So the only option is to COPY the pmResult, selectively replacing * the pmValueSets for the derived metrics, and then calling * pmFreeResult() to free the input structure and return the new one. * * In making the COPY it is critical that we reverse the algorithm * used in pmFreeResult() so that a later call to pmFreeResult() will * not cause a memory leak. * This means ... * - malloc() the pmResult (padded out to the right number of vset[] * entries) * - if valfmt is not PM_VAL_INSITU use PM_VAL_DPTR (not PM_VAL_SPTR), * so anything we point to is going to be released when our caller * calls pmFreeResult() * - use one malloc() for each pmValueSet with vlist[] sized to be 0 * if numval < 0 else numval * - pmValueBlocks are from malloc() * * For reference, the same logic appears in __pmLogFetchInterp() to * sythesize a pmResult there. */ void __dmpostfetch(__pmContext *ctxp, pmResult **result) { int i; int j; int m; int numval; int valfmt; size_t need; int rewrite; ctl_t *cp = (ctl_t *)ctxp->c_dm; pmResult *rp = *result; pmResult *newrp; /* if needed, init() called in __dmopencontext beforehand */ if (cp == NULL || cp->fetch_has_dm == 0) return; newrp = (pmResult *)malloc(sizeof(pmResult)+(cp->numpmid-1)*sizeof(pmValueSet *)); if (newrp == NULL) { __pmNoMem("__dmpostfetch: newrp", sizeof(pmResult)+(cp->numpmid-1)*sizeof(pmValueSet *), PM_FATAL_ERR); /*NOTREACHED*/ } newrp->timestamp = rp->timestamp; newrp->numpmid = cp->numpmid; for (j = 0; j < newrp->numpmid; j++) { numval = rp->vset[j]->numval; valfmt = rp->vset[j]->valfmt; rewrite = 0; /* * pandering to gcc ... m is not used unless rewrite == 1 in * which case m is well-defined */ m = 0; if (IS_DERIVED(rp->vset[j]->pmid)) { for (m = 0; m < cp->nmetric; m++) { if (rp->vset[j]->pmid == cp->mlist[m].pmid) { if (cp->mlist[m].expr == NULL) { numval = PM_ERR_PMID; } else { rewrite = 1; if (cp->mlist[m].expr->desc.type == PM_TYPE_32 || cp->mlist[m].expr->desc.type == PM_TYPE_U32) valfmt = PM_VAL_INSITU; else valfmt = PM_VAL_DPTR; numval = eval_expr(cp->mlist[m].expr, rp, 1); #ifdef PCP_DEBUG if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) { int k; char strbuf[20]; fprintf(stderr, "__dmpostfetch: [%d] root node %s: numval=%d", j, pmIDStr_r(rp->vset[j]->pmid, strbuf, sizeof(strbuf)), numval); for (k = 0; k < numval; k++) { fprintf(stderr, " vset[%d]: inst=%d", k, cp->mlist[m].expr->info->ivlist[k].inst); if (cp->mlist[m].expr->desc.type == PM_TYPE_32) fprintf(stderr, " l=%d", cp->mlist[m].expr->info->ivlist[k].value.l); else if (cp->mlist[m].expr->desc.type == PM_TYPE_U32) fprintf(stderr, " u=%u", cp->mlist[m].expr->info->ivlist[k].value.ul); else if (cp->mlist[m].expr->desc.type == PM_TYPE_64) fprintf(stderr, " ll=%"PRIi64, cp->mlist[m].expr->info->ivlist[k].value.ll); else if (cp->mlist[m].expr->desc.type == PM_TYPE_U64) fprintf(stderr, " ul=%"PRIu64, cp->mlist[m].expr->info->ivlist[k].value.ull); else if (cp->mlist[m].expr->desc.type == PM_TYPE_FLOAT) fprintf(stderr, " f=%f", (double)cp->mlist[m].expr->info->ivlist[k].value.f); else if (cp->mlist[m].expr->desc.type == PM_TYPE_DOUBLE) fprintf(stderr, " d=%f", cp->mlist[m].expr->info->ivlist[k].value.d); else if (cp->mlist[m].expr->desc.type == PM_TYPE_STRING) { fprintf(stderr, " cp=%s (len=%d)", cp->mlist[m].expr->info->ivlist[k].value.cp, cp->mlist[m].expr->info->ivlist[k].vlen); } else { fprintf(stderr, " vbp=" PRINTF_P_PFX "%p (len=%d)", cp->mlist[m].expr->info->ivlist[k].value.vbp, cp->mlist[m].expr->info->ivlist[k].vlen); } } fputc('\n', stderr); if (cp->mlist[m].expr->info != NULL) __dmdumpexpr(cp->mlist[m].expr, 1); } #endif } break; } } } if (numval <= 0) { /* only need pmid and numval */ need = sizeof(pmValueSet) - sizeof(pmValue); } else { /* already one pmValue in a pmValueSet */ need = sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue); } if (need > 0) { if ((newrp->vset[j] = (pmValueSet *)malloc(need)) == NULL) { __pmNoMem("__dmpostfetch: vset", need, PM_FATAL_ERR); /*NOTREACHED*/ } } newrp->vset[j]->pmid = rp->vset[j]->pmid; newrp->vset[j]->numval = numval; newrp->vset[j]->valfmt = valfmt; if (numval < 0) continue; for (i = 0; i < numval; i++) { pmValueBlock *vp; if (!rewrite) { newrp->vset[j]->vlist[i].inst = rp->vset[j]->vlist[i].inst; if (newrp->vset[j]->valfmt == PM_VAL_INSITU) { newrp->vset[j]->vlist[i].value.lval = rp->vset[j]->vlist[i].value.lval; } else { need = rp->vset[j]->vlist[i].value.pval->vlen; vp = (pmValueBlock *)malloc(need); if (vp == NULL) { __pmNoMem("__dmpostfetch: copy value", need, PM_FATAL_ERR); /*NOTREACHED*/ } memcpy((void *)vp, (void *)rp->vset[j]->vlist[i].value.pval, need); newrp->vset[j]->vlist[i].value.pval = vp; } continue; } /* * the rewrite case ... */ newrp->vset[j]->vlist[i].inst = cp->mlist[m].expr->info->ivlist[i].inst; switch (cp->mlist[m].expr->desc.type) { case PM_TYPE_32: case PM_TYPE_U32: newrp->vset[j]->vlist[i].value.lval = cp->mlist[m].expr->info->ivlist[i].value.l; break; case PM_TYPE_64: case PM_TYPE_U64: need = PM_VAL_HDR_SIZE + sizeof(__int64_t); if ((vp = (pmValueBlock *)malloc(need)) == NULL) { __pmNoMem("__dmpostfetch: 64-bit int value", need, PM_FATAL_ERR); /*NOTREACHED*/ } vp->vlen = need; vp->vtype = cp->mlist[m].expr->desc.type; memcpy((void *)vp->vbuf, (void *)&cp->mlist[m].expr->info->ivlist[i].value.ll, sizeof(__int64_t)); newrp->vset[j]->vlist[i].value.pval = vp; break; case PM_TYPE_FLOAT: need = PM_VAL_HDR_SIZE + sizeof(float); if ((vp = (pmValueBlock *)malloc(need)) == NULL) { __pmNoMem("__dmpostfetch: float value", need, PM_FATAL_ERR); /*NOTREACHED*/ } vp->vlen = need; vp->vtype = PM_TYPE_FLOAT; memcpy((void *)vp->vbuf, (void *)&cp->mlist[m].expr->info->ivlist[i].value.f, sizeof(float)); newrp->vset[j]->vlist[i].value.pval = vp; break; case PM_TYPE_DOUBLE: need = PM_VAL_HDR_SIZE + sizeof(double); if ((vp = (pmValueBlock *)malloc(need)) == NULL) { __pmNoMem("__dmpostfetch: double value", need, PM_FATAL_ERR); /*NOTREACHED*/ } vp->vlen = need; vp->vtype = PM_TYPE_DOUBLE; memcpy((void *)vp->vbuf, (void *)&cp->mlist[m].expr->info->ivlist[i].value.f, sizeof(double)); newrp->vset[j]->vlist[i].value.pval = vp; break; case PM_TYPE_STRING: need = PM_VAL_HDR_SIZE + cp->mlist[m].expr->info->ivlist[i].vlen; vp = (pmValueBlock *)malloc(need); if (vp == NULL) { __pmNoMem("__dmpostfetch: string value", need, PM_FATAL_ERR); /*NOTREACHED*/ } vp->vlen = need; vp->vtype = cp->mlist[m].expr->desc.type; memcpy((void *)vp->vbuf, cp->mlist[m].expr->info->ivlist[i].value.cp, cp->mlist[m].expr->info->ivlist[i].vlen); newrp->vset[j]->vlist[i].value.pval = vp; break; case PM_TYPE_AGGREGATE: case PM_TYPE_AGGREGATE_STATIC: case PM_TYPE_EVENT: case PM_TYPE_HIGHRES_EVENT: need = cp->mlist[m].expr->info->ivlist[i].vlen; vp = (pmValueBlock *)malloc(need); if (vp == NULL) { __pmNoMem("__dmpostfetch: aggregate or event value", need, PM_FATAL_ERR); /*NOTREACHED*/ } memcpy((void *)vp, cp->mlist[m].expr->info->ivlist[i].value.vbp, cp->mlist[m].expr->info->ivlist[i].vlen); newrp->vset[j]->vlist[i].value.pval = vp; break; default: /* * really nothing should end up here ... * do nothing as numval should have been < 0 */ #ifdef PCP_DEBUG if (pmDebug & DBG_TRACE_DERIVE) { char strbuf[20]; fprintf(stderr, "__dmpostfetch: botch: drived metric[%d]: operand %s has odd type (%d)\n", m, pmIDStr_r(rp->vset[j]->pmid, strbuf, sizeof(strbuf)), cp->mlist[m].expr->desc.type); } #endif break; } } } /* * cull the original pmResult and return the rewritten one */ pmFreeResult(rp); *result = newrp; return; }