added an int version of updateValue()
[dyninst.git] / paradynd / src / metricFocusNode.h
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
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.
10  * 
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.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
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.
29  * 
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.
40  */
41
42 /*
43  * metric.h 
44  *
45  * $Log: metricFocusNode.h,v $
46  * Revision 1.54  1997/09/26 15:55:34  tamches
47  * added an int version of updateValue()
48  * renamed cumulativeValue to cumulativeValue_float, in anticipation
49  * of someday changing cumulativeValue to a union of {float, double, int,
50  * long, long long} values.
51  *
52  * Revision 1.53  1997/07/29 14:36:05  naim
53  * Fixing problem with inferiorRPC, non-shared memory sampling and sigalrm - naim
54  *
55  * Revision 1.52  1997/06/23 17:05:07  tamches
56  * slight changes to #include
57  *
58  * Revision 1.51  1997/06/16 22:07:15  ssuen
59  * Added `int deleteComp = 1' to end of argument list for function
60  *   metricDefinitionNode::removeFromAggregate
61  * to control whether or not to `delete' the `comp' argument.
62  *
63  * Revision 1.50  1997/06/05 18:04:20  naim
64  * Cleaning up dataReqNodes for certain cases of deletion of metricDefinitionNodes
65  * - naim
66  *
67  * Revision 1.49  1997/05/08 00:12:16  mjrg
68  * changes for Visual C++ compiler: added return to functions
69  *
70  * Revision 1.48  1997/05/07 19:01:27  naim
71  * Getting rid of old support for threads and turning it off until the new
72  * version is finished. Additionally, new superTable, baseTable and superVector
73  * classes for future support of multiple threads. The fastInferiorHeap class has
74  * also changed - naim
75  *
76  * Revision 1.47  1997/04/21 16:56:15  hseom
77  * added support for trace data
78  *
79  * Revision 1.46  1997/03/18 19:45:57  buck
80  * first commit of dyninst library.  Also includes:
81  *      moving templates from paradynd to dyninstAPI
82  *      converting showError into a function (in showerror.C)
83  *      many ifdefs for BPATCH_LIBRARY in dyinstAPI/src.
84  *
85  * Revision 1.45  1997/02/26 23:46:43  mjrg
86  * First part of WindowsNT port: changes for compiling with Visual C++;
87  * moved unix specific code to unix.C file
88  *
89  * Revision 1.44  1997/02/24 14:22:58  naim
90  * Minor fix to my previous commit - naim
91  *
92  * Revision 1.43  1997/02/21 20:15:59  naim
93  * Moving files from paradynd to dyninstAPI + eliminating references to
94  * dataReqNode from the ast class. This is the first pre-dyninstAPI commit! - naim
95  *
96  * Revision 1.42  1997/01/27 19:41:07  naim
97  * Part of the base instrumentation for supporting multithreaded applications
98  * (vectors of counter/timers) implemented for all current platforms +
99  * different bug fixes - naim
100  *
101  * Revision 1.41  1997/01/15 01:11:34  tamches
102  * completely revamped fork & exec -- they now work for shm sampling.
103  *
104  * Revision 1.40  1996/11/14 14:28:01  naim
105  * Changing AstNodes back to pointers to improve performance - naim
106  *
107  * Revision 1.39  1996/10/31 09:25:59  tamches
108  * the shm-sampling commit; completely redesigned dataReqNode; designed
109  * a handful of derived classes of dataReqNode, which replaces a lot of
110  * existing code.
111  *
112  * Revision 1.38  1996/10/03 22:12:03  mjrg
113  * Removed multiple stop/continues when inserting instrumentation
114  * Fixed bug on process termination
115  * Removed machine dependent code from metric.C and process.C
116  *
117  * Revision 1.37  1996/08/20 19:03:17  lzheng
118  * Implementation of moving multiple instructions sequence and
119  * Splitting the instrumentation into two phases
120  *
121  */
122
123 #ifndef METRIC_H
124 #define METRIC_H
125
126 #include "util/h/String.h"
127 // trace data streams
128 #include "util/h/ByteArray.h"
129 #include "util/h/Vector.h"
130 #include "util/h/Dictionary.h"
131 #include "util/h/aggregateSample.h"
132 #include "dyninstAPI/src/ast.h"
133 #include "dyninstAPI/src/util.h"
134 #include "rtinst/h/trace.h"
135 #include "dyninstAPI/src/inst.h" // for "enum callWhen"
136
137 class instInstance; // enough since we only use instInstance* in this file
138
139 #if defined(SHM_SAMPLING)
140 #include "paradynd/src/superTable.h"
141 #endif
142
143 class dataReqNode {
144  private:
145   // Since we don't define these, make sure they're not used:
146   dataReqNode &operator=(const dataReqNode &src);
147   dataReqNode (const dataReqNode &src);
148
149  protected:
150   dataReqNode() {}
151
152  public:
153   virtual ~dataReqNode() {};
154
155   virtual unsigned getInferiorPtr(process *proc=NULL) const = 0;
156   virtual unsigned getAllocatedIndex() const = 0;
157   virtual unsigned getAllocatedLevel() const = 0;
158
159   virtual int getSampleId() const = 0;
160
161   virtual bool insertInstrumentation(process *, metricDefinitionNode *, bool) = 0;
162      // Allocates stuff from inferior heap, instrumenting DYNINSTreportCounter
163      // as appropriate.  
164      // Returns true iff successful.
165
166   virtual void disable(process *,
167                        const vector< vector<unsigned> > &pointsToCheck) = 0;
168      // the opposite of insertInstrumentation.  Deinstruments, deallocates
169      // from inferior heap, etc.
170
171   virtual dataReqNode *dup(process *childProc, metricDefinitionNode *,
172                            int iCounterId,
173                            const dictionary_hash<instInstance*,instInstance*> &map
174                            ) const = 0;
175      // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
176
177      // "map" provides a dictionary that maps instInstance's of the parent process to
178      // those in the child process; dup() may find it useful. (for now, the shm
179      // dataReqNodes have no need for it; the alarm sampled ones need it).
180
181   virtual bool unFork(dictionary_hash<instInstance*,instInstance*> &map) = 0;
182      // the fork syscall duplicates all instrumentation (except on AIX), which is a
183      // problem when we determine that a certain mi shouldn't be propagated to the child
184      // process.  Hence this routine.
185 };
186
187 /*
188  * Classes derived from dataReqNode
189  *
190  * There are a lot of classes derived from dataReqNode, so things can get a little
191  * confusing.  Most of them are used in either shm_sampling mode or not; few are
192  * used in both.  Here's a bit of documentation that should sort things out:
193  *
194  * A) classes used in _both_ shm_sampling and non-shm-sampling
195  *
196  *    nonSampledIntCounterReqNode --
197  *       provides an intCounter value that is never sampled.  Currently useful
198  *       for predicates (constraint booleans).  The intCounter is allocated from
199  *       the "conventional" heap (where tramps are allocated) using good old
200  *       inferiorMalloc(), even when shm_sampling.
201  *       (In the future, we may provide a separate shm_sampling version, to make
202  *       allocation faster [allocation in the shm seg heap is always faster])
203  *
204  * B) classes used only when shm_sampling
205  *
206  *    shmSampledIntCounterReqNode --
207  *       provides an intCounter value that is sampled with shm sampling.  The
208  *       intCounter is allocated from the shm segment (i.e., not with inferiorMalloc).
209  *
210  *    shmSampledWallTimerReqNode --
211  *       provides a wall timer value that is sampled with shm sampling.  The tTimer is
212  *       allocated from the shm segment (i.e., not with inferiorMalloc)
213  *    
214  *    shmSampledProcTimerReqNode --
215  *       provides a process timer value that is sampled with shm sampling.  The tTimer
216  *       is allocated from the shm segment (i.e., not with inferiorMalloc)
217  *    
218  * C) classes used only when _not_ shm-sampling
219  *    
220  *    alarmSampledIntCounterReqNode --
221  *       provides an intCounter value that is sampled.  The intCounter is allocated
222  *       in the conventional heap with inferiorMalloc().  Sampling is done the
223  *       old-fasioned SIGALRM way: by instrumenting DYNINSTsampleValues to call
224  *       DYNINSTreportTimer
225  *
226  *    alarmSampledTimerReqNode --
227  *       provides a tTimer value (can be wall or process timer) that is sampled.  The
228  *       tTimer is allocated in the conventional heap with inferiorMalloc().  Sampling
229  *       is done the old-fasioned SIGALRM way: by instrumenting DYNINSTsampleValues to
230  *       call DYNINSTreportTimer.
231  *
232  */
233
234 #ifndef SHM_SAMPLING
235 class sampledIntCounterReqNode : public dataReqNode {
236  // intCounter for use when not shm sampling.  Allocated in the conventional heap
237  // with inferiorMalloc().  Sampled the old-fasioned way: by instrumenting
238  // DYNINSTsampleValues() to call DYNINSTreportCounter.
239  private:
240    // The following fields are always properly initialized in ctor:
241    int theSampleId;
242    int initialValue; // needed when dup()'ing
243
244    // The following fields are NULL until insertInstrumentation() called:   
245    intCounter *counterPtr;              /* NOT in our address space !!!! */
246    instInstance *sampler;               /* function to sample value */
247
248    // Since we don't use these, disallow:
249    sampledIntCounterReqNode &operator=(const sampledIntCounterReqNode &);
250    sampledIntCounterReqNode(const sampledIntCounterReqNode &);
251
252    // private fork-ctor called by dup():
253    sampledIntCounterReqNode(const sampledIntCounterReqNode &src,
254                             process *childProc, metricDefinitionNode *, int iCounterId,
255                             const dictionary_hash<instInstance*,instInstance*> &map);
256
257    void writeToInferiorHeap(process *theProc, const intCounter &src) const;
258
259  public:
260    sampledIntCounterReqNode(int iValue, int iCounterId,
261                             metricDefinitionNode *iMi, bool computingCost);
262   ~sampledIntCounterReqNode() {}
263       // Hopefully, disable() has already been called.  A bit of a complication
264       // since disable() needs an arg passed, which we can't do here.  Too bad.
265
266    dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
267                     const dictionary_hash<instInstance*,instInstance*> &map) const;
268
269    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
270       // allocates from inferior heap; initializes it; instruments
271       // DYNINSTsampleValues
272
273    void disable(process *, const vector< vector<unsigned> > &);
274
275    unsigned getInferiorPtr(process *) const {
276       // counterPtr could be NULL if we are building AstNodes just to compute
277       // the cost - naim 2/18/97
278       //assert(counterPtr != NULL); // NULL until insertInstrumentation()
279       return (unsigned)counterPtr;
280    }
281
282    unsigned getAllocatedIndex() const {assert(0); return 0;}
283    unsigned getAllocatedLevel() const {assert(0); return 0;}
284
285    int getSampleId() const {return theSampleId;}
286
287    bool unFork(dictionary_hash<instInstance*,instInstance*> &map);
288      // the fork syscall duplicates all instrumentation (except on AIX), which is a
289      // problem when we determine that a certain mi shouldn't be propagated to the child
290      // process.  Hence this routine (to remove unwanted instr of DYNINSTsampleValues())
291 };
292 #endif
293
294 #ifdef SHM_SAMPLING
295 class sampledShmIntCounterReqNode : public dataReqNode {
296  // intCounter for use when shm-sampling.  Allocated in the shm segment heap.
297  // Sampled using shm sampling.
298  private:
299    // The following fields are always properly initialized in ctor:
300    int theSampleId; // obsolete with shm sampling; can be removed.
301
302    int initialValue; // needed when dup()'ing
303
304    // The following fields are NULL until insertInstrumentation() called:
305    unsigned allocatedIndex;
306    unsigned allocatedLevel;
307
308    unsigned position_;
309
310    // Since we don't use these, making them privates ensures they're not used.
311    sampledShmIntCounterReqNode &operator=(const sampledShmIntCounterReqNode &);
312    sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &);
313
314    // private fork-ctor called by dup():
315    sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &src,
316                                process *childProc, metricDefinitionNode *,
317                                int iCounterId, const process *parentProc);
318
319  public:
320    sampledShmIntCounterReqNode(int iValue, int iCounterId, 
321                                metricDefinitionNode *iMi, bool computingCost,
322                                bool doNotSample);
323   ~sampledShmIntCounterReqNode() {}
324       // Hopefully, disable() has already been called.
325       // A bit of a complication since disable() needs an
326       // arg passed, which we can't do here.  Too bad.
327
328    dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
329                     const dictionary_hash<instInstance*,instInstance*> &) const;
330
331    bool insertInstrumentation(process *, metricDefinitionNode *, bool);
332       // allocates from inferior heap; initializes it, etc.
333
334    void disable(process *, const vector< vector<unsigned> > &);
335
336    unsigned getInferiorPtr(process *) const;
337
338    unsigned getAllocatedIndex() const {return allocatedIndex;}
339    unsigned getAllocatedLevel() const {return allocatedLevel;}
340
341    unsigned getPosition() const {return position_;}
342    int getSampleId() const {return theSampleId;}
343
344    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
345 };
346 #endif
347
348 class nonSampledIntCounterReqNode : public dataReqNode {
349  // intCounter for predicates (because they don't need to be sampled).
350  // Allocated in the conventional heap with inferiorMalloc().
351  private:
352    // The following fields are always properly initialized in ctor:
353    int theSampleId;
354    int initialValue; // needed when dup()'ing
355
356    // The following is NULL until insertInstrumentation() called:   
357    intCounter *counterPtr;              /* NOT in our address space !!!! */
358
359    // Since we don't use these, disallow:
360    nonSampledIntCounterReqNode &operator=(const nonSampledIntCounterReqNode &);
361    nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &);
362
363    // private fork-ctor called by dup():
364    nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &src,
365                                process *childProc, metricDefinitionNode *,
366                                int iCounterId);
367
368    void writeToInferiorHeap(process *theProc, const intCounter &src) const;
369
370  public:
371    nonSampledIntCounterReqNode(int iValue, int iCounterId,
372                                metricDefinitionNode *iMi, bool computingCost);
373   ~nonSampledIntCounterReqNode() {}
374       // Hopefully, disable() has already been called.
375       // A bit of a complication since disable() needs an
376       // arg passed, which we can't do here.  Too bad.
377
378    dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
379                     const dictionary_hash<instInstance*,instInstance*> &) const;
380
381    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
382       // allocates from inferior heap; initializes it
383
384    void disable(process *, const vector< vector<unsigned> > &);
385
386    unsigned getInferiorPtr(process *) const {
387       //assert(counterPtr != NULL); // NULL until insertInstrumentation()
388       // counterPtr could be NULL if we are building AstNodes just to compute
389       // the cost - naim 2/18/97
390       return (unsigned)counterPtr;
391    }
392
393    unsigned getAllocatedIndex() const {assert(0); return 0;}
394    unsigned getAllocatedLevel() const {assert(0); return 0;}
395
396    int getSampleId() const {return theSampleId;}
397
398    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
399 };
400
401 #ifndef SHM_SAMPLING
402 class sampledTimerReqNode : public dataReqNode {
403  // tTimer for use when not shm sampling.  Allocated in the conventional heap with
404  // inferiorMalloc().  Sampled the old-fasioned way: by instrumenting
405  // DYNINSTsampleValues to call DYNINSTreportTimer.
406  private:
407    // The following fields are always initialized in the ctor:   
408    int theSampleId;
409    timerType theTimerType;
410
411    // The following fields are NULL until insertInstrumentation():
412    tTimer *timerPtr;                    /* NOT in our address space !!!! */
413    instInstance *sampler;               /* function to sample value */
414
415    // since we don't use these, disallow:
416    sampledTimerReqNode(const sampledTimerReqNode &);
417    sampledTimerReqNode &operator=(const sampledTimerReqNode &);
418
419    // fork ctor:
420    sampledTimerReqNode(const sampledTimerReqNode &src, process *childProc,
421                        metricDefinitionNode *, int iCounterId,
422                        const dictionary_hash<instInstance*,instInstance*> &map);
423
424    void writeToInferiorHeap(process *theProc, const tTimer &dataSrc) const;
425
426  public:
427    sampledTimerReqNode(timerType iType, int iCounterId,
428                        metricDefinitionNode *iMi, bool computingCost);
429   ~sampledTimerReqNode() {}
430       // hopefully, freeInInferior() has already been called
431       // a bit of a complication since freeInInferior() needs an
432       // arg passed, which we can't do here.  Too bad.
433
434    dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
435                     const dictionary_hash<instInstance*,instInstance*> &map) const;
436
437    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
438    void disable(process *, const vector< vector<unsigned> > &);
439
440    unsigned getInferiorPtr(process *) const {
441       // counterPtr could be NULL if we are building AstNodes just to compute
442       // the cost - naim 2/18/97
443       //assert(timerPtr != NULL); // NULL until insertInstrumentation()
444       return (unsigned)timerPtr;
445    }
446
447    unsigned getAllocatedIndex() const {assert(0); return 0;}
448    unsigned getAllocatedLevel() const {assert(0); return 0;}
449
450    int getSampleId() const {return theSampleId;}
451
452    bool unFork(dictionary_hash<instInstance*,instInstance*> &map);
453      // the fork syscall duplicates all instrumentation (except on AIX), which is a
454      // problem when we determine that a certain mi shouldn't be propagated to the child
455      // process.  Hence this routine (to remove unwanted instr of DYNINSTsampleValues())
456 };
457 #endif
458
459 #ifdef SHM_SAMPLING
460 class sampledShmWallTimerReqNode : public dataReqNode {
461  // wall tTimer for use when shm sampling.  Allocated in the shm segment heap.
462  // Sampled using shm-sampling.
463  private:
464    // The following fields are always initialized in the ctor:   
465    int theSampleId;
466
467    // The following fields are NULL until insertInstrumentatoin():
468    unsigned allocatedIndex;
469    unsigned allocatedLevel;
470
471    unsigned position_;
472
473    // since we don't use these, disallow:
474    sampledShmWallTimerReqNode(const sampledShmWallTimerReqNode &);
475    sampledShmWallTimerReqNode &operator=(const sampledShmWallTimerReqNode &);
476
477    // fork ctor:
478    sampledShmWallTimerReqNode(const sampledShmWallTimerReqNode &src, 
479                               process *childProc,
480                               metricDefinitionNode *, int iCounterId,
481                               const process *parentProc);
482
483  public:
484    sampledShmWallTimerReqNode(int iCounterId,
485                               metricDefinitionNode *iMi, bool computingCost);
486   ~sampledShmWallTimerReqNode() {}
487       // hopefully, freeInInferior() has already been called
488       // a bit of a complication since freeInInferior() needs an
489       // arg passed, which we can't do here.  Too bad.
490
491    dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
492                     const dictionary_hash<instInstance*,instInstance*> &) const;
493
494    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
495    void disable(process *, const vector< vector<unsigned> > &);
496
497    unsigned getInferiorPtr(process *) const;
498
499    unsigned getAllocatedIndex() const {return allocatedIndex;}
500    unsigned getAllocatedLevel() const {return allocatedLevel;}
501
502    unsigned getPosition() const {return position_;}
503
504    int getSampleId() const {return theSampleId;}
505
506    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
507 };
508
509 class sampledShmProcTimerReqNode : public dataReqNode {
510  // process tTimer for use when shm sampling.  Allocated in the shm segment heap.
511  // Sampled using shm-sampling.
512  private:
513    // The following fields are always initialized in the ctor:   
514    int theSampleId;
515
516    // The following fields are NULL until insertInstrumentatoin():
517    unsigned allocatedIndex;
518    unsigned allocatedLevel;
519
520    unsigned position_;
521
522    // since we don't use these, disallow:
523    sampledShmProcTimerReqNode(const sampledShmProcTimerReqNode &);
524    sampledShmProcTimerReqNode &operator=(const sampledShmProcTimerReqNode &);
525
526    // fork ctor:
527    sampledShmProcTimerReqNode(const sampledShmProcTimerReqNode &src, 
528                               process *childProc,
529                               metricDefinitionNode *, int iCounterId,
530                               const process *parentProc);
531
532  public:
533    sampledShmProcTimerReqNode(int iCounterId,
534                               metricDefinitionNode *iMi, bool computingCost);
535   ~sampledShmProcTimerReqNode() {}
536       // hopefully, freeInInferior() has already been called
537       // a bit of a complication since freeInInferior() needs an
538       // arg passed, which we can't do here.  Too bad.
539
540    dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
541                     const dictionary_hash<instInstance*,instInstance*> &) const;
542
543    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
544    void disable(process *, const vector< vector<unsigned> > &);
545
546    unsigned getInferiorPtr(process *) const;
547
548    unsigned getAllocatedIndex() const {return allocatedIndex;}
549    unsigned getAllocatedLevel() const {return allocatedLevel;}
550
551    unsigned getPosition() const {return position_;}
552
553    int getSampleId() const {return theSampleId;}
554
555    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
556 };
557 #endif
558
559 /* ************************************************************************ */
560
561 class instReqNode {
562 public:
563   instReqNode(instPoint*, AstNode *, callWhen, callOrder order,
564               bool iManuallyTrigger);
565  ~instReqNode();
566
567   instReqNode() {
568      // needed by Vector class
569      ast = NULL; point=NULL; instance = NULL; manuallyTrigger = false;
570   }
571
572   instReqNode(const instReqNode &src) {
573      point = src.point;
574      when = src.when;
575      order = src.order;
576      instance = src.instance;
577      ast = assignAst(src.ast);
578      manuallyTrigger = src.manuallyTrigger;
579   }
580   instReqNode &operator=(const instReqNode &src) {
581      if (this == &src)
582         return *this;
583
584      point = src.point;
585      ast = assignAst(src.ast);
586      when = src.when;
587      order = src.order;
588      instance = src.instance;
589      manuallyTrigger = src.manuallyTrigger;
590
591      return *this;
592   }
593
594   bool insertInstrumentation(process *theProc,
595                              returnInstance *&retInstance);
596
597   void disable(const vector<unsigned> &pointsToCheck);
598   float cost(process *theProc) const;
599
600   static instReqNode forkProcess(const instReqNode &parent,
601                                  const dictionary_hash<instInstance*,instInstance*> &);
602      // should become a copy-ctor...or at least, a non-static member fn.
603
604   bool unFork(dictionary_hash<instInstance*, instInstance*> &map) const;
605      // The fork syscall duplicates all trampolines from the parent into the child. For
606      // those mi's which we don't want to propagate to the child, this creates a
607      // problem.  We need to remove instrumentation code from the child.  This routine
608      // does that.  "map" maps instInstances of the parent to those in the child.
609
610   instInstance *getInstance() const { return instance; }
611
612   bool anythingToManuallyTrigger() const {return manuallyTrigger;}
613   bool triggerNow(process *theProc, int mid);
614
615 private:
616   instPoint     *point;
617   AstNode       *ast;
618   callWhen      when;
619   callOrder     order;
620   instInstance  *instance; // undefined until insertInstrumentation() calls addInstFunc
621   bool manuallyTrigger;
622      // if true, then 'ast' is manually executed (inferiorRPC) when
623      // inserting instrumentation.
624 };
625
626
627 /*
628    metricDefinitionNode describe metric instances. There are two types of
629    nodes: aggregates and non-aggregates (Maybe this class should be divided in
630    two).
631    Aggregate nodes represent a metric instance with one or more components.
632    Each component is represented by a non-aggregate metricDefinitionNode, and
633    is associated with a different process.
634    All metric instance have an aggregate metricDefinitionNode, even if it has 
635    only one component (this simplifies doing metric propagation when new 
636    processes start).
637    Components can be shared by two or more aggregate metricDefinitionNodes, 
638    so for example if there are two metric/focus pairs enabled, cpu time for
639    the whole program and cpu time for process p, there will be one non-aggregate
640    instance shared between two aggregate metricDefinitionNodes.
641 */
642 class metricDefinitionNode {
643 friend int startCollecting(string&, vector<u_int>&, int id, 
644                            vector<process *> &procsToContinue); // called by dynrpc.C
645
646  private:
647    /* unique id for a counter or timer */
648    static int counterId;
649
650 public:
651   // styles are enumerated in util/h/aggregation.h
652   metricDefinitionNode(process *p, const string& metric_name, 
653                        const vector< vector<string> >& foc,
654                        const vector< vector<string> >& component_foc,
655                        const string& component_flat_name, int agg_style = aggSum);
656      // for component (per-process) (non-aggregate) mdn's
657
658   metricDefinitionNode(const string& metric_name, const vector< vector<string> >& foc,
659                        const string& cat_name,
660                        vector<metricDefinitionNode*>& parts,
661                        int agg_op);
662      // for aggregate (not component) mdn's
663
664   ~metricDefinitionNode();
665   void disable();
666   void cleanup_drn();
667   void updateValue(time64, int);
668   void updateValue(time64, sampleValue);
669   void forwardSimpleValue(timeStamp, timeStamp, sampleValue,unsigned,bool);
670
671   int getMId() const { return id_; }
672   const string &getMetName() const { return met_; }
673   const string &getFullName() const { return flat_name_; }
674   const vector< vector<string> > &getFocus() const {return focus_;}
675   const vector< vector<string> > &getComponentFocus() const {
676      assert(!aggregate_); // defined for component mdn's only
677      return component_focus;
678   }
679
680   process *proc() const { return proc_; }
681
682   bool nonNull() const { return (instRequests.size() || dataRequests.size()); }
683   bool insertInstrumentation();
684
685   float cost() const;
686   bool checkAndInstallInstrumentation();
687
688   float originalCost() const { return originalCost_; }
689
690   // The following routines are (from the outside world's viewpoint)
691   // the heart of it all.  They append to dataRequets or instRequests, so that
692   // a future call to metricDefinitionNode::insertInstrumentation() will
693   // "do their thing".  The MDL calls these routines.
694   dataReqNode *addSampledIntCounter(int initialValue, bool computingCost,
695                                     bool doNotSample=false);
696   dataReqNode *addUnSampledIntCounter(int initialValue, bool computingCost);
697   dataReqNode *addWallTimer(bool computingCost);
698   dataReqNode *addProcessTimer(bool computingCost);
699   inline void addInst(instPoint *point, AstNode *, callWhen when, 
700                       callOrder o,
701                       bool manuallyTrigger);
702
703   // propagate this aggregate mi to a newly started process p (not for processes
704   // started via fork or exec, just for those started "normally")
705   void propagateToNewProcess(process *p);  
706
707   metricDefinitionNode *forkProcess(process *child,
708                                     const dictionary_hash<instInstance*,instInstance*> &map) const;
709      // called when it's determined that an mi should be propagated from the
710      // parent to the child.  "this" is a component mi, not an aggregator mi.
711   bool unFork(dictionary_hash<instInstance*, instInstance*> &map,
712               bool unForkInstRequests, bool unForkDataRequests);
713      // the fork() sys call copies all trampoline code, so the child process can be
714      // left with code that writes to counters/timers that don't exist (in the case
715      // where we don't propagate the mi to the new process).  In such cases, we must
716      // remove instrumentation from the child process.  That's what this routine is
717      // for.  It looks at the instReqNodes of the mi, which are in place in the parent
718      // process, and removes them from the child process.  "this" is a component mi
719      // representing the parent process.  "map" maps instInstance's of the parent to
720      // those of the child.
721
722   static void handleFork(const process *parent, process *child,
723                          dictionary_hash<instInstance*, instInstance*> &map);
724      // called once per fork.  "map" maps all instInstance's of the parent
725      // process to the corresponding copy in the child process...we'll delete some
726      // instrumentation in the child process if we find that some instrumentation
727      // in the parent doesn't belong in the child.
728
729   static void handleExec(process *);
730      // called once per exec, once the "new" process has been bootstrapped.
731      // We decide which mi's that were present in the pre-exec process should be
732      // carried over to the new process.  For those that should, the instrumentation
733      // is actually inserted.  For others, the component mi in question is removed from
734      // the system.
735
736   // remove an instance from an aggregate metric
737   void removeThisInstance();
738
739   bool anythingToManuallyTrigger() const;
740
741   void manuallyTrigger(int);
742
743 private:
744   // Since we don't define these, make sure they're not used:
745   metricDefinitionNode &operator=(const metricDefinitionNode &src);
746   metricDefinitionNode(const metricDefinitionNode &src);
747
748   void removeComponent(metricDefinitionNode *comp);
749   void endOfDataCollection();
750   void removeFromAggregate(metricDefinitionNode *comp, int deleteComp = 1);
751
752   void updateAggregateComponent();
753
754   bool                  aggregate_;
755   int aggOp; // the aggregate operator
756   bool                  inserted_;
757   bool                  installed_;
758   string met_;                  // what type of metric
759   vector< vector<string> > focus_;
760   vector< vector<string> > component_focus; // defined for component mdn's only
761   string flat_name_;
762
763   /* for aggregate metrics */
764   vector<metricDefinitionNode*>   components;   
765   aggregateSample aggSample;    // current aggregate value
766
767   /* for non-aggregate metrics */
768   vector<dataReqNode*>  dataRequests;
769
770   vector<instReqNode> instRequests;
771   vector<returnInstance *> returnInsts;
772
773 //  sampleValue cumulativeValue; // cumulative value for this metric
774    sampleValue cumulativeValue_float;
775    
776
777   // which metricDefinitionNode depend on this value.
778   vector<metricDefinitionNode*>   aggregators;
779      // remember, there can be more than one.  E.g. if cpu for whole program and
780      // cpu for process 100 are chosen, then we'll have just one component mi which is
781      // present in two aggregate mi's (cpu/whole and cpu/proc-100).
782
783   vector<sampleInfo *> samples;
784      // defined for component mi's only -- one sample for each aggregator, usually
785      // allocated with "aggregateMI.aggSample.newComponent()".
786      // samples[i] is the sample of aggregators[i].
787
788   int id_;                              // unique id for this one 
789   float originalCost_;
790
791   process *proc_;
792
793   string metric_name_;
794   metricStyle style_; 
795
796   metricDefinitionNode* handleExec();
797      // called by static void handleExec(process *), for each component mi
798      // returns new component mi if propagation succeeded; NULL if not.
799 };
800
801 inline void metricDefinitionNode::addInst(instPoint *point, AstNode *ast,
802                                           callWhen when,
803                                           callOrder o,
804                                           bool manuallyTrigger) {
805   if (!point) return;
806
807   instReqNode temp(point, ast, when, o, manuallyTrigger);
808   instRequests += temp;
809 };
810
811 // allMIs: all aggregate (as opposed to component) metricDefinitionNodes
812 extern dictionary_hash<unsigned, metricDefinitionNode*> allMIs;
813
814 // allMIComponents: all component (as opposed to aggregate) metricDefinitionNodes,
815 // indexed by the component's unique flat_name.
816 extern dictionary_hash<string, metricDefinitionNode*> allMIComponents;
817
818 extern double currentPredictedCost;
819
820 #ifndef SHM_SAMPLING
821 extern void processCost(process *proc, traceHeader *h, costUpdate *s);
822 #endif
823
824 extern void reportInternalMetrics(bool force);
825
826 /*
827  * Routines to control data collection.
828  *
829  * focus                - a list of resources
830  * metricName           - what metric to collect data for
831  * id                   - metric id
832  * procsToContinue      - a list of processes that had to be stopped to insert
833  *                        instrumentation. The caller must continue these processes.
834  */
835 int startCollecting(string& metricName, vector<u_int>& focus, int id,
836                     vector<process *> &procsToContinue); 
837
838 /*
839  * Return the expected cost of collecting performance data for a single
840  *    metric at a given focus.  The value returned is the fraction of
841  *    perturbation expected (i.e. 0.10 == 10% slow down expected).
842  */
843 float guessCost(string& metric_name, vector<u_int>& focus);
844
845
846 /*
847  * process a sample ariving from an inferior process
848  *
849  */
850 #ifndef SHM_SAMPLING
851 void processSample(int pid, traceHeader*, traceSample *);
852 #endif
853
854 #endif