1 /***********************************************************************
2 * eval.c - task scheduling and expression evaluation
3 ***********************************************************************
4 *
5 * Copyright (c) 1995-2002 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 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include <limits.h>
23 #include "dstruct.h"
24 #include "eval.h"
25 #include "fun.h"
26 #include "pragmatics.h"
27 #include "show.h"
28
29 /***********************************************************************
30 * scheduling
31 ***********************************************************************/
32
33 /* enter Task into task queue */
34 static void
35 enque(Task *t)
36 {
37 Task *q;
38 RealTime tt;
39 RealTime qt;
40
41 q = taskq;
42 if (q == NULL) {
43 taskq = t;
44 t->next = NULL;
45 t->prev = NULL;
46 }
47 else {
48 tt = (t->retry && t->retry < t->eval) ? t->retry : t->eval;
49 while (q) {
50 qt = (q->retry && q->retry < q->eval) ? q->retry : q->eval;
51 if (tt <= qt) {
52 t->next = q;
53 t->prev = q->prev;
54 if (q->prev) q->prev->next = t;
55 else taskq = t;
56 q->prev = t;
57 break;
58 }
59 if (q->next == NULL) {
60 q->next = t;
61 t->next = NULL;
62 t->prev = q;
63 break;
64 }
65 q = q->next;
66 }
67 }
68 }
69
70
71 /***********************************************************************
72 * reconnect
73 ***********************************************************************/
74
75 /* any hosts down or unavailable metrics in this task? */
76 static int
77 waiting(Task *t)
78 {
79 Host *h;
80
81 h = t->hosts;
82 while (h) {
83 if (h->down || h->waits)
84 return 1;
85 h = h->next;
86 }
87 return 0;
88 }
89
90 /*
91 * state values
92 * STATE_INIT
93 * STATE_FAILINIT
94 * STATE_RECONN
95 * STATE_LOSTCONN
96 */
97
98 typedef struct hstate {
99 struct hstate *next;
100 char *name;
101 int state;
102 } hstate_t;
103
104 static hstate_t *host_map = NULL;
105
106 int
107 host_state_changed(char *host, int state)
108 {
109 hstate_t *hsp;
110
111 for (hsp = host_map; hsp != NULL; hsp = hsp->next) {
112 if (strcmp(host, hsp->name) == 0)
113 break;
114 }
115
116 if (hsp == NULL) {
117 hsp = (hstate_t *)alloc(sizeof(*hsp));
118 hsp->next = host_map;
119 hsp->name = sdup(host);
120 hsp->state = STATE_INIT;
121 host_map = hsp;
122 }
123
124 if (state == hsp->state) return 0;
125
126 if (state == STATE_FAILINIT)
127 __pmNotifyErr(LOG_INFO, "Cannot connect to pmcd on host %s\n", host);
128 else if (state == STATE_RECONN && hsp->state != STATE_INIT)
129 __pmNotifyErr(LOG_INFO, "Re-established connection to pmcd on host %s\n", host);
130 else if (state == STATE_LOSTCONN)
131 __pmNotifyErr(LOG_INFO, "Lost connection to pmcd on host %s\n", host);
132
133 hsp->state = state;
134 return 1;
135 }
136
137 /* try to reconnect to hosts and initialize missing metrics */
138 static void
139 enable(Task *t)
140 {
141 Host *h;
142 Metric *m;
143 Metric **p;
144
145 h = t->hosts;
146 while (h) {
147
148 /* reconnect to host */
149 if (h->down) {
150 if (reconnect(h)) {
151 h->down = 0;
152 host_state_changed(symName(h->name), STATE_RECONN);
153 }
154 }
155
156 /* reinitialize waiting Metrics */
157 if ((! h->down) && (h->waits)) {
158 p = &h->waits;
159 m = *p;
160 while (m) {
161 switch (reinitMetric(m)) {
162 case 1:
163 *p = m->next;
164 unwaitMetric(m);
165 bundleMetric(h,m);
166 break;
167 case 0:
168 p = &m->next;
169 break;
170 case -1:
171 *p = m->next;
172 m->next = h->duds;
173 h->duds = m;
174 break;
175 }
176 m = *p;
177 }
178 }
179
180 h = h->next;
181 }
182 }
183
184
185 /***********************************************************************
186 * evaluation
187 ***********************************************************************/
188
189 int showTimeFlag = 0; /* set when -e used on the command line */
190
191 /* evaluate Task */
192 static void
193 eval(Task *task)
194 {
195 Symbol *s;
196 pmValueSet *vset;
197 int i;
198
199 /* fetch metrics */
200 taskFetch(task);
201
202 /* evaluate rule expressions */
203 s = task->rules;
204 for (i = 0; i < task->nrules; i++) {
205 curr = symValue(*s);
206 if (curr->op < NOP) {
207 (curr->eval)(curr);
208 perf->eval_actual++;
209 }
210 s++;
211 }
212
213 if (verbose) {
214
215 /* send binary values */
216 if (agent) {
217 int sts;
218 s = task->rules;
219 for (i = 0; i < task->nrules; i++) {
220 vset = task->rslt->vset[i];
221 fillVSet(symValue(*s), vset);
222 s++;
223 }
224 __pmOverrideLastFd(PDU_OVERRIDE2);
225 sts = __pmSendResult(STDOUT_FILENO, pmWhichContext(), task->rslt);
226 if (sts < 0) {
227 fprintf(stderr, "Error: __pmSendResult to summary agent failed: %s\n", pmErrStr(sts));
228 exit(0);
229 }
230
231 }
232
233 /* send values to applet */
234 else if (applet) {
235 s = task->rules;
236 for (i = 0; i < task->nrules; i++) {
237 showValue(stdout, symValue(*s));
238 putchar(' ');
239 s++;
240 }
241 putchar('\n');
242 }
243
244 /* print values in ASCII */
245 else {
246 s = task->rules;
247 for (i = 0; i < task->nrules; i++) {
248 printf("%s", symName(*s));
249 if (archives || showTimeFlag) {
250 printf(" (");
251 showTime(stdout, now);
252 putchar(')');
253 }
254 printf(": ");
255 switch (verbose) {
256 case 1:
257 showValue(stdout, symValue(*s));
258 break;
259 case 2:
260 showAnnotatedValue(stdout, symValue(*s));
261 break;
262 case 3:
263 showSatisfyingValue(stdout, symValue(*s));
264 break;
265 }
266 putchar('\n');
267 s++;
268 }
269 putchar('\n');
270 }
271 }
272 }
273
274
275 /* Mark expression as having invalid values */
276 void
277 clobber(Expr *x)
278 {
279 int i;
280 Truth *t;
281 double *d;
282
283 if (x->op < NOP) {
284 if (x->arg1)
285 clobber(x->arg1);
286 if (x->arg2)
287 clobber(x->arg2);
288 x->valid = 0;
289 /*
290 * numeric variable or variable?
291 */
292 if (x->sem == PM_SEM_COUNTER ||
293 x->sem == PM_SEM_INSTANT || x->sem == PM_SEM_DISCRETE ||
294 x->sem == SEM_NUMVAR) {
295 d = (double *) x->ring;
296 for (i = 0; i < x->nvals; i++)
297 *d++ = mynan;
298 }
299 else if (x->sem == SEM_TRUTH) {
300 t = (Truth *) x->ring;
301 for (i = 0; i < x->nvals; i++)
302 *t++ = DUNNO;
303 }
304 }
305 }
306
307
308 /***********************************************************************
309 * exported functions
310 ***********************************************************************/
311
312 /* fill in appropriate evaluator function for given Expr */
313 void
314 findEval(Expr *x)
315 {
316 int arity = 0;
317 Metric *m;
318
319 /*
320 * arity values constructed from bit masks
321 * 1 arg1 has tspan 1, and must always have one metric value
322 * 2 arg2 has tspan 1, and must always have one metric value
323 */
324 if (x->arg1 && x->arg1->tspan == 1) {
325 for (m = x->arg1->metrics; m; m = m->next) {
326 if (m->desc.indom == PM_INDOM_NULL) continue;
327 if (m->specinst == 0) break;
328 }
329 if (m == NULL) arity |= 1;
330 }
331 if (x->arg2 && x->arg2->tspan == 1) {
332 for (m = x->arg2->metrics; m; m = m->next) {
333 if (m->desc.indom == PM_INDOM_NULL) continue;
334 if (m->specinst == 0) break;
335 }
336 if (m == NULL) arity |= 2;
337 }
338
339 switch (x->op) {
340
341 case NOP:
|
Event unterminated_case: |
This case (value 90) is not terminated by a 'break' statement. |
| Also see events: |
[fallthrough] |
342 case OP_VAR:
343 x->eval = NULL;
344
|
Event fallthrough: |
The above case falls through to this one. |
| Also see events: |
[unterminated_case] |
345 case RULE:
346 x->eval = rule;
347 break;
348
349 case CND_FETCH:
350 if (x->metrics->desc.indom == PM_INDOM_NULL ||
351 x->metrics->conv == 0)
352 x->eval = cndFetch_1;
353 else if (x->metrics->specinst == 0)
354 x->eval = cndFetch_all;
355 else
356 x->eval = cndFetch_n;
357 break;
358
359 case CND_SUM_HOST:
360 x->eval = cndSum_host;
361 break;
362
363 case CND_SUM_INST:
364 x->eval = cndSum_inst;
365 break;
366
367 case CND_SUM_TIME:
368 x->eval = cndSum_time;
369 break;
370
371 case CND_AVG_HOST:
372 x->eval = cndAvg_host;
373 break;
374
375 case CND_AVG_INST:
376 x->eval = cndAvg_inst;
377 break;
378
379 case CND_AVG_TIME:
380 x->eval = cndAvg_time;
381 break;
382
383 case CND_MAX_HOST:
384 x->eval = cndMax_host;
385 break;
386
387 case CND_MAX_INST:
388 x->eval = cndMax_inst;
389 break;
390
391 case CND_MAX_TIME:
392 x->eval = cndMax_time;
393 break;
394
395 case CND_MIN_HOST:
396 x->eval = cndMin_host;
397 break;
398
399 case CND_MIN_INST:
400 x->eval = cndMin_inst;
401 break;
402
403 case CND_MIN_TIME:
404 x->eval = cndMin_time;
405 break;
406
407 case CND_ALL_HOST:
408 x->eval = cndAll_host;
409 break;
410
411 case CND_ALL_INST:
412 x->eval = cndAll_inst;
413 break;
414
415 case CND_ALL_TIME:
416 x->eval = cndAll_time;
417 break;
418
419 case CND_SOME_HOST:
420 x->eval = cndSome_host;
421 break;
422
423 case CND_SOME_INST:
424 x->eval = cndSome_inst;
425 break;
426
427 case CND_SOME_TIME:
428 x->eval = cndSome_time;
429 break;
430
431 case CND_PCNT_HOST:
432 x->eval = cndPcnt_host;
433 break;
434
435 case CND_PCNT_INST:
436 x->eval = cndPcnt_inst;
437 break;
438
439 case CND_PCNT_TIME:
440 x->eval = cndPcnt_time;
441 break;
442
443 case CND_COUNT_HOST:
444 x->eval = cndCount_host;
445 break;
446
447 case CND_COUNT_INST:
448 x->eval = cndCount_inst;
449 break;
450
451 case CND_COUNT_TIME:
452 x->eval = cndCount_time;
453 break;
454
455 case ACT_SEQ:
456 x->eval = actAnd;
457 break;
458
459 case ACT_ALT:
460 x->eval = actOr;
461 break;
462
463 case ACT_SHELL:
464 x->eval = actShell;
465 break;
466
467 case ACT_ALARM:
468 x->eval = actAlarm;
469 break;
470
471 case ACT_STOMP:
472 x->eval = actStomp;
473 break;
474
475 case ACT_SYSLOG:
476 x->eval = actSyslog;
477 break;
478
479 case ACT_PRINT:
480 x->eval = actPrint;
481 break;
482
483 case ACT_ARG:
484 x->eval = actArg;
485 break;
486
487 case CND_DELAY:
488 if (arity & 1)
489 x->eval = cndDelay_1;
490 else
491 x->eval = cndDelay_n;
492 break;
493
494 case CND_RATE:
495 if (arity & 1)
496 x->eval = cndRate_1;
497 else
498 x->eval = cndRate_n;
499 break;
500
501 case CND_NEG:
502 if (arity & 1)
503 x->eval = cndNeg_1;
504 else
505 x->eval = cndNeg_n;
506 break;
507
508 case CND_NOT:
509 if (arity & 1)
510 x->eval = cndNot_1;
511 else
512 x->eval = cndNot_n;
513 break;
514
515 case CND_RISE:
516 if (arity & 1)
517 x->eval = cndRise_1;
518 else
519 x->eval = cndRise_n;
520 break;
521
522 case CND_FALL:
523 if (arity & 1)
524 x->eval = cndFall_1;
525 else
526 x->eval = cndFall_n;
527 break;
528
529 case CND_ADD:
530 if (arity & 1) {
531 if (arity & 2)
532 x->eval = cndAdd_1_1;
533 else
534 x->eval = cndAdd_1_n;
535 }
536 else {
537 if (arity & 2)
538 x->eval = cndAdd_n_1;
539 else
540 x->eval = cndAdd_n_n;
541 }
542 break;
543
544 case CND_SUB:
545 if (arity & 1) {
546 if (arity & 2)
547 x->eval = cndSub_1_1;
548 else
549 x->eval = cndSub_1_n;
550 }
551 else {
552 if (arity & 2)
553 x->eval = cndSub_n_1;
554 else
555 x->eval = cndSub_n_n;
556 }
557 break;
558
559 case CND_MUL:
560 if (arity & 1) {
561 if (arity & 2)
562 x->eval = cndMul_1_1;
563 else
564 x->eval = cndMul_1_n;
565 }
566 else {
567 if (arity & 2)
568 x->eval = cndMul_n_1;
569 else
570 x->eval = cndMul_n_n;
571 }
572 break;
573
574 case CND_DIV:
575 if (arity & 1) {
576 if (arity & 2)
577 x->eval = cndDiv_1_1;
578 else
579 x->eval = cndDiv_1_n;
580 }
581 else {
582 if (arity & 2)
583 x->eval = cndDiv_n_1;
584 else
585 x->eval = cndDiv_n_n;
586 }
587 break;
588
589 case CND_EQ:
590 if (arity & 1) {
591 if (arity & 2)
592 x->eval = cndEq_1_1;
593 else
594 x->eval = cndEq_1_n;
595 }
596 else {
597 if (arity & 2)
598 x->eval = cndEq_n_1;
599 else
600 x->eval = cndEq_n_n;
601 }
602 break;
603
604 case CND_NEQ:
605 if (arity & 1) {
606 if (arity & 2)
607 x->eval = cndNeq_1_1;
608 else
609 x->eval = cndNeq_1_n;
610 }
611 else {
612 if (arity & 2)
613 x->eval = cndNeq_n_1;
614 else
615 x->eval = cndNeq_n_n;
616 }
617 break;
618
619 case CND_LT:
620 if (arity & 1) {
621 if (arity & 2)
622 x->eval = cndLt_1_1;
623 else
624 x->eval = cndLt_1_n;
625 }
626 else {
627 if (arity & 2)
628 x->eval = cndLt_n_1;
629 else
630 x->eval = cndLt_n_n;
631 }
632 break;
633
634 case CND_LTE:
635 if (arity & 1) {
636 if (arity & 2)
637 x->eval = cndLte_1_1;
638 else
639 x->eval = cndLte_1_n;
640 }
641 else {
642 if (arity & 2)
643 x->eval = cndLte_n_1;
644 else
645 x->eval = cndLte_n_n;
646 }
647 break;
648
649 case CND_GT:
650 if (arity & 1) {
651 if (arity & 2)
652 x->eval = cndGt_1_1;
653 else
654 x->eval = cndGt_1_n;
655 }
656 else {
657 if (arity & 2)
658 x->eval = cndGt_n_1;
659 else
660 x->eval = cndGt_n_n;
661 }
662 break;
663
664 case CND_GTE:
665 if (arity & 1) {
666 if (arity & 2)
667 x->eval = cndGte_1_1;
668 else
669 x->eval = cndGte_1_n;
670 }
671 else {
672 if (arity & 2)
673 x->eval = cndGte_n_1;
674 else
675 x->eval = cndGte_n_n;
676 }
677 break;
678
679 case CND_AND:
680 if (arity & 1) {
681 if (arity & 2)
682 x->eval = cndAnd_1_1;
683 else
684 x->eval = cndAnd_1_n;
685 }
686 else {
687 if (arity & 2)
688 x->eval = cndAnd_n_1;
689 else
690 x->eval = cndAnd_n_n;
691 }
692 break;
693
694 case CND_OR:
695 if (arity & 1) {
696 if (arity & 2)
697 x->eval = cndOr_1_1;
698 else
699 x->eval = cndOr_1_n;
700 }
701 else {
702 if (arity & 2)
703 x->eval = cndOr_n_1;
704 else
705 x->eval = cndOr_n_n;
706 }
707 break;
708
709 case CND_MATCH:
710 case CND_NOMATCH:
711 x->eval = cndMatch_inst;
712 break;
713
714 default:
715 __pmNotifyErr(LOG_ERR, "findEval: internal error: bad op (%d)\n", x->op);
716 dumpExpr(x);
717 exit(1);
718 }
719
720 /* patch in fake actions for archive mode */
721 if (archives &&
722 ((x->op >= ACT_SHELL && x->op <= ACT_PRINT) || x->op == ACT_STOMP)) {
723 x->eval = actFake;
724 }
725 }
726
727
728 /* run evaluator */
729 void
730 run(void)
731 {
732 Task *t;
733
734 /* empty task queue */
735 if (taskq == NULL)
736 return;
737
738 /* initialize task scheduling */
739 t = taskq;
740 while (t) {
741 t->eval = t->epoch = start;
742 t->retry = 0;
743 t->tick = 0;
744 t = t->next;
745 }
746
747 /* evaluate and reschedule */
748 t = taskq;
749 for (;;) {
750 if (t->retry && t->retry < t->eval) {
751 now = t->retry;
752 if (now > stop)
753 break;
754 sleepTight(t, SLEEP_RETRY);
755 enable(t);
756 t->retry = waiting(t) ? now + RETRY : 0;
757 }
758 else {
759 now = t->eval;
760 if (now > stop)
761 break;
762 reflectTime(t->delta);
763 sleepTight(t, SLEEP_EVAL);
764 eval(t);
765 t->tick++;
766 t->eval = t->epoch + t->tick * t->delta;
767 if ((! t->retry) && waiting(t))
768 t->retry = now + RETRY;
769 }
770 taskq = t->next;
771 if (taskq) taskq->prev = NULL;
772 enque(t);
773 t = taskq;
774 }
775 __pmNotifyErr(LOG_INFO, "evaluator exiting\n");
776 }
777
778
779 /* invalidate all expressions being evaluated
780 i.e. mark values as unknown */
781 void
782 invalidate(void)
783 {
784 Task *t;
785 Expr *x;
786 Symbol *s;
787 int i;
788
789 t = taskq;
790 while (t) {
791 s = t->rules;
792 for (i = 0; i < t->nrules; i++) {
793 x = symValue(*s);
794 clobber(x);
795 s++;
796 }
797 t = t->next;
798 }
799 }