1 /***********************************************************************
2 * dstruct.c - central data structures and associated operations
3 ***********************************************************************
4 *
5 * Copyright (c) 1995-2003 Silicon Graphics, Inc. All Rights Reserved.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17 #include "pmapi.h"
18 #include "impl.h"
19 #include <math.h>
20 #include <ctype.h>
21 #include <limits.h>
22 #ifdef HAVE_SYS_WAIT_H
23 #include <sys/wait.h>
24 #endif
25 #include "dstruct.h"
26 #include "symbol.h"
27 #include "pragmatics.h"
28 #include "fun.h"
29 #include "eval.h"
30 #include "show.h"
31
32 #if defined(HAVE_VALUES_H)
33 #include <values.h>
34 #endif
35 #if defined(HAVE_IEEEFP_H)
36 #include <ieeefp.h>
37 #endif
38 #ifndef HAVE_MEMALIGN
39 #define memalign(a,b) malloc(b)
40 #endif
41
42 /***********************************************************************
43 * constants
44 ***********************************************************************/
45
46 char localHost[MAXHOSTNAMELEN+1]; /* "official" name of localhost */
47 double mynan; /* not-a-number run time initialized */
48
49
50 /***********************************************************************
51 * user supplied parameters
52 ***********************************************************************/
53
54 char *pmnsfile = PM_NS_DEFAULT; /* alternate name space */
55 Archive *archives; /* list of open archives */
56 RealTime first = -1; /* archive starting point */
57 RealTime last = 0.0; /* archive end point */
58 char *dfltHost; /* default host */
59 RealTime dfltDelta = DELTA_DFLT; /* default sample interval */
60 char *startFlag; /* start time specified? */
61 char *stopFlag; /* end time specified? */
62 char *alignFlag; /* align time specified? */
63 char *offsetFlag; /* offset time specified? */
64 RealTime runTime; /* run time interval */
65 int hostZone; /* timezone from host? */
66 char *timeZone; /* timezone from command line */
67 int verbose; /* verbosity 0, 1 or 2 */
68 int interactive; /* interactive mode, -d */
69 int isdaemon; /* run as a daemon */
70 int agent; /* secret agent mode? */
71 int applet; /* applet mode? */
72 int dowrap; /* counter wrap? default no */
73 int noDnsFlag; /* do a default name lookup? */
74 pmiestats_t *perf; /* live performance data */
75 pmiestats_t instrument; /* used if no mmap (archive) */
76
77
78 /***********************************************************************
79 * this is where the action is
80 ***********************************************************************/
81
82 Task *taskq = NULL; /* evaluator task queue */
83 Expr *curr; /* current executing rule expression */
84
85 SymbolTable hosts; /* currently known hosts */
86 SymbolTable metrics; /* currently known metrics */
87 SymbolTable rules; /* currently known rules */
88 SymbolTable vars; /* currently known variables */
89
90
91 /***********************************************************************
92 * time
93 ***********************************************************************/
94
95 RealTime now; /* current time */
96 RealTime start; /* start evaluation time */
97 RealTime stop; /* stop evaluation time */
98
99 Symbol symDelta; /* current sample interval */
100 Symbol symMinute; /* minutes after the hour 0..59 */
101 Symbol symHour; /* hours since midnight 0..23 */
102 Symbol symDay; /* day of the month 1..31 */
103 Symbol symMonth; /* month of the year 1..12 */
104 Symbol symYear; /* year 1996.. */
105 Symbol symWeekday; /* days since Sunday 0..6 */
106
107 static double delta; /* current sample interval */
108 static double second; /* seconds after the minute 0..59 */
109 static double minute; /* minutes after the hour 0..59 */
110 static double hour; /* hours since midnight 0..23 */
111 static double day; /* day of the month 1..31 */
112 static double month; /* month of the year 1..12 */
113 static double year; /* year 1996.. */
114 static double weekday; /* days since Sunday 0..6 */
115
116 /***********************************************************************
117 * process creation control
118 ***********************************************************************/
119 int need_wait;
120
121
122 /* return real time */
123 RealTime
124 getReal(void)
125 {
126 struct timeval t;
127
128 __pmtimevalNow(&t);
129 return realize(t);
130 }
131
132
133 /* update time variables to reflect current time */
134 void
135 reflectTime(RealTime d)
136 {
137 static time_t then = 0; /* previous time */
138 int skip = now - then;
139 struct tm tm;
140
141 then = (time_t)now;
142
143 /* sample interval */
144 delta = d;
145
146 /* try short path for current time */
147 if (skip >= 0 && skip < 24 * 60 * 60) {
148 second += skip;
149 if (second < 60)
150 return;
151 skip = (int)(second / 60);
152 second -= (double)(60 * skip);
153 minute += (double)skip;
154 if (minute < 60)
155 return;
156 skip = (int)(minute / 60);
157 minute -= (double)(60 * skip);
158 hour += (double)skip;
159 if (hour < 24)
160 return;
161 }
162
163 /* long path for current time */
164 pmLocaltime(&then, &tm);
165 second = (double) tm.tm_sec;
166 minute = (double) tm.tm_min;
167 hour = (double) tm.tm_hour;
168 day = (double) tm.tm_mday;
169 month = (double) tm.tm_mon;
170 /* tm_year is years since 1900, so this is Y2K safe */
171 year = (double) tm.tm_year + 1900;
172 weekday = (double) tm.tm_wday;
173 }
174
175
176 /* convert RealTime to timeval */
177 void
178 unrealize(RealTime rt, struct timeval *tv)
179 {
180 tv->tv_sec = (time_t)rt;
181 tv->tv_usec = (int)(1000000 * (rt - tv->tv_sec));
182 }
183
184
185 /* convert RealTime to timespec */
186 void
187 unrealizenano(RealTime rt, struct timespec *ts)
188 {
189 ts->tv_sec = (time_t)rt;
190 ts->tv_nsec = (int)(1000000000 * (rt - ts->tv_sec));
191 }
192
193 #define SLEEP_EVAL 0
194 #define SLEEP_RETRY 1
195
196 /* sleep until eval or retry RealTime */
197 void
198 sleepTight(Task *t, int type)
199 {
200 RealTime sched;
201 RealTime delay; /* interval to sleep */
202 int sts;
203 RealTime cur_entry = getReal();
204 #ifdef HAVE_WAITPID
205 pid_t pid;
206
207 if (need_wait) {
208 /* harvest terminated children */
209 while ((pid = waitpid(-1, &sts, WNOHANG)) > (pid_t)0) {
210 #if PCP_DEBUG
211 if (pmDebug & DBG_TRACE_APPL2) {
212 fprintf(stderr, "sleepTight: wait: pid=%" FMT_PID " done status=0x%x", pid, sts);
213 if (WIFEXITED(sts))
214 fprintf(stderr, " exit=%d", WEXITSTATUS(sts));
215 if (WIFSIGNALED(sts))
216 fprintf(stderr, " signal=%d", WTERMSIG(sts));
217 fprintf(stderr, "\n");
218 }
219 #endif
220 ;
221 }
222 need_wait = 0;
223 }
224 #endif
225
226 if (!archives) {
227 struct timespec ts, tleft;
228 static RealTime last_sched = -1;
229 static Task *last_t;
230 static int last_type;
231 RealTime cur = getReal();
232
233 sched = type == SLEEP_EVAL ? t->eval : t->retry;
234
235 delay = sched - cur;
236 if (delay < 0) {
237 int show_detail = 0;
238 if (delay <= -1) {
239 fprintf(stderr, "sleepTight: negative delay (%f). sched=%f, cur=%f\n",
240 delay, sched, cur);
241 show_detail = 1;
242 }
243 #if PCP_DEBUG
244 else {
245 if (pmDebug & DBG_TRACE_APPL2) {
246 fprintf(stderr, "sleepTight: small negative delay (%f). sched=%f, cur=%f\n",
247 delay, sched, cur);
248 show_detail = 1;
249 }
250 }
251 #endif
252 if (show_detail) {
253 if (last_sched > 0) {
254 fprintf(stderr, "Last sleepTight (%s) until: ", last_type == SLEEP_EVAL ? "eval" : "retry");
255 showFullTime(stderr, last_sched);
256 fputc('\n', stderr);
257 fprintf(stderr, "Last ");
258 dumpTask(last_t);
259 }
260 fprintf(stderr, "This sleepTight() entry: ");
261 showFullTime(stderr, cur_entry);
262 fputc('\n', stderr);
263 fprintf(stderr, "Harvest children done: ");
264 showFullTime(stderr, cur);
265 fputc('\n', stderr);
266 fprintf(stderr, "Want sleepTight (%s) until: ", type == SLEEP_EVAL ? "eval" : "retry");
267 showFullTime(stderr, sched);
268 fputc('\n', stderr);
269 fprintf(stderr, "This ");
270 dumpTask(t);
271 }
272 }
273 else {
274 unrealizenano(delay, &ts);
275 for (;;) { /* loop to catch early wakeup from nanosleep */
276 if (ts.tv_sec < 0 || ts.tv_nsec > 999999999) {
277 fprintf(stderr, "sleepTight: invalid args: %ld %ld\n",
278 ts.tv_sec, ts.tv_nsec);
279 break;
280 }
281 sts = nanosleep(&ts, &tleft);
282 if (sts == 0 || (sts < 0 && oserror() != EINTR))
283 break;
284 ts = tleft;
285 }
286 }
287 last_t = t;
288 last_type = type;
289 last_sched = sched;
290 }
291 }
292
293
294 /***********************************************************************
295 * ring buffer management
296 ***********************************************************************/
297
298 void
299 newRingBfr(Expr *x)
300 {
301 size_t sz;
302 char *p;
303 int i;
304
305 sz = ((x->sem == SEM_TRUTH) || (x->sem == SEM_CHAR)) ?
306 sizeof(char) * x->tspan :
307 sizeof(double) * x->tspan;
308 if (x->ring) free(x->ring);
309 x->ring = alloc(x->nsmpls * sz);
310 p = (char *) x->ring;
311 for (i = 0; i < x->nsmpls; i++) {
312 x->smpls[i].ptr = (void *) p;
313 p += sz;
314 }
315 }
316
317
318 void
319 newStringBfr(Expr *x, size_t length, char *bfr)
320 {
321 if (x->e_idom != (int)length) {
322 x->e_idom = (int)length;
323 x->tspan = (int)length;
324 x->nvals = (int)length;
325 }
326 if (x->ring)
327 free(x->ring);
328 x->ring = bfr;
329 x->smpls[0].ptr = (void *) bfr;
330 }
331
332
333 /* Rotate ring buffer - safe to call only if x->nsmpls > 1 */
334 void
335 rotate(Expr *x)
336 {
337 int n = x->nsmpls-1;
338 Sample *q = &x->smpls[n];
339 Sample *p = q - 1;
340 void *t = q->ptr;
341 int i;
342
343 for (i = n; i > 0; i--)
344 *q-- = *p--;
345 x->smpls[0].ptr = t;
346 }
347
348
349 /***********************************************************************
350 * memory allocation
351 ***********************************************************************/
352
353 void *
354 alloc(size_t size)
355 {
356 void *p;
357
358 if ((p = malloc(size)) == NULL) {
359 __pmNoMem("pmie.alloc", size, PM_FATAL_ERR);
360 }
361 return p;
362 }
363
364
365 void *
366 zalloc(size_t size)
367 {
368 void *p;
369
370 if ((p = calloc(1, size)) == NULL) {
371 __pmNoMem("pmie.zalloc", size, PM_FATAL_ERR);
372 }
373 return p;
374 }
375
376
377 void *
378 aalloc(size_t align, size_t size)
379 {
380 void *p;
381
382 if ((p = memalign(align, size)) == NULL) {
383 __pmNoMem("pmie.aalloc", size, PM_FATAL_ERR);
384 }
385 return p;
386 }
387
388
389 void *
390 ralloc(void *p, size_t size)
391 {
392 void *q;
393
394 if ((q = realloc(p, size)) == NULL) {
395 __pmNoMem("pmie.ralloc", size, PM_FATAL_ERR);
396 }
397 return q;
398 }
399
400 char *
401 sdup(char *p)
402 {
403 char *q;
404
405 if ((q = strdup(p)) == NULL) {
406 __pmNoMem("pmie.sdup", strlen(p), PM_FATAL_ERR);
407 }
408 return q;
409 }
410
411
412 Expr *
413 newExpr(int op, Expr *arg1, Expr *arg2,
414 int hdom, int idom, int tdom, int nsmpls,
415 int sem)
416 {
417 Expr *x;
418 Expr *arg;
419
420 x = (Expr *) zalloc(sizeof(Expr) + (nsmpls - 1) * sizeof(Sample));
421 x->op = op;
422 if (arg1) {
423 x->arg1 = arg1;
424 arg1->parent = x;
425 }
426 if (arg2) {
427 x->arg2 = arg2;
428 arg2->parent = x;
429 }
430 x->hdom = hdom;
431 x->e_idom = idom;
432 x->tdom = tdom;
433 x->nsmpls = nsmpls;
434 x->tspan = (x->e_idom >= 0) ? x->e_idom : abs(x->hdom);
435 x->nvals = x->tspan * nsmpls;
436 if (arg1) {
437 arg = primary(arg1, arg2);
438 x->metrics = arg->metrics;
439 }
440 x->units = noUnits;
441 x->sem = sem;
442 return x;
443 }
444
445
446 Profile *
447 newProfile(Fetch *owner, pmInDom indom)
448 {
449 Profile *p = (Profile *) zalloc(sizeof(Profile));
450 p->indom = indom;
451 p->fetch = owner;
452 return p;
453 }
454
455
456 Fetch *
457 newFetch(Host *owner)
458 {
459 Fetch *f = (Fetch *) zalloc(sizeof(Fetch));
460 f->host = owner;
461 return f;
462 }
463
464
465 Host *
466 newHost(Task *owner, Symbol name)
467 {
468 Host *h = (Host *) zalloc(sizeof(Host));
469
470 h->name = symCopy(name);
471 h->task = owner;
472 return h;
473 }
474
475
476 Task *
477 newTask(RealTime delta, int nth)
478 {
479 Task *t = (Task *) zalloc(sizeof(Task));
480 t->nth = nth;
481 t->delta = delta;
482 return t;
483 }
484
485 /* translate new metric name to internal pmid for agent mode */
486 static pmID
487 agentId(char *name)
488 {
489 int sts;
490 pmID pmid;
491
492 if ((sts = pmLookupName(1, &name, &pmid)) < 0) {
493 fprintf(stderr, "%s: agentId: metric %s not found in namespace: %s\n",
494 pmProgname, name, pmErrStr(sts));
495 exit(1);
496 }
497 return pmid;
498 }
499
500
501 void
502 newResult(Task *t)
503 {
504 pmResult *rslt;
505 Symbol *sym;
506 pmValueSet *vset;
507 pmValueBlock *vblk;
508 int i;
509 int len;
510
511 /* allocate pmResult */
512 rslt = (pmResult *) zalloc(sizeof(pmResult) + (t->nrules - 1) * sizeof(pmValueSet *));
513 rslt->numpmid = t->nrules;
514
515 /* allocate pmValueSet's */
516 sym = t->rules;
517 for (i = 0; i < t->nrules; i++) {
518 vset = (pmValueSet *)alloc(sizeof(pmValueSet));
519 vset->pmid = agentId(symName(*sym));
520 vset->numval = 0;
521 vset->valfmt = PM_VAL_DPTR;
522 vset->vlist[0].inst = PM_IN_NULL;
523 len = PM_VAL_HDR_SIZE + sizeof(double);
524 vblk = (pmValueBlock *)zalloc(len);
525 vblk->vlen = len;
526 vblk->vtype = PM_TYPE_DOUBLE;
527 vset->vlist[0].value.pval = vblk;
528 rslt->vset[i] = vset;
529 sym++;
530 }
531
532 t->rslt = rslt;
533 }
534
535
536 /***********************************************************************
537 * memory deallocation
538 *
539 * IMPORTANT: These functions free the argument structure plus any
540 * structures it owns below it in the expression tree.
541 ***********************************************************************/
542
543 void
544 freeTask(Task *t)
545 {
546 if ((t->hosts == NULL) && (t->rules == NULL)) {
547 if (t->next) t->next->prev = t->prev;
548 if (t->prev) t->prev->next = t->next;
549 else taskq = t->next;
550 free(t);
551 }
552 }
553
554
555 void
556 freeHost(Host *h)
557 {
558 if ((h->fetches == NULL) && (h->waits == NULL)) {
559 if (h->next) h->next->prev = h->prev;
560 if (h->prev) h->prev->next = h->next;
561 else {
562 h->task->hosts = h->next;
563 freeTask(h->task);
564 }
565 symFree(h->name);
566 free(h);
567 }
568 }
569
570
571 void
572 freeFetch(Fetch *f)
573 {
574 if (f->profiles == NULL) {
575 if (f->next) f->next->prev = f->prev;
576 if (f->prev) f->prev->next = f->next;
577 else {
578 f->host->fetches = f->next;
579 freeHost(f->host);
580 }
581 pmDestroyContext(f->handle);
582 if (f->result) pmFreeResult(f->result);
583 if (f->pmids) free(f->pmids);
584 free(f);
585 }
586 }
587
588
589 void
590 FreeProfile(Profile *p)
591 {
592 if (p->metrics == NULL) {
593 if (p->next) p->next->prev = p->prev;
594 if (p->prev) p->prev->next = p->next;
595 else {
596 p->fetch->profiles = p->next;
597 freeFetch(p->fetch);
598 }
599 free(p);
600 }
601 }
602
603
604 void
605 freeMetric(Metric *m)
606 {
607 int numinst;
608
609 /* Metric is on fetch list */
610 if (m->profile) {
611 if (m->prev) {
612 m->prev->next = m->next;
613 if (m->next) m->next->prev = m->prev;
614 }
615 else {
616 m->host->waits = m->next;
617 if (m->next) m->next->prev = NULL;
618 }
619 if (m->host) freeHost(m->host);
620 }
621
622 symFree(m->hname);
623 numinst = m->specinst == 0 ? m->m_idom : m->specinst;
624 if (numinst > 0 && m->inames) {
625 int i;
626 for (i = 0; i < numinst; i++) {
627 if (m->inames[i] != NULL) free(m->inames[i]);
628 }
629 free(m->inames);
630 }
631 if (numinst && m->iids) free(m->iids);
632 if (m->vals) free(m->vals);
633 free(m);
634 }
635
636
637 void
638 freeExpr(Expr *x)
639 {
640 Metric *m;
641 int i;
642
643 if (x) {
644 if (x->arg1 && x->arg1->parent == x)
645 freeExpr(x->arg1);
646 if (x->arg2 && x->arg2->parent == x)
647 freeExpr(x->arg2);
648 if (x->metrics && x->op == CND_FETCH) {
649 if (x->hdom < 0) {
650 /*
651 * no trips through the loop to call freeMetric(),
652 * so free partially allocated structure
653 */
654 free(x->metrics);
655 }
656 else {
657 for (m = x->metrics, i = 0; i < x->hdom; m++, i++)
658 freeMetric(m);
659 }
660 }
661 if (x->ring) free(x->ring);
662 free(x);
663 }
664 }
665
666
667 /***********************************************************************
668 * comparison functions (for use by qsort)
669 ***********************************************************************/
670
671 /* Compare two instance identifiers.
672 - This function is passed as an argument to qsort, hence the casts. */
673 int /* -1 less, 0 equal, 1 greater */
674 compid(const void *i1, const void *i2)
675 {
676 if (*(int *)i1 < *(int *)i2) return -1;
677 if (*(int *)i1 > *(int *)i2) return 1;
678 return 0;
679 }
680
681
682 /* Compare two pmValue's on their inst fields
683 - This function is passed as an argument to qsort, hence the casts. */
684 int /* -1 less, 0 equal, 1 greater */
685 compair(const void *pmv1, const void *pmv2)
686 {
687 if (((pmValue *)pmv1)->inst < ((pmValue *)pmv2)->inst) return -1;
688 if (((pmValue *)pmv1)->inst > ((pmValue *)pmv2)->inst) return 1;
689 return 0;
690 }
691
692
693 /***********************************************************************
694 * Expr manipulation
695 ***********************************************************************/
696
697 /* Decide primary argument for inheritance of Expr attributes */
698 Expr *
699 primary(Expr *arg1, Expr *arg2)
700 {
701 if (arg2 == NULL || arg1->nvals > 1)
702 return arg1;
703 if (arg2->nvals > 1)
704 return arg2;
705 if (arg1->metrics &&
706 (arg1->hdom != -1 || arg1->e_idom != -1 || arg1->tdom != -1))
707 return arg1;
708 if (arg2->metrics &&
709 (arg2->hdom != -1 || arg2->e_idom != -1 || arg2->tdom != -1))
710 return arg2;
711 return arg1;
712 }
713
714
715 /* change number of samples allocated in ring buffer */
716 void
717 changeSmpls(Expr **p, int nsmpls)
718 {
719 Expr *x = *p;
720 Metric *m;
721 int i;
722
723 if (nsmpls == x->nsmpls) return;
724 *p = x = (Expr *) ralloc(x, sizeof(Expr) + (nsmpls - 1) * sizeof(Sample));
725 x->nsmpls = nsmpls;
726 x->nvals = x->tspan * nsmpls;
727 x->valid = 0;
728 if (x->op == CND_FETCH) {
729 m = x->metrics;
730 for (i = 0; i < x->hdom; i++) {
731 m->expr = x;
732 m++;
733 }
734 }
735 newRingBfr(x);
736 }
737
738
739 /* propagate instance domain, semantics and units from
740 argument expressions to parents */
741 static void
742 instExpr(Expr *x)
743 {
744 int up = 0;
745 Expr *arg1 = x->arg1;
746 Expr *arg2 = x->arg2;
747 Expr *arg = primary(arg1, arg2);
|
Event var_decl: |
Declaring variable "u" without initializer. |
| Also see events: |
[uninit_use] |
748 pmUnits u;
749
750 /* semantics and units */
|
At conditional (1): "x->sem == 0": Taking true branch.
|
751 if (x->sem == SEM_UNKNOWN) {
752
753 /* unary expression */
|
At conditional (2): "arg2 == NULL": Taking false branch.
|
754 if (arg2 == NULL) {
755 up = 1;
756 x->sem = arg1->sem;
757 x->units = arg1->units;
758 }
759
760 /* bianry expression with known args */
|
At conditional (3): "arg1->sem != 0": Taking true branch.
|
|
At conditional (4): "arg2->sem != 0": Taking true branch.
|
761 else if ((arg1->sem != SEM_UNKNOWN) &&
762 (arg2->sem != SEM_UNKNOWN)) {
763 up = 1;
764 x->sem = arg->sem;
|
At conditional (5): "x->op == 7": Taking true branch.
|
765 if (x->op == CND_MUL) {
766 u.dimSpace = arg1->units.dimSpace + arg2->units.dimSpace;
767 u.dimTime = arg1->units.dimTime + arg2->units.dimTime;
768 u.dimCount = arg1->units.dimCount + arg2->units.dimCount;
769 }
770 else if (x->op == CND_DIV) {
771 u.dimSpace = arg1->units.dimSpace - arg2->units.dimSpace;
772 u.dimTime = arg1->units.dimTime - arg2->units.dimTime;
773 u.dimCount = arg1->units.dimCount - arg2->units.dimCount;
774 }
775 else
776 u = arg->units;
|
Event uninit_use: |
Using uninitialized value "u": field "u".scaleSpace is uninitialized. |
| Also see events: |
[var_decl] |
777 x->units = u;
778 }
779
780 /* binary expression with unknown arg */
781 else
782 return;
783 }
784
785 /* instance domain */
786 if ((x->e_idom != -1) && (x->e_idom != arg->e_idom)) {
787 up = 1;
788 x->e_idom = arg->e_idom;
789 x->tspan = (x->e_idom >= 0) ? x->e_idom : abs(x->hdom);
790 x->nvals = x->tspan * x->nsmpls;
791 x->valid = 0;
792 newRingBfr(x);
793 }
794
795 if (up && x->parent)
796 instExpr(x->parent);
797 }
798
799
800 /* propagate instance domain, semantics and units from given
801 fetch expression to its parents */
802 void
803 instFetchExpr(Expr *x)
804 {
805 Metric *m;
806 int ninst;
807 int up = 0;
808 int i;
809
810 /* update semantics and units */
811 if (x->sem == SEM_UNKNOWN) {
812 m = x->metrics;
813 for (i = 0; i < x->hdom; i++) {
814 if (m->desc.sem != SEM_UNKNOWN) {
815 if (m->desc.sem == PM_SEM_COUNTER) {
816 x->sem = PM_SEM_INSTANT;
817 x->units = canon(m->desc.units);
818 x->units.dimTime--;
819 }
820 else {
821 x->sem = m->desc.sem;
822 x->units = canon(m->desc.units);
823 }
824 up = 1;
825 break;
826 }
827 }
828 }
829
830 /*
831 * update number of instances ... need to be careful because may be more
832 * than one host, and instances may not be fully available ...
833 * m_idom < 0 => no idea how many instances there might be (cannot
834 * contact pmcd, unknown metric, can't get indom, ...)
835 * m_idom == 0 => no values, but otherwise OK
836 * m_idom > 0 => have this many values (and hence instances)
837 */
838 m = x->metrics;
839 ninst = -1;
840 for (i = 0; i < x->hdom; i++) {
841 m->offset = ninst;
842 if (m->m_idom >= 0) {
843 if (ninst == -1)
844 ninst = m->m_idom;
845 else
846 ninst += m->m_idom;
847 }
848 m++;
849 }
850 if (x->e_idom != ninst) {
851 x->e_idom = ninst;
852 x->tspan = (x->e_idom >= 0) ? x->e_idom : abs(x->hdom);
853 x->nvals = x->nsmpls * x->tspan;
854 x->valid = 0;
855 newRingBfr(x);
856 up = 1;
857 }
858 if (up && x->parent)
859 instExpr(x->parent);
860 }
861
862
863 /***********************************************************************
864 * compulsory initialization
865 ***********************************************************************/
866
867 void dstructInit(void)
868 {
869 Expr *x;
870 double zero = 0.0;
871
872 /* not-a-number initialization */
873 mynan = zero / zero;
874
875 /* initialize default host */
876 gethostname(localHost, MAXHOSTNAMELEN);
877 localHost[MAXHOSTNAMELEN-1] = '\0';
878 dfltHost = localHost;
879
880 /* set up symbol tables */
881 symSetTable(&hosts);
882 symSetTable(&metrics);
883 symSetTable(&rules);
884 symSetTable(&vars);
885
886 /* set yp inter-sample interval (delta) symbol */
887 symDelta = symIntern(&vars, "delta");
888 x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR);
889 x->smpls[0].ptr = δ
890 x->valid = 1;
891 symValue(symDelta) = x;
892
893 /* set up time symbols */
894 symMinute = symIntern(&vars, "minute");
895 x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR);
896 x->smpls[0].ptr = &minute;
897 x->valid = 1;
898 symValue(symMinute) = x;
899 symHour = symIntern(&vars, "hour");
900 x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR);
901 x->smpls[0].ptr = &hour;
902 x->valid = 1;
903 symValue(symHour) = x;
904 symDay = symIntern(&vars, "day");
905 x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR);
906 x->smpls[0].ptr = &day;
907 x->valid = 1;
908 symValue(symDay) = x;
909 symMonth = symIntern(&vars, "month");
910 x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR);
911 x->smpls[0].ptr = &month;
912 x->valid = 1;
913 symValue(symMonth) = x;
914 symYear = symIntern(&vars, "year");
915 x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR);
916 x->smpls[0].ptr = &year;
917 x->valid = 1;
918 symValue(symYear) = x;
919 symWeekday = symIntern(&vars, "day_of_week");
920 x = newExpr(OP_VAR, NULL,NULL, -1, -1, -1, 1, SEM_NUMVAR);
921 x->smpls[0].ptr = &weekday;
922 x->valid = 1;
923 symValue(symWeekday) = x;
924 }
925
926
927 /* get ready to run evaluator */
928 void
929 agentInit(void)
930 {
931 Task *t;
932 int sts;
933
934 /* Set up local name space for agent */
935 /* Only load PMNS if it's default and hence not already loaded */
936 if (pmnsfile == PM_NS_DEFAULT && (sts = pmLoadNameSpace(pmnsfile)) < 0) {
937 fprintf(stderr, "%s: agentInit: cannot load metric namespace: %s\n",
938 pmProgname, pmErrStr(sts));
939 exit(1);
940 }
941
942 /* allocate pmResult's and send pmDescs for secret agent mode */
943 t = taskq;
944 while (t) {
945 newResult(t);
946 sendDescs(t);
947 t = t->next;
948 }
949 }
950
951 /*
952 * useful for diagnostics and with dbx
953 */
954
955 static struct {
956 void (*addr)(Expr *);
957 char *name;
958 } fn_map[] = {
959 { actAlarm, "actAlarm" },
960 { actAnd, "actAnd" },
961 { actArg, "actArg" },
962 { actFake, "actFake" },
963 { actOr, "actOr" },
964 { actPrint, "actPrint" },
965 { actShell, "actShell" },
966 { actStomp, "actStomp" },
967 { actSyslog, "actSyslog" },
968 { cndAdd_1_1, "cndAdd_1_1" },
969 { cndAdd_1_n, "cndAdd_1_n" },
970 { cndAdd_n_1, "cndAdd_n_1" },
971 { cndAdd_n_n, "cndAdd_n_n" },
972 { cndAll_host, "cndAll_host" },
973 { cndAll_inst, "cndAll_inst" },
974 { cndAll_time, "cndAll_time" },
975 { cndAnd_1_1, "cndAnd_1_1" },
976 { cndAnd_1_n, "cndAnd_1_n" },
977 { cndAnd_n_1, "cndAnd_n_1" },
978 { cndAnd_n_n, "cndAnd_n_n" },
979 { cndAvg_host, "cndAvg_host" },
980 { cndAvg_inst, "cndAvg_inst" },
981 { cndAvg_time, "cndAvg_time" },
982 { cndCount_host, "cndCount_host" },
983 { cndCount_inst, "cndCount_inst" },
984 { cndCount_time, "cndCount_time" },
985 { cndDelay_1, "cndDelay_1" },
986 { cndDelay_n, "cndDelay_n" },
987 { cndDiv_1_1, "cndDiv_1_1" },
988 { cndDiv_1_n, "cndDiv_1_n" },
989 { cndDiv_n_1, "cndDiv_n_1" },
990 { cndDiv_n_n, "cndDiv_n_n" },
991 { cndEq_1_1, "cndEq_1_1" },
992 { cndEq_1_n, "cndEq_1_n" },
993 { cndEq_n_1, "cndEq_n_1" },
994 { cndEq_n_n, "cndEq_n_n" },
995 { cndFall_1, "cndFall_1" },
996 { cndFall_n, "cndFall_n" },
997 { cndFetch_1, "cndFetch_1" },
998 { cndFetch_all, "cndFetch_all" },
999 { cndFetch_n, "cndFetch_n" },
1000 { cndGt_1_1, "cndGt_1_1" },
1001 { cndGt_1_n, "cndGt_1_n" },
1002 { cndGt_n_1, "cndGt_n_1" },
1003 { cndGt_n_n, "cndGt_n_n" },
1004 { cndGte_1_1, "cndGte_1_1" },
1005 { cndGte_1_n, "cndGte_1_n" },
1006 { cndGte_n_1, "cndGte_n_1" },
1007 { cndGte_n_n, "cndGte_n_n" },
1008 { cndLt_1_1, "cndLt_1_1" },
1009 { cndLt_1_n, "cndLt_1_n" },
1010 { cndLt_n_1, "cndLt_n_1" },
1011 { cndLt_n_n, "cndLt_n_n" },
1012 { cndLte_1_1, "cndLte_1_1" },
1013 { cndLte_1_n, "cndLte_1_n" },
1014 { cndLte_n_1, "cndLte_n_1" },
1015 { cndLte_n_n, "cndLte_n_n" },
1016 { cndMax_host, "cndMax_host" },
1017 { cndMax_inst, "cndMax_inst" },
1018 { cndMax_time, "cndMax_time" },
1019 { cndMin_host, "cndMin_host" },
1020 { cndMin_inst, "cndMin_inst" },
1021 { cndMin_time, "cndMin_time" },
1022 { cndMul_1_1, "cndMul_1_1" },
1023 { cndMul_1_n, "cndMul_1_n" },
1024 { cndMul_n_1, "cndMul_n_1" },
1025 { cndMul_n_n, "cndMul_n_n" },
1026 { cndNeg_1, "cndNeg_1" },
1027 { cndNeg_n, "cndNeg_n" },
1028 { cndNeq_1_1, "cndNeq_1_1" },
1029 { cndNeq_1_n, "cndNeq_1_n" },
1030 { cndNeq_n_1, "cndNeq_n_1" },
1031 { cndNeq_n_n, "cndNeq_n_n" },
1032 { cndNot_1, "cndNot_1" },
1033 { cndNot_n, "cndNot_n" },
1034 { cndOr_1_1, "cndOr_1_1" },
1035 { cndOr_1_n, "cndOr_1_n" },
1036 { cndOr_n_1, "cndOr_n_1" },
1037 { cndOr_n_n, "cndOr_n_n" },
1038 { cndPcnt_host, "cndPcnt_host" },
1039 { cndPcnt_inst, "cndPcnt_inst" },
1040 { cndPcnt_time, "cndPcnt_time" },
1041 { cndRate_1, "cndRate_1" },
1042 { cndRate_n, "cndRate_n" },
1043 { cndRise_1, "cndRise_1" },
1044 { cndRise_n, "cndRise_n" },
1045 { cndSome_host, "cndSome_host" },
1046 { cndSome_inst, "cndSome_inst" },
1047 { cndSome_time, "cndSome_time" },
1048 { cndSub_1_1, "cndSub_1_1" },
1049 { cndSub_1_n, "cndSub_1_n" },
1050 { cndSub_n_1, "cndSub_n_1" },
1051 { cndSub_n_n, "cndSub_n_n" },
1052 { cndSum_host, "cndSum_host" },
1053 { cndSum_inst, "cndSum_inst" },
1054 { cndSum_time, "cndSum_time" },
1055 { rule, "rule" },
1056 { NULL, NULL },
1057 };
1058
1059 static struct {
1060 int val;
1061 char *name;
1062 } sem_map[] = {
1063 { SEM_UNKNOWN, "UNKNOWN" },
1064 { SEM_NUMVAR, "NUMVAR" },
1065 { SEM_NUMCONST, "NUMCONST" },
1066 { SEM_TRUTH, "TRUTH" },
1067 { SEM_CHAR, "CHAR" },
1068 { SEM_REGEX, "REGEX" },
1069 { PM_SEM_COUNTER, "COUNTER" },
1070 { PM_SEM_INSTANT, "INSTANT" },
1071 { PM_SEM_DISCRETE, "DISCRETE" },
1072 { 0, NULL },
1073 };
1074
1075 void
1076 __dumpExpr(int level, Expr *x)
1077 {
1078 int i;
1079 int j;
1080 int k;
1081
1082 for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1083 fprintf(stderr, "Expr dump @ " PRINTF_P_PFX "%p\n", x);
1084 if (x == NULL) return;
1085 for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1086 fprintf(stderr, " op=%d (%s) arg1=" PRINTF_P_PFX "%p arg2=" PRINTF_P_PFX "%p parent=" PRINTF_P_PFX "%p\n",
1087 x->op, opStrings(x->op), x->arg1, x->arg2, x->parent);
1088 for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1089 fprintf(stderr, " eval=");
1090 for (j = 0; fn_map[j].addr; j++) {
1091 if (x->eval == fn_map[j].addr) {
1092 fprintf(stderr, "%s", fn_map[j].name);
1093 break;
1094 }
1095 }
1096 if (fn_map[j].addr == NULL)
1097 fprintf(stderr, "" PRINTF_P_PFX "%p()", x->eval);
1098 fprintf(stderr, " metrics=" PRINTF_P_PFX "%p ring=" PRINTF_P_PFX "%p\n", x->metrics, x->ring);
1099 for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1100 fprintf(stderr, " valid=%d cardinality[H,I,T]=[%d,%d,%d] tspan=%d\n",
1101 x->valid, x->hdom, x->e_idom, x->tdom, x->tspan);
1102 for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1103 fprintf(stderr, " nsmpls=%d nvals=%d sem=", x->nsmpls, x->nvals);
1104 for (j = 0; sem_map[j].name; j++) {
1105 if (x->sem == sem_map[j].val) {
1106 fprintf(stderr, "%s", sem_map[j].name);
1107 break;
1108 }
1109 }
1110 if (sem_map[j].name == NULL)
1111 fprintf(stderr, "%d", x->sem);
1112 fprintf(stderr, " units=%s\n", pmUnitsStr(&x->units));
1113 if (x->valid > 0) {
1114 if (x->sem == SEM_TRUTH || x->sem == SEM_CHAR ||
1115 x->sem == SEM_NUMVAR || x->sem == SEM_NUMCONST ||
1116 x->sem == PM_SEM_COUNTER || x->sem == PM_SEM_INSTANT ||
1117 x->sem == PM_SEM_DISCRETE) {
1118 for (j = 0; j < x->nsmpls; j++) {
1119 for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1120 fprintf(stderr, " smpls[%d].ptr " PRINTF_P_PFX "%p ", j, x->smpls[j].ptr);
1121 for (k = 0; k < x->tspan; k++) {
1122 if (x->tspan > 1 && x->sem != SEM_CHAR) {
1123 if (k > 0)
1124 fprintf(stderr, ", ");
1125 fprintf(stderr, "{%d} ", k);
1126 }
1127 if (x->sem == SEM_TRUTH) {
1128 char c = *((char *)x->smpls[j].ptr+k);
1129 if ((int)c == TRUE)
1130 fprintf(stderr, "true");
1131 else if ((int)c == FALSE)
1132 fprintf(stderr, "false");
1133 else if ((int)c == DUNNO)
1134 fprintf(stderr, "unknown");
1135 else
1136 fprintf(stderr, "bogus (0x%x)", c & 0xff);
1137 }
1138 else if (x->sem == SEM_CHAR) {
1139 if (k == 0)
1140 fprintf(stderr, "\"%s\"", (char *)x->smpls[j].ptr);
1141 }
1142 else {
1143 double v = *((double *)x->smpls[j].ptr+k);
1144 if (isnand(v))
1145 fputc('?', stderr);
1146 else
1147 fprintf(stderr, "%g", v);
1148 }
1149 }
1150 fputc('\n', stderr);
1151 }
1152 }
1153 else if (x->sem == SEM_REGEX) {
1154 for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1155 fprintf(stderr, " handle=" PRINTF_P_PFX "%p\n", x->ring);
1156 }
1157 }
1158 }
1159
1160 void
1161 __dumpMetric(int level, Metric *m)
1162 {
1163 int i;
1164 int j;
1165 int numinst;
1166
1167 for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1168 fprintf(stderr, "Metric dump @ " PRINTF_P_PFX "%p\n", m);
1169 for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1170 fprintf(stderr, "expr=" PRINTF_P_PFX "%p profile=" PRINTF_P_PFX "%p host=" PRINTF_P_PFX "%p next=" PRINTF_P_PFX "%p prev=" PRINTF_P_PFX "%p\n",
1171 m->expr, m->profile, m->host, m->next, m->prev);
1172 for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1173 fprintf(stderr, "metric=%s host=%s conv=%g specinst=%d m_indom=%d\n",
1174 symName(m->mname), symName(m->hname), m->conv, m->specinst, m->m_idom);
1175 if (m->desc.indom != PM_INDOM_NULL) {
1176 numinst = m->specinst == 0 ? m->m_idom : m->specinst;
1177 for (j = 0; j < numinst; j++) {
1178 for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1179 fprintf(stderr, "[%d] iid=", j);
1180 if (m->iids[j] == PM_IN_NULL)
1181 fprintf(stderr, "?missing");
1182 else
1183 fprintf(stderr, "%d", m->iids[j]);
1184 fprintf(stderr, " iname=\"%s\"\n", m->inames[j]);
1185 }
1186 }
1187 for (i = 0; i < level; i++) fprintf(stderr, ".. ");
1188 fputc('\n', stderr);
1189
1190 #if 0
1191 pmDesc desc; /* pmAPI metric description */
1192 RealTime stamp; /* time stamp for current values */
1193 pmValueSet *vset; /* current values */
1194 RealTime stomp; /* previous time stamp for rate calculation */
1195 double *vals; /* vector of values for rate computation */
1196 int offset; /* offset within sample in expr ring buffer */
1197 ... Metric;
1198 #endif
1199
1200 }
1201
1202
1203 void
1204 __dumpTree(int level, Expr *x)
1205 {
1206 __dumpExpr(level, x);
1207 if (x->arg1 != NULL) __dumpTree(level+1, x->arg1);
1208 if (x->arg2 != NULL) __dumpTree(level+1, x->arg2);
1209 }
1210
1211 void
1212 dumpTree(Expr *x)
1213 {
1214 __dumpTree(0, x);
1215 }
1216
1217 void
1218 dumpRules(void)
1219 {
1220 Task *t;
1221 Symbol *s;
1222 int i;
1223
1224 for (t = taskq; t != NULL; t = t->next) {
1225 s = t->rules;
1226 for (i = 0; i < t->nrules; i++, s++) {
1227 fprintf(stderr, "\nRule: %s\n", symName(*s));
1228 dumpTree((Expr *)symValue(*s));
1229 }
1230 }
1231 }
1232
1233 void
1234 dumpExpr(Expr *x)
1235 {
1236 __dumpExpr(0, x);
1237 }
1238
1239 void
1240 dumpMetric(Metric *m)
1241 {
1242 __dumpMetric(0, m);
1243 }
1244
1245 void
1246 dumpTask(Task *t)
1247 {
1248 int i;
1249 fprintf(stderr, "Task dump @ " PRINTF_P_PFX "%p\n", t);
1250 fprintf(stderr, " nth=%d delta=%.3f tick=%d next=" PRINTF_P_PFX "%p prev=" PRINTF_P_PFX "%p\n", t->nth, t->delta, t->tick, t->next, t->prev);
1251 fprintf(stderr, " eval time: ");
1252 showFullTime(stderr, t->eval);
1253 fputc('\n', stderr);
1254 fprintf(stderr, " retry time: ");
1255 showFullTime(stderr, t->retry);
1256 fputc('\n', stderr);
1257 if (t->hosts == NULL)
1258 fprintf(stderr, " host=<null>\n");
1259 else
1260 fprintf(stderr, " host=%s (%s)\n", symName(t->hosts->name), t->hosts->down ? "down" : "up");
1261 fprintf(stderr, " rules:\n");
1262 for (i = 0; i < t->nrules; i++) {
1263 fprintf(stderr, " %s\n", symName(t->rules[i]));
1264 }
1265 }