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