2 * Copyright 1993 Jeff Hollingsworth. All rights reserved.
7 static char Copyright[] = "@(#) Copyright (c) 1993 Jeff Hollingsowrth\
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 $";
14 * metric.C - define and create metrics.
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.
20 * Revision 1.17 1994/01/20 17:47:16 hollings
21 * moved getMetricValue to this file.
23 * Revision 1.16 1993/12/15 21:02:42 hollings
26 * Revision 1.15 1993/12/13 19:55:16 hollings
29 * Revision 1.14 1993/10/19 15:27:54 hollings
30 * AST based mini-tramp code generator.
32 * Revision 1.13 1993/10/07 19:42:43 jcargill
33 * Added true combines for global instrumentation
35 * Revision 1.12 1993/10/01 21:29:41 hollings
36 * Added resource discovery and filters.
38 * Revision 1.11 1993/09/03 18:36:16 hollings
39 * removed extra printfs.
41 * Revision 1.10 1993/09/03 16:01:56 hollings
42 * removed extra printf.
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.
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.
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.
55 * Revision 1.6 1993/08/11 01:52:12 hollings
56 * chages for new build before use mode.
58 * Revision 1.5 1993/07/13 18:28:30 hollings
59 * new include file syntax.
61 * Revision 1.4 1993/06/24 16:18:06 hollings
64 * Revision 1.3 1993/06/22 19:00:01 hollings
67 * Revision 1.2 1993/06/08 20:14:34 hollings
68 * state prior to bc net ptrace replacement.
70 * Revision 1.1 1993/03/19 22:45:45 hollings
80 #include "rtinst/h/rtinst.h"
81 #include "rtinst/h/trace.h"
92 extern int metricCount;
93 extern int metResPairsEnabled;
94 extern HTable<metric> metricsUsed;
95 extern HTable<resourceList> fociUsed;
98 HTable<metricInstance> midToMiMap;
100 metricList globalMetricList;
101 extern struct _metricRec DYNINSTallMetrics[];
102 extern process *nodePseudoProcess;
104 // used to indicate the mi is no longer used.
107 metricDefinitionNode::metricDefinitionNode(process *p)
109 memset(this, '\0', sizeof(metricDefinitionNode));
113 sampleData.lastSampleEnd = 0.0;
114 sampleData.lastSampleStart = 0.0;
117 float metricDefinitionNode::getMetricValue()
120 List<metricDefinitionNode*> curr;
124 for (curr = components; *curr; curr++) {
125 total += (*curr)->getMetricValue();
129 return((*data)->getMetricValue());
132 metricDefinitionNode::metricDefinitionNode(metric m,
133 List<metricDefinitionNode*> parts)
136 memset(this, '\0', sizeof(metricDefinitionNode));
141 inform = FALSE; // change this latter.
143 for (; *parts; parts++) {
144 (*parts)->aggregators.add(this);
148 metricInstance buildMetricInstRequest(resourceList l, metric m)
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;
167 if (!processList.count()) return(NULL);
169 /* first find the named metric */
170 for (i=0; i < metricCount; i++) {
171 curr = &DYNINSTallMetrics[i];
177 if (curr != m) return(NULL);
180 // check that the predicates are valid.
182 for (pred = curr->definition.predicates; pred->namePrefix; pred++) {
183 for (i=0; i < l->count; i++) {
186 /* test predicate for this resource */
187 if (!strcmp(pred->namePrefix, r->parent->info.fullName) ||
188 !strcmp(pred->namePrefix, r->info.fullName)) {
192 if (i== l->count) continue;
194 if (!strcmp(pred->namePrefix, r->info.fullName)) {
195 // null refinement skip it .
198 if (pred->type == invalidPredicate) {
204 * Identify if one or all processes should be inst.
208 for (i=0; i < l->count; i++) {
210 /* HACK for process for now */
211 if (!strcmp("/Process", r->parent->info.fullName)) {
212 proc = (process *) r->handle;
214 /* HACK for machine for now */
215 if (!strcmp("/Machine", r->parent->info.fullName)) {
216 tid = (int) r->handle;
221 instProcessList = (process **) xcalloc(sizeof(process *), 2);
222 if (!tid || (proc->thread == tid)) {
223 instProcessList[0] = proc;
225 } else if (nodePseudoProcess) {
226 instProcessList = (process **) xcalloc(sizeof(process *), 3);
227 instProcessList[0] = nodePseudoProcess;
228 instProcessList[1] = nodePseudoProcess->parent;
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;
240 /* check all proceses are in an ok state */
241 if (!isApplicationPaused()) {
245 for (count=0; proc = instProcessList[count]; count++) {
246 mn = new metricDefinitionNode(proc);
252 * iterate through possible predicates.
253 * Predicates must be the outer loop so predicates are
254 * created in the correct order.
258 for (pred = curr->definition.predicates; pred->namePrefix; pred++) {
259 for (i=0; i < l->count; i++) {
262 /* test predicate for this resource */
263 if (!strcmp(pred->namePrefix, r->parent->info.fullName) ||
264 !strcmp(pred->namePrefix, r->info.fullName)) {
268 if (i== l->count) continue;
272 if (!strcmp(pred->namePrefix, r->info.fullName)) {
273 // null refinement skip it .
277 assert(pred->type != invalidPredicate);
278 if (pred->type == nullPredicate) {
280 } else if (pred->type == simplePredicate) {
281 predInstance = pred->creator(mn, r->info.name, predInstance);
284 printf("Error two complex predicates in a single metric\n");
287 complexPredResource = r;
289 printf("Error predicate before complex in list\n");
297 if (covered != l->count) {
298 printf("unable to find a predicate\n");
303 * now the base metric with the built-up trigger.
308 * complex preds replace base definitions.
311 (void) complexPred->creator(mn,
312 complexPredResource->info.name, predInstance);
314 curr->definition.baseFunc(mn, predInstance);
318 // currMi->proc = proc;
323 if (parts.count() > 1) {
324 ret = new metricDefinitionNode(m, parts);
338 List<metricDefinitionNode*> allMIs;
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.
352 metricInstance createMetricInstance(resourceList l, metric m)
355 metricDefinitionNode *mi;
356 List<metricDefinitionNode*> curr;
358 // first see if it already defined.
359 for (curr = allMIs; *curr; curr++) {
360 if ((*curr)->match(l, m)) break;
362 if (*curr) return(*curr);
364 // not found, build it.
365 mi = buildMetricInstRequest(l, m);
367 if (mi) allMIs.add(mi, (void *) mi->id);
371 int startCollecting(resourceList l, metric m)
374 extern void printResourceList(resourceList);
376 mi = createMetricInstance(l, m);
379 // cost = mi->cost();
380 // printf("*** metric cost = %f\n", cost);
382 mi->insertInstrumentation();
385 printf("enable of %s for RL =", getMetricName(m));
386 printResourceList(l);
389 // collect some stats.
390 metResPairsEnabled++;
391 fociUsed.addUnique(l, (void *) l);
392 metricsUsed.addUnique(m, (void *) m);
397 float guessCost(resourceList l , metric m)
402 mi = createMetricInstance(l, m);
403 if (!mi) return(0.0);
409 Boolean metricDefinitionNode::insertInstrumentation()
411 List<instReqNode*> req;
412 List<dataReqNode*> dp;
413 List<metricDefinitionNode*> curr;
415 if (inserted) return(True);
419 for (curr = components; *curr; curr++) {
420 (*curr)->insertInstrumentation();
423 for (dp = data; *dp; dp++) {
424 (*dp)->insertInstrumentation(this);
426 for (req = requests; *req; req++) {
427 (*req)->insertInstrumentation();
433 float metricDefinitionNode::cost()
437 List<instReqNode*> req;
438 List<metricDefinitionNode*> curr;
442 for (curr = components; *curr; curr++) {
443 nc = (*curr)->cost();
444 if (nc > ret) ret = nc;
447 for (req = requests; *req; req++) {
448 ret += (*req)->cost();
454 void metricDefinitionNode::disable()
456 List<dataReqNode*> dp;
457 List<instReqNode*> req;
458 metricDefinitionNode *mi;
459 List<metricDefinitionNode*> curr;
461 if (!inserted) return;
465 /* disable components of aggregate metrics */
466 for (curr = components; mi = *curr; curr++) {
470 for (dp = data; *dp; dp++) {
473 for (req = requests; *req; req++) {
479 metricDefinitionNode::~metricDefinitionNode()
481 List<instReqNode*> req;
482 List<dataReqNode*> dp;
483 metricDefinitionNode *mi;
484 List<metricDefinitionNode*> curr;
487 /* delete components of aggregate metrics */
488 for (curr = components; mi = *curr; curr++) {
492 for (dp = data; *dp; dp++) {
495 for (req = requests; *req; req++) {
501 void metricDefinitionNode::updateValue(time64 wallTime,
504 timeStamp sampleTime;
505 timeStamp endInterval;
506 timeStamp startInterval;
507 List<metricDefinitionNode*> curr;
508 // extern timeStamp elapsedPauseTime;
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);
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;
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;
532 startInterval = sampleData.lastSampleEnd;
533 endInterval = sampleTime;
534 sampleData.lastSample = value;
536 // update start of next sample to end of this one.
537 sampleData.lastSampleStart = sampleData.lastSampleEnd;
539 /* just add it to value to create an interval from the previous sample
542 sampleData.lastSample += value;
544 sampleData.lastSampleEnd = sampleTime;
546 for (curr = aggregators; *curr; curr++) {
547 (*curr)->updateAggregateComponent(this, wallTime, value);
551 * must do this after all updates are done, because it may turn off this
555 /* invoke call backs */
556 tp->sampleDataCallbackFunc(0, id, startInterval,endInterval,value);
560 void metricDefinitionNode::updateAggregateComponent(metricDefinitionNode *curr,
565 sampleValue component;
566 timeStamp earlyestTime;
567 sampleValue aggregateVal;
568 List<metricDefinitionNode*> cp;
570 earlyestTime = (*components)->sampleData.lastSampleEnd;
571 for (cp=components; curr = *cp; cp++) {
572 if (curr->sampleData.lastSampleEnd < earlyestTime) {
573 earlyestTime = curr->sampleData.lastSampleEnd;
576 if (earlyestTime > sampleData.lastSampleEnd + 0.0001) {
578 for (cp=components; curr=*cp; cp++) {
579 // assert(earlyestTime >= curr->sampleData.lastSampleStart);
581 fract = (earlyestTime - sampleData.lastSampleEnd)/
582 (curr->sampleData.lastSampleEnd - curr->sampleData.lastSampleStart);
583 component = (curr->sampleData.lastSample) * fract;
586 assert(fract <= 1.0);
587 assert(component >= -0.01);
589 curr->sampleData.lastSample -= component;
590 aggregateVal += component;
591 /* move forward our time of our earliest sample */
592 curr->sampleData.lastSampleStart = earlyestTime;
595 /* eat the first one to get a good interval basis */
596 if (!sampleData.firstSampleReceived) {
597 sampleData.firstSampleReceived = True;
599 /* inform higher levels of a new sample */
600 tp->sampleDataCallbackFunc(0,
602 sampleData.lastSampleEnd,
607 sampleData.lastSampleStart = sampleData.lastSampleEnd;
608 sampleData.lastSampleEnd = earlyestTime;
612 void processSample(traceHeader *h, traceSample *s)
615 metricDefinitionNode *mi;
616 extern int samplesDelivered;
618 mi = midToMiMap.find((void *) s->id.id);
620 // printf("sample %d not for a valid metric instance\n", s->id.id);
625 // printf("sample id %d at time %f = %f\n", s->id.id, now, s->value);
626 mi->updateValue(h->wall, s->value);
630 metricList getMetricList()
632 if (!globalMetricList) {
633 globalMetricList = (metricList)
634 xcalloc(sizeof(struct _metricListRec), 1);
635 globalMetricList->elements = DYNINSTallMetrics;
636 globalMetricList->count = metricCount;
638 return(globalMetricList);
641 metric findMetric(char *name)
647 metrics = getMetricList();
648 for (i=0, met = metrics->elements; i < metrics->count; i++, met++) {
649 if (!strcmp(met->info.name, name)) {
656 char *getMetricName(metric m)
658 return(m->info.name);
661 metricInfo *getMetricInfo(metric m)
666 metric getMetric(metricInstance mi)
671 void metricNotification(performanceStream perf)
674 struct _metricRec *curr;
676 if (!perf->controlFunc.mFunc) return;
678 for (i=0; i < metricCount; i++) {
679 curr = &DYNINSTallMetrics[i];
680 perf->controlFunc.mFunc(perf, curr);
685 * functions to operate on inst request graph.
688 instReqNode::instReqNode(process *iProc,
701 Boolean instReqNode::insertInstrumentation()
703 instance = addInstFunc(proc, point, ast, when, order);
704 if (instance) return(True);
709 void instReqNode::disable()
711 deleteInst(instance);
715 instReqNode::~instReqNode()
720 float instReqNode::cost()
726 unitCost = ast->cost();
727 frequency = getPointFrequency(point);
728 value = unitCost * frequency;
733 dataReqNode::dataReqNode(dataObjectType iType,
741 initialValue = iInitialValue;
747 float dataReqNode::getMetricValue()
751 if (type == intCounter) {
752 ret = getIntCounterValue((intCounterHandle*) instance);
753 } else if (type == timer) {
754 ret = getTimerValue((timerHandle*) instance);
763 void *dataReqNode::getInferriorPtr()
766 timerHandle *timerInst;
767 intCounterHandle *counterInst;
769 if (type == intCounter) {
770 counterInst = (intCounterHandle *) instance;
772 param = (void *) counterInst->counterPtr;
776 } else if (type == timer) {
777 timerInst = (timerHandle *) instance;
779 param = (void *) timerInst->timerPtr;
789 timerHandle *dataReqNode::createTimerInstance()
793 ret = createTimer(proc, tType, report);
797 intCounterHandle *dataReqNode::createCounterInstance()
799 intCounterHandle *ret;
801 ret = createIntCounter(proc, initialValue, report);
805 void dataReqNode::insertInstrumentation(metricDefinitionNode *mi)
807 if (type == intCounter) {
808 intCounterHandle *ret;
809 ret = createCounterInstance();
810 instance = (void *) ret;
812 midToMiMap.add(mi, (void *) id.id);
815 ret = createTimerInstance();
816 instance = (void *) ret;
818 midToMiMap.add(mi, (void *) id.id);
822 void dataReqNode::disable()
827 if (!instance) return;
829 found = midToMiMap.remove((void *) id.id);
830 assert(found == True);
832 /* make sure it is gone =-- debugging code */
833 mi = midToMiMap.find((void *) id.id);
837 freeTimer((timerHandle *) instance);
838 } else if (type == intCounter) {
839 freeIntCounter((intCounterHandle *) instance);
846 dataReqNode::~dataReqNode()