Changed sample time to be consistant.
[dyninst.git] / paradynd / src / metricFocusNode.C
1 /*
2  *  Copyright 1993 Jeff Hollingsworth.  All rights reserved.
3  *
4  */
5
6 #ifndef lint
7 static char Copyright[] = "@(#) Copyright (c) 1993 Jeff Hollingsowrth\
8     All rights reserved.";
9
10 static char rcsid[] = "@(#) $Header: /home/jaw/CVSROOT_20081103/CVSROOT/core/paradynd/src/metricFocusNode.C,v 1.6 1994/03/26 19:31:36 hollings Exp $";
11 #endif
12
13 /*
14  * metric.C - define and create metrics.
15  *
16  * $Log: metricFocusNode.C,v $
17  * Revision 1.6  1994/03/26 19:31:36  hollings
18  * Changed sample time to be consistant.
19  *
20  * Revision 1.5  1994/03/24  16:41:59  hollings
21  * Moved sample aggregation to lib/util (so paradyn could use it).
22  *
23  * Revision 1.4  1994/03/01  21:23:58  hollings
24  * removed unused now variable.
25  *
26  * Revision 1.3  1994/02/24  04:32:34  markc
27  * Changed header files to reflect igen changes.  main.C does not look at the number of command line arguments now.
28  *
29  * Revision 1.2  1994/02/01  18:46:52  hollings
30  * Changes for adding perfConsult thread.
31  *
32  * Revision 1.1  1994/01/27  20:31:28  hollings
33  * Iinital version of paradynd speaking dynRPC igend protocol.
34  *
35  * Revision 1.17  1994/01/20  17:47:16  hollings
36  * moved getMetricValue to this file.
37  *
38  * Revision 1.16  1993/12/15  21:02:42  hollings
39  * added PVM support.
40  *
41  * Revision 1.15  1993/12/13  19:55:16  hollings
42  * counter operations.
43  *
44  * Revision 1.14  1993/10/19  15:27:54  hollings
45  * AST based mini-tramp code generator.
46  *
47  * Revision 1.13  1993/10/07  19:42:43  jcargill
48  * Added true combines for global instrumentation
49  *
50  * Revision 1.12  1993/10/01  21:29:41  hollings
51  * Added resource discovery and filters.
52  *
53  * Revision 1.11  1993/09/03  18:36:16  hollings
54  * removed extra printfs.
55  *
56  * Revision 1.10  1993/09/03  16:01:56  hollings
57  * removed extra printf.
58  *
59  * Revision 1.9  1993/09/03  15:45:51  hollings
60  * eat the first sample from an aggregate to get a good start interval time.
61  *
62  * Revision 1.8  1993/08/20  22:00:51  hollings
63  * added getMetricValue for controller.
64  * moved insertInstrumentation for predicates to before pred users.
65  *
66  * Revision 1.7  1993/08/16  16:24:50  hollings
67  * commented out elapsedPauseTime because of CM-5 problems with node processes.
68  * removed many debugging printfs.
69  *
70  * Revision 1.6  1993/08/11  01:52:12  hollings
71  * chages for new build before use mode.
72  *
73  * Revision 1.5  1993/07/13  18:28:30  hollings
74  * new include file syntax.
75  *
76  * Revision 1.4  1993/06/24  16:18:06  hollings
77  * global fixes.
78  *
79  * Revision 1.3  1993/06/22  19:00:01  hollings
80  * global inst state.
81  *
82  * Revision 1.2  1993/06/08  20:14:34  hollings
83  * state prior to bc net ptrace replacement.
84  *
85  * Revision 1.1  1993/03/19  22:45:45  hollings
86  * Initial revision
87  *
88  *
89  */
90 #include <stdio.h>
91 #include <stdlib.h>
92 #include <assert.h>
93 #include <string.h>
94
95 #include "rtinst/h/rtinst.h"
96 #include "rtinst/h/trace.h"
97 #include "util/h/aggregateSample.h"
98 #include "symtab.h"
99 #include "process.h"
100 #include "inst.h"
101 #include "instP.h"
102 #include "dyninstP.h"
103 #include "metric.h"
104 #include "ast.h"
105 #include "util.h"
106 #include "dyninstRPC.SRVR.h"
107
108 extern dynRPC *tp;
109 extern int metricCount;
110 extern int metResPairsEnabled;
111 extern HTable<metric> metricsUsed;
112 extern HTable<resourceList> fociUsed;
113
114
115 HTable<metricInstance> midToMiMap;
116
117 metricList globalMetricList;
118 extern struct _metricRec DYNINSTallMetrics[];
119 extern process *nodePseudoProcess;
120
121 // used to indicate the mi is no longer used.
122 #define DELETED_MI 1
123
124 metricDefinitionNode::metricDefinitionNode(process *p)
125 {
126     memset(this, '\0', sizeof(metricDefinitionNode));
127
128     proc = p;
129     aggregate = FALSE;
130     sample.lastSampleEnd = 0.0;
131     sample.lastSampleStart = 0.0;
132 }
133
134 float metricDefinitionNode::getMetricValue()
135 {
136     float total;
137     List<metricDefinitionNode*> curr;
138
139     if (aggregate) {
140         total = 0.0;
141         for (curr = components; *curr; curr++) {
142             total += (*curr)->getMetricValue();
143         }
144         return(0.0);
145     }
146     return((*data)->getMetricValue());
147 }
148
149 metricDefinitionNode::metricDefinitionNode(metric m, 
150                                             List<metricDefinitionNode*> parts)
151 {
152
153     memset(this, '\0', sizeof(metricDefinitionNode));
154
155     met = m;
156     aggregate = TRUE;
157     components = parts;
158     inform = FALSE;             // change this latter.
159
160     for (; *parts; parts++) {
161         (*parts)->aggregators.add(this);
162         valueList.add(&(*parts)->sample);
163     }
164 }
165
166 metricInstance buildMetricInstRequest(resourceList l, metric m)
167 {
168     int i;
169     int tid;
170     int count;
171     resource r;
172     int covered;
173     List<process*> pl;
174     metricInstance ret;
175     process *proc = NULL;
176     resourcePredicate *pred;
177     struct _metricRec *curr;
178     process **instProcessList;
179     resource complexPredResource;
180     resourcePredicate *complexPred;
181     List<metricDefinitionNode*> parts;
182     metricDefinitionNode *mn;
183     AstNode *predInstance = NULL;
184
185     if (!processList.count()) return(NULL);
186
187     /* first find the named metric */
188     for (i=0; i < metricCount; i++) {
189         curr = &DYNINSTallMetrics[i];
190         if (curr == m) {
191             break;
192         }
193     }
194
195     if (curr != m) return(NULL);
196
197     // 
198     // check that the predicates are valid.
199     //
200     for (pred = curr->definition.predicates; pred->namePrefix; pred++) {
201         for (i=0; i < l->count; i++) {
202             r = l->elements[i];
203
204             /* test predicate for this resource */
205             if (!strcmp(pred->namePrefix, r->parent->info.fullName) ||
206                 !strcmp(pred->namePrefix, r->info.fullName)) {
207                 break;
208             }
209         }
210         if (i== l->count) continue;
211
212         if (!strcmp(pred->namePrefix, r->info.fullName)) {
213             // null refinement skip it .
214             continue;
215         }
216         if (pred->type == invalidPredicate) {
217             return(NULL);
218         }
219     }
220
221     /*
222      * Identify if one or all processes should be inst.
223      *
224      */
225     tid = 0;
226     for (i=0; i < l->count; i++) {
227         r = l->elements[i];
228         /* HACK for process for now */
229         if (!strcmp("/Process", r->parent->info.fullName)) {
230             proc = (process *) r->handle;
231         }
232         /* HACK for machine for now */
233         if (!strcmp("/Machine", r->parent->info.fullName)) {
234             tid = (int) r->handle;
235         }
236     }
237
238     if (proc) {
239         instProcessList = (process **) xcalloc(sizeof(process *), 2);
240         if (!tid || (proc->thread == tid)) {
241             instProcessList[0] = proc;
242         }
243     } else if (nodePseudoProcess) {
244         instProcessList = (process **) xcalloc(sizeof(process *), 3);
245         instProcessList[0] = nodePseudoProcess;
246         instProcessList[1] = nodePseudoProcess->parent;
247     } else {
248         count = processList.count();
249         instProcessList = (process **) xcalloc(sizeof(process *), count+1);
250         for (pl = processList,count = 0; proc = *pl; pl++) {
251             /* HACK for machine for now */
252             if (!tid || (proc->thread == tid)) {
253                 instProcessList[count++] = proc;
254             }
255         }
256     }
257
258     /* check all proceses are in an ok state */
259     if (!isApplicationPaused()) {
260         return(NULL);
261     }
262
263     for (count=0; proc = instProcessList[count]; count++) {
264         mn = new metricDefinitionNode(proc);
265
266         complexPred = NULL;
267         predInstance = NULL;
268
269         /*
270          * iterate through possible predicates.
271          *   Predicates must be the outer loop so predicates are
272          *     created in the correct order.
273          *
274          */
275         covered = 0;
276         for (pred = curr->definition.predicates; pred->namePrefix; pred++) {
277             for (i=0; i < l->count; i++) {
278                 r = l->elements[i];
279
280                 /* test predicate for this resource */
281                 if (!strcmp(pred->namePrefix, r->parent->info.fullName) ||
282                     !strcmp(pred->namePrefix, r->info.fullName)) {
283                     break;
284                 }
285             }
286             if (i== l->count) continue;
287
288             covered++;
289
290             if (!strcmp(pred->namePrefix, r->info.fullName)) {
291                 // null refinement skip it .
292                 continue;
293             }
294
295             assert(pred->type != invalidPredicate);
296             if (pred->type == nullPredicate) {
297                 continue;
298             } else if (pred->type == simplePredicate) {
299                 predInstance = pred->creator(mn, r->info.name, predInstance);
300             } else {
301                 if (complexPred) {
302                     printf("Error two complex predicates in a single metric\n");
303                     abort();
304                 } else {
305                     complexPredResource = r;
306                     if (predInstance) {
307                         printf("Error predicate before complex in list\n");
308                         abort();
309                     }
310                     complexPred = pred;
311                     predInstance = NULL;
312                 }
313             }
314         }
315         if (covered != l->count) {
316             printf("unable to find a predicate\n");
317             abort();
318         }
319
320         /*
321          * now the base metric with the built-up trigger.
322          *
323          */
324         if (complexPred) {
325             /* 
326              * complex preds replace base definitions.
327              *
328              */
329             (void) complexPred->creator(mn, 
330                 complexPredResource->info.name, predInstance);
331         } else {
332             curr->definition.baseFunc(mn, predInstance);
333         }
334         if (mn) {
335             mn->met = m;
336             // currMi->proc = proc;
337             parts.add(mn, mn);
338         }
339     }
340
341     if (parts.count() > 1) {
342         ret = new metricDefinitionNode(m, parts);
343     } else {
344         ret = *parts;
345     }
346
347     if (ret) {
348         ret->inform = TRUE;
349         ret->resList = l;
350     }
351
352     return(ret);
353 }
354
355
356 List<metricDefinitionNode*> allMIs;
357
358 /*
359  * See if we can find the requested metric instance.
360  *   Currently this is only used to cache structs built for cost requests 
361  *   which are then instantuadted.  This could be used as a general system
362  *   to request find sub-metrics that are already defined and use them to
363  *   reduce cost.  This would require adding the componenets of an aggregate
364  *   into the allMIs list since searching tends to be top down, not bottom
365  *   up.  This would also require adding a ref count to many of the structures
366  *   so they only get deleted when we are really done with them.
367  *
368  */
369
370 metricInstance createMetricInstance(resourceList l, metric m)
371 {
372     static int MICount;
373     metricDefinitionNode *mi;
374     List<metricDefinitionNode*> curr;
375
376     // first see if it already defined.
377     for (curr = allMIs; *curr; curr++) {
378         if ((*curr)->match(l, m)) break;
379     }
380     if (*curr) return(*curr);
381
382     // not found, build it.
383     mi = buildMetricInstRequest(l, m);
384     mi->id = ++MICount;
385     if (mi) allMIs.add(mi, (void *) mi->id);
386     return(mi);
387 }
388
389 int startCollecting(resourceList l, metric m)
390 {
391     metricInstance mi;
392     extern void printResourceList(resourceList);
393
394     mi = createMetricInstance(l, m);
395     if (!mi) return(-1);
396
397     // cost = mi->cost();
398     // printf("*** metric cost = %f\n", cost);
399
400     mi->insertInstrumentation();
401     flushPtrace();
402
403     printf("enable of %s for RL =", getMetricName(m));
404     printResourceList(l);
405     printf("\n");
406
407     // collect some stats.
408     metResPairsEnabled++;
409     fociUsed.addUnique(l, (void *) l);
410     metricsUsed.addUnique(m, (void *) m);
411
412     return(mi->id);
413 }
414
415 float guessCost(resourceList l , metric m)
416 {
417     float cost;
418     metricInstance mi;
419
420     mi = createMetricInstance(l, m);
421     if (!mi) return(0.0);
422
423     cost = mi->cost();
424     return(cost);
425 }
426
427 Boolean metricDefinitionNode::insertInstrumentation()
428 {
429     List<instReqNode*> req;
430     List<dataReqNode*> dp;
431     List<metricDefinitionNode*> curr;
432
433     if (inserted) return(True);
434
435     inserted = True;
436     if (aggregate) {
437         for (curr = components; *curr; curr++) {
438              (*curr)->insertInstrumentation();
439         }
440     } else {
441         for (dp = data; *dp; dp++) {
442             (*dp)->insertInstrumentation(this);
443         }
444         for (req = requests; *req; req++) {
445             (*req)->insertInstrumentation();
446         }
447     }
448     return(True);
449 }
450
451 float metricDefinitionNode::cost()
452 {
453     float ret;
454     float nc;
455     List<instReqNode*> req;
456     List<metricDefinitionNode*> curr;
457
458     ret = 0.0;
459     if (aggregate) {
460         for (curr = components; *curr; curr++) {
461              nc = (*curr)->cost();
462              if (nc > ret) ret = nc;
463         }
464     } else {
465         for (req = requests; *req; req++) {
466             ret += (*req)->cost();
467         }
468     }
469     return(ret);
470 }
471
472 void metricDefinitionNode::disable()
473 {
474     List<dataReqNode*> dp;
475     List<instReqNode*> req;
476     metricDefinitionNode *mi;
477     List<metricDefinitionNode*> curr;
478
479     if (!inserted) return;
480
481     inserted = False;
482     if (aggregate) {
483         /* disable components of aggregate metrics */
484         for (curr = components; mi = *curr; curr++) {
485             mi->disable();
486         }
487     } else {
488         for (dp = data; *dp; dp++) {
489             (*dp)->disable();
490         }
491         for (req = requests; *req; req++) {
492             (*req)->disable();
493         }
494     }
495 }
496
497 metricDefinitionNode::~metricDefinitionNode()
498 {
499     List<instReqNode*> req;
500     List<dataReqNode*> dp;
501     metricDefinitionNode *mi;
502     List<metricDefinitionNode*> curr;
503
504     if (aggregate) {
505         /* delete components of aggregate metrics */
506         for (curr = components; mi = *curr; curr++) {
507             delete(mi);
508         }
509     } else {
510         for (dp = data; *dp; dp++) {
511             delete(*dp);
512         }
513         for (req = requests; *req; req++) {
514             delete(*req);
515         }
516     }
517 }
518
519 void metricDefinitionNode::updateValue(time64 wallTime, 
520                                        sampleValue value)
521 {
522     timeStamp sampleTime;
523     struct sampleInterval ret;
524     List<metricDefinitionNode*> curr;
525     // extern timeStamp elapsedPauseTime;
526
527     // sampleTime = (wallTime - elapsedPauseTime) / 1000000.0; 
528     // commented out elapsedPauseTime because we don't currently stop CM-5
529     // node processes. (brought it back jkh 11/9/93).
530     sampleTime = wallTime / 1000000.0; 
531     assert(value >= -0.01);
532
533     if (met->info.style == EventCounter) {
534         // only use delta from last sample.
535         assert(value + 0.0001 >= sample.value);
536         value -= sample.value;
537         sample.value += value;
538     }
539
540     ret = sample.newValue(valueList, sampleTime, value);
541
542     for (curr = aggregators; *curr; curr++) {
543         (*curr)->updateAggregateComponent(this, sampleTime, value);
544     }
545
546     /* 
547      * must do this after all updates are done, because it may turn off this
548      *  metric instance.
549      */
550     if (inform && ret.valid) {
551         /* invoke call backs */
552         tp->sampleDataCallbackFunc(0, id, ret.start, ret.end, ret.value);
553     }
554 }
555
556 void metricDefinitionNode::updateAggregateComponent(metricDefinitionNode *curr,
557                                                     timeStamp sampleTime, 
558                                                     sampleValue value)
559 {
560     struct sampleInterval ret;
561
562     ret = sample.newValue(valueList, sampleTime, value);
563     if (ret.valid) {
564         tp->sampleDataCallbackFunc(0, id, ret.start, ret.end, ret.value);
565     }
566 }
567
568 void processSample(traceHeader *h, traceSample *s)
569 {
570     metricDefinitionNode *mi;
571     extern int samplesDelivered;
572
573     mi = midToMiMap.find((void *) s->id.id);
574     if (!mi) {
575         // printf("sample %d not for a valid metric instance\n", s->id.id);
576         return;
577     }
578      
579     // printf("sample id %d at time %f = %f\n", s->id.id, now, s->value);
580     mi->updateValue(h->wall, s->value);
581     samplesDelivered++;
582 }
583
584 metricList getMetricList()
585 {
586     if (!globalMetricList) {
587          globalMetricList = (metricList) 
588              xcalloc(sizeof(struct _metricListRec), 1);
589          globalMetricList->elements = DYNINSTallMetrics;
590          globalMetricList->count = metricCount;
591     }
592     return(globalMetricList);
593 }
594
595 metric findMetric(char *name)
596 {
597     int i;
598     metric met;
599     metricList metrics;
600
601     metrics = getMetricList();
602     for (i=0, met = metrics->elements; i < metrics->count; i++, met++) {
603         if (!strcmp(met->info.name, name)) {
604             return(met);
605         }
606     }
607     return(NULL);
608 }
609
610 char *getMetricName(metric m)
611 {
612     return(m->info.name);
613 }
614
615 metricInfo *getMetricInfo(metric m)
616 {
617     return(&m->info);
618 }
619
620 metric getMetric(metricInstance mi)
621 {
622     return(mi->met);
623 }
624
625 /*
626  * functions to operate on inst request graph.
627  *
628  */
629 instReqNode::instReqNode(process *iProc,
630                          instPoint *iPoint,
631                          AstNode *iAst,
632                          callWhen  iWhen,
633                          callOrder o) 
634 {
635     proc = iProc;
636     point = iPoint;
637     ast = iAst;
638     when = iWhen;
639     order = o;
640 }
641
642 Boolean instReqNode::insertInstrumentation()
643 {
644     instance = addInstFunc(proc, point, ast, when, order);
645     if (instance) return(True);
646
647     return(False);
648 }
649
650 void instReqNode::disable()
651 {
652     deleteInst(instance);
653     instance = NULL;
654 }
655
656 instReqNode::~instReqNode()
657 {
658     instance = NULL;
659 }
660
661 float instReqNode::cost()
662 {
663     float value;
664     float unitCost;
665     float frequency;
666
667     unitCost = ast->cost();
668     frequency = getPointFrequency(point);
669     value = unitCost * frequency;
670
671     return(value);
672 }
673
674 dataReqNode::dataReqNode(dataObjectType iType,
675                       process *iProc,
676                       int iInitialValue,
677                       Boolean iReport,
678                       timerType iTType) 
679 {
680     type = iType;
681     proc = iProc;
682     initialValue = iInitialValue;
683     report = iReport;
684     tType = iTType;
685     instance = NULL;
686 };
687
688 float dataReqNode::getMetricValue()
689 {
690     float ret;
691
692     if (type == intCounter) {
693         ret = getIntCounterValue((intCounterHandle*) instance);
694     } else if (type == timer) {
695         ret = getTimerValue((timerHandle*) instance);
696     } else {
697         // unknown type.
698         abort();
699         return(0.0);
700     }
701     return(ret);
702 }
703
704 void *dataReqNode::getInferriorPtr() 
705 {
706     void *param;
707     timerHandle *timerInst;
708     intCounterHandle *counterInst;
709
710     if (type == intCounter) {
711         counterInst = (intCounterHandle *) instance;
712         if (counterInst) {
713             param = (void *) counterInst->counterPtr;
714         } else {
715             param = NULL;
716         }
717     } else if (type == timer) {
718         timerInst = (timerHandle *) instance;
719         if (timerInst) {
720             param = (void *) timerInst->timerPtr;
721         } else {
722             param = NULL;
723         }
724     } else {
725         abort();
726     }
727     return(param);
728 }
729
730 timerHandle *dataReqNode::createTimerInstance()
731 {
732     timerHandle *ret;
733
734     ret = createTimer(proc, tType, report);
735     return(ret);
736 }
737
738 intCounterHandle *dataReqNode::createCounterInstance()
739 {
740     intCounterHandle *ret;
741
742     ret = createIntCounter(proc, initialValue, report);
743     return(ret);
744 }
745
746 void dataReqNode::insertInstrumentation(metricDefinitionNode *mi) 
747 {
748     if (type == intCounter) {
749         intCounterHandle *ret;
750         ret = createCounterInstance();
751         instance = (void *) ret;
752         id = ret->data.id;
753         midToMiMap.add(mi, (void *) id.id);
754     } else {
755         timerHandle *ret;
756         ret = createTimerInstance();
757         instance = (void *) ret;
758         id = ret->data.id;
759         midToMiMap.add(mi, (void *) id.id);
760     }
761 }
762
763 void dataReqNode::disable()
764 {
765     Boolean found;
766     metricInstance mi;
767
768     if (!instance) return;
769
770     found = midToMiMap.remove((void *) id.id);
771     assert(found == True);
772
773     /* make sure it is gone =-- debugging code */
774     mi = midToMiMap.find((void *) id.id);
775     assert(mi == NULL);
776
777     if (type == timer) {
778         freeTimer((timerHandle *) instance);
779     } else if (type == intCounter) {
780         freeIntCounter((intCounterHandle *) instance);
781     } else {
782         abort();
783     }
784     instance = NULL;
785 }
786
787 dataReqNode::~dataReqNode()
788 {
789     instance = NULL;
790 }
791