2 * Copyright (c) 1996 Barton P. Miller
4 * We provide the Paradyn Parallel Performance Tools (below
5 * described as Paradyn") on an AS IS basis, and do not warrant its
6 * validity or performance. We reserve the right to update, modify,
7 * or discontinue this software at any time. We shall have no
8 * obligation to supply such updates or modifications or any other
9 * form of support to you.
11 * This license is for research uses. For such uses, there is no
12 * charge. We define "research use" to mean you may freely use it
13 * inside your organization for whatever purposes you see fit. But you
14 * may not re-distribute Paradyn or parts of Paradyn, in any form
15 * source or binary (including derivatives), electronic or otherwise,
16 * to any other organization or entity without our permission.
18 * (for other uses, please contact us at paradyn@cs.wisc.edu)
20 * All warranties, including without limitation, any warranty of
21 * merchantability or fitness for a particular purpose, are hereby
24 * By your use of Paradyn, you understand and agree that we (or any
25 * other person or entity with proprietary rights in Paradyn) are
26 * under no obligation to provide either maintenance services,
27 * update services, notices of latent defects, or correction of
28 * defects for Paradyn.
30 * Even if advised of the possibility of such damages, under no
31 * circumstances shall we (or any other person or entity with
32 * proprietary rights in the software licensed hereunder) be liable
33 * to you or any third party for direct, indirect, or consequential
34 * damages of any character regardless of type of action, including,
35 * without limitation, loss of profits, loss of use, loss of good
36 * will, or computer failure or malfunction. You agree to indemnify
37 * us (and any other person or entity with proprietary rights in the
38 * software licensed hereunder) for any and all liability it may
39 * incur to third parties resulting from your use of Paradyn.
45 * $Log: metricFocusNode.h,v $
46 * Revision 1.50 1997/06/05 18:04:20 naim
47 * Cleaning up dataReqNodes for certain cases of deletion of metricDefinitionNodes
50 * Revision 1.49 1997/05/08 00:12:16 mjrg
51 * changes for Visual C++ compiler: added return to functions
53 * Revision 1.48 1997/05/07 19:01:27 naim
54 * Getting rid of old support for threads and turning it off until the new
55 * version is finished. Additionally, new superTable, baseTable and superVector
56 * classes for future support of multiple threads. The fastInferiorHeap class has
59 * Revision 1.47 1997/04/21 16:56:15 hseom
60 * added support for trace data
62 * Revision 1.46 1997/03/18 19:45:57 buck
63 * first commit of dyninst library. Also includes:
64 * moving templates from paradynd to dyninstAPI
65 * converting showError into a function (in showerror.C)
66 * many ifdefs for BPATCH_LIBRARY in dyinstAPI/src.
68 * Revision 1.45 1997/02/26 23:46:43 mjrg
69 * First part of WindowsNT port: changes for compiling with Visual C++;
70 * moved unix specific code to unix.C file
72 * Revision 1.44 1997/02/24 14:22:58 naim
73 * Minor fix to my previous commit - naim
75 * Revision 1.43 1997/02/21 20:15:59 naim
76 * Moving files from paradynd to dyninstAPI + eliminating references to
77 * dataReqNode from the ast class. This is the first pre-dyninstAPI commit! - naim
79 * Revision 1.42 1997/01/27 19:41:07 naim
80 * Part of the base instrumentation for supporting multithreaded applications
81 * (vectors of counter/timers) implemented for all current platforms +
82 * different bug fixes - naim
84 * Revision 1.41 1997/01/15 01:11:34 tamches
85 * completely revamped fork & exec -- they now work for shm sampling.
87 * Revision 1.40 1996/11/14 14:28:01 naim
88 * Changing AstNodes back to pointers to improve performance - naim
90 * Revision 1.39 1996/10/31 09:25:59 tamches
91 * the shm-sampling commit; completely redesigned dataReqNode; designed
92 * a handful of derived classes of dataReqNode, which replaces a lot of
95 * Revision 1.38 1996/10/03 22:12:03 mjrg
96 * Removed multiple stop/continues when inserting instrumentation
97 * Fixed bug on process termination
98 * Removed machine dependent code from metric.C and process.C
100 * Revision 1.37 1996/08/20 19:03:17 lzheng
101 * Implementation of moving multiple instructions sequence and
102 * Splitting the instrumentation into two phases
109 #include "util/h/String.h"
110 // trace data streams
111 #include "util/h/ByteArray.h"
112 #include "util/h/Vector.h"
113 #include "util/h/Dictionary.h"
114 #include "util/h/aggregateSample.h"
115 #include "dyninstAPI/src/ast.h"
116 #include "dyninstAPI/src/util.h"
117 #include "rtinst/h/trace.h"
119 #if defined(SHM_SAMPLING)
120 #include "paradynd/src/superTable.h"
125 // Since we don't define these, make sure they're not used:
126 dataReqNode &operator=(const dataReqNode &src);
127 dataReqNode (const dataReqNode &src);
133 virtual ~dataReqNode() {};
135 virtual unsigned getInferiorPtr(process *proc=NULL) const = 0;
136 virtual unsigned getAllocatedIndex() const = 0;
137 virtual unsigned getAllocatedLevel() const = 0;
139 virtual int getSampleId() const = 0;
141 virtual bool insertInstrumentation(process *, metricDefinitionNode *, bool) = 0;
142 // Allocates stuff from inferior heap, instrumenting DYNINSTreportCounter
144 // Returns true iff successful.
146 virtual void disable(process *,
147 const vector< vector<unsigned> > &pointsToCheck) = 0;
148 // the opposite of insertInstrumentation. Deinstruments, deallocates
149 // from inferior heap, etc.
151 virtual dataReqNode *dup(process *childProc, metricDefinitionNode *,
153 const dictionary_hash<instInstance*,instInstance*> &map
155 // duplicate 'this' (allocate w/ new) and return. Call after a fork().
157 // "map" provides a dictionary that maps instInstance's of the parent process to
158 // those in the child process; dup() may find it useful. (for now, the shm
159 // dataReqNodes have no need for it; the alarm sampled ones need it).
161 virtual bool unFork(dictionary_hash<instInstance*,instInstance*> &map) = 0;
162 // the fork syscall duplicates all instrumentation (except on AIX), which is a
163 // problem when we determine that a certain mi shouldn't be propagated to the child
164 // process. Hence this routine.
168 * Classes derived from dataReqNode
170 * There are a lot of classes derived from dataReqNode, so things can get a little
171 * confusing. Most of them are used in either shm_sampling mode or not; few are
172 * used in both. Here's a bit of documentation that should sort things out:
174 * A) classes used in _both_ shm_sampling and non-shm-sampling
176 * nonSampledIntCounterReqNode --
177 * provides an intCounter value that is never sampled. Currently useful
178 * for predicates (constraint booleans). The intCounter is allocated from
179 * the "conventional" heap (where tramps are allocated) using good old
180 * inferiorMalloc(), even when shm_sampling.
181 * (In the future, we may provide a separate shm_sampling version, to make
182 * allocation faster [allocation in the shm seg heap is always faster])
184 * B) classes used only when shm_sampling
186 * shmSampledIntCounterReqNode --
187 * provides an intCounter value that is sampled with shm sampling. The
188 * intCounter is allocated from the shm segment (i.e., not with inferiorMalloc).
190 * shmSampledWallTimerReqNode --
191 * provides a wall timer value that is sampled with shm sampling. The tTimer is
192 * allocated from the shm segment (i.e., not with inferiorMalloc)
194 * shmSampledProcTimerReqNode --
195 * provides a process timer value that is sampled with shm sampling. The tTimer
196 * is allocated from the shm segment (i.e., not with inferiorMalloc)
198 * C) classes used only when _not_ shm-sampling
200 * alarmSampledIntCounterReqNode --
201 * provides an intCounter value that is sampled. The intCounter is allocated
202 * in the conventional heap with inferiorMalloc(). Sampling is done the
203 * old-fasioned SIGALRM way: by instrumenting DYNINSTsampleValues to call
206 * alarmSampledTimerReqNode --
207 * provides a tTimer value (can be wall or process timer) that is sampled. The
208 * tTimer is allocated in the conventional heap with inferiorMalloc(). Sampling
209 * is done the old-fasioned SIGALRM way: by instrumenting DYNINSTsampleValues to
210 * call DYNINSTreportTimer.
215 class sampledIntCounterReqNode : public dataReqNode {
216 // intCounter for use when not shm sampling. Allocated in the conventional heap
217 // with inferiorMalloc(). Sampled the old-fasioned way: by instrumenting
218 // DYNINSTsampleValues() to call DYNINSTreportCounter.
220 // The following fields are always properly initialized in ctor:
222 int initialValue; // needed when dup()'ing
224 // The following fields are NULL until insertInstrumentation() called:
225 intCounter *counterPtr; /* NOT in our address space !!!! */
226 instInstance *sampler; /* function to sample value */
228 // Since we don't use these, disallow:
229 sampledIntCounterReqNode &operator=(const sampledIntCounterReqNode &);
230 sampledIntCounterReqNode(const sampledIntCounterReqNode &);
232 // private fork-ctor called by dup():
233 sampledIntCounterReqNode(const sampledIntCounterReqNode &src,
234 process *childProc, metricDefinitionNode *, int iCounterId,
235 const dictionary_hash<instInstance*,instInstance*> &map);
237 void writeToInferiorHeap(process *theProc, const intCounter &src) const;
240 sampledIntCounterReqNode(int iValue, int iCounterId,
241 metricDefinitionNode *iMi, bool computingCost);
242 ~sampledIntCounterReqNode() {}
243 // Hopefully, disable() has already been called. A bit of a complication
244 // since disable() needs an arg passed, which we can't do here. Too bad.
246 dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
247 const dictionary_hash<instInstance*,instInstance*> &map) const;
249 bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
250 // allocates from inferior heap; initializes it; instruments
251 // DYNINSTsampleValues
253 void disable(process *, const vector< vector<unsigned> > &);
255 unsigned getInferiorPtr(process *) const {
256 // counterPtr could be NULL if we are building AstNodes just to compute
257 // the cost - naim 2/18/97
258 //assert(counterPtr != NULL); // NULL until insertInstrumentation()
259 return (unsigned)counterPtr;
262 unsigned getAllocatedIndex() const {assert(0); return 0;}
263 unsigned getAllocatedLevel() const {assert(0); return 0;}
265 int getSampleId() const {return theSampleId;}
267 bool unFork(dictionary_hash<instInstance*,instInstance*> &map);
268 // the fork syscall duplicates all instrumentation (except on AIX), which is a
269 // problem when we determine that a certain mi shouldn't be propagated to the child
270 // process. Hence this routine (to remove unwanted instr of DYNINSTsampleValues())
275 class sampledShmIntCounterReqNode : public dataReqNode {
276 // intCounter for use when shm-sampling. Allocated in the shm segment heap.
277 // Sampled using shm sampling.
279 // The following fields are always properly initialized in ctor:
280 int theSampleId; // obsolete with shm sampling; can be removed.
282 int initialValue; // needed when dup()'ing
284 // The following fields are NULL until insertInstrumentation() called:
285 unsigned allocatedIndex;
286 unsigned allocatedLevel;
290 // Since we don't use these, making them privates ensures they're not used.
291 sampledShmIntCounterReqNode &operator=(const sampledShmIntCounterReqNode &);
292 sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &);
294 // private fork-ctor called by dup():
295 sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &src,
296 process *childProc, metricDefinitionNode *,
297 int iCounterId, const process *parentProc);
300 sampledShmIntCounterReqNode(int iValue, int iCounterId,
301 metricDefinitionNode *iMi, bool computingCost,
303 ~sampledShmIntCounterReqNode() {}
304 // Hopefully, disable() has already been called.
305 // A bit of a complication since disable() needs an
306 // arg passed, which we can't do here. Too bad.
308 dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
309 const dictionary_hash<instInstance*,instInstance*> &) const;
311 bool insertInstrumentation(process *, metricDefinitionNode *, bool);
312 // allocates from inferior heap; initializes it, etc.
314 void disable(process *, const vector< vector<unsigned> > &);
316 unsigned getInferiorPtr(process *) const;
318 unsigned getAllocatedIndex() const {return allocatedIndex;}
319 unsigned getAllocatedLevel() const {return allocatedLevel;}
321 unsigned getPosition() const {return position_;}
322 int getSampleId() const {return theSampleId;}
324 bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
328 class nonSampledIntCounterReqNode : public dataReqNode {
329 // intCounter for predicates (because they don't need to be sampled).
330 // Allocated in the conventional heap with inferiorMalloc().
332 // The following fields are always properly initialized in ctor:
334 int initialValue; // needed when dup()'ing
336 // The following is NULL until insertInstrumentation() called:
337 intCounter *counterPtr; /* NOT in our address space !!!! */
339 // Since we don't use these, disallow:
340 nonSampledIntCounterReqNode &operator=(const nonSampledIntCounterReqNode &);
341 nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &);
343 // private fork-ctor called by dup():
344 nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &src,
345 process *childProc, metricDefinitionNode *,
348 void writeToInferiorHeap(process *theProc, const intCounter &src) const;
351 nonSampledIntCounterReqNode(int iValue, int iCounterId,
352 metricDefinitionNode *iMi, bool computingCost);
353 ~nonSampledIntCounterReqNode() {}
354 // Hopefully, disable() has already been called.
355 // A bit of a complication since disable() needs an
356 // arg passed, which we can't do here. Too bad.
358 dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
359 const dictionary_hash<instInstance*,instInstance*> &) const;
361 bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
362 // allocates from inferior heap; initializes it
364 void disable(process *, const vector< vector<unsigned> > &);
366 unsigned getInferiorPtr(process *) const {
367 //assert(counterPtr != NULL); // NULL until insertInstrumentation()
368 // counterPtr could be NULL if we are building AstNodes just to compute
369 // the cost - naim 2/18/97
370 return (unsigned)counterPtr;
373 unsigned getAllocatedIndex() const {assert(0); return 0;}
374 unsigned getAllocatedLevel() const {assert(0); return 0;}
376 int getSampleId() const {return theSampleId;}
378 bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
382 class sampledTimerReqNode : public dataReqNode {
383 // tTimer for use when not shm sampling. Allocated in the conventional heap with
384 // inferiorMalloc(). Sampled the old-fasioned way: by instrumenting
385 // DYNINSTsampleValues to call DYNINSTreportTimer.
387 // The following fields are always initialized in the ctor:
389 timerType theTimerType;
391 // The following fields are NULL until insertInstrumentation():
392 tTimer *timerPtr; /* NOT in our address space !!!! */
393 instInstance *sampler; /* function to sample value */
395 // since we don't use these, disallow:
396 sampledTimerReqNode(const sampledTimerReqNode &);
397 sampledTimerReqNode &operator=(const sampledTimerReqNode &);
400 sampledTimerReqNode(const sampledTimerReqNode &src, process *childProc,
401 metricDefinitionNode *, int iCounterId,
402 const dictionary_hash<instInstance*,instInstance*> &map);
404 void writeToInferiorHeap(process *theProc, const tTimer &dataSrc) const;
407 sampledTimerReqNode(timerType iType, int iCounterId,
408 metricDefinitionNode *iMi, bool computingCost);
409 ~sampledTimerReqNode() {}
410 // hopefully, freeInInferior() has already been called
411 // a bit of a complication since freeInInferior() needs an
412 // arg passed, which we can't do here. Too bad.
414 dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
415 const dictionary_hash<instInstance*,instInstance*> &map) const;
417 bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
418 void disable(process *, const vector< vector<unsigned> > &);
420 unsigned getInferiorPtr(process *) const {
421 // counterPtr could be NULL if we are building AstNodes just to compute
422 // the cost - naim 2/18/97
423 //assert(timerPtr != NULL); // NULL until insertInstrumentation()
424 return (unsigned)timerPtr;
427 unsigned getAllocatedIndex() const {assert(0); return 0;}
428 unsigned getAllocatedLevel() const {assert(0); return 0;}
430 int getSampleId() const {return theSampleId;}
432 bool unFork(dictionary_hash<instInstance*,instInstance*> &map);
433 // the fork syscall duplicates all instrumentation (except on AIX), which is a
434 // problem when we determine that a certain mi shouldn't be propagated to the child
435 // process. Hence this routine (to remove unwanted instr of DYNINSTsampleValues())
440 class sampledShmWallTimerReqNode : public dataReqNode {
441 // wall tTimer for use when shm sampling. Allocated in the shm segment heap.
442 // Sampled using shm-sampling.
444 // The following fields are always initialized in the ctor:
447 // The following fields are NULL until insertInstrumentatoin():
448 unsigned allocatedIndex;
449 unsigned allocatedLevel;
453 // since we don't use these, disallow:
454 sampledShmWallTimerReqNode(const sampledShmWallTimerReqNode &);
455 sampledShmWallTimerReqNode &operator=(const sampledShmWallTimerReqNode &);
458 sampledShmWallTimerReqNode(const sampledShmWallTimerReqNode &src,
460 metricDefinitionNode *, int iCounterId,
461 const process *parentProc);
464 sampledShmWallTimerReqNode(int iCounterId,
465 metricDefinitionNode *iMi, bool computingCost);
466 ~sampledShmWallTimerReqNode() {}
467 // hopefully, freeInInferior() has already been called
468 // a bit of a complication since freeInInferior() needs an
469 // arg passed, which we can't do here. Too bad.
471 dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
472 const dictionary_hash<instInstance*,instInstance*> &) const;
474 bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
475 void disable(process *, const vector< vector<unsigned> > &);
477 unsigned getInferiorPtr(process *) const;
479 unsigned getAllocatedIndex() const {return allocatedIndex;}
480 unsigned getAllocatedLevel() const {return allocatedLevel;}
482 unsigned getPosition() const {return position_;}
484 int getSampleId() const {return theSampleId;}
486 bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
489 class sampledShmProcTimerReqNode : public dataReqNode {
490 // process tTimer for use when shm sampling. Allocated in the shm segment heap.
491 // Sampled using shm-sampling.
493 // The following fields are always initialized in the ctor:
496 // The following fields are NULL until insertInstrumentatoin():
497 unsigned allocatedIndex;
498 unsigned allocatedLevel;
502 // since we don't use these, disallow:
503 sampledShmProcTimerReqNode(const sampledShmProcTimerReqNode &);
504 sampledShmProcTimerReqNode &operator=(const sampledShmProcTimerReqNode &);
507 sampledShmProcTimerReqNode(const sampledShmProcTimerReqNode &src,
509 metricDefinitionNode *, int iCounterId,
510 const process *parentProc);
513 sampledShmProcTimerReqNode(int iCounterId,
514 metricDefinitionNode *iMi, bool computingCost);
515 ~sampledShmProcTimerReqNode() {}
516 // hopefully, freeInInferior() has already been called
517 // a bit of a complication since freeInInferior() needs an
518 // arg passed, which we can't do here. Too bad.
520 dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
521 const dictionary_hash<instInstance*,instInstance*> &) const;
523 bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
524 void disable(process *, const vector< vector<unsigned> > &);
526 unsigned getInferiorPtr(process *) const;
528 unsigned getAllocatedIndex() const {return allocatedIndex;}
529 unsigned getAllocatedLevel() const {return allocatedLevel;}
531 unsigned getPosition() const {return position_;}
533 int getSampleId() const {return theSampleId;}
535 bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
539 /* ************************************************************************ */
543 instReqNode(instPoint*, AstNode *, callWhen, callOrder order,
544 bool iManuallyTrigger);
548 // needed by Vector class
549 ast = NULL; point=NULL; instance = NULL; manuallyTrigger = false;
552 instReqNode(const instReqNode &src) {
556 instance = src.instance;
557 ast = assignAst(src.ast);
558 manuallyTrigger = src.manuallyTrigger;
560 instReqNode &operator=(const instReqNode &src) {
565 ast = assignAst(src.ast);
568 instance = src.instance;
569 manuallyTrigger = src.manuallyTrigger;
574 bool insertInstrumentation(process *theProc,
575 returnInstance *&retInstance);
577 void disable(const vector<unsigned> &pointsToCheck);
578 float cost(process *theProc) const;
580 static instReqNode forkProcess(const instReqNode &parent,
581 const dictionary_hash<instInstance*,instInstance*> &);
582 // should become a copy-ctor...or at least, a non-static member fn.
584 bool unFork(dictionary_hash<instInstance*, instInstance*> &map) const;
585 // The fork syscall duplicates all trampolines from the parent into the child. For
586 // those mi's which we don't want to propagate to the child, this creates a
587 // problem. We need to remove instrumentation code from the child. This routine
588 // does that. "map" maps instInstances of the parent to those in the child.
590 instInstance *getInstance() const { return instance; }
592 bool anythingToManuallyTrigger() const {return manuallyTrigger;}
593 bool triggerNow(process *theProc);
600 instInstance *instance; // undefined until insertInstrumentation() calls addInstFunc
601 bool manuallyTrigger;
602 // if true, then 'ast' is manually executed (inferiorRPC) when
603 // inserting instrumentation.
608 metricDefinitionNode describe metric instances. There are two types of
609 nodes: aggregates and non-aggregates (Maybe this class should be divided in
611 Aggregate nodes represent a metric instance with one or more components.
612 Each component is represented by a non-aggregate metricDefinitionNode, and
613 is associated with a different process.
614 All metric instance have an aggregate metricDefinitionNode, even if it has
615 only one component (this simplifies doing metric propagation when new
617 Components can be shared by two or more aggregate metricDefinitionNodes,
618 so for example if there are two metric/focus pairs enabled, cpu time for
619 the whole program and cpu time for process p, there will be one non-aggregate
620 instance shared between two aggregate metricDefinitionNodes.
622 class metricDefinitionNode {
623 friend int startCollecting(string&, vector<u_int>&, int id,
624 vector<process *> &procsToContinue); // called by dynrpc.C
627 /* unique id for a counter or timer */
628 static int counterId;
631 // styles are enumerated in util/h/aggregation.h
632 metricDefinitionNode(process *p, const string& metric_name,
633 const vector< vector<string> >& foc,
634 const vector< vector<string> >& component_foc,
635 const string& component_flat_name, int agg_style = aggSum);
636 // for component (per-process) (non-aggregate) mdn's
638 metricDefinitionNode(const string& metric_name, const vector< vector<string> >& foc,
639 const string& cat_name,
640 vector<metricDefinitionNode*>& parts,
642 // for aggregate (not component) mdn's
644 ~metricDefinitionNode();
647 void updateValue(time64, sampleValue);
648 void forwardSimpleValue(timeStamp, timeStamp, sampleValue,unsigned,bool);
650 int getMId() const { return id_; }
651 const string &getMetName() const { return met_; }
652 const string &getFullName() const { return flat_name_; }
653 const vector< vector<string> > &getFocus() const {return focus_;}
654 const vector< vector<string> > &getComponentFocus() const {
655 assert(!aggregate_); // defined for component mdn's only
656 return component_focus;
659 process *proc() const { return proc_; }
661 bool nonNull() const { return (instRequests.size() || dataRequests.size()); }
662 bool insertInstrumentation();
665 bool checkAndInstallInstrumentation();
667 float originalCost() const { return originalCost_; }
669 // The following routines are (from the outside world's viewpoint)
670 // the heart of it all. They append to dataRequets or instRequests, so that
671 // a future call to metricDefinitionNode::insertInstrumentation() will
672 // "do their thing". The MDL calls these routines.
673 dataReqNode *addSampledIntCounter(int initialValue, bool computingCost,
674 bool doNotSample=false);
675 dataReqNode *addUnSampledIntCounter(int initialValue, bool computingCost);
676 dataReqNode *addWallTimer(bool computingCost);
677 dataReqNode *addProcessTimer(bool computingCost);
678 inline void addInst(instPoint *point, AstNode *, callWhen when,
680 bool manuallyTrigger);
682 // propagate this aggregate mi to a newly started process p (not for processes
683 // started via fork or exec, just for those started "normally")
684 void propagateToNewProcess(process *p);
686 metricDefinitionNode *forkProcess(process *child,
687 const dictionary_hash<instInstance*,instInstance*> &map) const;
688 // called when it's determined that an mi should be propagated from the
689 // parent to the child. "this" is a component mi, not an aggregator mi.
690 bool unFork(dictionary_hash<instInstance*, instInstance*> &map,
691 bool unForkInstRequests, bool unForkDataRequests);
692 // the fork() sys call copies all trampoline code, so the child process can be
693 // left with code that writes to counters/timers that don't exist (in the case
694 // where we don't propagate the mi to the new process). In such cases, we must
695 // remove instrumentation from the child process. That's what this routine is
696 // for. It looks at the instReqNodes of the mi, which are in place in the parent
697 // process, and removes them from the child process. "this" is a component mi
698 // representing the parent process. "map" maps instInstance's of the parent to
699 // those of the child.
701 static void handleFork(const process *parent, process *child,
702 dictionary_hash<instInstance*, instInstance*> &map);
703 // called once per fork. "map" maps all instInstance's of the parent
704 // process to the corresponding copy in the child process...we'll delete some
705 // instrumentation in the child process if we find that some instrumentation
706 // in the parent doesn't belong in the child.
708 static void handleExec(process *);
709 // called once per exec, once the "new" process has been bootstrapped.
710 // We decide which mi's that were present in the pre-exec process should be
711 // carried over to the new process. For those that should, the instrumentation
712 // is actually inserted. For others, the component mi in question is removed from
715 // remove an instance from an aggregate metric
716 void removeThisInstance();
718 bool anythingToManuallyTrigger() const;
720 void manuallyTrigger();
723 // Since we don't define these, make sure they're not used:
724 metricDefinitionNode &operator=(const metricDefinitionNode &src);
725 metricDefinitionNode(const metricDefinitionNode &src);
727 void removeComponent(metricDefinitionNode *comp);
728 void endOfDataCollection();
729 void removeFromAggregate(metricDefinitionNode *comp);
731 void updateAggregateComponent();
734 int aggOp; // the aggregate operator
737 string met_; // what type of metric
738 vector< vector<string> > focus_;
739 vector< vector<string> > component_focus; // defined for component mdn's only
742 /* for aggregate metrics */
743 vector<metricDefinitionNode*> components;
744 aggregateSample aggSample; // current aggregate value
746 /* for non-aggregate metrics */
747 vector<dataReqNode*> dataRequests;
749 vector<instReqNode> instRequests;
750 vector<returnInstance *> returnInsts;
752 sampleValue cumulativeValue; // cumulative value for this metric
754 // which metricDefinitionNode depend on this value.
755 vector<metricDefinitionNode*> aggregators;
756 // remember, there can be more than one. E.g. if cpu for whole program and
757 // cpu for process 100 are chosen, then we'll have just one component mi which is
758 // present in two aggregate mi's (cpu/whole and cpu/proc-100).
760 vector<sampleInfo *> samples;
761 // defined for component mi's only -- one sample for each aggregator, usually
762 // allocated with "aggregateMI.aggSample.newComponent()".
763 // samples[i] is the sample of aggregators[i].
765 int id_; // unique id for this one
773 metricDefinitionNode* handleExec();
774 // called by static void handleExec(process *), for each component mi
775 // returns new component mi if propagation succeeded; NULL if not.
778 inline void metricDefinitionNode::addInst(instPoint *point, AstNode *ast,
781 bool manuallyTrigger) {
784 instReqNode temp(point, ast, when, o, manuallyTrigger);
785 instRequests += temp;
788 // allMIs: all aggregate (as opposed to component) metricDefinitionNodes
789 extern dictionary_hash<unsigned, metricDefinitionNode*> allMIs;
791 // allMIComponents: all component (as opposed to aggregate) metricDefinitionNodes,
792 // indexed by the component's unique flat_name.
793 extern dictionary_hash<string, metricDefinitionNode*> allMIComponents;
795 extern double currentPredictedCost;
798 extern void processCost(process *proc, traceHeader *h, costUpdate *s);
801 extern void reportInternalMetrics(bool force);
804 * Routines to control data collection.
806 * focus - a list of resources
807 * metricName - what metric to collect data for
809 * procsToContinue - a list of processes that had to be stopped to insert
810 * instrumentation. The caller must continue these processes.
812 int startCollecting(string& metricName, vector<u_int>& focus, int id,
813 vector<process *> &procsToContinue);
816 * Return the expected cost of collecting performance data for a single
817 * metric at a given focus. The value returned is the fraction of
818 * perturbation expected (i.e. 0.10 == 10% slow down expected).
820 float guessCost(string& metric_name, vector<u_int>& focus);
824 * process a sample ariving from an inferior process
828 void processSample(int pid, traceHeader*, traceSample *);