Beispiel #1
0
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, &current->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);
}
Beispiel #2
0
void
dodso(int pdu)
{
    int			sts = 0;		/* initialize to pander to gcc */
    int			length;
    pmDesc		desc;
    pmDesc		*desc_list = NULL;
    pmResult		*result;
    __pmInResult	*inresult;
    int			i;
    int			j;
    char		*buffer;
    struct timeval	start;
    struct timeval	end;
    char		name[32];
    char		**namelist;
    int			*statuslist;
    pmID		pmid;

    if (timer != 0)
        __pmtimevalNow(&start);

    switch (pdu) {

    case PDU_DESC_REQ:
        printf("PMID: %s\n", pmIDStr(param.pmid));
        if ((sts = dodso_desc(param.pmid, &desc)) >= 0)
            __pmPrintDesc(stdout, &desc);
        else
            printf("Error: DSO desc() failed: %s\n", pmErrStr(sts));
        break;

    case PDU_FETCH:
        printf("PMID(s):");
        for (i = 0; i < param.numpmid; i++)
            printf(" %s", pmIDStr(param.pmidlist[i]));
        putchar('\n');

        if (get_desc) {
            desc_list = (pmDesc *)malloc(param.numpmid * sizeof(pmDesc));
            if (desc_list == NULL) {
                printf("Error: DSO fetch() failed: %s\n", pmErrStr(ENOMEM));
                return;
            }
            for (i = 0; i < param.numpmid; i++) {
                if ((sts = dodso_desc(param.pmidlist[i], &desc_list[i])) < 0) {
                    printf("Error: DSO desc() failed: %s\n", pmErrStr(sts));
                    free(desc_list);
                    return;
                }
            }
        }
        sts = 0;
        if (profile_changed) {
#ifdef PCP_DEBUG
            if (pmDebug & DBG_TRACE_PDU)
                fprintf(stderr, "DSO profile()\n");
#endif
            sts = dispatch.version.any.profile(profile, dispatch.version.any.ext);
            if (sts < 0)
                printf("Error: DSO profile() failed: %s\n", pmErrStr(sts));
            else
                profile_changed = 0;
        }
        if (sts >= 0) {
#ifdef PCP_DEBUG
            if (pmDebug & DBG_TRACE_PDU)
                fprintf(stderr, "DSO fetch()\n");
#endif
            sts = dispatch.version.any.fetch(param.numpmid, param.pmidlist,
                                             &result, dispatch.version.any.ext);
            if (sts >= 0) {
                if (desc_list)
                    _dbDumpResult(stdout, result, desc_list);
                else
                    __pmDumpResult(stdout, result);
                /*
                 * DSO PMDA will manage the pmResult skelton, but
                 * we need to free the pmValueSets and values here
                 */
                __pmFreeResultValues(result);
            }
            else {
                printf("Error: DSO fetch() failed: %s\n", pmErrStr(sts));
            }
        }
        if (desc_list)
            free(desc_list);
        break;

    case PDU_INSTANCE_REQ:
        printf("pmInDom: %s\n", pmInDomStr(param.indom));
#ifdef PCP_DEBUG
        if (pmDebug & DBG_TRACE_PDU)
            fprintf(stderr, "DSO instance()\n");
#endif

        sts = dispatch.version.any.instance(param.indom, param.number,
                                            param.name, &inresult,
                                            dispatch.version.any.ext);
        if (sts >= 0)
            printindom(stdout, inresult);
        else
            printf("Error: DSO instance() failed: %s\n", pmErrStr(sts));
        break;

    case PDU_RESULT:

        printf("PMID: %s\n", pmIDStr(param.pmid));
        printf("Getting description...\n");
        desc_list = &desc;
        if ((sts = dodso_desc(param.pmid, desc_list)) < 0) {
            printf("Error: DSO desc() failed: %s\n", pmErrStr(sts));
            return;
        }

        if (profile_changed) {
            printf("Sending Profile...\n");
            sts = dispatch.version.any.profile(profile, dispatch.version.any.ext);
            if (sts < 0) {
                printf("Error: DSO profile() failed: %s\n", pmErrStr(sts));
                return;
            }
            else
                profile_changed = 0;
        }

        printf("Getting Result Structure...\n");
        sts = dispatch.version.any.fetch(1, &(desc.pmid), &result,
                                         dispatch.version.any.ext);
        if (sts < 0) {
            printf("Error: DSO fetch() failed: %s\n", pmErrStr(sts));
            return;
        }

#ifdef PCP_DEBUG
        else if (pmDebug & DBG_TRACE_FETCH)
            _dbDumpResult(stdout, result, desc_list);
#endif

        sts = fillResult(result, desc.type);
        if (sts < 0) {
            pmFreeResult(result);
            return;
        }

        sts = dispatch.version.any.store(result, dispatch.version.any.ext);
        if (sts < 0)
            printf("Error: DSO store() failed: %s\n", pmErrStr(sts));

        break;

    case PDU_TEXT_REQ:
        if (param.number == PM_TEXT_PMID) {
            printf("PMID: %s\n", pmIDStr(param.pmid));
            i = param.pmid;
        }
        else {
            printf("pmInDom: %s\n", pmInDomStr(param.indom));
            i = param.indom;
        }

        for (j = 0; j < 2; j++) {

            if (j == 0)
                param.number |= PM_TEXT_ONELINE;
            else {
                param.number &= ~PM_TEXT_ONELINE;
                param.number |= PM_TEXT_HELP;
            }

            sts = dispatch.version.any.text(i, param.number, &buffer, dispatch.version.any.ext);
            if (sts >= 0) {
                if (j == 0) {
                    if (*buffer != '\0')
                        printf("[%s]\n", buffer);
                    else
                        printf("[<no one line help text specified>]\n");
                }
                else if (*buffer != '\0')
                    printf("%s\n", buffer);
                else
                    printf("<no help text specified>\n");
            }
            else
                printf("Error: DSO text() failed: %s\n", pmErrStr(sts));
        }
        break;

    case PDU_PMNS_IDS:
        if (dispatch.comm.pmda_interface < PMDA_INTERFACE_4) {
            printf("Error: PMDA Interface %d does not support dynamic metric names\n", dispatch.comm.pmda_interface);
            break;
        }
        printf("PMID: %s\n", pmIDStr(param.pmid));
        sts = dispatch.version.four.name(param.pmid, &namelist, dispatch.version.four.ext);
        if (sts > 0) {
            for (i = 0; i < sts; i++) {
                printf("   %s\n", namelist[i]);
            }
            free(namelist);
        }
        else if (sts == 0)
            printf("Warning: DSO name() returns 0\n");
        else
            printf("Error: DSO name() failed: %s\n", pmErrStr(sts));
        break;

    case PDU_PMNS_NAMES:
        if (dispatch.comm.pmda_interface < PMDA_INTERFACE_4) {
            printf("Error: PMDA Interface %d does not support dynamic metric names\n", dispatch.comm.pmda_interface);
            break;
        }
        printf("Metric: %s\n", param.name);
        sts = dispatch.version.four.pmid(param.name, &pmid, dispatch.version.four.ext);
        if (sts >= 0)
            printf("   %s\n", pmIDStr(pmid));
        else
            printf("Error: DSO pmid() failed: %s\n", pmErrStr(sts));
        break;

    case PDU_PMNS_CHILD:
        if (dispatch.comm.pmda_interface < PMDA_INTERFACE_4) {
            printf("Error: PMDA Interface %d does not support dynamic metric names\n", dispatch.comm.pmda_interface);
            break;
        }
        printf("Metric: %s\n", param.name);
        sts = dispatch.version.four.children(param.name, 0, &namelist, &statuslist, dispatch.version.four.ext);
        if (sts > 0) {
            for (i = 0; i < sts; i++) {
                printf("   %8.8s %s\n", statuslist[i] == 1 ? "non-leaf" : "leaf", namelist[i]);
            }
            free(namelist);
            free(statuslist);
        }
        else if (sts == 0)
            printf("Warning: DSO children() returns 0\n");
        else
            printf("Error: DSO children() failed: %s\n", pmErrStr(sts));
        break;

    case PDU_PMNS_TRAVERSE:
        if (dispatch.comm.pmda_interface < PMDA_INTERFACE_4) {
            printf("Error: PMDA Interface %d does not support dynamic metric names\n", dispatch.comm.pmda_interface);
            break;
        }
        printf("Metric: %s\n", param.name);
        sts = dispatch.version.four.children(param.name, 1, &namelist, &statuslist, dispatch.version.four.ext);
        if (sts > 0) {
            for (i = 0; i < sts; i++) {
                printf("   %8.8s %s\n", statuslist[i] == 1 ? "non-leaf" : "leaf", namelist[i]);
            }
            free(namelist);
            free(statuslist);
        }
        else if (sts == 0)
            printf("Warning: DSO children() returns 0\n");
        else
            printf("Error: DSO children() failed: %s\n", pmErrStr(sts));
        break;

    case PDU_AUTH:
        if (dispatch.comm.pmda_interface < PMDA_INTERFACE_6) {
            printf("Error: PMDA Interface %d does not support authentication\n", dispatch.comm.pmda_interface);
            break;
        }
        j = param.number;			/* attribute key */
        buffer = param.name;		/* attribute value */
        if (buffer)
            length = strlen(buffer) + 1;	/* length of value */
        else
            length = 0;
        i = 0;				/* client ID */

        __pmAttrKeyStr_r(j, name, sizeof(name)-1);
        name[sizeof(name)-1] = '\0';

        printf("Attribute: %s=%s\n", name, buffer ? buffer : "''");
        sts = dispatch.version.six.attribute(i, j, buffer, length, dispatch.version.six.ext);
        if (sts >= 0)
            printf("Success\n");
        else
            printf("Error: DSO attribute() failed: %s\n", pmErrStr(sts));
        break;

    default:
        printf("Error: DSO PDU (%s) botch!\n", __pmPDUTypeStr(pdu));
        break;
    }

    if (sts >= 0 && timer != 0) {
        __pmtimevalNow(&end);
        printf("Timer: %f seconds\n", __pmtimevalSub(&end, &start));
    }
}
Beispiel #3
0
int
pmFetch(int numpmid, pmID pmidlist[], pmResult **result)
{
    int		n;

    if (numpmid < 1) {
	n = PM_ERR_TOOSMALL;
	goto done;
    }

    if ((n = pmWhichContext()) >= 0) {
	__pmContext	*ctxp = __pmHandleToPtr(n);
	int		newcnt;
	pmID		*newlist = NULL;
	int		have_dm;

	if (ctxp == NULL) {
	    n = PM_ERR_NOCONTEXT;
	    goto done;
	}
	if (ctxp->c_type == PM_CONTEXT_LOCAL && PM_MULTIPLE_THREADS(PM_SCOPE_DSO_PMDA)) {
	    /* Local context requires single-threaded applications */
	    n = PM_ERR_THREAD;
	    PM_UNLOCK(ctxp->c_lock);
	    goto done;
	}

	/* for derived metrics, may need to rewrite the pmidlist */
	have_dm = newcnt = __pmPrepareFetch(ctxp, numpmid, pmidlist, &newlist);
	if (newcnt > numpmid) {
	    /* replace args passed into pmFetch */
	    numpmid = newcnt;
	    pmidlist = newlist;
	}

	if (ctxp->c_type == PM_CONTEXT_HOST) {
	    /*
	     * Thread-safe note
	     *
	     * Need to be careful here, because the PMCD changed protocol
	     * may mean several PDUs are returned, but __pmDecodeResult()
	     * may request more info from PMCD if pmDebug is set.
	     *
	     * So unlock ctxp->c_pmcd->pc_lock as soon as possible.
	     */
	    PM_LOCK(ctxp->c_pmcd->pc_lock);
	    if ((n = request_fetch(n, ctxp, numpmid, pmidlist)) >= 0) {
		int changed = 0;
		do {
		    __pmPDU	*pb;
		    int		pinpdu;

		    pinpdu = n = __pmGetPDU(ctxp->c_pmcd->pc_fd, ANY_SIZE,
					    ctxp->c_pmcd->pc_tout_sec, &pb);
		    if (n == PDU_RESULT) {
			PM_UNLOCK(ctxp->c_pmcd->pc_lock);
			n = __pmDecodeResult(pb, result);
		    }
		    else if (n == PDU_ERROR) {
			__pmDecodeError(pb, &n);
			if (n > 0)
			    /* PMCD state change protocol */
			    changed = n;
			else
			    PM_UNLOCK(ctxp->c_pmcd->pc_lock);
		    }
		    else {
			PM_UNLOCK(ctxp->c_pmcd->pc_lock);
			if (n != PM_ERR_TIMEOUT)
			    n = PM_ERR_IPC;
		    }
		    if (pinpdu > 0)
			__pmUnpinPDUBuf(pb);
		} while (n > 0);

		if (n == 0)
		    n |= changed;
	    }
	    else
		PM_UNLOCK(ctxp->c_pmcd->pc_lock);
	}
	else if (ctxp->c_type == PM_CONTEXT_LOCAL) {
	    n = __pmFetchLocal(ctxp, numpmid, pmidlist, result);
	}
	else {
	    /* assume PM_CONTEXT_ARCHIVE */
	    n = __pmLogFetch(ctxp, numpmid, pmidlist, result);
	    if (n >= 0 && (ctxp->c_mode & __PM_MODE_MASK) != PM_MODE_INTERP) {
		ctxp->c_origin.tv_sec = (__int32_t)(*result)->timestamp.tv_sec;
		ctxp->c_origin.tv_usec = (__int32_t)(*result)->timestamp.tv_usec;
	    }
	}

	/* process derived metrics, if any */
	if (have_dm) {
	    __pmFinishResult(ctxp, n, result);
	    if (newlist != NULL)
		free(newlist);
	}
	PM_UNLOCK(ctxp->c_lock);
    }

done:
#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_FETCH) {
	fprintf(stderr, "pmFetch returns ...\n");
	if (n > 0) {
	    fprintf(stderr, "PMCD state changes: agent(s)");
	    if (n & PMCD_ADD_AGENT) fprintf(stderr, " added");
	    if (n & PMCD_RESTART_AGENT) fprintf(stderr, " restarted");
	    if (n & PMCD_DROP_AGENT) fprintf(stderr, " dropped");
	    fputc('\n', stderr);
	}
	if (n >= 0)
	    __pmDumpResult(stderr, *result);
	else {
	    char	errmsg[PM_MAXERRMSGLEN];
	    fprintf(stderr, "Error: %s\n", pmErrStr_r(n, errmsg, sizeof(errmsg)));
	}
    }
#endif

    return n;
}
Beispiel #4
0
int
main(int argc, char **argv)
{
    int		sts;
    char	*msg;
    pmResult	*irp;		/* input pmResult */
    pmResult	*orp;		/* output pmResult */
    __pmPDU	*pb;		/* pdu buffer */
    struct timeval	unused;
    unsigned long	peek_offset;

    /* process cmd line args */
    if (parseargs(argc, argv) < 0) {
	pmUsageMessage(&opts);
	exit(1);
    }

    /* input  archive name is argv[opts.optind] */
    /* output archive name is argv[argc-1]) */

    /* output archive */
    oname = argv[argc-1];

    /* input archive */
    iname = argv[opts.optind];

    /*
     * This is the interp mode context
     */
    if ((ictx_a = pmNewContext(PM_CONTEXT_ARCHIVE, iname)) < 0) {
	fprintf(stderr, "%s: Error: cannot open archive \"%s\" (ctx_a): %s\n",
		pmProgname, iname, pmErrStr(ictx_a));
	exit(1);
    }

    if ((sts = pmGetArchiveLabel(&ilabel)) < 0) {
	fprintf(stderr, "%s: Error: cannot get archive label record (%s): %s\n", pmProgname, iname, pmErrStr(sts));
	exit(1);
    }

    /* start time */
    logstart_tval.tv_sec = ilabel.ll_start.tv_sec;
    logstart_tval.tv_usec = ilabel.ll_start.tv_usec;

    /* end time */
    if ((sts = pmGetArchiveEnd(&logend_tval)) < 0) {
	fprintf(stderr, "%s: Error: cannot get end of archive (%s): %s\n",
		pmProgname, iname, pmErrStr(sts));
	exit(1);
    }

    if (zarg) {
	/* use TZ from metrics source (input-archive) */
	if ((sts = pmNewZone(ilabel.ll_tz)) < 0) {
	    fprintf(stderr, "%s: Cannot set context timezone: %s\n",
		    pmProgname, pmErrStr(sts));
            exit(1);
	}
	printf("Note: timezone set to local timezone of host \"%s\" from archive\n\n", ilabel.ll_hostname);
    }
    else if (tz != NULL) {
	/* use TZ as specified by user */
	if ((sts = pmNewZone(tz)) < 0) {
	    fprintf(stderr, "%s: Cannot set timezone to \"%s\": %s\n",
		    pmProgname, tz, pmErrStr(sts));
	    exit(1);
	}
	printf("Note: timezone set to \"TZ=%s\"\n\n", tz);
    }
    else {
	char	*tz;
        tz = __pmTimezone();
	/* use TZ from local host */
	if ((sts = pmNewZone(tz)) < 0) {
	    fprintf(stderr, "%s: Cannot set local host's timezone: %s\n",
		    pmProgname, pmErrStr(sts));
	    exit(1);
	}
    }

    /* set winstart and winend timevals */
    sts = pmParseTimeWindow(Sarg, Targ, Aarg, Oarg,
			    &logstart_tval, &logend_tval,
			    &winstart_tval, &winend_tval, &unused, &msg);
    if (sts < 0) {
	fprintf(stderr, "%s: Invalid time window specified: %s\n",
		pmProgname, msg);
	exit(1);
    }
#if PCP_DEBUG
    if (pmDebug & DBG_TRACE_APPL0) {
	char	buf[26];
	pmCtime((const time_t *)&winstart_tval.tv_sec, buf);
	fprintf(stderr, "Start time: %s", buf);
	pmCtime((const time_t *)&winend_tval.tv_sec, buf);
	fprintf(stderr, "End time: %s", buf);
    }
#endif

    if ((sts = pmSetMode(PM_MODE_INTERP | PM_XTB_SET(PM_TIME_SEC),
                         &winstart_tval, (int)targ)) < 0) {
	fprintf(stderr, "%s: pmSetMode(PM_MODE_INTERP ...) failed: %s\n",
		pmProgname, pmErrStr(sts));
	exit(1);
    }

    /* create output log - must be done before writing label */
    if ((sts = __pmLogCreate("", oname, PM_LOG_VERS02, &logctl)) < 0) {
	fprintf(stderr, "%s: Error: __pmLogCreate: %s\n",
		pmProgname, pmErrStr(sts));
	exit(1);
    }

    /* This must be done after log is created:
     *		- checks that archive version, host, and timezone are ok
     *		- set archive version, host, and timezone of output archive
     *		- set start time
     *		- write labels
     */
    newlabel();
    current.tv_sec = logctl.l_label.ill_start.tv_sec = winstart_tval.tv_sec;
    current.tv_usec = logctl.l_label.ill_start.tv_usec = winstart_tval.tv_usec;
    /* write label record */
    writelabel();
    /*
     * Supress any automatic label creation in libpcp at the first
     * pmResult write.
     */
    logctl.l_state = PM_LOG_STATE_INIT;

    /*
     * Traverse the PMNS to get all the metrics and their metadata
     */
    if ((sts = pmTraversePMNS ("", dometric)) < 0) {
	fprintf(stderr, "%s: Error traversing namespace ... %s\n",
		pmProgname, pmErrStr(sts));
	goto cleanup;
    }

    /*
     * All the initial metadata has been generated, add timestamp
     */
    fflush(logctl.l_mdfp);
    __pmLogPutIndex(&logctl, &current);

    written = 0;

    /*
     * main loop
     */
    while (sarg == -1 || written < sarg) {
	/*
	 * do stuff
	 */
	if ((sts = pmUseContext(ictx_a)) < 0) {
	    fprintf(stderr, "%s: Error: cannot use context (%s): %s\n",
		    pmProgname, iname, pmErrStr(sts));
	    goto cleanup;
	}
	if ((sts = pmFetch(numpmid, pmidlist, &irp)) < 0) {
	    if (sts == PM_ERR_EOL)
		break;
	    fprintf(stderr,
		"%s: Error: pmFetch failed: %s\n", pmProgname, pmErrStr(sts));
	    exit(1);
	}
	if (irp->timestamp.tv_sec > winend_tval.tv_sec ||
	    (irp->timestamp.tv_sec == winend_tval.tv_sec &&
	     irp->timestamp.tv_usec > winend_tval.tv_usec)) {
	    /* past end time as per -T */
	    break;
	}
#if PCP_DEBUG
	if (pmDebug & DBG_TRACE_APPL2) {
	    fprintf(stderr, "input record ...\n");
	    __pmDumpResult(stderr, irp);
	}
#endif

	/*
	 * traverse the interval, looking at every archive record ...
	 * we are particularly interested in:
	 * 	- metric-values that are interpolated but not present in
	 * 	  this interval
	 * 	- counter wraps
	 *	- mark records
	 */
	doscan(&irp->timestamp);

	if ((sts = pmUseContext(ictx_a)) < 0) {
	    fprintf(stderr, "%s: Error: cannot use context (%s): %s\n",
		    pmProgname, iname, pmErrStr(sts));
	    goto cleanup;
	}

	orp = rewrite(irp);
#if PCP_DEBUG
	if (pmDebug & DBG_TRACE_APPL2) {
	    if (orp == NULL)
		fprintf(stderr, "output record ... none!\n");
	    else {
		fprintf(stderr, "output record ...\n");
		__pmDumpResult(stderr, orp);
	    }
	}
#endif
	if (orp == NULL)
	    goto next;

	/*
	 * convert log record to a PDU, and enforce V2 encoding semantics,
	 * then write it out
	 */
	sts = __pmEncodeResult(PDU_OVERRIDE2, orp, &pb);
	if (sts < 0) {
	    fprintf(stderr, "%s: Error: __pmEncodeResult: %s\n",
		    pmProgname, pmErrStr(sts));
	    goto cleanup;
	}

	/* switch volumes if required */
	if (varg > 0) {
	    if (written > 0 && (written % varg) == 0) {
		__pmTimeval	next_stamp;
		next_stamp.tv_sec = irp->timestamp.tv_sec;
		next_stamp.tv_usec = irp->timestamp.tv_usec;
		newvolume(oname, &next_stamp);
	    }
	}
	/*
	 * Even without a -v option, we may need to switch volumes
	 * if the data file exceeds 2^31-1 bytes
	 */
	peek_offset = ftell(logctl.l_mfp);
	peek_offset += ((__pmPDUHdr *)pb)->len - sizeof(__pmPDUHdr) + 2*sizeof(int);
	if (peek_offset > 0x7fffffff) {
	    __pmTimeval	next_stamp;
	    next_stamp.tv_sec = irp->timestamp.tv_sec;
	    next_stamp.tv_usec = irp->timestamp.tv_usec;
	    newvolume(oname, &next_stamp);
	}

	current.tv_sec = orp->timestamp.tv_sec;
	current.tv_usec = orp->timestamp.tv_usec;

	doindom(orp);

	/* write out log record */
	sts = __pmLogPutResult2(&logctl, pb);
	__pmUnpinPDUBuf(pb);
	if (sts < 0) {
	    fprintf(stderr, "%s: Error: __pmLogPutResult2: log data: %s\n",
		    pmProgname, pmErrStr(sts));
	    goto cleanup;
	}
	written++;

	rewrite_free();

next:
	pmFreeResult(irp);
    }

    /* write the last time stamp */
    fflush(logctl.l_mfp);
    fflush(logctl.l_mdfp);
    __pmLogPutIndex(&logctl, &current);

    exit(exit_status);

cleanup:
    {
	char    fname[MAXNAMELEN];
	fprintf(stderr, "Archive \"%s\" not created.\n", oname);
	snprintf(fname, sizeof(fname), "%s.0", oname);
	unlink(fname);
	snprintf(fname, sizeof(fname), "%s.meta", oname);
	unlink(fname);
	snprintf(fname, sizeof(fname), "%s.index", oname);
	unlink(fname);
	exit(1);
    }
}
Beispiel #5
0
void
doindom(pmResult *rp)
{
    pmValueSet		*vsp;
    int			i;
    int			j;
    int			needti = 0;
    int			need;
    metric_t		*mp = NULL;
    int			*instlist;
    char		**namelist;
    int			sts;

    for (i = 0; i < rp->numpmid; i++) {
	vsp = rp->vset[i];
	if (vsp->numval <= 0)
	    continue;

	/*
	 * pmidlist[] and rp->vset[]->pmid may not be in 1:1
	 * correspondence because we come here after rewrite() has
	 * been called ... search for matching pmid
	 */
	for (j = 0; j < numpmid; j++) {
	    if (pmidlist[j] == vsp->pmid) {
		mp = &metriclist[j];
		break;
	    }
	}
	if (mp == NULL) {
	    fprintf(stderr,
		"%s: doindom: Arrgh, unexpected PMID %s @ vset[%d]\n",
		    pmProgname, pmIDStr(vsp->pmid), i);
	    __pmDumpResult(stderr, rp);
	    exit(1);
	}
	if (mp->idp == NULL)
	    continue;

	if ((sts = pmGetInDom(mp->idp->indom, &instlist, &namelist)) < 0) {
	    fprintf(stderr,
		"%s: doindom: pmGetInDom (%s) failed: %s\n",
		    pmProgname, pmInDomStr(mp->idp->indom), pmErrStr(sts));
	    exit(1);
	}

	need = 1;
	/*
	 * Need to output the indom if the number of instances changes
	 * or the set of instance ids are not the same from the last
	 * time.
	 */
	if (sts == mp->idp->numinst) {
	    for (j = 0; j < mp->idp->numinst; j++) {
		if (mp->idp->inst[j] != instlist[j])
		    break;
	    }
	    if (j == mp->idp->numinst) {
		/*
		 * Do we need to check the namelist elts as well, e.g.
		 * using strcmp()?
		 * Not at this stage ... if the instance ids are all the
		 * same, then only a very odd (and non-compliant) PMDA
		 * would change the mapping from id to name on the fly
		 */
		need = 0;
	    }
	}

	if (need) {
#if PCP_DEBUG
	    if (pmDebug & DBG_TRACE_APPL0) {
		fprintf(stderr, "Add metadata: indom %s for metric %s\n", pmInDomStr(mp->idp->indom), pmIDStr(vsp->pmid));
	    }
#endif
	    if (mp->idp->name != NULL) free(mp->idp->name);
	    if (mp->idp->inst != NULL) free(mp->idp->inst);
	    mp->idp->name = namelist;
	    mp->idp->inst = instlist;
	    mp->idp->numinst = sts;
	    if ((sts = __pmLogPutInDom(&logctl, mp->idp->indom, &current, mp->idp->numinst, mp->idp->inst, mp->idp->name)) < 0) {
		fprintf(stderr,
		    "%s: Error: failed to add pmInDom: indom %s (for pmid %s): %s\n",
			pmProgname, pmInDomStr(mp->idp->indom), pmIDStr(vsp->pmid), pmErrStr(sts));
		exit(1);
	    }
	    needti = 1;		/* requires a temporal index update */
	}
	else {
	    free(instlist);
	    free(namelist);
	}

    }

    if (needti) {
	fflush(logctl.l_mdfp);
	__pmLogPutIndex(&logctl, &current);
    }

}
Beispiel #6
0
/*
 * Tests 4. and 5.
 * Set up an explicit profile of ourself and our parent
 * If any of the metrics are not in the proc indom, we'll get no values back.
 * Checks if profile is being handled correctly.
 * Checks if fetch is using profile correctly.
 */
void
test_prof_fetch(void)
{
    int 	sts;
    int		i;
    int		pids[2];
    pmResult	*result1, *result2;

    print_banner_start("profile/fetch");

    pids[0] = (int)getpid();
    pids[1] = (int)getppid();
    pmDelProfile(indom, 0, NULL);
    pmAddProfile(indom, 2, pids);

    printf("\n--- Check profile in context dump... ---\n");
    if ((sts = pmWhichContext()) < 0) {
	printf("%s: pmWhichContext: %s\n", pmProgname, pmErrStr(sts));
	exit(1);
    }
    __pmDumpContext(stdout, sts, PM_INDOM_NULL);
    printf("--- End Check profile in context dump... ---\n");

    printf("\n--- Fetch Over Restricted Instance Domain ... ---\n");
    for (i=0; i < iterations; i++) {
	int j,k;

	sts = pmFetch(nmetrics, pmids, &result1);
	if (sts < 0) {
	    printf("%s: iteration %d : %s\n", pmProgname, i, pmErrStr(sts));
	    exit(1);
	}
	__pmDumpResult(stdout, result1);


	for (j = 0; j < result1->numpmid; j++) {
	    pmValueSet *set = result1->vset[j];

	    if (set->numval != 2) {
		printf("%s: Error: num of inst == %d\n", pmProgname, set->numval);
	    }        

	    for (k = 0; k < set->numval; k++) {
		pmValue *val = &set->vlist[k];
		if (val->inst != pids[0] && val->inst != pids[1]) {
		    printf("%s: Error: inst ids do not match pids\n", pmProgname);
		    exit(1);
		}        
	    } 
	}

	pmFreeResult(result1);
    }
    printf("--- End Fetch Over Restricted Instance Domain ... ---\n");



    printf("\n--- Fetch Over Entire Instance Domain ... ---\n");
    if (indom != PM_INDOM_NULL) {
	pmDelProfile(indom, 0, NULL);
	pmAddProfile(indom, all_n, all_inst);
    }
    sts = pmFetch(nmetrics, pmids, &result2);
    if (sts < 0) {
	printf("%s: fetch all %d instances : %s\n", pmProgname, all_n, pmErrStr(sts));
	exit(1);
    }
    __pmDumpResult(stdout, result2);
    pmFreeResult(result2);
    printf("--- End Fetch Over Entire Instance Domain ... ---\n");

    print_banner_end("profile/fetch");

}
Beispiel #7
0
int
main(int argc, char **argv)
{
    int		type = PM_CONTEXT_HOST;
    int		c;
    int		sts;
    int		errflag = 0;
    char	*host = "localhost";
    static char	*usage = "[-D N] [-h hostname] metric stringvalue";
    int			len;
    int			n;
    char		*namelist[1];
    pmID		pmidlist[1];
    pmResult		*res;

    __pmSetProgname(argv[0]);

    while ((c = getopt(argc, argv, "D:h:")) != EOF) {
	switch (c) {

#ifdef PCP_DEBUG
	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;
#endif

	case 'h':	/* hostname for PMCD to contact */
	    host = optarg;
	    break;

	case '?':
	default:
	    errflag++;
	    break;
	}
    }

    if (errflag || optind != argc-2) {
	printf("Usage: %s %s\n", pmProgname, usage);
	exit(1);
    }

    if ((sts = pmNewContext(type, host)) < 0) {
	printf("%s: Cannot connect to PMCD on host \"%s\": %s\n",
	    pmProgname, host, pmErrStr(sts));
	exit(1);
    }

    namelist[0] = argv[optind];
    n = pmLookupName(1, namelist, pmidlist);
    if (n < 0 || pmidlist[0] == PM_ID_NULL) {
	printf("pmLookupName: %s\n", pmErrStr(n));
	exit(1);
    }

    if ((n = pmFetch(1, pmidlist, &res)) < 0) {
	printf("pmFetch: %s\n", pmErrStr(n));
	exit(1);
    }

    /*
     * expecting one value and a pmValueBlock with a type
     * of PM_TYPE_AGGREGATE
     */
    if (res->vset[0]->numval != 1) {
	printf("Expecting numval 1, found %d\n", res->vset[0]->numval);
	__pmDumpResult(stdout, res);
	exit(1);
    }
    if (res->vset[0]->valfmt == PM_VAL_INSITU) {
	printf("Not expecing PM_VAL_INSITU\n");
	__pmDumpResult(stdout, res);
	exit(1);
    }
    if (res->vset[0]->vlist[0].value.pval->vtype != PM_TYPE_AGGREGATE) {
	printf("Not expecing type %s\n", pmTypeStr(res->vset[0]->vlist[0].value.pval->vtype));
	__pmDumpResult(stdout, res);
	exit(1);
    }
    printf("%s old value: ", namelist[0]);
    pmPrintValue(stdout, res->vset[0]->valfmt, res->vset[0]->vlist[0].value.pval->vtype, &res->vset[0]->vlist[0], 0);

    /*
     * old value is probably from a pinned PDU buffer ... don't free
     * and accept small mem leak here
     */
    len = strlen(argv[optind+1]);
    res->vset[0]->vlist[0].value.pval = (pmValueBlock *)malloc(len + PM_VAL_HDR_SIZE);

    res->vset[0]->vlist[0].value.pval->vtype = PM_TYPE_AGGREGATE;
    res->vset[0]->vlist[0].value.pval->vlen = len + PM_VAL_HDR_SIZE;
    memcpy(res->vset[0]->vlist[0].value.pval->vbuf, argv[optind+1], len);

    if ((n = pmStore(res)) < 0) {
	printf("pmStore: %s\n", pmErrStr(n));
	exit(1);
    }
    pmFreeResult(res);

    if ((n = pmFetch(1, pmidlist, &res)) < 0) {
	printf("pmFetch again: %s\n", pmErrStr(n));
	exit(1);
    }
    printf(" new value: ");
    pmPrintValue(stdout, res->vset[0]->valfmt, res->vset[0]->vlist[0].value.pval->vtype, &res->vset[0]->vlist[0], 0);
    putchar('\n');

    pmFreeResult(res);

    exit(0);
}
Beispiel #8
0
static int
do_control(__pmPDU *pb)
{
    int			sts;
    int			control;
    int			state;
    int			delta;
    pmResult		*request;
    pmResult		*result;
    int			siamised = 0;	/* the verb from siamese (as in twins) */
    int			i;
    int			j;
    int			val;
    pmValueSet		*vsp;
    optreq_t		*rqp;
    task_t		*tp;
    time_t		now;
    int			reqstate = 0;

    /*
     * TODO	- encoding for logging interval in requests and results?
     */
    if ((sts = __pmDecodeLogControl(pb, &request, &control, &state, &delta)) < 0)
	return sts;

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_LOG) {
	fprintf(stderr, "do_control: control=%d state=%d delta=%d request ...\n",
		control, state, delta);
	dumpcontrol(stderr, request, 0);
    }
#endif

    if (control == PM_LOG_MANDATORY || control == PM_LOG_ADVISORY) {
	time(&now);
	fprintf(stderr, "\n%s", ctime(&now));
	fprintf(stderr, "pmlc request from %s: %s",
	    pmlc_host, control == PM_LOG_MANDATORY ? "mandatory" : "advisory");
	if (state == PM_LOG_ON) {
	    if (delta == 0)
		fprintf(stderr, " on once\n");
	    else
		fprintf(stderr, " on %.1f sec\n", (float)delta/1000);
	}
	else if (state == PM_LOG_OFF)
	    fprintf(stderr, " off\n");
	else
	    fprintf(stderr, " maybe\n");
    }

    /*
     * access control checks
     */
    sts = 0;
    switch (control) {
	case PM_LOG_MANDATORY:
	    if (denyops & PM_OP_LOG_MAND)
		sts = PM_ERR_PERMISSION;
	    break;

	case PM_LOG_ADVISORY:
	    if (denyops & PM_OP_LOG_ADV)
		sts = PM_ERR_PERMISSION;
	    break;

	case PM_LOG_ENQUIRE:
	    /*
	     * Don't need to check [access] as you have to have _some_
	     * permission (at least one of PM_OP_LOG_ADV or PM_OP_LOG_MAND
	     * and PM_OP_LOG_ENQ) to make a connection ... and if you
	     * have either PM_OP_LOG_ADV or PM_OP_LOG_MAND it makes no
	     * sense to deny PM_OP_LOG_ENQ operations.
	     */
	    break;

	default:
	    fprintf(stderr, "Bad control PDU type %d\n", control);
	    sts = PM_ERR_IPC;
	    break;
    }
    if (sts < 0) {
	fprintf(stderr, "Error: %s\n", pmErrStr(sts));
	if ((sts = __pmSendError(clientfd, FROM_ANON, sts)) < 0)
	    __pmNotifyErr(LOG_ERR,
			 "do_control: error sending Error PDU to client: %s\n",
			 pmErrStr(sts));
	pmFreeResult(request);
	return sts;
    }

    /* handle everything except PM_LOG_ENQUIRE */
    if (control == PM_LOG_MANDATORY || control == PM_LOG_ADVISORY) {
	/* update the logging status of metrics */

	task_t		*newtp = NULL; /* task for metrics/insts in request */
	struct timeval	tdelta = { 0 };
	int		newtask;
	int		mflags;

	/* convert state and control to the bitmask used in pmlogger and values
	 * returned in results.  Remember that reqstate starts with nothing on.
	 */
	if (state == PM_LOG_ON)
	    PMLC_SET_ON(reqstate, 1);
	else
	    PMLC_SET_ON(reqstate, 0);
	if (control == PM_LOG_MANDATORY) {
	    if (state == PM_LOG_MAYBE)
		/* mandatory+maybe => maybe+advisory+off  */
		PMLC_SET_MAYBE(reqstate, 1);
	    else
		PMLC_SET_MAND(reqstate, 1);
	}

	/* try to find an existing task for the request
	 * Never return a "once only" task, it may have gone off already and just
	 * be hanging around like a bad smell.
	 */
	if (delta != 0) {
	    tdelta.tv_sec = delta / 1000;
	    tdelta.tv_usec = (delta % 1000) * 1000;
	    newtp = find_task(reqstate, &tdelta);
	}
	newtask = (newtp == NULL);

	for (i = 0; i < request->numpmid; i++) {
	    vsp = request->vset[i];
	    if (vsp->numval < 0)
		/*
		 * request is malformed, as we cannot control logging
		 * for an undefined instance ... there is no way to
		 * return an error from here, so simply ignore this
		 * metric
		 */
		continue;
	    mflags = find_metric(vsp->pmid);
	    if (mflags < 0) {
		/* only add new metrics if they are ON or MANDATORY OFF
		 * Careful: mandatory+maybe is mandatory+maybe+off
		 */
		if (PMLC_GET_ON(reqstate) ||
		    (PMLC_GET_MAND(reqstate) && !PMLC_GET_MAYBE(reqstate)))
		    add_metric(vsp, &newtp);
	    }
	    else
		/* already a specification for this metric */
		update_metric(vsp, reqstate, mflags, &newtp);
	}

	/* schedule new logging task if new metric(s) specified */
	if (newtask && newtp != NULL) {
	    if (newtp->t_fetch == NULL) {
		/* the new task ended up with no fetch groups, throw it away */
		if (newtp->t_pmidlist != NULL)
		    free(newtp->t_pmidlist);
		free(newtp);
	    }
	    else {
		/* link new task into tasklist */
		newtp->t_next = tasklist;
		tasklist = newtp;

		/* use only the MAND/ADV and ON/OFF bits of reqstate */
		newtp->t_state = PMLC_GET_STATE(reqstate);
		if (PMLC_GET_ON(reqstate)) {
		    newtp->t_delta = tdelta;
		    newtp->t_afid = __pmAFregister(&tdelta, (void *)newtp,
					       log_callback);
		}
		else
		    newtp->t_delta.tv_sec = newtp->t_delta.tv_usec = 0;
		linkback(newtp);
	    }
	}
    }

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_APPL0)
	dumpit();
#endif

    /* just ignore advisory+maybe---the returned pmResult will have the metrics
     * in their original state indicating that the request could not be
     * satisfied.
     */

    result = request;
    result->timestamp.tv_sec = result->timestamp.tv_usec = 0;	/* for purify */
    /* write the current state of affairs into the result _pmResult */
    for (i = 0; i < request->numpmid; i++) {

	if (control == PM_LOG_MANDATORY || control == PM_LOG_ADVISORY) {
	    char	**names;

	    sts = pmNameAll(request->vset[i]->pmid, &names);
	    if (sts < 0)
		fprintf(stderr, "  metric: %s", pmIDStr(request->vset[i]->pmid));
	    else {
		fprintf(stderr, "  metric: ");
		__pmPrintMetricNames(stderr, sts, names, " or ");
		free(names);
	    }
	}

	if (request->vset[i]->numval <= 0 && !siamised) {
	    result = siamise_request(request);
	    siamised = 1;
	}
	/*
	 * pmids with numval <= 0 in the request have a null vset ptr in the
	 * in the corresponding place in the siamised result.
	 */
	if (result->vset[i] != NULL)
	    vsp = result->vset[i];
	else {
	    /* the result should also contain the history for an all instances
	     * enquire request.  Control requests just get the current indom
	     * since the user of pmlc really wants to see what's being logged
	     * now rather than in the past.
	     */
	    vsp = build_vset(request->vset[i]->pmid, control == PM_LOG_ENQUIRE);
	    result->vset[i] = vsp;
	}
	vsp->valfmt = PM_VAL_INSITU;
	for (j = 0; j < vsp->numval; j++) {
	    rqp = findoptreq(vsp->pmid, vsp->vlist[j].inst);
	    val = 0;
	    if (rqp == NULL) {
		PMLC_SET_STATE(val, 0);
		PMLC_SET_DELTA(val, 0);
	    }
	    else {
		tp = rqp->r_fetch->f_aux;
		PMLC_SET_STATE(val, tp->t_state);
		PMLC_SET_DELTA(val, (tp->t_delta.tv_sec*1000 + tp->t_delta.tv_usec/1000));
	    }

	    val |= gethistflags(vsp->pmid, vsp->vlist[j].inst);
	    vsp->vlist[j].value.lval = val;

	    if (control == PM_LOG_MANDATORY || control == PM_LOG_ADVISORY) {
		int	expstate = 0;
		int	statemask = 0;
		int	expdelta;
		if (rqp != NULL && rqp->r_desc->indom != PM_INDOM_NULL) {
		    char	*p;
		    if (j == 0)
			fputc('\n', stderr);
		    if (pmNameInDom(rqp->r_desc->indom, vsp->vlist[j].inst, &p) >= 0) {
			fprintf(stderr, "    instance: %s", p);
			free(p);
		    }
		    else
			fprintf(stderr, "    instance: #%d", vsp->vlist[j].inst);
		}
		else {
		    /* no pmDesc ... punt */
		    if (vsp->numval > 1 || vsp->vlist[j].inst != PM_IN_NULL) {
			if (j == 0)
			    fputc('\n', stderr);
			fprintf(stderr, "    instance: #%d", vsp->vlist[j].inst);
		    }
		}
		if (state != PM_LOG_MAYBE) {
		    if (control == PM_LOG_MANDATORY)
			PMLC_SET_MAND(expstate, 1);
		    else
			PMLC_SET_MAND(expstate, 0);
		    if (state == PM_LOG_ON)
			PMLC_SET_ON(expstate, 1);
		    else
			PMLC_SET_ON(expstate, 0);
		    PMLC_SET_MAND(statemask, 1);
		    PMLC_SET_ON(statemask, 1);
		}
		else {
		    PMLC_SET_MAND(expstate, 0);
		    PMLC_SET_MAND(statemask, 1);
		}
		expdelta = PMLC_GET_ON(expstate) ? delta : 0;
		if ((PMLC_GET_STATE(val) & statemask) != expstate ||
		    PMLC_GET_DELTA(val) != expdelta)
			fprintf(stderr, " [request failed]");
		fputc('\n', stderr);
	    }
	}
    }

#ifdef PCP_DEBUG
    if (pmDebug & DBG_TRACE_LOG) {
	__pmDumpResult(stderr, result);
    }
#endif

    if ((sts = __pmSendResult(clientfd, FROM_ANON, result)) < 0)
		__pmNotifyErr(LOG_ERR,
			     "do_control: error sending Error PDU to client: %s\n",
			     pmErrStr(sts));

    if (siamised) {
	for (i = 0; i < request->numpmid; i++)
	    if (request->vset[i]->numval <= 0)
		free(result->vset[i]);
	free(result);
    }
    pmFreeResult(request);

    return 0;
}
Beispiel #9
0
/*
 * 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*/
}