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