1    	/*
2    	 * Copyright (c) 1995,2004 Silicon Graphics, Inc.  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   	
15   	#include <limits.h>
16   	#include <inttypes.h>
17   	#include "pmapi.h"
18   	#include "impl.h"
19   	
20   	#define UPD_MARK_NONE	0
21   	#define UPD_MARK_FORW	1
22   	#define UPD_MARK_BACK	2
23   	
24   	#if defined(HAVE_CONST_LONGLONG)
25   	#define SIGN_64_MASK 0x8000000000000000LL
26   	#else
27   	#define SIGN_64_MASK 0x8000000000000000
28   	#endif
29   	
30   	typedef union {				/* value from pmResult */
31   	    pmValueBlock	*pval;
32   	    int			lval;
33   	} value;
34   	
35   	typedef struct instcntl {		/* metric-instance control */
36   	    struct instcntl	*next;		/* next for this metric control */
37   	    struct instcntl	*want;		/* ones of interest */
38   	    struct instcntl	*unbound;	/* not yet bound above [or below] */
39   	    int			search;		/* looking for found this one? */
40   	    int			inst;		/* instance identifier */
41   	    int			inresult;	/* will be in this result */
42   	    double		t_prior;
43   	    int			m_prior;	/* mark, not value at t_prior */
44   	    value		v_prior;
45   	    double		t_next;
46   	    int			m_next;		/* mark, not value at t_next */
47   	    value		v_next;
48   	    double		t_first;	/* no records before this */
49   	    double		t_last;		/* no records after this */
50   	    struct pmidcntl	*metric;	/* back to metric control */
51   	} instcntl_t;
52   	
53   	static instcntl_t	*want_head;
54   	static instcntl_t	*unbound_head;
55   	
56   	typedef struct pmidcntl {		/* metric control */
57   	    pmDesc		desc;
58   	    int			valfmt;		/* used to build result */
59   	    int			numval;		/* number of instances in this result */
60   	    struct instcntl	*first;		/* first metric-instace control */
61   	} pmidcntl_t;
62   	
63   	#ifdef PCP_DEBUG
64   	static void
65   	printstamp(__pmTimeval *tp)
66   	{
67   	    static struct tm	*tmp;
68   	    time_t t = (time_t)tp->tv_sec;
69   	
70   	    tmp = localtime(&t);
71   	    fprintf(stderr, "%02d:%02d:%02d.%03d", tmp->tm_hour, tmp->tm_min, tmp->tm_sec, tp->tv_usec/1000);
72   	}
73   	#endif
74   	
75   	typedef struct {
76   	    pmResult	*rp;		/* cached pmResult from __pmLogRead */
77   	    int		sts;		/* from __pmLogRead */
78   	    FILE	*mfp;		/* log stream */
79   	    int		vol;		/* log volume */
80   	    long	head_posn;	/* posn in file before forwards __pmLogRead */
81   	    long	tail_posn;	/* posn in file after forwards __pmLogRead */
82   	    int		mode;		/* PM_MODE_FORW or PM_MODE_BACK */
83   	    int		used;		/* used count for LFU replacement */
84   	} cache_t;
85   	
86   	#define NUMCACHE 4
87   	static cache_t		cache[NUMCACHE];
88   	
89   	/*
90   	 * diagnostic counters ... indexed by PM_MODE_FORW (2) and
91   	 * PM_MODE_BACK	(3), hence 4 elts for cached and non-cached reads
92   	 */
93   	static long	nr_cache[4];
94   	static long	nr[4];
95   	
96   	static int
97   	cache_read(__pmArchCtl *acp, int mode, pmResult **rp)
98   	{
99   	    long	posn;
100  	    cache_t	*cp;
101  	    cache_t	*lfup;
102  	    int		save_curvol;
103  	    static int	round_robin = -1;
104  	
105  	    if (acp->ac_vol == acp->ac_log->l_curvol)
106  		posn = ftell(acp->ac_log->l_mfp);
107  	    else
108  		posn = 0;
109  	
110  	    if (round_robin == -1) {
111  		/* cache initialization */
112  		for (cp = cache; cp < &cache[NUMCACHE]; cp++) {
113  		    cp->rp = NULL;
114  		    cp->mfp = NULL;
115  		}
116  		round_robin = 0;
117  	    }
118  	
119  	#ifdef PCP_DEBUG
120  	    if ((pmDebug & DBG_TRACE_LOG) && (pmDebug & DBG_TRACE_INTERP)) {
121  		fprintf(stderr, "cache_read: fd=%d mode=%s vol=%d (curvol=%d) %s_posn=%ld ",
122  		    fileno(acp->ac_log->l_mfp),
123  		    mode == PM_MODE_FORW ? "forw" : "back",
124  		    acp->ac_vol, acp->ac_log->l_curvol,
125  		    mode == PM_MODE_FORW ? "head" : "tail",
126  		    (long)posn);
127  	    }
128  	#endif
129  	
130  	    round_robin = (round_robin + 1) % NUMCACHE;
131  	    lfup = &cache[round_robin];
132  	    for (cp = cache; cp < &cache[NUMCACHE]; cp++) {
133  		if (cp->mfp == acp->ac_log->l_mfp && cp->vol == acp->ac_vol &&
134  		    ((mode == PM_MODE_FORW && cp->head_posn == posn) ||
135  		     (mode == PM_MODE_BACK && cp->tail_posn == posn)) &&
136  		    cp->rp != NULL) {
137  		    *rp = cp->rp;
138  		    cp->used++;
139  		    if (mode == PM_MODE_FORW)
140  			fseek(acp->ac_log->l_mfp, cp->tail_posn, SEEK_SET);
141  		    else
142  			fseek(acp->ac_log->l_mfp, cp->head_posn, SEEK_SET);
143  	#ifdef PCP_DEBUG
144  		    if ((pmDebug & DBG_TRACE_LOG) && (pmDebug & DBG_TRACE_INTERP)) {
145  			__pmTimeval	tmp;
146  			double		t_this;
147  			tmp.tv_sec = (__int32_t)cp->rp->timestamp.tv_sec;
148  			tmp.tv_usec = (__int32_t)cp->rp->timestamp.tv_usec;
149  			t_this = __pmTimevalSub(&tmp, &acp->ac_log->l_label.ill_start);
150  			fprintf(stderr, "hit cache[%d] t=%.6f\n",
151  			    (int)(cp - cache), t_this);
152  			nr_cache[mode]++;
153  		    }
154  	#endif
155  		    return cp->sts;
156  		}
157  	    }
158  	
159  	#ifdef PCP_DEBUG
160  	    if ((pmDebug & DBG_TRACE_LOG) && (pmDebug & DBG_TRACE_INTERP))
161  		fprintf(stderr, "miss\n");
162  	    nr[mode]++;
163  	#endif
164  	
165  	    if (lfup->rp != NULL)
166  		pmFreeResult(lfup->rp);
167  	
168  	    save_curvol = acp->ac_log->l_curvol;
169  	
170  	    lfup->sts = __pmLogRead(acp->ac_log, mode, NULL, &lfup->rp);
171  	    if (lfup->sts < 0)
172  		lfup->rp = NULL;
173  	    *rp = lfup->rp;
174  	
175  	    if (posn == 0 || save_curvol != acp->ac_log->l_curvol) {
176  		/*
177  		 * vol switch since last time, or vol switch in __pmLogRead() ...
178  		 * new vol, stdio stream and we don't know where we started from
179  		 * ... don't cache
180  		 */
181  		lfup->mfp = NULL;
182  	#ifdef PCP_DEBUG
183  		if ((pmDebug & DBG_TRACE_LOG) && (pmDebug & DBG_TRACE_INTERP))
184  		    fprintf(stderr, "cache_read: reload vol switch, mark cache[%d] unused\n",
185  			(int)(lfup - cache));
186  	#endif
187  	    }
188  	    else {
189  		lfup->mode = mode;
190  		lfup->vol = acp->ac_vol;
191  		lfup->mfp = acp->ac_log->l_mfp;
192  		lfup->used = 1;
193  		if (mode == PM_MODE_FORW) {
194  		    lfup->head_posn = posn;
195  		    lfup->tail_posn = ftell(acp->ac_log->l_mfp);
196  		}
197  		else {
198  		    lfup->tail_posn = posn;
199  		    lfup->head_posn = ftell(acp->ac_log->l_mfp);
200  		}
201  	#ifdef PCP_DEBUG
202  		if ((pmDebug & DBG_TRACE_LOG) && (pmDebug & DBG_TRACE_INTERP)) {
203  		    fprintf(stderr, "cache_read: reload cache[%d] vol=%d (curvol=%d) head=%ld tail=%ld ",
204  			(int)(lfup - cache), lfup->vol, acp->ac_log->l_curvol,
205  			(long)lfup->head_posn, (long)lfup->tail_posn);
206  		    if (lfup->sts == 0)
207  			fprintf(stderr, "sts=%d\n", lfup->sts);
208  		    else
209  			fprintf(stderr, "sts=%s\n", pmErrStr(lfup->sts));
210  		}
211  	#endif
212  	    }
213  	
214  	    return lfup->sts;
215  	}
216  	
217  	void
218  	__pmLogCacheClear(FILE *mfp)
219  	{
220  	    cache_t	*cp;
221  	
222  	    for (cp = cache; cp < &cache[NUMCACHE]; cp++) {
223  		if (cp->mfp == mfp) {
224  		    if (cp->rp != NULL)
225  			pmFreeResult(cp->rp);
226  		    cp->rp = NULL;
227  		    cp->mfp = NULL;
228  		    cp->used = 0;
229  		}
230  	    }
231  	}
232  	
233  	#ifdef PCP_DEBUG
234  	static void
235  	dumpval(FILE *f, int type, int valfmt, int mark, value *vp)
236  	{
237  	    if (mark) {
238  		fprintf(f, " <mark>");
239  		return;
240  	    }
241  	    if (type == PM_TYPE_32 || type == PM_TYPE_U32)
242  		fprintf(f, " v=%d", vp->lval);
243  	    else if (type == PM_TYPE_FLOAT && valfmt == PM_VAL_INSITU)
244  		fprintf(f, " v=%f", (double)((float)vp->lval));
245  	    else if (type == PM_TYPE_64)
246  	        fprintf(f, " v=%"PRIi64, *((__int64_t *)&vp->pval->vbuf));
247  	    else if (type == PM_TYPE_U64)
248  	        fprintf(f, " v=%"PRIu64, *((__uint64_t *)&vp->pval->vbuf));
249  	    else if (type == PM_TYPE_FLOAT)
250  	        fprintf(f, " v=%f", (double)*((float *)&vp->pval->vbuf));
251  	    else if (type == PM_TYPE_DOUBLE)
252  	        fprintf(f, " v=%f", *((double *)&vp->pval->vbuf));
253  	    else
254  	        fprintf(f, "v=??? (lval=%d)", vp->lval);
255  	}
256  	#endif
257  	
258  	static void
259  	update_bounds(__pmContext *ctxp, double t_req, pmResult *logrp, int do_mark, int *done_prior, int *done_next)
260  	{
261  	    /*
262  	     * for every metric in the result from the log
263  	     *   for every instance in the result from the log
264  	     *     if we have ever asked for this metric and instance, update the
265  	     *        range bounds, if necessary
266  	     */
267  	    int		k;
268  	    int		i;
269  	    __pmHashCtl	*hcp = &ctxp->c_archctl->ac_pmid_hc;
270  	    __pmHashNode	*hp;
271  	    pmidcntl_t	*pcp;
272  	    instcntl_t	*icp;
273  	    double	t_this;
274  	    __pmTimeval	tmp;
275  	    int		changed;
276  	
277  	    tmp.tv_sec = (__int32_t)logrp->timestamp.tv_sec;
278  	    tmp.tv_usec = (__int32_t)logrp->timestamp.tv_usec;
279  	    t_this = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start);
280  	
281  	    if (logrp->numpmid == 0 && do_mark != UPD_MARK_NONE) {
282  		/* mark record, discontinuity in log */
283  		for (icp = want_head; icp != NULL; icp = icp->want) {
284  		    if (t_this <= t_req &&
285  			(t_this >= icp->t_prior || icp->t_prior > t_req)) {
286  			/* <mark> is closer than best lower bound to date */
287  			icp->t_prior = t_this;
288  			icp->m_prior = 1;
289  			if (icp->metric->valfmt != PM_VAL_INSITU) {
290  			    if (icp->v_prior.pval != NULL)
291  				__pmUnpinPDUBuf((void *)icp->v_prior.pval);
292  			    icp->v_prior.pval = NULL;
293  			}
294  	#ifdef PCP_DEBUG
295  			if (pmDebug & DBG_TRACE_INTERP) {
296  			    fprintf(stderr, "pmid %s inst %d <mark> t_prior=%.6f t_first=%.6f t_last=%.6f\n",
297  				pmIDStr(icp->metric->desc.pmid), icp->inst, icp->t_prior, icp->t_first, icp->t_last);
298  			}
299  	#endif
300  			if (icp->search && done_prior != NULL) {
301  			    icp->search = 0;
302  			    (*done_prior)++;
303  			}
304  		    }
305  		    if (t_this >= t_req &&
306  			((t_this <= icp->t_next || icp->t_next < 0) ||
307  			  icp->t_next < t_req)) {
308  			/* <mark> is closer than best upper bound to date */
309  			icp->t_next = t_this;
310  			icp->m_next = 1;
311  			if (icp->metric->valfmt != PM_VAL_INSITU) {
312  			    if (icp->v_next.pval != NULL)
313  				__pmUnpinPDUBuf((void *)icp->v_next.pval);
314  			    icp->v_next.pval = NULL;
315  			}
316  	#ifdef PCP_DEBUG
317  			if (pmDebug & DBG_TRACE_INTERP) {
318  			    fprintf(stderr, "pmid %s inst %d <mark> t_next=%.6f t_first=%.6f t_last=%.6f\n",
319  				pmIDStr(icp->metric->desc.pmid), icp->inst, icp->t_next, icp->t_first, icp->t_last);
320  			}
321  	#endif
322  			if (icp->search && done_next != NULL) {
323  			    icp->search = 0;
324  			    (*done_next)++;
325  			}
326  		    }
327  		}
328  		return;
329  	    }
330  	
331  	    changed = 0;
332  	    for (k = 0; k < logrp->numpmid; k++) {
333  		hp = __pmHashSearch((int)logrp->vset[k]->pmid, hcp);
334  		if (hp == NULL)
335  		    continue;
336  		pcp = (pmidcntl_t *)hp->data;
337  		if (pcp->valfmt == -1 && logrp->vset[k]->numval > 0)
338  		    pcp->valfmt = logrp->vset[k]->valfmt;
339  		for (icp = pcp->first; icp != NULL; icp = icp->next) {
340  		    for (i = 0; i < logrp->vset[k]->numval; i++) {
341  			if (logrp->vset[k]->vlist[i].inst == icp->inst ||
342  			    icp->inst == PM_IN_NULL) {
343  			    /* matched on instance */
344  	#if defined(PCP_DEBUG) && defined(DESPERATE)
345  			    if (pmDebug & DBG_TRACE_INTERP) {
346  				fprintf(stderr, "update: match pmid %s inst %d t_this=%.6f t_prior=%.6f t_next=%.6f t_first=%.6f t_last=%.6f\n",
347  				    pmIDStr(logrp->vset[k]->pmid), icp->inst,
348  				    t_this, icp->t_prior, icp->t_next,
349  				    icp->t_first, icp->t_last);
350  			    }
351  	#endif
352  			    if (t_this <= t_req &&
353  				(icp->t_prior > t_req || t_this >= icp->t_prior)) {
354  				/*
355  				 * at or before the requested time, and this is the
356  				 * closest-to-date lower bound
357  				 */
358  				changed = 1;
359  				if (icp->t_prior < icp->t_next && icp->t_prior >= t_req) {
360  				    /* shuffle prior to next */
361  				    icp->t_next = icp->t_prior;
362  				    if (pcp->valfmt == PM_VAL_INSITU)
363  					icp->v_next.lval = icp->v_prior.lval;
364  				    else {
365  					if (icp->v_next.pval != NULL)
366  					    __pmUnpinPDUBuf((void *)icp->v_next.pval);
367  					icp->v_next.pval = icp->v_prior.pval;
368  				    }
369  				}
370  				icp->t_prior = t_this;
371  				icp->m_prior = 0;
372  				if (pcp->valfmt == PM_VAL_INSITU)
373  				    icp->v_prior.lval = logrp->vset[k]->vlist[i].value.lval;
374  				else {
375  				    if (icp->v_prior.pval != NULL)
376  					__pmUnpinPDUBuf((void *)icp->v_prior.pval);
377  				    icp->v_prior.pval = logrp->vset[k]->vlist[i].value.pval;
378  				    __pmPinPDUBuf((void *)icp->v_prior.pval);
379  				}
380  				if (icp->search && done_prior != NULL) {
381  				    /* one we were looking for */
382  				    changed |= 2;
383  				    icp->search = 0;
384  				    (*done_prior)++;
385  				}
386  			    }
387  			    if (t_this >= t_req &&
388  				    (icp->t_next < t_req || t_this <= icp->t_next)) {
389  				/*
390  				 * at or after the requested time, and this is the
391  				 * closest-to-date upper bound
392  				 */
393  				changed |= 1;
394  				if (icp->t_prior < icp->t_next && icp->t_next <= t_req) {
395  				    /* shuffle next to prior */
396  				    icp->t_prior = icp->t_next;
397  				    icp->m_prior = icp->m_next;
398  				    if (pcp->valfmt == PM_VAL_INSITU)
399  					icp->v_prior.lval = icp->v_next.lval;
400  				    else {
401  					if (icp->v_prior.pval != NULL)
402  					    __pmUnpinPDUBuf((void *)icp->v_prior.pval);
403  					icp->v_prior.pval = icp->v_next.pval;
404  				    }
405  				}
406  				icp->t_next = t_this;
407  				icp->m_next = 0;
408  				if (pcp->valfmt == PM_VAL_INSITU)
409  				    icp->v_next.lval = logrp->vset[k]->vlist[i].value.lval;
410  				else {
411  				    if (icp->v_next.pval != NULL)
412  					__pmUnpinPDUBuf((void *)icp->v_next.pval);
413  				    icp->v_next.pval = logrp->vset[k]->vlist[i].value.pval;
414  				    __pmPinPDUBuf((void *)icp->v_next.pval);
415  				}
416  				if (icp->search && done_next != NULL) {
417  				    /* one we were looking for */
418  				    changed |= 2;
419  				    icp->search = 0;
420  				    (*done_next)++;
421  				}
422  			    }
423  	#ifdef PCP_DEBUG
424  			    if ((pmDebug & DBG_TRACE_INTERP) && changed) {
425  				fprintf(stderr, "update%s pmid %s inst %d prior: t=%.6f",
426  				    changed & 2 ? "+search" : "",
427  				    pmIDStr(logrp->vset[k]->pmid), icp->inst, icp->t_prior);
428  				dumpval(stderr, pcp->desc.type, icp->metric->valfmt, icp->m_prior, &icp->v_prior);
429  				fprintf(stderr, " next: t=%.6f", icp->t_next);
430  				dumpval(stderr, pcp->desc.type, icp->metric->valfmt, icp->m_next, &icp->v_next);
431  				fprintf(stderr, " t_first=%.6f t_last=%.6f\n",
432  				    icp->t_first, icp->t_last);
433  			    }
434  	#endif
435  			    goto next_inst;
436  			}
437  		    }
438  	next_inst:
439  		    ;
440  		}
441  	    }
442  	
443  	    return;
444  	}
445  	
446  	static void
447  	do_roll(__pmContext *ctxp, double t_req)
448  	{
449  	    pmResult	*logrp;
450  	    __pmTimeval	tmp;
451  	    double	t_this;
452  	
453  	    /*
454  	     * now roll forwards in the direction of log reading
455  	     * to make sure we are up to t_req
456  	     */
457  	    if (ctxp->c_delta > 0) {
458  		while (cache_read(ctxp->c_archctl, PM_MODE_FORW, &logrp) >= 0) {
459  		    tmp.tv_sec = (__int32_t)logrp->timestamp.tv_sec;
460  		    tmp.tv_usec = (__int32_t)logrp->timestamp.tv_usec;
461  		    t_this = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start);
462  		    if (t_this > t_req)
463  			break;
464  	
465  	#ifdef PCP_DEBUG
466  		    if (pmDebug & DBG_TRACE_INTERP)
467  			fprintf(stderr, "roll forw to t=%.6f%s\n",
468  			    t_this, logrp->numpmid == 0 ? " <mark>" : "");
469  	#endif
470  		    ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp);
471  		    ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol;
472  		    update_bounds(ctxp, t_req, logrp, UPD_MARK_FORW, NULL, NULL);
473  		}
474  	    }
475  	    else {
476  		while (cache_read(ctxp->c_archctl, PM_MODE_BACK, &logrp) >= 0) {
477  		    tmp.tv_sec = (__int32_t)logrp->timestamp.tv_sec;
478  		    tmp.tv_usec = (__int32_t)logrp->timestamp.tv_usec;
479  		    t_this = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start);
480  		    if (t_this < t_req)
481  			break;
482  	
483  	#ifdef PCP_DEBUG
484  		    if (pmDebug & DBG_TRACE_INTERP)
485  			fprintf(stderr, "roll back to t=%.6f%s\n",
486  			    t_this, logrp->numpmid == 0 ? " <mark>" : "");
487  	#endif
488  		    ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp);
489  		    ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol;
490  		    update_bounds(ctxp, t_req, logrp, UPD_MARK_BACK, NULL, NULL);
491  		}
492  	    }
493  	}
494  	
495  	#define pmXTBdeltaToTimeval(d, m, t) { \
496  	    (t)->tv_sec = 0; \
497  	    (t)->tv_usec = (long)0; \
498  	    switch(PM_XTB_GET(m)) { \
499  	    case PM_TIME_NSEC: (t)->tv_usec = (long)((d) / 1000); break; \
500  	    case PM_TIME_USEC: (t)->tv_usec = (long)(d); break; \
501  	    case PM_TIME_MSEC: (t)->tv_sec = (d) / 1000; (t)->tv_usec = (long)(1000 * ((d) % 1000)); break; \
502  	    case PM_TIME_SEC: (t)->tv_sec = (d); break; \
503  	    case PM_TIME_MIN: (t)->tv_sec = (d) * 60; break; \
504  	    case PM_TIME_HOUR: (t)->tv_sec = (d) * 360; break; \
505  	    default: (t)->tv_sec = (d) / 1000; (t)->tv_usec = (long)(1000 * ((d) % 1000)); break; \
506  	    } \
507  	}
508  	
509  	int
510  	__pmLogFetchInterp(__pmContext *ctxp, int numpmid, pmID pmidlist[], pmResult **result)
511  	{
512  	    int		i;
513  	    int		j;
514  	    int		sts;
515  	    double	t_req;
516  	    double	t_this;
517  	    pmResult	*rp;
518  	    pmResult	*logrp;
519  	    __pmHashCtl	*hcp = &ctxp->c_archctl->ac_pmid_hc;
520  	    __pmHashNode	*hp;
521  	    pmidcntl_t	*pcp = NULL;	/* initialize to pander to gcc */
522  	    instcntl_t	*icp;
523  	    int		back = 0;
524  	    int		forw = 0;
525  	    int		done;
526  	    int		done_roll;
527  	    static double	t_end = 0;
528  	    static int	dowrap = -1;
529  	    __pmTimeval	tmp;
530  	    struct timeval delta_tv;
531  	
532  	    if (dowrap == -1) {
533  		/* PCP_COUNTER_WRAP in environment enables "counter wrap" logic */
534  		if (getenv("PCP_COUNTER_WRAP") == NULL)
535  		    dowrap = 0;
536  		else
537  		    dowrap = 1;
538  	    }
539  	
540  	    t_req = __pmTimevalSub(&ctxp->c_origin, &ctxp->c_archctl->ac_log->l_label.ill_start);
541  	
542  	#ifdef PCP_DEBUG
543  	    if (pmDebug & DBG_TRACE_INTERP) {
544  		fprintf(stderr, "__pmLogFetchInterp @ ");
545  		printstamp(&ctxp->c_origin);
546  		fprintf(stderr, " t_req=%.6f curvol=%d posn=%ld (vol=%d) serial=%d\n",
547  		    t_req, ctxp->c_archctl->ac_log->l_curvol,
548  		    (long)ctxp->c_archctl->ac_offset, ctxp->c_archctl->ac_vol,
549  		    ctxp->c_archctl->ac_serial);
550  		nr_cache[PM_MODE_FORW] = nr[PM_MODE_FORW] = 0;
551  		nr_cache[PM_MODE_BACK] = nr[PM_MODE_BACK] = 0;
552  	    }
553  	#endif
554  	
555  	    /*
556  	     * the 0.001 is magic slop for 1 msec, which is about as accurate
557  	     * as we can expect any of this timing stuff to be ...
558  	     */
559  	    if (t_req < -0.001) {
560  		sts = PM_ERR_EOL;
561  		goto all_done;
562  	    }
563  	
564  	    if (t_req > t_end + 0.001) {
565  		struct timeval	end;
566  		__pmTimeval	tmp;
567  	
568  		/*
569  		 * past end of archive ... see if it has grown since we last looked
570  		 */
571  		if (pmGetArchiveEnd(&end) >= 0)
572  		    tmp.tv_sec = (__int32_t)end.tv_sec;
573  		    tmp.tv_usec = (__int32_t)end.tv_usec;
574  		    t_end = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start);
575  		if (t_req > t_end) {
576  		    sts = PM_ERR_EOL;
577  		    goto all_done;
578  		}
579  	    }
580  	
581  	    if ((rp = (pmResult *) malloc(sizeof(pmResult) + (numpmid - 1) * sizeof(pmValueSet *))) == NULL)
582  		return -oserror();
583  	
584  	    rp->timestamp.tv_sec = ctxp->c_origin.tv_sec;
585  	    rp->timestamp.tv_usec = ctxp->c_origin.tv_usec;
586  	    rp->numpmid = numpmid;
587  	
588  	    /* zeroth pass ... clear search and inresult flags */
589  	    for (j = 0; j < hcp->hsize; j++) {
590  		for (hp = hcp->hash[j]; hp != NULL; hp = hp->next) {
591  		    pcp = (pmidcntl_t *)hp->data;
592  		    for (icp = pcp->first; icp != NULL; icp = icp->next) {
593  			icp->search = icp->inresult = 0;
594  			icp->unbound = icp->want = NULL;
595  		    }
596  		}
597  	    }
598  	
599  	    /*
600  	     * first pass ... scan all metrics, establish which ones are in
601  	     * the log, and which instances are being requested ... also build
602  	     * the skeletal pmResult
603  	     */
604  	    want_head = NULL;
605  	    for (j = 0; j < numpmid; j++) {
606  		if (pmidlist[j] == PM_ID_NULL)
607  		    continue;
608  		hp = __pmHashSearch((int)pmidlist[j], hcp);
609  		if (hp == NULL) {
610  		    /* first time we've been asked for this one in this context */
611  		    if ((pcp = (pmidcntl_t *)malloc(sizeof(pmidcntl_t))) == NULL) {
612  			__pmNoMem("__pmLogFetchInterp.pmidcntl_t", sizeof(pmidcntl_t), PM_FATAL_ERR);
613  			/*NOTREACHED*/
614  		    }
615  		    pcp->valfmt = -1;
616  		    pcp->first = NULL;
617  		    sts = __pmHashAdd((int)pmidlist[j], (void *)pcp, hcp);
618  		    if (sts < 0) {
619  			rp->numpmid = j;
620  			pmFreeResult(rp);
621  			return sts;
622  		    }
623  		    sts = __pmLogLookupDesc(ctxp->c_archctl->ac_log, pmidlist[j], &pcp->desc);
624  		    if (sts < 0)
625  			/* not in the archive log */
626  			pcp->desc.type = -1;
627  		    else {
628  			/* enumerate all the instances from the domain underneath */
629  			int		*instlist;
630  			char		**namelist;
631  			instcntl_t	*lcp;
632  			if (pcp->desc.indom == PM_INDOM_NULL) {
633  			    sts = 1;
634  			    if ((instlist = (int *)malloc(sizeof(int))) == NULL) {
635  				__pmNoMem("__pmLogFetchInterp.instlist", sizeof(int), PM_FATAL_ERR);
636  			    }
637  			    instlist[0] = PM_IN_NULL;
638  			}
639  			else {
640  			    sts = pmGetInDomArchive(pcp->desc.indom, &instlist, &namelist);
641  			}
642  			lcp = NULL;
643  			for (i = 0; i < sts; i++) {
644  			    if ((icp = (instcntl_t *)malloc(sizeof(instcntl_t))) == NULL) {
645  				__pmNoMem("__pmLogFetchInterp.instcntl_t", sizeof(instcntl_t), PM_FATAL_ERR);
646  			    }
647  			    if (lcp)
648  				lcp->next = icp;
649  			    else
650  				pcp->first = icp;
651  			    lcp = icp;
652  			    icp->metric = pcp;
653  			    icp->inresult = icp->search = 0;
654  			    icp->next = icp->want = icp->unbound = NULL;
655  			    icp->inst = instlist[i];
656  			    icp->t_prior = icp->t_next = icp->t_first = icp->t_last = -1;
657  			    icp->m_prior = icp->m_next = 1;
658  			    icp->v_prior.pval = icp->v_next.pval = NULL;
659  			}
660  			if (sts > 0) {
661  			    free(instlist);
662  			    if (pcp->desc.indom != PM_INDOM_NULL)
663  				free(namelist);
664  			}
665  		    }
666  		}
667  		else
668  		    /* seen this one before */
669  		    pcp = (pmidcntl_t *)hp->data;
670  	
671  		pcp->numval = 0;
672  		if (pcp->desc.type == -1) {
673  		    pcp->numval = PM_ERR_PMID_LOG;
674  		}
675  		else if (pcp->desc.type == PM_TYPE_EVENT) {
676  		    pcp->numval = PM_ERR_TYPE;
677  		}
678  		else if (pcp->desc.indom != PM_INDOM_NULL) {
679  		    /* use the profile to filter the instances to be returned */
680  		    for (icp = pcp->first; icp != NULL; icp = icp->next) {
681  			if (__pmInProfile(pcp->desc.indom, ctxp->c_instprof, icp->inst)) {
682  			    icp->inresult = 1;
683  			    icp->want = want_head;
684  			    want_head = icp;
685  			    pcp->numval++;
686  			}
687  			else
688  			    icp->inresult = 0;
689  		    }
690  		}
691  		else {
692  		    pcp->first->inresult = 1;
693  		    pcp->first->want = want_head;
694  		    want_head = pcp->first;
695  		    pcp->numval = 1;
696  		}
697  	    }
698  	
699  	    if (ctxp->c_archctl->ac_serial == 0) {
700  		/* need gross positioning from temporal index */
701  		__pmLogSetTime(ctxp);
702  		ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp);
703  		ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol;
704  	
705  		/*
706  		 * and now fine-tuning ...
707  		 * back-up (relative to the direction we are reading the log)
708  		 * to make sure
709  		 */
710  		if (ctxp->c_delta > 0) {
711  		    while (cache_read(ctxp->c_archctl, PM_MODE_BACK, &logrp) >= 0) {
712  			tmp.tv_sec = (__int32_t)logrp->timestamp.tv_sec;
713  			tmp.tv_usec = (__int32_t)logrp->timestamp.tv_usec;
714  			t_this = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start);
715  			if (t_this <= t_req) {
716  			    break;
717  			}
718  			ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp);
719  			ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol;
720  			update_bounds(ctxp, t_req, logrp, UPD_MARK_NONE, NULL, NULL);
721  		    }
722  		}
723  		else {
724  		    while (cache_read(ctxp->c_archctl, PM_MODE_FORW, &logrp) >= 0) {
725  			tmp.tv_sec = (__int32_t)logrp->timestamp.tv_sec;
726  			tmp.tv_usec = (__int32_t)logrp->timestamp.tv_usec;
727  			t_this = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start);
728  			if (t_this > t_req) {
729  			    break;
730  			}
731  			ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp);
732  			ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol;
733  			update_bounds(ctxp, t_req, logrp, UPD_MARK_NONE, NULL, NULL);
734  		    }
735  		}
736  		ctxp->c_archctl->ac_serial = 1;
737  	    }
738  	
739  	    /* get to the last remembered place */
740  	    __pmLogChangeVol(ctxp->c_archctl->ac_log, ctxp->c_archctl->ac_vol);
741  	    fseek(ctxp->c_archctl->ac_log->l_mfp, ctxp->c_archctl->ac_offset, SEEK_SET);
742  	
743  	    /*
744  	     * optimization to supress roll forwards unless really needed ...
745  	     * if the sample interval is much shorter than the time between log
746  	     * records, then do not roll forwards unless some scanning is
747  	     * required ... and if scanning is required in the "forwards"
748  	     * direction, no need to roll forwards
749  	     */
750  	    done_roll = 0;
751  	
752  	    /*
753  	     * second pass ... see which metrics are not currently bounded below
754  	     */
755  	    unbound_head = NULL;
756  	    for (j = 0; j < numpmid; j++) {
757  		if (pmidlist[j] == PM_ID_NULL)
758  		    continue;
759  		hp = __pmHashSearch((int)pmidlist[j], hcp);
760  		pcp = (pmidcntl_t *)hp->data;
761  		if (pcp->numval > 0) {
762  		    for (icp = pcp->first; icp != NULL; icp = icp->next) {
763  			if (!icp->inresult)
764  			    continue;
765  			if (icp->t_first >= 0 && t_req < icp->t_first)
766  			    /* before earliest, don't bother */
767  			    continue;
768  	retry_back:
769  			/*
770  			 *  At this stage there _may_ be a value earlier in the
771  			 *  archive of interest ...
772  			 *  t_prior = -1 => have not explored in this direction,
773  			 *  	so need to go back
774  			 *  t_prior > t_req => need to push t_prior to be <= t_req
775  			 *  	if possible, so go back
776  			 *  t_next is valid and a mark and t_next > t_req => need
777  			 *  to search back also
778  			 */
779  			if (icp->t_prior < 0 || icp->t_prior > t_req ||
780  			    (icp->t_next >= 0 && icp->m_next && icp->t_next > t_req)) {
781  			    if (back == 0 && !done_roll) {
782  				done_roll = 1;
783  				if (ctxp->c_delta > 0)  {
784  				    /* forwards before scanning back */
785  				    do_roll(ctxp, t_req);
786  				    goto retry_back;
787  				}
788  			    }
789  			    back++;
790  			    icp->search = 1;
791  			    icp->unbound = unbound_head;
792  			    unbound_head = icp;
793  	#ifdef PCP_DEBUG
794  			    if (pmDebug & DBG_TRACE_INTERP)
795  				fprintf(stderr, "search back for inst %d and pmid %s (t_first=%.6f t_prior=%.6f%s t_next=%.6f%s t_last=%.6f)\n",
796  				    icp->inst, pmIDStr(pmidlist[j]), icp->t_first,
797  				    icp->t_prior, icp->m_prior ? " <mark>" : "",
798  				    icp->t_next, icp->m_next ? " <mark>" : "",
799  				    icp->t_last);
800  	#endif
801  			}
802  		    }
803  		}
804  	    }
805  	
806  	    if (back) {
807  		/*
808  		 * at least one metric requires a bound from earlier in the log ...
809  		 * position ourselves, ... and search
810  		 */
811  		__pmLogChangeVol(ctxp->c_archctl->ac_log, ctxp->c_archctl->ac_vol);
812  		fseek(ctxp->c_archctl->ac_log->l_mfp, ctxp->c_archctl->ac_offset, SEEK_SET);
813  		done = 0;
814  	
815  		while (done < back) {
816  		    if (cache_read(ctxp->c_archctl, PM_MODE_BACK, &logrp) < 0) {
817  			/* ran into start of log */
818  	#ifdef PCP_DEBUG
819  			if (pmDebug & DBG_TRACE_INTERP) {
820  			    fprintf(stderr, "Start of Log, %d metric-inst not found\n",
821  				    back - done);
822  			}
823  	#endif
824  			break;
825  		    }
826  		    tmp.tv_sec = (__int32_t)logrp->timestamp.tv_sec;
827  		    tmp.tv_usec = (__int32_t)logrp->timestamp.tv_usec;
828  		    t_this = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start);
829  		    if (ctxp->c_delta < 0 && t_this >= t_req) {
830  			/* going backwards, and not up to t_req yet */
831  			ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp);
832  			ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol;
833  		    }
834  		    update_bounds(ctxp, t_req, logrp, UPD_MARK_BACK, &done, NULL);
835  	
836  		    /*
837  		     * forget about those that can never be found from here
838  		     * in this direction
839  		     */
840  		    for (icp = unbound_head; icp != NULL; icp = icp->unbound) {
841  			if (icp->search && t_this <= icp->t_first) {
842  			    icp->search = 0;
843  			    done++;
844  			}
845  		    }
846  		}
847  		/* end of search, trim t_first as required */
848  		for (icp = unbound_head; icp != NULL; icp = icp->unbound) {
849  		    if ((icp->t_prior == -1 || icp->t_prior > t_req) &&
850  			icp->t_first < t_req) {
851  			icp->t_first = t_req;
852  	#ifdef PCP_DEBUG
853  			if (pmDebug & DBG_TRACE_INTERP) {
854  			    fprintf(stderr, "pmid %s inst %d no values before t_first=%.6f\n",
855  				pmIDStr(icp->metric->desc.pmid), icp->inst, icp->t_first);
856  			}
857  	#endif
858  		    }
859  		    icp->search = 0;
860  		}
861  	    }
862  	
863  	    /*
864  	     * third pass ... see which metrics are not currently bounded above
865  	     */
866  	    unbound_head = NULL;
867  	    for (j = 0; j < numpmid; j++) {
868  		if (pmidlist[j] == PM_ID_NULL)
869  		    continue;
Event returned_null: Function "__pmHashSearch" returns null (checked 37 out of 37 times). [details]
Event var_assigned: Assigning: "hp" = null return value from "__pmHashSearch".
Also see events: [example_checked][example_checked][example_checked][example_checked][example_checked][dereference]
870  		hp = __pmHashSearch((int)pmidlist[j], hcp);
Event dereference: Dereferencing a null pointer "hp".
Also see events: [returned_null][example_checked][example_checked][example_checked][example_checked][example_checked][var_assigned]
871  		pcp = (pmidcntl_t *)hp->data;
872  		if (pcp->numval > 0) {
873  		    for (icp = pcp->first; icp != NULL; icp = icp->next) {
874  			if (!icp->inresult)
875  			    continue;
876  			if (icp->t_last >= 0 && t_req > icp->t_last)
877  			    /* after latest, don't bother */
878  			    continue;
879  	retry_forw:
880  			/*
881  			 *  At this stage there _may_ be a value later in the
882  			 *  archive of interest ...
883  			 *  t_next = -1 => have not explored in this direction,
884  			 *  	so need to go forward
885  			 *  t_next < t_req => need to push t_next to be >= t_req
886  			 *  	if possible, so go forward
887  			 *  t_prior is valid and a mark and t_prior < t_req => need
888  			 *  to search forward also
889  			 */
890  			if (icp->t_next < 0 || icp->t_next < t_req ||
891  			    (icp->t_prior >= 0 && icp->m_prior && icp->t_prior < t_req)) {
892  			    if (forw == 0 && !done_roll) {
893  				done_roll = 1;
894  				if (ctxp->c_delta < 0)  {
895  				    /* backwards before scanning forwards */
896  				    do_roll(ctxp, t_req);
897  				    goto retry_forw;
898  				}
899  			    }
900  			    forw++;
901  			    icp->search = 1;
902  			    icp->unbound = unbound_head;
903  			    unbound_head = icp;
904  	#ifdef PCP_DEBUG
905  			    if (pmDebug & DBG_TRACE_INTERP)
906  				fprintf(stderr, "search forw for inst %d and pmid %s (t_first=%.6f t_prior=%.6f%s t_next=%.6f%s t_last=%.6f)\n",
907  				    icp->inst, pmIDStr(pmidlist[j]), icp->t_first,
908  				    icp->t_prior, icp->m_prior ? " <mark>" : "",
909  				    icp->t_next, icp->m_next ? " <mark>" : "",
910  				    icp->t_last);
911  	#endif
912  			}
913  		    }
914  		}
915  	    }
916  	
917  	    if (forw) {
918  		/*
919  		 * at least one metric requires a bound from later in the log ...
920  		 * position ourselves ... and search
921  		 */
922  		__pmLogChangeVol(ctxp->c_archctl->ac_log, ctxp->c_archctl->ac_vol);
923  		fseek(ctxp->c_archctl->ac_log->l_mfp, ctxp->c_archctl->ac_offset, SEEK_SET);
924  		done = 0;
925  	
926  		while (done < forw) {
927  		    if (cache_read(ctxp->c_archctl, PM_MODE_FORW, &logrp) < 0) {
928  			/* ran into end of log */
929  	#ifdef PCP_DEBUG
930  			if (pmDebug & DBG_TRACE_INTERP) {
931  			    fprintf(stderr, "End of Log, %d metric-inst not found\n",
932  			    		forw - done);
933  			}
934  	#endif
935  			break;
936  		    }
937  		    tmp.tv_sec = (__int32_t)logrp->timestamp.tv_sec;
938  		    tmp.tv_usec = (__int32_t)logrp->timestamp.tv_usec;
939  		    t_this = __pmTimevalSub(&tmp, &ctxp->c_archctl->ac_log->l_label.ill_start);
940  		    if (ctxp->c_delta > 0 && t_this <= t_req) {
941  			/* going forwards, and not up to t_req yet */
942  			ctxp->c_archctl->ac_offset = ftell(ctxp->c_archctl->ac_log->l_mfp);
943  			ctxp->c_archctl->ac_vol = ctxp->c_archctl->ac_log->l_curvol;
944  		    }
945  		    update_bounds(ctxp, t_req, logrp, UPD_MARK_FORW, NULL, &done);
946  	
947  		    /*
948  		     * forget about those that can never be found from here
949  		     * in this direction
950  		     */
951  		    for (icp = unbound_head; icp != NULL; icp = icp->unbound) {
952  			if (icp->search && icp->t_last >= 0 && t_this >= icp->t_last) {
953  			    icp->search = 0;
954  			    done++;
955  			}
956  		    }
957  		}
958  		/* end of search, trim t_last as required */
959  		for (icp = unbound_head; icp != NULL; icp = icp->unbound) {
960  		    if (icp->t_next < t_req &&
961  			(icp->t_last < 0 || t_req < icp->t_last)) {
962  			icp->t_last = t_req;
963  	#ifdef PCP_DEBUG
964  			if (pmDebug & DBG_TRACE_INTERP) {
965  			    fprintf(stderr, "pmid %s inst %d no values after t_last=%.6f\n",
966  				pmIDStr(icp->metric->desc.pmid), icp->inst, icp->t_last);
967  			}
968  	#endif
969  		    }
970  		    icp->search = 0;
971  		}
972  	    }
973  	
974  	    /*
975  	     * check to see how many qualifying values there are really going to be
976  	     */
977  	    for (j = 0; j < numpmid; j++) {
978  		if (pmidlist[j] == PM_ID_NULL)
979  		    continue;
980  		hp = __pmHashSearch((int)pmidlist[j], hcp);
981  		pcp = (pmidcntl_t *)hp->data;
982  		for (icp = pcp->first; icp != NULL; icp = icp->next) {
983  		    if (!icp->inresult)
984  			continue;
985  		    if (pcp->desc.sem == PM_SEM_DISCRETE) {
986  			if (icp->m_prior || icp->t_prior == -1 ||
987  			    icp->t_prior > t_req) {
988  			    /* no earlier value, so no value */
989  			    pcp->numval--;
990  			    icp->inresult = 0;
991  			}
992  		    }
993  		    else {
994  			/* assume COUNTER or INSTANT */
995  			if (icp->m_prior || icp->t_prior == -1 ||
996  			    icp->t_prior > t_req ||
997  			    icp->m_next || icp->t_next == -1 || icp->t_next < t_req) {
998  			    /* in mid-range, and no bound, so no value */
999  			    pcp->numval--;
1000 			    icp->inresult = 0;
1001 			}
1002 			else if (pcp->desc.sem == PM_SEM_COUNTER) {
1003 			    /*
1004 			     * for counters, has to be arithmetic also,
1005 			     * else cannot interpolate ...
1006 			     */
1007 			    if (pcp->desc.type != PM_TYPE_32 &&
1008 				pcp->desc.type != PM_TYPE_U32 &&
1009 				pcp->desc.type != PM_TYPE_64 &&
1010 				pcp->desc.type != PM_TYPE_U64 &&
1011 				pcp->desc.type != PM_TYPE_FLOAT &&
1012 				pcp->desc.type != PM_TYPE_DOUBLE)
1013 				    pcp->numval = PM_ERR_TYPE;
1014 			}
1015 		    }
1016 		}
1017 	    }
1018 	
1019 	    for (j = 0; j < numpmid; j++) {
1020 		if (pmidlist[j] == PM_ID_NULL) {
1021 		    rp->vset[j] = (pmValueSet *)malloc(sizeof(pmValueSet) -
1022 						    sizeof(pmValue));
1023 		}
1024 		else {
1025 		    hp = __pmHashSearch((int)pmidlist[j], hcp);
1026 		    pcp = (pmidcntl_t *)hp->data;
1027 	
1028 		    if (pcp->numval == 1)
1029 			rp->vset[j] = (pmValueSet *)__pmPoolAlloc(sizeof(pmValueSet));
1030 		    else if (pcp->numval > 1)
1031 			rp->vset[j] = (pmValueSet *)malloc(sizeof(pmValueSet) +
1032 							(pcp->numval - 1)*sizeof(pmValue));
1033 		    else
1034 			rp->vset[j] = (pmValueSet *)malloc(sizeof(pmValueSet) -
1035 							sizeof(pmValue));
1036 		}
1037 	
1038 		if (rp->vset[j] == NULL) {
1039 		    __pmNoMem("__pmLogFetchInterp.vset", sizeof(pmValueSet), PM_FATAL_ERR);
1040 		}
1041 	
1042 		rp->vset[j]->pmid = pmidlist[j];
1043 		if (pmidlist[j] == PM_ID_NULL) {
1044 		    rp->vset[j]->numval = 0;
1045 		    continue;
1046 		}
1047 		rp->vset[j]->numval = pcp->numval;
1048 		rp->vset[j]->valfmt = pcp->valfmt;
1049 	
1050 		i = 0;
1051 		if (pcp->numval > 0) {
1052 		    for (icp = pcp->first; icp != NULL; icp = icp->next) {
1053 			if (!icp->inresult)
1054 			    continue;
1055 	#ifdef PCP_DEBUG
1056 			if (pmDebug & DBG_TRACE_INTERP && done_roll) {
1057 			    fprintf(stderr, "pmid %s inst %d prior: t=%.6f",
1058 				    pmIDStr(pmidlist[j]), icp->inst, icp->t_prior);
1059 			    dumpval(stderr, pcp->desc.type, icp->metric->valfmt, icp->m_prior, &icp->v_prior);
1060 			    fprintf(stderr, " next: t=%.6f", icp->t_next);
1061 			    dumpval(stderr, pcp->desc.type, icp->metric->valfmt, icp->m_next, &icp->v_next);
1062 			    fprintf(stderr, " t_first=%.6f t_last=%.6f\n",
1063 				icp->t_first, icp->t_last);
1064 			}
1065 	#endif
1066 			rp->vset[j]->vlist[i].inst = icp->inst;
1067 			if (pcp->desc.type == PM_TYPE_32 || pcp->desc.type == PM_TYPE_U32) {
1068 			    if (icp->t_prior == t_req)
1069 				rp->vset[j]->vlist[i++].value.lval = icp->v_prior.lval;
1070 			    else if (icp->t_next == t_req)
1071 				rp->vset[j]->vlist[i++].value.lval = icp->v_next.lval;
1072 			    else {
1073 				if (pcp->desc.sem == PM_SEM_DISCRETE) {
1074 				    if (icp->t_prior >= 0)
1075 					rp->vset[j]->vlist[i++].value.lval = icp->v_prior.lval;
1076 				}
1077 				else if (pcp->desc.sem == PM_SEM_INSTANT) {
1078 				    if (icp->t_prior >= 0 && icp->t_next >= 0)
1079 					rp->vset[j]->vlist[i++].value.lval = icp->v_prior.lval;
1080 				}
1081 				else {
1082 				    /* assume COUNTER */
1083 				    if (icp->t_prior >= 0 && icp->t_next >= 0) {
1084 					if (pcp->desc.type == PM_TYPE_32) {
1085 					    if (icp->v_next.lval >= icp->v_prior.lval ||
1086 						dowrap == 0) {
1087 						rp->vset[j]->vlist[i++].value.lval = 0.5 +
1088 						    icp->v_prior.lval + (t_req - icp->t_prior) *
1089 						    (icp->v_next.lval - icp->v_prior.lval) /
1090 						    (icp->t_next - icp->t_prior);
1091 					    }
1092 					    else {
1093 						/* not monotonic increasing and want wrap */
1094 						rp->vset[j]->vlist[i++].value.lval = 0.5 +
1095 						    (t_req - icp->t_prior) *
1096 						    (__int32_t)(UINT_MAX - icp->v_prior.lval + 1 + icp->v_next.lval) /
1097 						    (icp->t_next - icp->t_prior);
1098 						rp->vset[j]->vlist[i].value.lval += icp->v_prior.lval;
1099 					    }
1100 					}
1101 					else {
1102 					    pmAtomValue     av;
1103 					    pmAtomValue     *avp_prior = (pmAtomValue *)&icp->v_prior.lval;
1104 					    pmAtomValue     *avp_next = (pmAtomValue *)&icp->v_next.lval;
1105 					    if (avp_next->ul >= avp_prior->ul) {
1106 						av.ul = 0.5 + avp_prior->ul +
1107 							(t_req - icp->t_prior) *
1108 							(avp_next->ul - avp_prior->ul) /
1109 							(icp->t_next - icp->t_prior);
1110 					    }
1111 					    else {
1112 						/* not monotonic increasing */
1113 						if (dowrap) {
1114 						    av.ul = 0.5 +
1115 							    (t_req - icp->t_prior) *
1116 							    (__uint32_t)(UINT_MAX - avp_prior->ul + 1 + avp_next->ul ) /
1117 							    (icp->t_next - icp->t_prior);
1118 						    av.ul += avp_prior->ul;
1119 						}
1120 						else {
1121 						    __uint32_t	tmp;
1122 						    tmp = avp_prior->ul - avp_next->ul;
1123 						    av.ul = 0.5 + avp_prior->ul -
1124 							    (t_req - icp->t_prior) * tmp /
1125 							    (icp->t_next - icp->t_prior);
1126 						}
1127 					    }
1128 					    rp->vset[j]->vlist[i++].value.lval = av.ul;
1129 					}
1130 				    }
1131 				}
1132 			    }
1133 			}
1134 			else if (pcp->desc.type == PM_TYPE_FLOAT && icp->metric->valfmt == PM_VAL_INSITU) {
1135 			    /* OLD style FLOAT insitu */
1136 			    if (icp->t_prior == t_req)
1137 				rp->vset[j]->vlist[i++].value.lval = icp->v_prior.lval;
1138 			    else if (icp->t_next == t_req)
1139 				rp->vset[j]->vlist[i++].value.lval = icp->v_next.lval;
1140 			    else {
1141 				if (pcp->desc.sem == PM_SEM_DISCRETE) {
1142 				    if (icp->t_prior >= 0)
1143 					rp->vset[j]->vlist[i++].value.lval = icp->v_prior.lval;
1144 				}
1145 				else if (pcp->desc.sem == PM_SEM_INSTANT) {
1146 				    if (icp->t_prior >= 0 && icp->t_next >= 0)
1147 					rp->vset[j]->vlist[i++].value.lval = icp->v_prior.lval;
1148 				}
1149 				else {
1150 				    /* assume COUNTER */
1151 				    pmAtomValue	av;
1152 				    pmAtomValue	*avp_prior = (pmAtomValue *)&icp->v_prior.lval;
1153 				    pmAtomValue	*avp_next = (pmAtomValue *)&icp->v_next.lval;
1154 				    if (icp->t_prior >= 0 && icp->t_next >= 0) {
1155 					av.f = avp_prior->f + (t_req - icp->t_prior) *
1156 						(avp_next->f - avp_prior->f) /
1157 						(icp->t_next - icp->t_prior);
1158 					/* yes this IS correct ... */
1159 					rp->vset[j]->vlist[i++].value.lval = av.l;
1160 				    }
1161 				}
1162 			    }
1163 			}
1164 			else if (pcp->desc.type == PM_TYPE_FLOAT) {
1165 			    /* NEW style FLOAT in pmValueBlock */
1166 			    int			need;
1167 			    pmValueBlock	*vp;
1168 			    int			ok = 1;
1169 	
1170 			    need = PM_VAL_HDR_SIZE + sizeof(float);
1171 			    if ((vp = (pmValueBlock *)malloc(need)) == NULL) {
1172 				sts = -oserror();
1173 				goto bad_alloc;
1174 			    }
1175 			    vp->vlen = need;
1176 			    vp->vtype = PM_TYPE_FLOAT;
1177 			    rp->vset[j]->valfmt = PM_VAL_DPTR;
1178 			    rp->vset[j]->vlist[i++].value.pval = vp;
1179 			    if (icp->t_prior == t_req)
1180 				memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(float));
1181 			    else if (icp->t_next == t_req)
1182 				memcpy((void *)vp->vbuf, (void *)icp->v_next.pval->vbuf, sizeof(float));
1183 			    else {
1184 				if (pcp->desc.sem == PM_SEM_DISCRETE) {
1185 				    if (icp->t_prior >= 0)
1186 					memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(float));
1187 				    else
1188 					ok = 0;
1189 				}
1190 				else if (pcp->desc.sem == PM_SEM_INSTANT) {
1191 				    if (icp->t_prior >= 0 && icp->t_next >= 0)
1192 					memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(float));
1193 				    else
1194 					ok = 0;
1195 				}
1196 				else {
1197 				    /* assume COUNTER */
1198 				    if (icp->t_prior >= 0 && icp->t_next >= 0) {
1199 					pmAtomValue	av;
1200 					pmAtomValue	*avp_prior = (pmAtomValue *)icp->v_prior.pval->vbuf;
1201 					pmAtomValue	*avp_next = (pmAtomValue *)icp->v_next.pval->vbuf;
1202 					float	f_prior;
1203 					float	f_next;
1204 	
1205 					memcpy((void *)&f_prior, (void *)&avp_prior->f, sizeof(float));
1206 					memcpy((void *)&f_next, (void *)&avp_next->f, sizeof(float));
1207 	
1208 					av.f = f_prior + (t_req - icp->t_prior) *
1209 						(f_next - f_prior) /
1210 						(icp->t_next - icp->t_prior);
1211 					memcpy((void *)vp->vbuf, (void *)&av.f, sizeof(av.f));
1212 				    }
1213 				    else
1214 					ok = 0;
1215 				}
1216 			    }
1217 			    if (!ok) {
1218 				i--;
1219 				free(vp);
1220 			    }
1221 			}
1222 			else if (pcp->desc.type == PM_TYPE_64 || pcp->desc.type == PM_TYPE_U64) {
1223 			    int			need;
1224 			    pmValueBlock	*vp;
1225 			    int			ok = 1;
1226 	
1227 			    need = PM_VAL_HDR_SIZE + sizeof(__int64_t);
1228 			    if ((vp = (pmValueBlock *)__pmPoolAlloc(need)) == NULL) {
1229 				sts = -oserror();
1230 				goto bad_alloc;
1231 			    }
1232 			    vp->vlen = need;
1233 			    if (pcp->desc.type == PM_TYPE_64)
1234 				vp->vtype = PM_TYPE_64;
1235 			    else
1236 				vp->vtype = PM_TYPE_U64;
1237 			    rp->vset[j]->valfmt = PM_VAL_DPTR;
1238 			    rp->vset[j]->vlist[i++].value.pval = vp;
1239 			    if (icp->t_prior == t_req)
1240 				memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(__int64_t));
1241 			    else if (icp->t_next == t_req)
1242 				memcpy((void *)vp->vbuf, (void *)icp->v_next.pval->vbuf, sizeof(__int64_t));
1243 			    else {
1244 				if (pcp->desc.sem == PM_SEM_DISCRETE) {
1245 				    if (icp->t_prior >= 0)
1246 					memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(__int64_t));
1247 				    else
1248 					ok = 0;
1249 				}
1250 				else if (pcp->desc.sem == PM_SEM_INSTANT) {
1251 				    if (icp->t_prior >= 0 && icp->t_next >= 0)
1252 					memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(__int64_t));
1253 				    else
1254 					ok = 0;
1255 				}
1256 				else {
1257 				    /* assume COUNTER */
1258 				    if (icp->t_prior >= 0 && icp->t_next >= 0) {
1259 					pmAtomValue	av;
1260 					pmAtomValue	*avp_prior = (pmAtomValue *)icp->v_prior.pval->vbuf;
1261 					pmAtomValue	*avp_next = (pmAtomValue *)icp->v_next.pval->vbuf;
1262 					if (pcp->desc.type == PM_TYPE_64) {
1263 					    __int64_t	ll_prior;
1264 					    __int64_t	ll_next;
1265 					    memcpy(&ll_prior, &avp_prior->ll, sizeof(ll_prior));
1266 					    memcpy(&ll_next, &avp_next->ll, sizeof(ll_next));
1267 					    if (ll_next >= ll_prior || dowrap == 0)
1268 						av.ll = ll_next - ll_prior;
1269 					    else
1270 						/* not monotonic increasing and want wrap */
1271 						av.ll = (__int64_t)(ULONGLONG_MAX - ll_prior + 1 +  ll_next);
1272 					    av.ll = (__int64_t)(0.5 + (double)ll_prior +
1273 						    (t_req - icp->t_prior) * (double)av.ll / (icp->t_next - icp->t_prior));
1274 					    memcpy((void *)vp->vbuf, (void *)&av.ll, sizeof(av.ll));
1275 					}
1276 					else {
1277 					    __int64_t	ull_prior;
1278 					    __int64_t	ull_next;
1279 					    memcpy(&ull_prior, &avp_prior->ull, sizeof(ull_prior));
1280 					    memcpy(&ull_next, &avp_next->ull, sizeof(ull_next));
1281 					    if (ull_next >= ull_prior) {
1282 						av.ull = ull_next - ull_prior;
1283 	#if !defined(HAVE_CAST_U64_DOUBLE)
1284 						{
1285 						    double tmp;
1286 	
1287 						    if (SIGN_64_MASK & av.ull)
1288 							tmp = (double)(__int64_t)(av.ull & (~SIGN_64_MASK)) + (__uint64_t)SIGN_64_MASK;
1289 						    else
1290 							tmp = (double)(__int64_t)av.ull;
1291 	
1292 						    av.ull = (__uint64_t)(0.5 + (double)ull_prior +
1293 							    (t_req - icp->t_prior) * tmp /
1294 							    (icp->t_next - icp->t_prior));
1295 						}
1296 	#else
1297 						av.ull = (__uint64_t)(0.5 + (double)ull_prior +
1298 							(t_req - icp->t_prior) * (double)av.ull /
1299 							(icp->t_next - icp->t_prior));
1300 	#endif
1301 					    }
1302 					    else {
1303 						/* not monotonic increasing */
1304 						if (dowrap) {
1305 						    av.ull = ULONGLONG_MAX - ull_prior + 1 +
1306 							     ull_next;
1307 	#if !defined(HAVE_CAST_U64_DOUBLE)
1308 						    {
1309 							double tmp;
1310 	
1311 							if (SIGN_64_MASK & av.ull)
1312 							    tmp = (double)(__int64_t)(av.ull & (~SIGN_64_MASK)) + (__uint64_t)SIGN_64_MASK;
1313 							else
1314 							    tmp = (double)(__int64_t)av.ull;
1315 	
1316 							av.ull = (__uint64_t)(0.5 + (double)ull_prior +
1317 								(t_req - icp->t_prior) * tmp /
1318 								(icp->t_next - icp->t_prior));
1319 						    }
1320 	#else
1321 						    av.ull = (__uint64_t)(0.5 + (double)ull_prior +
1322 							    (t_req - icp->t_prior) * (double)av.ull /
1323 							    (icp->t_next - icp->t_prior));
1324 	#endif
1325 						}
1326 						else {
1327 						    __uint64_t	tmp;
1328 						    tmp = ull_prior - ull_next;
1329 	#if !defined(HAVE_CAST_U64_DOUBLE)
1330 						    {
1331 							double xtmp;
1332 	
1333 							if (SIGN_64_MASK & av.ull)
1334 							    xtmp = (double)(__int64_t)(tmp & (~SIGN_64_MASK)) + (__uint64_t)SIGN_64_MASK;
1335 							else
1336 							    xtmp = (double)(__int64_t)tmp;
1337 								
1338 							av.ull = (__uint64_t)(0.5 + (double)ull_prior -
1339 								(t_req - icp->t_prior) * xtmp /
1340 								(icp->t_next - icp->t_prior));
1341 						    }
1342 	#else
1343 						    av.ull = (__uint64_t)(0.5 + (double)ull_prior -
1344 							    (t_req - icp->t_prior) * (double)tmp /
1345 							    (icp->t_next - icp->t_prior));
1346 	#endif
1347 						}
1348 					    }
1349 					    memcpy((void *)vp->vbuf, (void *)&av.ull, sizeof(av.ull));
1350 					}
1351 				    }
1352 				    else
1353 					ok = 0;
1354 				}
1355 			    }
1356 			    if (!ok) {
1357 				i--;
1358 				free(vp);
1359 			    }
1360 			}
1361 			else if (pcp->desc.type == PM_TYPE_DOUBLE) {
1362 			    int			need;
1363 			    pmValueBlock	*vp;
1364 			    int			ok = 1;
1365 	
1366 			    need = PM_VAL_HDR_SIZE + sizeof(double);
1367 			    if ((vp = (pmValueBlock *)__pmPoolAlloc(need)) == NULL) {
1368 				sts = -oserror();
1369 				goto bad_alloc;
1370 			    }
1371 			    vp->vlen = need;
1372 			    vp->vtype = PM_TYPE_DOUBLE;
1373 			    rp->vset[j]->valfmt = PM_VAL_DPTR;
1374 			    rp->vset[j]->vlist[i++].value.pval = vp;
1375 			    if (icp->t_prior == t_req)
1376 				memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(double));
1377 			    else if (icp->t_next == t_req)
1378 				memcpy((void *)vp->vbuf, (void *)icp->v_next.pval->vbuf, sizeof(double));
1379 			    else {
1380 				if (pcp->desc.sem == PM_SEM_DISCRETE) {
1381 				    if (icp->t_prior >= 0)
1382 					memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(double));
1383 				    else
1384 					ok = 0;
1385 				}
1386 				else if (pcp->desc.sem == PM_SEM_INSTANT) {
1387 				    if (icp->t_prior >= 0 && icp->t_next >= 0)
1388 					memcpy((void *)vp->vbuf, (void *)icp->v_prior.pval->vbuf, sizeof(double));
1389 				    else
1390 					ok = 0;
1391 				}
1392 				else {
1393 				    /* assume COUNTER */
1394 				    if (icp->t_prior >= 0 && icp->t_next >= 0) {
1395 					pmAtomValue	av;
1396 					pmAtomValue	*avp_prior = (pmAtomValue *)icp->v_prior.pval->vbuf;
1397 					pmAtomValue	*avp_next = (pmAtomValue *)icp->v_next.pval->vbuf;
1398 					double	d_prior;
1399 					double	d_next;
1400 	
1401 					memcpy((void *)&d_prior, (void *)&avp_prior->d, sizeof(double));
1402 					memcpy((void *)&d_next, (void *)&avp_next->d, sizeof(double));
1403 	
1404 					av.d = d_prior + (t_req - icp->t_prior) *
1405 						(d_next - d_prior) /
1406 						(icp->t_next - icp->t_prior);
1407 					memcpy((void *)vp->vbuf, (void *)&av.d, sizeof(av.d));
1408 				    }
1409 				    else
1410 					ok = 0;
1411 				}
1412 			    }
1413 			    if (!ok) {
1414 				i--;
1415 				free(vp);
1416 			    }
1417 			}
1418 			else if ((pcp->desc.type == PM_TYPE_AGGREGATE ||
1419 				  pcp->desc.type == PM_TYPE_STRING) &&
1420 				 icp->t_prior >= 0) {
1421 			    int		need;
1422 			    pmValueBlock	*vp;
1423 	
1424 			    need = icp->v_prior.pval->vlen;
1425 	
1426 			    if (need == PM_VAL_HDR_SIZE + sizeof(__int64_t))
1427 				vp = (pmValueBlock *)__pmPoolAlloc(need);
1428 			    else
1429 				vp = (pmValueBlock *)malloc(need);
1430 			    if (vp == NULL) {
1431 				sts = -oserror();
1432 				goto bad_alloc;
1433 			    }
1434 			    rp->vset[j]->valfmt = PM_VAL_DPTR;
1435 			    rp->vset[j]->vlist[i++].value.pval = vp;
1436 			    memcpy((void *)vp, icp->v_prior.pval, need);
1437 			}
1438 		    }
1439 		}
1440 	    }
1441 	
1442 	    *result = rp;
1443 	    sts = 0;
1444 	
1445 	all_done:
1446 	    pmXTBdeltaToTimeval(ctxp->c_delta, ctxp->c_mode, &delta_tv);
1447 	    ctxp->c_origin.tv_sec += delta_tv.tv_sec;
1448 	    ctxp->c_origin.tv_usec += delta_tv.tv_usec;
1449 	    while (ctxp->c_origin.tv_usec > 1000000) {
1450 		ctxp->c_origin.tv_sec++;
1451 		ctxp->c_origin.tv_usec -= 1000000;
1452 	    }
1453 	    while (ctxp->c_origin.tv_usec < 0) {
1454 		ctxp->c_origin.tv_sec--;
1455 		ctxp->c_origin.tv_usec += 1000000;
1456 	    }
1457 	
1458 	#ifdef PCP_DEBUG
1459 	    if (pmDebug & DBG_TRACE_INTERP) {
1460 		fprintf(stderr, "__pmLogFetchInterp: log reads: forward %ld",
1461 		    nr[PM_MODE_FORW]);
1462 		if (nr_cache[PM_MODE_FORW])
1463 		    fprintf(stderr, " (+%ld cached)", nr_cache[PM_MODE_FORW]);
1464 		fprintf(stderr, " backwards %ld",
1465 		    nr[PM_MODE_BACK]);
1466 		if (nr_cache[PM_MODE_BACK])
1467 		    fprintf(stderr, " (+%ld cached)", nr_cache[PM_MODE_BACK]);
1468 		fprintf(stderr, "\n");
1469 	    }
1470 	#endif
1471 	
1472 	    return sts;
1473 	
1474 	bad_alloc:
1475 	    /*
1476 	     * leaks a little (vlist[] stuff) ... but does not really matter at
1477 	     * this point, chance of anything good happening from here on are
1478 	     * pretty remote
1479 	     */
1480 	    rp->vset[j]->numval = i;
1481 	    while (++j < numpmid)
1482 		rp->vset[j]->numval = 0;
1483 	    pmFreeResult(rp);
1484 	
1485 	    return sts;
1486 	
1487 	}
1488 	
1489 	void
1490 	__pmLogResetInterp(__pmContext *ctxp)
1491 	{
1492 	    __pmHashCtl	*hcp = &ctxp->c_archctl->ac_pmid_hc;
1493 	    double	t_req;
1494 	    __pmHashNode	*hp;
1495 	    int		k;
1496 	    pmidcntl_t	*pcp;
1497 	    instcntl_t	*icp;
1498 	
1499 	    if (hcp->hsize == 0)
1500 		return;
1501 	
1502 	    t_req = __pmTimevalSub(&ctxp->c_origin, &ctxp->c_archctl->ac_log->l_label.ill_start);
1503 	
1504 	    for (k = 0; k < hcp->hsize; k++) {
1505 		for (hp = hcp->hash[k]; hp != NULL; hp = hp->next) {
1506 		    pcp = (pmidcntl_t *)hp->data;
1507 		    for (icp = pcp->first; icp != NULL; icp = icp->next) {
1508 			if (icp->t_prior > t_req || icp->t_next < t_req) {
1509 			    icp->t_prior = icp->t_next = -1;
1510 			    if (pcp->valfmt != PM_VAL_INSITU) {
1511 				if (icp->v_prior.pval != NULL)
1512 				    __pmUnpinPDUBuf((void *)icp->v_prior.pval);
1513 				if (icp->v_next.pval != NULL)
1514 				    __pmUnpinPDUBuf((void *)icp->v_next.pval);
1515 			    }
1516 			    icp->v_prior.pval = icp->v_next.pval = NULL;
1517 			}
1518 		    }
1519 		}
1520 	    }
1521 	}