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