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