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  	}