1    	/*
2    	 * Copyright (c) 2009 Ken McDonell.  All Rights Reserved.
3    	 * 
4    	 * This library is free software; you can redistribute it and/or modify it
5    	 * under the terms of the GNU Lesser General Public License as published
6    	 * by the Free Software Foundation; either version 2.1 of the License, or
7    	 * (at your option) any later version.
8    	 * 
9    	 * This library is distributed in the hope that it will be useful, but
10   	 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11   	 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
12   	 * License for more details.
13   	 *
14   	 * Debug Flags
15   	 *	DERIVE - high-level diagnostics
16   	 *	DERIVE & APPL0 - configuration and static syntax analysis
17   	 *	DERIVE & APPL1 - expression binding and semantic analysis
18   	 *	DERIVE & APPL2 - fetch handling
19   	 */
20   	
21   	#include <inttypes.h>
22   	#include "derive.h"
23   	
24   	static void
25   	get_pmids(node_t *np, int *cnt, pmID **list)
26   	{
27   	    assert(np != NULL);
28   	    if (np->left != NULL) get_pmids(np->left, cnt, list);
29   	    if (np->right != NULL) get_pmids(np->right, cnt, list);
30   	    if (np->type == L_NAME) {
31   		(*cnt)++;
32   		if ((*list = (pmID *)realloc(*list, (*cnt)*sizeof(pmID))) == NULL) {
33   		    __pmNoMem("__dmprefetch: realloc xtralist", (*cnt)*sizeof(pmID), PM_FATAL_ERR);
34   		    /*NOTREACHED*/
35   		}
36   		(*list)[*cnt-1] = np->info->pmid;
37   	    }
38   	}
39   	
40   	/*
41   	 * Walk the pmidlist[] from pmFetch.
42   	 * For each derived metric found in the list add all the operand metrics,
43   	 * and build a combined pmID list (newlist).
44   	 *
45   	 * Return 0 if no derived metrics in the list, else the number of pmIDs
46   	 * in the combined list.
47   	 *
48   	 * The derived metric pmIDs are left in the combined list (they will
49   	 * return PM_ERR_NOAGENT from the fetch) to simplify the post-processing
50   	 * of the pmResult in __dmpostfetch()
51   	 */
52   	int
53   	__dmprefetch(__pmContext *ctxp, int numpmid, pmID *pmidlist, pmID **newlist)
54   	{
55   	    int		i;
56   	    int		j;
57   	    int		m;
58   	    int		xtracnt = 0;
59   	    pmID	*xtralist = NULL;
60   	    pmID	*list;
61   	    ctl_t	*cp = (ctl_t *)ctxp->c_dm;
62   	
63   	    /* if needed, init() called in __dmopencontext beforehand */
64   	
65   	    if (cp == NULL) return 0;
66   	
67   	    /*
68   	     * save numpmid to be used in __dmpostfetch() ... works because calls
69   	     * to pmFetch cannot be nested (at all, but certainly for the same
70   	     * context).
71   	     * Ditto for the fast path flag (fetch_has_dm).
72   	     */
73   	    cp->numpmid = numpmid;
74   	    cp->fetch_has_dm = 0;
75   	
76   	    for (m = 0; m < numpmid; m++) {
77   		if (pmid_domain(pmidlist[m]) != DYNAMIC_PMID ||
78   		    pmid_item(pmidlist[m]) == 0)
79   		    continue;
80   		for (i = 0; i < cp->nmetric; i++) {
81   		    if (pmidlist[m] == cp->mlist[i].pmid) {
82   			if (cp->mlist[i].expr != NULL) {
83   			    get_pmids(cp->mlist[i].expr, &xtracnt, &xtralist);
84   			    cp->fetch_has_dm = 1;
85   			}
86   			break;
87   		    }
88   		}
89   	    }
90   	    if (xtracnt == 0) {
91   		if (cp->fetch_has_dm)
92   		    return numpmid;
93   		else
94   		    return 0;
95   	    }
96   	
97   	    /*
98   	     * Some of the "extra" ones, may already be in the caller's pmFetch 
99   	     * list, or repeated in xtralist[] (if the same metric operand appears
100  	     * more than once as a leaf node in the expression tree.
101  	     * Remove these duplicates
102  	     */
103  	    j = 0;
104  	    for (i = 0; i < xtracnt; i++) {
105  		for (m = 0; m < numpmid; m++) {
106  		    if (xtralist[i] == pmidlist[m])
107  			/* already in pmFetch list */
108  			break;
109  		}
110  		if (m < numpmid) continue;
111  		for (m = 0; m < j; m++) {
112  		    if (xtralist[i] == xtralist[m])
113  		    	/* already in xtralist[] */
114  			break;
115  		}
116  		if (m == j)
117  		    xtralist[j++] = xtralist[i];
118  	    }
119  	    xtracnt = j;
120  	    if (xtracnt == 0) {
121  		free(xtralist);
122  		return numpmid;
123  	    }
124  	
125  	#ifdef PCP_DEBUG
126  	    if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) {
127  		fprintf(stderr, "derived metrics prefetch added %d metrics:", xtracnt);
128  		for (i = 0; i < xtracnt; i++)
129  		    fprintf(stderr, " %s", pmIDStr(xtralist[i]));
130  		fputc('\n', stderr);
131  	    }
132  	#endif
133  	    if ((list = (pmID *)malloc((numpmid+xtracnt)*sizeof(pmID))) == NULL) {
134  		__pmNoMem("__dmprefetch: alloc list", (numpmid+xtracnt)*sizeof(pmID), PM_FATAL_ERR);
135  		/*NOTREACHED*/
136  	    }
137  	    for (m = 0; m < numpmid; m++) {
138  		list[m] = pmidlist[m];
139  	    }
140  	    for (i = 0; i < xtracnt; i++) {
141  		list[m++] = xtralist[i];
142  	    }
143  	    free(xtralist);
144  	    *newlist = list;
145  	
146  	    return m;
147  	}
148  	
149  	/*
150  	 * Free the old ivlist[] (if any) ... may need to walk the list because
151  	 * the pmAtomValues may have buffers attached in the type STRING,
152  	 * type AGGREGATE* and type EVENT cases.
153  	 * Includes logic to save one history sample (for delta()).
154  	 */
155  	static void
156  	free_ivlist(node_t *np)
157  	{
158  	    int		i;
159  	
160  	    assert(np->info != NULL);
161  	
162  	    if (np->save_last) {
163  		if (np->info->last_ivlist != NULL) {
164  		    /*
165  		     * no STRING, AGGREGATE or EVENT types for delta(),
166  		     * so simple free()
167  		     */
168  		    free(np->info->last_ivlist);
169  		}
170  		np->info->last_numval = np->info->numval;
171  		np->info->last_ivlist = np->info->ivlist;
172  	    }
173  	    else {
174  		/* no history */
175  		if (np->info->ivlist != NULL) {
176  		    if (np->desc.type == PM_TYPE_STRING) {
177  			for (i = 0; i < np->info->numval; i++) {
178  			    if (np->info->ivlist[i].value.cp != NULL)
179  				free(np->info->ivlist[i].value.cp);
180  			}
181  		    }
182  		    else if (np->desc.type == PM_TYPE_AGGREGATE ||
183  			     np->desc.type == PM_TYPE_AGGREGATE_STATIC ||
184  			     np->desc.type == PM_TYPE_EVENT) {
185  			for (i = 0; i < np->info->numval; i++) {
186  			    if (np->info->ivlist[i].value.vbp != NULL)
187  				free(np->info->ivlist[i].value.vbp);
188  			}
189  		    }
190  		}
191  		free(np->info->ivlist);
192  		np->info->ivlist = NULL;
193  		np->info->numval = 0;
194  	    }
195  	}
196  	
197  	/*
198  	 * Binary arithmetic.
199  	 *
200  	 * result = <a> <op> <b>
201  	 * ltype, rtype and type are the types of <a>, <b> and the result
202  	 * respectively
203  	 *
204  	 * If type is PM_TYPE_DOUBLE then lmul, ldiv, rmul and rdiv are
205  	 * the scale factors for units scale conversion of <a> and <b>
206  	 * respectively, so lmul*<a>/ldiv ... all are 1 in the common cases.
207  	 */
208  	static pmAtomValue
209  	bin_op(int type, int op, pmAtomValue a, int ltype, int lmul, int ldiv, pmAtomValue b, int rtype, int rmul, int rdiv)
210  	{
211  	    static pmAtomValue	res;
212  	    pmAtomValue		l;
213  	    pmAtomValue		r;
214  	
215  	    l = a;	/* struct assignments */
216  	    r = b;
217  	
218  	    /* 
219  	     * Promote each operand to the type of the result ... there are limited
220  	     * cases to be considered here, see promote[][] and map_desc().
221  	     */
222  	    switch (type) {
223  		case PM_TYPE_32:
224  		case PM_TYPE_U32:
225  		    /* do nothing */
226  		    break;
227  		case PM_TYPE_64:
228  		    switch (ltype) {
229  			case PM_TYPE_32:
230  			    l.ll = a.l;
231  			    break;
232  			case PM_TYPE_U32:
233  			    l.ll = a.ul;
234  			    break;
235  			case PM_TYPE_64:
236  			case PM_TYPE_U64:
237  			    /* do nothing */
238  			    break;
239  		    }
240  		    switch (rtype) {
241  			case PM_TYPE_32:
242  			    r.ll = b.l;
243  			    break;
244  			case PM_TYPE_U32:
245  			    r.ll = b.ul;
246  			    break;
247  			case PM_TYPE_64:
248  			case PM_TYPE_U64:
249  			    /* do nothing */
250  			    break;
251  		    }
252  		    break;
253  		case PM_TYPE_U64:
254  		    switch (ltype) {
255  			case PM_TYPE_32:
256  			    l.ull = a.l;
257  			    break;
258  			case PM_TYPE_U32:
259  			    l.ull = a.ul;
260  			    break;
261  			case PM_TYPE_64:
262  			case PM_TYPE_U64:
263  			    /* do nothing */
264  			    break;
265  		    }
266  		    switch (rtype) {
267  			case PM_TYPE_32:
268  			    r.ull = b.l;
269  			    break;
270  			case PM_TYPE_U32:
271  			    r.ull = b.ul;
272  			    break;
273  			case PM_TYPE_64:
274  			case PM_TYPE_U64:
275  			    /* do nothing */
276  			    break;
277  		    }
278  		    break;
279  		case PM_TYPE_FLOAT:
280  		    switch (ltype) {
281  			case PM_TYPE_32:
282  			    l.f = a.l;
283  			    break;
284  			case PM_TYPE_U32:
285  			    l.f = a.ul;
286  			    break;
287  			case PM_TYPE_64:
288  			    l.f = a.ll;
289  			    break;
290  			case PM_TYPE_U64:
291  			    l.f = a.ull;
292  			    break;
293  			case PM_TYPE_FLOAT:
294  			    /* do nothing */
295  			    break;
296  		    }
297  		    switch (rtype) {
298  			case PM_TYPE_32:
299  			    r.f = b.l;
300  			    break;
301  			case PM_TYPE_U32:
302  			    r.f = b.ul;
303  			    break;
304  			case PM_TYPE_64:
305  			    r.f = b.ll;
306  			    break;
307  			case PM_TYPE_U64:
308  			    r.f = b.ull;
309  			    break;
310  			case PM_TYPE_FLOAT:
311  			    /* do nothing */
312  			    break;
313  		    }
314  		    break;
315  		case PM_TYPE_DOUBLE:
316  		    switch (ltype) {
317  			case PM_TYPE_32:
318  			    l.d = a.l;
319  			    break;
320  			case PM_TYPE_U32:
321  			    l.d = a.ul;
322  			    break;
323  			case PM_TYPE_64:
324  			    l.d = a.ll;
325  			    break;
326  			case PM_TYPE_U64:
327  			    l.d = a.ull;
328  			    break;
329  			case PM_TYPE_FLOAT:
330  			    l.d = a.f;
331  			    break;
332  			case PM_TYPE_DOUBLE:
333  			    /* do nothing */
334  			    break;
335  		    }
336  		    l.d = (l.d / ldiv) * lmul;
337  		    switch (rtype) {
338  			case PM_TYPE_32:
339  			    r.d = b.l;
340  			    break;
341  			case PM_TYPE_U32:
342  			    r.d = b.ul;
343  			    break;
344  			case PM_TYPE_64:
345  			    r.d = b.ll;
346  			    break;
347  			case PM_TYPE_U64:
348  			    r.d = b.ull;
349  			    break;
350  			case PM_TYPE_FLOAT:
351  			    r.d = b.f;
352  			    break;
353  			case PM_TYPE_DOUBLE:
354  			    /* do nothing */
355  			    break;
356  		    }
357  		    r.d = (r.d / rdiv) * rmul;
358  		    break;
359  	    }
360  	
361  	    /*
362  	     * Do the aritmetic ... messy!
363  	     */
364  	    switch (type) {
365  		case PM_TYPE_32:
366  		    switch (op) {
367  			case L_PLUS:
368  			    res.l = l.l + r.l;
369  			    break;
370  			case L_MINUS:
371  			    res.l = l.l - r.l;
372  			    break;
373  			case L_STAR:
374  			    res.l = l.l * r.l;
375  			    break;
376  			/* semantics enforce no L_SLASH for integer results */
377  		    }
378  		    break;
379  		case PM_TYPE_U32:
380  		    switch (op) {
381  			case L_PLUS:
382  			    res.ul = l.ul + r.ul;
383  			    break;
384  			case L_MINUS:
385  			    res.ul = l.ul - r.ul;
386  			    break;
387  			case L_STAR:
388  			    res.ul = l.ul * r.ul;
389  			    break;
390  			/* semantics enforce no L_SLASH for integer results */
391  		    }
392  		    break;
393  		case PM_TYPE_64:
394  		    switch (op) {
395  			case L_PLUS:
396  			    res.ll = l.ll + r.ll;
397  			    break;
398  			case L_MINUS:
399  			    res.ll = l.ll - r.ll;
400  			    break;
401  			case L_STAR:
402  			    res.ll = l.ll * r.ll;
403  			    break;
404  			/* semantics enforce no L_SLASH for integer results */
405  		    }
406  		    break;
407  		case PM_TYPE_U64:
408  		    switch (op) {
409  			case L_PLUS:
410  			    res.ull = l.ull + r.ull;
411  			    break;
412  			case L_MINUS:
413  			    res.ull = l.ull - r.ull;
414  			    break;
415  			case L_STAR:
416  			    res.ull = l.ull * r.ull;
417  			    break;
418  			/* semantics enforce no L_SLASH for integer results */
419  		    }
420  		    break;
421  		case PM_TYPE_FLOAT:
422  		    switch (op) {
423  			case L_PLUS:
424  			    res.f = l.f + r.f;
425  			    break;
426  			case L_MINUS:
427  			    res.f = l.f - r.f;
428  			    break;
429  			case L_STAR:
430  			    res.f = l.f * r.f;
431  			    break;
432  			/* semantics enforce no L_SLASH for float results */
433  		    }
434  		    break;
435  		case PM_TYPE_DOUBLE:
436  		    switch (op) {
437  			case L_PLUS:
438  			    res.d = l.d + r.d;
439  			    break;
440  			case L_MINUS:
441  			    res.d = l.d - r.d;
442  			    break;
443  			case L_STAR:
444  			    res.d = l.d * r.d;
445  			    break;
446  			case L_SLASH:
447  			    if (l.d == 0)
448  				res.d = 0;
449  			    else
450  				res.d = l.d / r.d;
451  			    break;
452  		    }
453  		    break;
454  	    }
455  	
456  	    return res;
457  	}
458  	
459  	
460  	/*
461  	 * Walk an expression tree, filling in operand values from the
462  	 * pmResult at the leaf nodes and propagating the computed values
463  	 * towards the root node of the tree.
464  	 */
465  	static int
466  	eval_expr(node_t *np, pmResult *rp, int level)
467  	{
468  	    int		sts;
469  	    int		i;
470  	    int		j;
471  	    int		k;
472  	    size_t	need;
473  	
474  	    assert(np != NULL);
Event var_compare_op: Comparing "np->left" to null implies that "np->left" might be null.
Also see events: [var_deref_op][var_deref_op]
At conditional (1): "np->left != NULL": Taking false branch.
475  	    if (np->left != NULL) {
476  		sts = eval_expr(np->left, rp, level+1);
477  		if (sts < 0) return sts;
478  	    }
At conditional (2): "np->right != NULL": Taking true branch.
479  	    if (np->right != NULL) {
480  		sts = eval_expr(np->right, rp, level+1);
At conditional (3): "sts < 0": Taking false branch.
481  		if (sts < 0) return sts;
482  	    }
483  	
484  	    switch (np->type) {
485  	
486  		case L_NUMBER:
487  		    if (np->info->numval == 0) {
488  			/* initialize ivlist[] for singular instance first time through */
489  			np->info->numval = 1;
490  			if ((np->info->ivlist = (val_t *)malloc(sizeof(val_t))) == NULL) {
491  			    __pmNoMem("eval_expr: number ivlist", sizeof(val_t), PM_FATAL_ERR);
492  			    /*NOTREACHED*/
493  			}
494  			np->info->ivlist[0].inst = PM_INDOM_NULL;
495  			/* don't need error checking, done in the lexical scanner */
496  			np->info->ivlist[0].value.l = atoi(np->value);
497  		    }
498  		    return 1;
499  		    break;
500  	
At conditional (4): {CovLStr{v1}{switch case value {0}}{"11"}}: Taking true branch.
501  		case L_DELTA:
502  		    /*
503  		     * this and the last values are in the left expr
504  		     */
505  		    free_ivlist(np);
Event var_deref_op: Dereferencing null variable "np->left".
Also see events: [var_compare_op][var_deref_op]
506  		    np->info->numval = np->left->info->numval <= np->left->info->last_numval ? np->left->info->numval : np->left->info->last_numval;
507  		    if (np->info->numval <= 0)
508  			return np->info->numval;
509  		    if ((np->info->ivlist = (val_t *)malloc(np->info->numval*sizeof(val_t))) == NULL) {
510  			__pmNoMem("eval_expr: delta() ivlist", np->info->numval*sizeof(val_t), PM_FATAL_ERR);
511  			/*NOTREACHED*/
512  		    }
513  		    /*
514  		     * ivlist[k] = left-ivlist[i] - left-last-ivlist[j]
515  		     */
516  		    for (i = k = 0; i < np->left->info->numval; i++) {
517  			j = i;
518  			if (j >= np->left->info->last_numval)
519  			    j = 0;
520  			if (np->left->info->ivlist[i].inst != np->left->info->last_ivlist[j].inst) {
521  			    /* current ith inst != last jth inst ... search in last */
522  	#ifdef PCP_DEBUG
523  			    if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) {
524  				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);
525  			    }
526  	#endif
527  			    for (j = 0; j < np->left->info->last_numval; j++) {
528  				if (np->left->info->ivlist[i].inst == np->left->info->last_ivlist[j].inst)
529  				    break;
530  			    }
531  			    if (j == np->left->info->last_numval) {
532  				/* no match, skip this instance from this result */
533  				continue;
534  			    }
535  	#ifdef PCP_DEBUG
536  			    else {
537  				if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) {
538  				    fprintf(stderr, "eval_expr: recover @ last [%d]=%d\n", j, np->left->info->last_ivlist[j].inst);
539  				}
540  			    }
541  	#endif
542  			}
543  			np->info->ivlist[k].inst = np->left->info->ivlist[i].inst;
544  			switch (np->desc.type) {
545  			    case PM_TYPE_32:
546  				np->info->ivlist[k].value.l = np->left->info->ivlist[i].value.l - np->left->info->last_ivlist[j].value.l;
547  				break;
548  			    case PM_TYPE_U32:
549  				np->info->ivlist[k].value.ul = np->left->info->ivlist[i].value.ul - np->left->info->last_ivlist[j].value.ul;
550  				break;
551  			    case PM_TYPE_64:
552  				np->info->ivlist[k].value.ll = np->left->info->ivlist[i].value.ll - np->left->info->last_ivlist[j].value.ll;
553  				break;
554  			    case PM_TYPE_U64:
555  				np->info->ivlist[k].value.ull = np->left->info->ivlist[i].value.ull - np->left->info->last_ivlist[j].value.ull;
556  				break;
557  			    case PM_TYPE_FLOAT:
558  				np->info->ivlist[k].value.f = np->left->info->ivlist[i].value.f - np->left->info->last_ivlist[j].value.f;
559  				break;
560  			    case PM_TYPE_DOUBLE:
561  				np->info->ivlist[k].value.d = np->left->info->ivlist[i].value.d - np->left->info->last_ivlist[j].value.d;
562  				break;
563  			    default:
564  				/*
565  				 * Nothing should end up here as check_expr() checks
566  				 * for numeric data type at bind time
567  				 */
568  				return PM_ERR_CONV;
569  			}
570  			k++;
571  		    }
572  		    np->info->numval = k;
573  		    return np->info->numval;
574  		    break;
575  	
576  		case L_AVG:
577  		case L_COUNT:
578  		case L_SUM:
579  		case L_MAX:
580  		case L_MIN:
581  		    if (np->info->ivlist == NULL) {
582  			/* initialize ivlist[] for singular instance first time through */
583  			if ((np->info->ivlist = (val_t *)malloc(sizeof(val_t))) == NULL) {
584  			    __pmNoMem("eval_expr: aggr ivlist", sizeof(val_t), PM_FATAL_ERR);
585  			    /*NOTREACHED*/
586  			}
587  			np->info->ivlist[0].inst = PM_IN_NULL;
588  		    }
589  		    /*
590  		     * values are in the left expr
591  		     */
592  		    if (np->type == L_COUNT) {
593  			np->info->numval = 1;
594  			np->info->ivlist[0].value.l = np->left->info->numval;
595  		    }
596  		    else {
597  			np->info->numval = 1;
598  			if (np->type == L_AVG)
599  			    np->info->ivlist[0].value.f = 0;
600  			else if (np->type == L_SUM) {
601  			    switch (np->desc.type) {
602  				case PM_TYPE_32:
603  				    np->info->ivlist[0].value.l = 0;
604  				    break;
605  				case PM_TYPE_U32:
606  				    np->info->ivlist[0].value.ul = 0;
607  				    break;
608  				case PM_TYPE_64:
609  				    np->info->ivlist[0].value.ll = 0;
610  				    break;
611  				case PM_TYPE_U64:
612  				    np->info->ivlist[0].value.ull = 0;
613  				    break;
614  				case PM_TYPE_FLOAT:
615  				    np->info->ivlist[0].value.f = 0;
616  				    break;
617  				case PM_TYPE_DOUBLE:
618  				    np->info->ivlist[0].value.d = 0;
619  				    break;
620  			    }
621  			}
Event var_deref_op: Dereferencing null variable "np->left".
Also see events: [var_compare_op][var_deref_op]
622  			for (i = 0; i < np->left->info->numval; i++) {
623  			    switch (np->type) {
624  	
625  				case L_AVG:
626  				    switch (np->left->desc.type) {
627  					case PM_TYPE_32:
628  					    np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.l / np->left->info->numval;
629  					    break;
630  					case PM_TYPE_U32:
631  					    np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.ul / np->left->info->numval;
632  					    break;
633  					case PM_TYPE_64:
634  					    np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.ll / np->left->info->numval;
635  					    break;
636  					case PM_TYPE_U64:
637  					    np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.ull / np->left->info->numval;
638  					    break;
639  					case PM_TYPE_FLOAT:
640  					    np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.f / np->left->info->numval;
641  					    break;
642  					case PM_TYPE_DOUBLE:
643  					    np->info->ivlist[0].value.f += (float)np->left->info->ivlist[i].value.d / np->left->info->numval;
644  					    break;
645  					default:
646  					    /*
647  					     * check_expr() checks for numeric data
648  					     * type at bind time ... if here, botch!
649  					     */
650  					    return PM_ERR_CONV;
651  				    }
652  				    break;
653  	
654  				case L_MAX:
655  				    switch (np->desc.type) {
656  					case PM_TYPE_32:
657  					    if (i == 0 ||
658  					        np->info->ivlist[0].value.l < np->left->info->ivlist[i].value.l)
659  						np->info->ivlist[0].value.l = np->left->info->ivlist[i].value.l;
660  					    break;
661  					case PM_TYPE_U32:
662  					    if (i == 0 ||
663  					        np->info->ivlist[0].value.ul < np->left->info->ivlist[i].value.ul)
664  						np->info->ivlist[0].value.ul = np->left->info->ivlist[i].value.ul;
665  					    break;
666  					case PM_TYPE_64:
667  					    if (i == 0 ||
668  					        np->info->ivlist[0].value.ll < np->left->info->ivlist[i].value.ll)
669  						np->info->ivlist[0].value.ll = np->left->info->ivlist[i].value.ll;
670  					    break;
671  					case PM_TYPE_U64:
672  					    if (i == 0 ||
673  					        np->info->ivlist[0].value.ull < np->left->info->ivlist[i].value.ull)
674  						np->info->ivlist[0].value.ull = np->left->info->ivlist[i].value.ull;
675  					    break;
676  					case PM_TYPE_FLOAT:
677  					    if (i == 0 ||
678  					        np->info->ivlist[0].value.f < np->left->info->ivlist[i].value.f)
679  						np->info->ivlist[0].value.f = np->left->info->ivlist[i].value.f;
680  					    break;
681  					case PM_TYPE_DOUBLE:
682  					    if (i == 0 ||
683  					        np->info->ivlist[0].value.d < np->left->info->ivlist[i].value.d)
684  						np->info->ivlist[0].value.d = np->left->info->ivlist[i].value.d;
685  					    break;
686  					default:
687  					    /*
688  					     * check_expr() checks for numeric data
689  					     * type at bind time ... if here, botch!
690  					     */
691  					    return PM_ERR_CONV;
692  				    }
693  				    break;
694  	
695  				case L_MIN:
696  				    switch (np->desc.type) {
697  					case PM_TYPE_32:
698  					    if (i == 0 ||
699  					        np->info->ivlist[0].value.l > np->left->info->ivlist[i].value.l)
700  						np->info->ivlist[0].value.l = np->left->info->ivlist[i].value.l;
701  					    break;
702  					case PM_TYPE_U32:
703  					    if (i == 0 ||
704  					        np->info->ivlist[0].value.ul > np->left->info->ivlist[i].value.ul)
705  						np->info->ivlist[0].value.ul = np->left->info->ivlist[i].value.ul;
706  					    break;
707  					case PM_TYPE_64:
708  					    if (i == 0 ||
709  					        np->info->ivlist[0].value.ll > np->left->info->ivlist[i].value.ll)
710  						np->info->ivlist[0].value.ll = np->left->info->ivlist[i].value.ll;
711  					    break;
712  					case PM_TYPE_U64:
713  					    if (i == 0 ||
714  					        np->info->ivlist[0].value.ull > np->left->info->ivlist[i].value.ull)
715  						np->info->ivlist[0].value.ull = np->left->info->ivlist[i].value.ull;
716  					    break;
717  					case PM_TYPE_FLOAT:
718  					    if (i == 0 ||
719  					        np->info->ivlist[0].value.f > np->left->info->ivlist[i].value.f)
720  						np->info->ivlist[0].value.f = np->left->info->ivlist[i].value.f;
721  					    break;
722  					case PM_TYPE_DOUBLE:
723  					    if (i == 0 ||
724  					        np->info->ivlist[0].value.d > np->left->info->ivlist[i].value.d)
725  						np->info->ivlist[0].value.d = np->left->info->ivlist[i].value.d;
726  					    break;
727  					default:
728  					    /*
729  					     * check_expr() checks for numeric data
730  					     * type at bind time ... if here, botch!
731  					     */
732  					    return PM_ERR_CONV;
733  				    }
734  				    break;
735  	
736  				case L_SUM:
737  				    switch (np->desc.type) {
738  					case PM_TYPE_32:
739  					    np->info->ivlist[0].value.l += np->left->info->ivlist[i].value.l;
740  					    break;
741  					case PM_TYPE_U32:
742  					    np->info->ivlist[0].value.ul += np->left->info->ivlist[i].value.ul;
743  					    break;
744  					case PM_TYPE_64:
745  					    np->info->ivlist[0].value.ll += np->left->info->ivlist[i].value.ll;
746  					    break;
747  					case PM_TYPE_U64:
748  					    np->info->ivlist[0].value.ull += np->left->info->ivlist[i].value.ull;
749  					    break;
750  					case PM_TYPE_FLOAT:
751  					    np->info->ivlist[0].value.f += np->left->info->ivlist[i].value.f;
752  					    break;
753  					case PM_TYPE_DOUBLE:
754  					    np->info->ivlist[0].value.d += np->left->info->ivlist[i].value.d;
755  					    break;
756  					default:
757  					    /*
758  					     * check_expr() checks for numeric data
759  					     * type at bind time ... if here, botch!
760  					     */
761  					    return PM_ERR_CONV;
762  				    }
763  				    break;
764  	
765  			    }
766  			}
767  		    }
768  		    return np->info->numval;
769  		    break;
770  	
771  		case L_NAME:
772  		    /*
773  		     * Extract instance-values from pmResult and store them in
774  		     * ivlist[] as <int, pmAtomValue> pairs
775  		     */
776  		    for (j = 0; j < rp->numpmid; j++) {
777  			if (np->info->pmid == rp->vset[j]->pmid) {
778  			    free_ivlist(np);
779  			    np->info->numval = rp->vset[j]->numval;
780  			    if (np->info->numval <= 0)
781  				return np->info->numval;
782  			    if ((np->info->ivlist = (val_t *)malloc(np->info->numval*sizeof(val_t))) == NULL) {
783  				__pmNoMem("eval_expr: metric ivlist", np->info->numval*sizeof(val_t), PM_FATAL_ERR);
784  				/*NOTREACHED*/
785  			    }
786  			    for (i = 0; i < np->info->numval; i++) {
787  				np->info->ivlist[i].inst = rp->vset[j]->vlist[i].inst;
788  				switch (np->desc.type) {
789  				    case PM_TYPE_32:
790  				    case PM_TYPE_U32:
791  					np->info->ivlist[i].value.l = rp->vset[j]->vlist[i].value.lval;
792  					break;
793  	
794  				    case PM_TYPE_64:
795  				    case PM_TYPE_U64:
796  					memcpy((void *)&np->info->ivlist[i].value.ll, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, sizeof(__int64_t));
797  					break;
798  	
799  				    case PM_TYPE_FLOAT:
800  					if (rp->vset[j]->valfmt == PM_VAL_INSITU) {
801  					    /* old style insitu float */
802  					    np->info->ivlist[i].value.l = rp->vset[j]->vlist[i].value.lval;
803  					}
804  					else {
805  					    assert(rp->vset[j]->vlist[i].value.pval->vtype == PM_TYPE_FLOAT);
806  					    memcpy((void *)&np->info->ivlist[i].value.f, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, sizeof(float));
807  					}
808  					break;
809  	
810  				    case PM_TYPE_DOUBLE:
811  					memcpy((void *)&np->info->ivlist[i].value.d, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, sizeof(double));
812  					break;
813  	
814  				    case PM_TYPE_STRING:
815  					need = rp->vset[j]->vlist[i].value.pval->vlen-PM_VAL_HDR_SIZE;
816  					if ((np->info->ivlist[i].value.cp = (char *)malloc(need)) == NULL) {
817  					    __pmNoMem("eval_expr: string value", rp->vset[j]->vlist[i].value.pval->vlen, PM_FATAL_ERR);
818  					    /*NOTREACHED*/
819  					}
820  					memcpy((void *)np->info->ivlist[i].value.cp, (void *)rp->vset[j]->vlist[i].value.pval->vbuf, need);
821  					np->info->ivlist[i].vlen = need;
822  					break;
823  	
824  				    case PM_TYPE_AGGREGATE:
825  				    case PM_TYPE_AGGREGATE_STATIC:
826  				    case PM_TYPE_EVENT:
827  					if ((np->info->ivlist[i].value.vbp = (pmValueBlock *)malloc(rp->vset[j]->vlist[i].value.pval->vlen)) == NULL) {
828  					    __pmNoMem("eval_expr: aggregate value", rp->vset[j]->vlist[i].value.pval->vlen, PM_FATAL_ERR);
829  					    /*NOTREACHED*/
830  					}
831  					memcpy(np->info->ivlist[i].value.vbp, (void *)rp->vset[j]->vlist[i].value.pval, rp->vset[j]->vlist[i].value.pval->vlen);
832  					np->info->ivlist[i].vlen = rp->vset[j]->vlist[i].value.pval->vlen;
833  					break;
834  	
835  				    default:
836  					/*
837  					 * really only PM_TYPE_NOSUPPORT should
838  					 * end up here
839  					 */
840  					return PM_ERR_TYPE;
841  				}
842  			    }
843  			    return np->info->numval;
844  			}
845  		    }
846  	#ifdef PCP_DEBUG
847  		    if (pmDebug & DBG_TRACE_DERIVE) {
848  			fprintf(stderr, "eval_expr: botch: operand %s not in the extended pmResult\n", pmIDStr(np->info->pmid));
849  			__pmDumpResult(stderr, rp);
850  		    }
851  	#endif
852  		    return PM_ERR_PMID;
853  	
854  		case L_ANON:
855  		    /* no values available for anonymous metrics */
856  		    return 0;
857  	
858  		default:
859  		    /*
860  		     * binary operator cases ... always have a left and right
861  		     * operand and no errors (these are caught earlier when the
862  		     * recursive call on each of the operands would may have
863  		     * returned an error
864  		     */
865  		    assert(np->left != NULL);
866  		    assert(np->right != NULL);
867  	
868  		    free_ivlist(np);
869  		    /*
870  		     * empty result cases first
871  		     */
872  		    if (np->left->info->numval == 0) {
873  			np->info->numval = 0;
874  			return np->info->numval;
875  		    }
876  		    if (np->right->info->numval == 0) {
877  			np->info->numval = 0;
878  			return np->info->numval;
879  		    }
880  		    /*
881  		     * really got some work to do ...
882  		     */
883  		    if (np->left->desc.indom == PM_INDOM_NULL)
884  			np->info->numval = np->right->info->numval;
885  		    else if (np->right->desc.indom == PM_INDOM_NULL)
886  			np->info->numval = np->left->info->numval;
887  		    else {
888  			/*
889  			 * Generally have the same number of instances because
890  			 * both operands are over the same instance domain,
891  			 * fetched with the same profile.  When not the case,
892  			 * the result can contain no more instances than in
893  			 * the smaller of the operands.
894  			 */
895  			if (np->left->info->numval <= np->right->info->numval)
896  			    np->info->numval = np->left->info->numval;
897  			else
898  			    np->info->numval = np->right->info->numval;
899  		    }
900  		    if ((np->info->ivlist = (val_t *)malloc(np->info->numval*sizeof(val_t))) == NULL) {
901  			__pmNoMem("eval_expr: expr ivlist", np->info->numval*sizeof(val_t), PM_FATAL_ERR);
902  			/*NOTREACHED*/
903  		    }
904  		    /*
905  		     * ivlist[k] = left-ivlist[i] <op> right-ivlist[j]
906  		     */
907  		    for (i = j = k = 0; k < np->info->numval; ) {
908  			if (i >= np->left->info->numval || j >= np->right->info->numval) {
909  			    /* run out of operand instances, quit */
910  			    np->info->numval = k;
911  			    break;
912  			}
913  			if (np->left->desc.indom != PM_INDOM_NULL &&
914  			    np->right->desc.indom != PM_INDOM_NULL) {
915  			    if (np->left->info->ivlist[i].inst != np->right->info->ivlist[j].inst) {
916  				/* left ith inst != right jth inst ... search in right */
917  	#ifdef PCP_DEBUG
918  				if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) {
919  				    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);
920  				}
921  	#endif
922  				for (j = 0; j < np->right->info->numval; j++) {
923  				    if (np->left->info->ivlist[i].inst == np->right->info->ivlist[j].inst)
924  					break;
925  				}
926  				if (j == np->right->info->numval) {
927  				    /*
928  				     * no match, so next instance on left operand,
929  				     * and reset to start from first instance of
930  				     * right operand
931  				     */
932  				    i++;
933  				    j = 0;
934  				    continue;
935  				}
936  	#ifdef PCP_DEBUG
937  				else {
938  				    if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) {
939  					fprintf(stderr, "eval_expr: recover @ right [%d]=%d\n", j, np->right->info->ivlist[j].inst);
940  				    }
941  				}
942  	#endif
943  			    }
944  			}
945  			np->info->ivlist[k].value =
946  			    bin_op(np->desc.type, np->type,
947  				   np->left->info->ivlist[i].value, np->left->desc.type, np->left->info->mul_scale, np->left->info->div_scale,
948  				   np->right->info->ivlist[j].value, np->right->desc.type, np->right->info->mul_scale, np->right->info->div_scale);
949  			if (np->left->desc.indom != PM_INDOM_NULL)
950  			    np->info->ivlist[k].inst = np->left->info->ivlist[i].inst;
951  			else
952  			    np->info->ivlist[k].inst = np->right->info->ivlist[j].inst;
953  			k++;
954  			if (np->left->desc.indom != PM_INDOM_NULL) {
955  			    i++;
956  			    if (np->right->desc.indom != PM_INDOM_NULL) {
957  				j++;
958  				if (j >= np->right->info->numval) {
959  				    /* rescan if need be */
960  				    j = 0;
961  				}
962  			    }
963  			}
964  			else if (np->right->desc.indom != PM_INDOM_NULL) {
965  			    j++;
966  			}
967  		    }
968  		    return np->info->numval;
969  	    }
970  	    /*NOTREACHED*/
971  	}
972  	
973  	/*
974  	 * Algorithm here is complicated by trying to re-write the pmResult.
975  	 *
976  	 * On entry the pmResult is likely to be built over a pinned PDU buffer,
977  	 * which means individual pmValueSets cannot be selectively replaced
978  	 * (this would come to tears badly in pmFreeResult() where as soon as
979  	 * one pmValueSet is found to be in a pinned PDU buffer it is assumed
980  	 * they are all so ... leaving a memory leak for any ones we'd modified
981  	 * here).
982  	 *
983  	 * So the only option is to COPY the pmResult, selectively replacing
984  	 * the pmValueSets for the derived metrics, and then calling
985  	 * pmFreeResult() to free the input structure and return the new one.
986  	 *
987  	 * In making the COPY it is critical that we reverse the algorithm
988  	 * used in pmFreeResult() so that a later call to pmFreeResult() will
989  	 * not cause a memory leak.
990  	 * This means ...
991  	 * - malloc() the pmResult (padded out to the right number of vset[]
992  	 *   entries)
993  	 * - if valfmt is not PM_VAL_INSITU use PM_VAL_DPTR (not PM_VAL_SPTR),
994  	 *   so anything we point to is going to be released when our caller
995  	 *   calls pmFreeResult()
996  	 * - if numval == 1,  use __pmPoolAlloc() for the pmValueSet;
997  	 *   otherwise use one malloc() for each pmValueSet with vlist[] sized
998  	 *   to be 0 if numval < 0 else numval
999  	 * - pmValueBlocks for 64-bit integers, doubles or anything with a
1000 	 *   length equal to the size of a 64-bit integer are from
1001 	 *   __pmPoolAlloc(); otherwise pmValueBlocks are from malloc()
1002 	 *
1003 	 * For reference, the same logic appears in __pmLogFetchInterp() to
1004 	 * sythesize a pmResult there.
1005 	 */
1006 	void
1007 	__dmpostfetch(__pmContext *ctxp, pmResult **result)
1008 	{
1009 	    int		i;
1010 	    int		j;
1011 	    int		m;
1012 	    int		numval;
1013 	    int		valfmt;
1014 	    size_t	need;
1015 	    int		rewrite;
1016 	    ctl_t	*cp = (ctl_t *)ctxp->c_dm;
1017 	    pmResult	*rp = *result;
1018 	    pmResult	*newrp;
1019 	
1020 	    /* if needed, init() called in __dmopencontext beforehand */
1021 	
1022 	    if (cp == NULL || cp->fetch_has_dm == 0) return;
1023 	
1024 	    newrp = (pmResult *)malloc(sizeof(pmResult)+(cp->numpmid-1)*sizeof(pmValueSet *));
1025 	    if (newrp == NULL) {
1026 		__pmNoMem("__dmpostfetch: newrp", sizeof(pmResult)+(cp->numpmid-1)*sizeof(pmValueSet *), PM_FATAL_ERR);
1027 		/*NOTREACHED*/
1028 	    }
1029 	    newrp->timestamp = rp->timestamp;
1030 	    newrp->numpmid = cp->numpmid;
1031 	
1032 	    for (j = 0; j < newrp->numpmid; j++) {
1033 		numval = rp->vset[j]->numval;
1034 		valfmt = rp->vset[j]->valfmt;
1035 		rewrite = 0;
1036 		/*
1037 		 * pandering to gcc ... m is not used unless rewrite == 1 in
1038 		 * which case m is well-defined
1039 		 */
1040 		m = 0;
1041 		if (pmid_domain(rp->vset[j]->pmid) == DYNAMIC_PMID &&
1042 		    pmid_item(rp->vset[j]->pmid) != 0) {
1043 		    for (m = 0; m < cp->nmetric; m++) {
1044 			if (rp->vset[j]->pmid == cp->mlist[m].pmid) {
1045 			    if (cp->mlist[m].expr == NULL) {
1046 				numval = PM_ERR_PMID;
1047 			    }
1048 			    else {
1049 				rewrite = 1;
1050 				if (cp->mlist[m].expr->desc.type == PM_TYPE_32 ||
1051 				    cp->mlist[m].expr->desc.type == PM_TYPE_U32)
1052 				    valfmt = PM_VAL_INSITU;
1053 				else
1054 				    valfmt = PM_VAL_DPTR;
1055 				numval = eval_expr(cp->mlist[m].expr, rp, 1);
1056 	#ifdef PCP_DEBUG
1057 	    if ((pmDebug & DBG_TRACE_DERIVE) && (pmDebug & DBG_TRACE_APPL2)) {
1058 		int	k;
1059 	
1060 		fprintf(stderr, "__dmpostfetch: [%d] root node %s: numval=%d", j, pmIDStr(rp->vset[j]->pmid), numval);
1061 		for (k = 0; k < numval; k++) {
1062 		    fprintf(stderr, " vset[%d]: inst=%d", k, cp->mlist[m].expr->info->ivlist[k].inst);
1063 		    if (cp->mlist[m].expr->desc.type == PM_TYPE_32)
1064 			fprintf(stderr, " l=%d", cp->mlist[m].expr->info->ivlist[k].value.l);
1065 		    else if (cp->mlist[m].expr->desc.type == PM_TYPE_U32)
1066 			fprintf(stderr, " u=%u", cp->mlist[m].expr->info->ivlist[k].value.ul);
1067 		    else if (cp->mlist[m].expr->desc.type == PM_TYPE_64)
1068 			fprintf(stderr, " ll=%"PRIi64, cp->mlist[m].expr->info->ivlist[k].value.ll);
1069 		    else if (cp->mlist[m].expr->desc.type == PM_TYPE_U64)
1070 			fprintf(stderr, " ul=%"PRIu64, cp->mlist[m].expr->info->ivlist[k].value.ull);
1071 		    else if (cp->mlist[m].expr->desc.type == PM_TYPE_FLOAT)
1072 			fprintf(stderr, " f=%f", (double)cp->mlist[m].expr->info->ivlist[k].value.f);
1073 		    else if (cp->mlist[m].expr->desc.type == PM_TYPE_DOUBLE)
1074 			fprintf(stderr, " d=%f", cp->mlist[m].expr->info->ivlist[k].value.d);
1075 		    else if (cp->mlist[m].expr->desc.type == PM_TYPE_STRING) {
1076 			fprintf(stderr, " cp=%s (len=%d)", cp->mlist[m].expr->info->ivlist[k].value.cp, cp->mlist[m].expr->info->ivlist[k].vlen);
1077 		    }
1078 		    else {
1079 			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);
1080 		    }
1081 		}
1082 		fputc('\n', stderr);
1083 		if (cp->mlist[m].expr->info != NULL)
1084 		    __dmdumpexpr(cp->mlist[m].expr, 1);
1085 	    }
1086 	#endif
1087 			    }
1088 			    break;
1089 			}
1090 		    }
1091 		}
1092 	
1093 		if (numval < 0) {
1094 		    /* only need pmid and numval */
1095 		    need = sizeof(pmValueSet) - sizeof(pmValue);
1096 		}
1097 		else if (numval == 1) {
1098 		    /* special case for single value */
1099 		    newrp->vset[j] = (pmValueSet *)__pmPoolAlloc(sizeof(pmValueSet));
1100 		    need = 0;
1101 		}
1102 		else {
1103 		    /* already one pmValue in a pmValueSet */
1104 		    need = sizeof(pmValueSet) + (numval - 1)*sizeof(pmValue);
1105 		}
1106 		if (need > 0) {
1107 		    if ((newrp->vset[j] = (pmValueSet *)malloc(need)) == NULL) {
1108 			__pmNoMem("__dmpostfetch: vset", need, PM_FATAL_ERR);
1109 			/*NOTREACHED*/
1110 		    }
1111 		}
1112 		newrp->vset[j]->pmid = rp->vset[j]->pmid;
1113 		newrp->vset[j]->numval = numval;
1114 		newrp->vset[j]->valfmt = valfmt;
1115 		if (numval < 0)
1116 		    continue;
1117 	
1118 		for (i = 0; i < numval; i++) {
1119 		    pmValueBlock	*vp;
1120 	
1121 		    if (!rewrite) {
1122 			newrp->vset[j]->vlist[i].inst = rp->vset[j]->vlist[i].inst;
1123 			if (newrp->vset[j]->valfmt == PM_VAL_INSITU) {
1124 			    newrp->vset[j]->vlist[i].value.lval = rp->vset[j]->vlist[i].value.lval;
1125 			}
1126 			else {
1127 			    need = rp->vset[j]->vlist[i].value.pval->vlen;
1128 			    if (need == PM_VAL_HDR_SIZE + sizeof(__int64_t))
1129 				vp = (pmValueBlock *)__pmPoolAlloc(need);
1130 			    else
1131 				vp = (pmValueBlock *)malloc(need);
1132 			    if (vp == NULL) {
1133 				__pmNoMem("__dmpostfetch: copy value", need, PM_FATAL_ERR);
1134 				/*NOTREACHED*/
1135 			    }
1136 			    memcpy((void *)vp, (void *)rp->vset[j]->vlist[i].value.pval, need);
1137 			    newrp->vset[j]->vlist[i].value.pval = vp;
1138 			}
1139 			continue;
1140 		    }
1141 	
1142 		    /*
1143 		     * the rewrite case ...
1144 		     */
1145 		    newrp->vset[j]->vlist[i].inst = cp->mlist[m].expr->info->ivlist[i].inst;
1146 		    switch (cp->mlist[m].expr->desc.type) {
1147 			case PM_TYPE_32:
1148 			case PM_TYPE_U32:
1149 			    newrp->vset[j]->vlist[i].value.lval = cp->mlist[m].expr->info->ivlist[i].value.l;
1150 			    break;
1151 	
1152 			case PM_TYPE_64:
1153 			case PM_TYPE_U64:
1154 			    need = PM_VAL_HDR_SIZE + sizeof(__int64_t);
1155 			    if ((vp = (pmValueBlock *)__pmPoolAlloc(need)) == NULL) {
1156 				__pmNoMem("__dmpostfetch: 64-bit int value", need, PM_FATAL_ERR);
1157 				/*NOTREACHED*/
1158 			    }
1159 			    vp->vlen = need;
1160 			    vp->vtype = cp->mlist[m].expr->desc.type;
1161 			    memcpy((void *)vp->vbuf, (void *)&cp->mlist[m].expr->info->ivlist[i].value.ll, sizeof(__int64_t));
1162 			    newrp->vset[j]->vlist[i].value.pval = vp;
1163 			    break;
1164 	
1165 			case PM_TYPE_FLOAT:
1166 			    need = PM_VAL_HDR_SIZE + sizeof(float);
1167 			    if ((vp = (pmValueBlock *)malloc(need)) == NULL) {
1168 				__pmNoMem("__dmpostfetch: float value", need, PM_FATAL_ERR);
1169 				/*NOTREACHED*/
1170 			    }
1171 			    vp->vlen = need;
1172 			    vp->vtype = PM_TYPE_FLOAT;
1173 			    memcpy((void *)vp->vbuf, (void *)&cp->mlist[m].expr->info->ivlist[i].value.f, sizeof(float));
1174 			    newrp->vset[j]->vlist[i].value.pval = vp;
1175 			    break;
1176 	
1177 			case PM_TYPE_DOUBLE:
1178 			    need = PM_VAL_HDR_SIZE + sizeof(double);
1179 			    if ((vp = (pmValueBlock *)__pmPoolAlloc(need)) == NULL) {
1180 				__pmNoMem("__dmpostfetch: double value", need, PM_FATAL_ERR);
1181 				/*NOTREACHED*/
1182 			    }
1183 			    vp->vlen = need;
1184 			    vp->vtype = PM_TYPE_DOUBLE;
1185 			    memcpy((void *)vp->vbuf, (void *)&cp->mlist[m].expr->info->ivlist[i].value.f, sizeof(double));
1186 			    newrp->vset[j]->vlist[i].value.pval = vp;
1187 			    break;
1188 	
1189 			case PM_TYPE_STRING:
1190 			    need = PM_VAL_HDR_SIZE + cp->mlist[m].expr->info->ivlist[i].vlen;
1191 			    if (need == PM_VAL_HDR_SIZE + sizeof(__int64_t))
1192 				vp = (pmValueBlock *)__pmPoolAlloc(need);
1193 			    else
1194 				vp = (pmValueBlock *)malloc(need);
1195 			    if (vp == NULL) {
1196 				__pmNoMem("__dmpostfetch: string value", need, PM_FATAL_ERR);
1197 				/*NOTREACHED*/
1198 			    }
1199 			    vp->vlen = need;
1200 			    vp->vtype = cp->mlist[m].expr->desc.type;
1201 			    memcpy((void *)vp->vbuf, cp->mlist[m].expr->info->ivlist[i].value.cp, cp->mlist[m].expr->info->ivlist[i].vlen);
1202 			    newrp->vset[j]->vlist[i].value.pval = vp;
1203 			    break;
1204 	
1205 			case PM_TYPE_AGGREGATE:
1206 			case PM_TYPE_AGGREGATE_STATIC:
1207 			case PM_TYPE_EVENT:
1208 			    need = cp->mlist[m].expr->info->ivlist[i].vlen;
1209 			    if (need == PM_VAL_HDR_SIZE + sizeof(__int64_t))
1210 				vp = (pmValueBlock *)__pmPoolAlloc(need);
1211 			    else
1212 				vp = (pmValueBlock *)malloc(need);
1213 			    if (vp == NULL) {
1214 				__pmNoMem("__dmpostfetch: aggregate or event value", need, PM_FATAL_ERR);
1215 				/*NOTREACHED*/
1216 			    }
1217 			    memcpy((void *)vp, cp->mlist[m].expr->info->ivlist[i].value.vbp, cp->mlist[m].expr->info->ivlist[i].vlen);
1218 			    newrp->vset[j]->vlist[i].value.pval = vp;
1219 			    break;
1220 	
1221 			default:
1222 			    /*
1223 			     * really nothing should end up here ...
1224 			     * do nothing as numval should have been < 0
1225 			     */
1226 	#ifdef PCP_DEBUG
1227 			    if (pmDebug & DBG_TRACE_DERIVE) {
1228 				fprintf(stderr, "__dmpostfetch: botch: drived metric[%d]: operand %s has odd type (%d)\n", m, pmIDStr(rp->vset[j]->pmid), cp->mlist[m].expr->desc.type);
1229 			    }
1230 	#endif
1231 			    break;
1232 		    }
1233 		}
1234 	    }
1235 	
1236 	    /*
1237 	     * cull the original pmResult and return the rewritten one
1238 	     */
1239 	    pmFreeResult(rp);
1240 	    *result = newrp;
1241 	
1242 	    return;
1243 	}