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;
870 hp = __pmHashSearch((int)pmidlist[j], hcp);
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 }