Cleaning up dataReqNodes for certain cases of deletion of metricDefinitionNodes
[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.50  1997/06/05 18:04:20  naim
47  * Cleaning up dataReqNodes for certain cases of deletion of metricDefinitionNodes
48  * - naim
49  *
50  * Revision 1.49  1997/05/08 00:12:16  mjrg
51  * changes for Visual C++ compiler: added return to functions
52  *
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
57  * also changed - naim
58  *
59  * Revision 1.47  1997/04/21 16:56:15  hseom
60  * added support for trace data
61  *
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.
67  *
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
71  *
72  * Revision 1.44  1997/02/24 14:22:58  naim
73  * Minor fix to my previous commit - naim
74  *
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
78  *
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
83  *
84  * Revision 1.41  1997/01/15 01:11:34  tamches
85  * completely revamped fork & exec -- they now work for shm sampling.
86  *
87  * Revision 1.40  1996/11/14 14:28:01  naim
88  * Changing AstNodes back to pointers to improve performance - naim
89  *
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
93  * existing code.
94  *
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
99  *
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
103  *
104  */
105
106 #ifndef METRIC_H
107 #define METRIC_H
108
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"
118
119 #if defined(SHM_SAMPLING)
120 #include "paradynd/src/superTable.h"
121 #endif
122
123 class dataReqNode {
124  private:
125   // Since we don't define these, make sure they're not used:
126   dataReqNode &operator=(const dataReqNode &src);
127   dataReqNode (const dataReqNode &src);
128
129  protected:
130   dataReqNode() {}
131
132  public:
133   virtual ~dataReqNode() {};
134
135   virtual unsigned getInferiorPtr(process *proc=NULL) const = 0;
136   virtual unsigned getAllocatedIndex() const = 0;
137   virtual unsigned getAllocatedLevel() const = 0;
138
139   virtual int getSampleId() const = 0;
140
141   virtual bool insertInstrumentation(process *, metricDefinitionNode *, bool) = 0;
142      // Allocates stuff from inferior heap, instrumenting DYNINSTreportCounter
143      // as appropriate.  
144      // Returns true iff successful.
145
146   virtual void disable(process *,
147                        const vector< vector<unsigned> > &pointsToCheck) = 0;
148      // the opposite of insertInstrumentation.  Deinstruments, deallocates
149      // from inferior heap, etc.
150
151   virtual dataReqNode *dup(process *childProc, metricDefinitionNode *,
152                            int iCounterId,
153                            const dictionary_hash<instInstance*,instInstance*> &map
154                            ) const = 0;
155      // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
156
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).
160
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.
165 };
166
167 /*
168  * Classes derived from dataReqNode
169  *
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:
173  *
174  * A) classes used in _both_ shm_sampling and non-shm-sampling
175  *
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])
183  *
184  * B) classes used only when shm_sampling
185  *
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).
189  *
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)
193  *    
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)
197  *    
198  * C) classes used only when _not_ shm-sampling
199  *    
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
204  *       DYNINSTreportTimer
205  *
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.
211  *
212  */
213
214 #ifndef SHM_SAMPLING
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.
219  private:
220    // The following fields are always properly initialized in ctor:
221    int theSampleId;
222    int initialValue; // needed when dup()'ing
223
224    // The following fields are NULL until insertInstrumentation() called:   
225    intCounter *counterPtr;              /* NOT in our address space !!!! */
226    instInstance *sampler;               /* function to sample value */
227
228    // Since we don't use these, disallow:
229    sampledIntCounterReqNode &operator=(const sampledIntCounterReqNode &);
230    sampledIntCounterReqNode(const sampledIntCounterReqNode &);
231
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);
236
237    void writeToInferiorHeap(process *theProc, const intCounter &src) const;
238
239  public:
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.
245
246    dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
247                     const dictionary_hash<instInstance*,instInstance*> &map) const;
248
249    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
250       // allocates from inferior heap; initializes it; instruments
251       // DYNINSTsampleValues
252
253    void disable(process *, const vector< vector<unsigned> > &);
254
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;
260    }
261
262    unsigned getAllocatedIndex() const {assert(0); return 0;}
263    unsigned getAllocatedLevel() const {assert(0); return 0;}
264
265    int getSampleId() const {return theSampleId;}
266
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())
271 };
272 #endif
273
274 #ifdef SHM_SAMPLING
275 class sampledShmIntCounterReqNode : public dataReqNode {
276  // intCounter for use when shm-sampling.  Allocated in the shm segment heap.
277  // Sampled using shm sampling.
278  private:
279    // The following fields are always properly initialized in ctor:
280    int theSampleId; // obsolete with shm sampling; can be removed.
281
282    int initialValue; // needed when dup()'ing
283
284    // The following fields are NULL until insertInstrumentation() called:
285    unsigned allocatedIndex;
286    unsigned allocatedLevel;
287
288    unsigned position_;
289
290    // Since we don't use these, making them privates ensures they're not used.
291    sampledShmIntCounterReqNode &operator=(const sampledShmIntCounterReqNode &);
292    sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &);
293
294    // private fork-ctor called by dup():
295    sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &src,
296                                process *childProc, metricDefinitionNode *,
297                                int iCounterId, const process *parentProc);
298
299  public:
300    sampledShmIntCounterReqNode(int iValue, int iCounterId, 
301                                metricDefinitionNode *iMi, bool computingCost,
302                                bool doNotSample);
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.
307
308    dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
309                     const dictionary_hash<instInstance*,instInstance*> &) const;
310
311    bool insertInstrumentation(process *, metricDefinitionNode *, bool);
312       // allocates from inferior heap; initializes it, etc.
313
314    void disable(process *, const vector< vector<unsigned> > &);
315
316    unsigned getInferiorPtr(process *) const;
317
318    unsigned getAllocatedIndex() const {return allocatedIndex;}
319    unsigned getAllocatedLevel() const {return allocatedLevel;}
320
321    unsigned getPosition() const {return position_;}
322    int getSampleId() const {return theSampleId;}
323
324    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
325 };
326 #endif
327
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().
331  private:
332    // The following fields are always properly initialized in ctor:
333    int theSampleId;
334    int initialValue; // needed when dup()'ing
335
336    // The following is NULL until insertInstrumentation() called:   
337    intCounter *counterPtr;              /* NOT in our address space !!!! */
338
339    // Since we don't use these, disallow:
340    nonSampledIntCounterReqNode &operator=(const nonSampledIntCounterReqNode &);
341    nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &);
342
343    // private fork-ctor called by dup():
344    nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &src,
345                                process *childProc, metricDefinitionNode *,
346                                int iCounterId);
347
348    void writeToInferiorHeap(process *theProc, const intCounter &src) const;
349
350  public:
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.
357
358    dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
359                     const dictionary_hash<instInstance*,instInstance*> &) const;
360
361    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
362       // allocates from inferior heap; initializes it
363
364    void disable(process *, const vector< vector<unsigned> > &);
365
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;
371    }
372
373    unsigned getAllocatedIndex() const {assert(0); return 0;}
374    unsigned getAllocatedLevel() const {assert(0); return 0;}
375
376    int getSampleId() const {return theSampleId;}
377
378    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
379 };
380
381 #ifndef SHM_SAMPLING
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.
386  private:
387    // The following fields are always initialized in the ctor:   
388    int theSampleId;
389    timerType theTimerType;
390
391    // The following fields are NULL until insertInstrumentation():
392    tTimer *timerPtr;                    /* NOT in our address space !!!! */
393    instInstance *sampler;               /* function to sample value */
394
395    // since we don't use these, disallow:
396    sampledTimerReqNode(const sampledTimerReqNode &);
397    sampledTimerReqNode &operator=(const sampledTimerReqNode &);
398
399    // fork ctor:
400    sampledTimerReqNode(const sampledTimerReqNode &src, process *childProc,
401                        metricDefinitionNode *, int iCounterId,
402                        const dictionary_hash<instInstance*,instInstance*> &map);
403
404    void writeToInferiorHeap(process *theProc, const tTimer &dataSrc) const;
405
406  public:
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.
413
414    dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
415                     const dictionary_hash<instInstance*,instInstance*> &map) const;
416
417    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
418    void disable(process *, const vector< vector<unsigned> > &);
419
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;
425    }
426
427    unsigned getAllocatedIndex() const {assert(0); return 0;}
428    unsigned getAllocatedLevel() const {assert(0); return 0;}
429
430    int getSampleId() const {return theSampleId;}
431
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())
436 };
437 #endif
438
439 #ifdef SHM_SAMPLING
440 class sampledShmWallTimerReqNode : public dataReqNode {
441  // wall tTimer for use when shm sampling.  Allocated in the shm segment heap.
442  // Sampled using shm-sampling.
443  private:
444    // The following fields are always initialized in the ctor:   
445    int theSampleId;
446
447    // The following fields are NULL until insertInstrumentatoin():
448    unsigned allocatedIndex;
449    unsigned allocatedLevel;
450
451    unsigned position_;
452
453    // since we don't use these, disallow:
454    sampledShmWallTimerReqNode(const sampledShmWallTimerReqNode &);
455    sampledShmWallTimerReqNode &operator=(const sampledShmWallTimerReqNode &);
456
457    // fork ctor:
458    sampledShmWallTimerReqNode(const sampledShmWallTimerReqNode &src, 
459                               process *childProc,
460                               metricDefinitionNode *, int iCounterId,
461                               const process *parentProc);
462
463  public:
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.
470
471    dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
472                     const dictionary_hash<instInstance*,instInstance*> &) const;
473
474    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
475    void disable(process *, const vector< vector<unsigned> > &);
476
477    unsigned getInferiorPtr(process *) const;
478
479    unsigned getAllocatedIndex() const {return allocatedIndex;}
480    unsigned getAllocatedLevel() const {return allocatedLevel;}
481
482    unsigned getPosition() const {return position_;}
483
484    int getSampleId() const {return theSampleId;}
485
486    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
487 };
488
489 class sampledShmProcTimerReqNode : public dataReqNode {
490  // process tTimer for use when shm sampling.  Allocated in the shm segment heap.
491  // Sampled using shm-sampling.
492  private:
493    // The following fields are always initialized in the ctor:   
494    int theSampleId;
495
496    // The following fields are NULL until insertInstrumentatoin():
497    unsigned allocatedIndex;
498    unsigned allocatedLevel;
499
500    unsigned position_;
501
502    // since we don't use these, disallow:
503    sampledShmProcTimerReqNode(const sampledShmProcTimerReqNode &);
504    sampledShmProcTimerReqNode &operator=(const sampledShmProcTimerReqNode &);
505
506    // fork ctor:
507    sampledShmProcTimerReqNode(const sampledShmProcTimerReqNode &src, 
508                               process *childProc,
509                               metricDefinitionNode *, int iCounterId,
510                               const process *parentProc);
511
512  public:
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.
519
520    dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
521                     const dictionary_hash<instInstance*,instInstance*> &) const;
522
523    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
524    void disable(process *, const vector< vector<unsigned> > &);
525
526    unsigned getInferiorPtr(process *) const;
527
528    unsigned getAllocatedIndex() const {return allocatedIndex;}
529    unsigned getAllocatedLevel() const {return allocatedLevel;}
530
531    unsigned getPosition() const {return position_;}
532
533    int getSampleId() const {return theSampleId;}
534
535    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
536 };
537 #endif
538
539 /* ************************************************************************ */
540
541 class instReqNode {
542 public:
543   instReqNode(instPoint*, AstNode *, callWhen, callOrder order,
544               bool iManuallyTrigger);
545  ~instReqNode();
546
547   instReqNode() {
548      // needed by Vector class
549      ast = NULL; point=NULL; instance = NULL; manuallyTrigger = false;
550   }
551
552   instReqNode(const instReqNode &src) {
553      point = src.point;
554      when = src.when;
555      order = src.order;
556      instance = src.instance;
557      ast = assignAst(src.ast);
558      manuallyTrigger = src.manuallyTrigger;
559   }
560   instReqNode &operator=(const instReqNode &src) {
561      if (this == &src)
562         return *this;
563
564      point = src.point;
565      ast = assignAst(src.ast);
566      when = src.when;
567      order = src.order;
568      instance = src.instance;
569      manuallyTrigger = src.manuallyTrigger;
570
571      return *this;
572   }
573
574   bool insertInstrumentation(process *theProc,
575                              returnInstance *&retInstance);
576
577   void disable(const vector<unsigned> &pointsToCheck);
578   float cost(process *theProc) const;
579
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.
583
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.
589
590   instInstance *getInstance() const { return instance; }
591
592   bool anythingToManuallyTrigger() const {return manuallyTrigger;}
593   bool triggerNow(process *theProc);
594
595 private:
596   instPoint     *point;
597   AstNode       *ast;
598   callWhen      when;
599   callOrder     order;
600   instInstance  *instance; // undefined until insertInstrumentation() calls addInstFunc
601   bool manuallyTrigger;
602      // if true, then 'ast' is manually executed (inferiorRPC) when
603      // inserting instrumentation.
604 };
605
606
607 /*
608    metricDefinitionNode describe metric instances. There are two types of
609    nodes: aggregates and non-aggregates (Maybe this class should be divided in
610    two).
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 
616    processes start).
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.
621 */
622 class metricDefinitionNode {
623 friend int startCollecting(string&, vector<u_int>&, int id, 
624                            vector<process *> &procsToContinue); // called by dynrpc.C
625
626  private:
627    /* unique id for a counter or timer */
628    static int counterId;
629
630 public:
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
637
638   metricDefinitionNode(const string& metric_name, const vector< vector<string> >& foc,
639                        const string& cat_name,
640                        vector<metricDefinitionNode*>& parts,
641                        int agg_op);
642      // for aggregate (not component) mdn's
643
644   ~metricDefinitionNode();
645   void disable();
646   void cleanup_drn();
647   void updateValue(time64, sampleValue);
648   void forwardSimpleValue(timeStamp, timeStamp, sampleValue,unsigned,bool);
649
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;
657   }
658
659   process *proc() const { return proc_; }
660
661   bool nonNull() const { return (instRequests.size() || dataRequests.size()); }
662   bool insertInstrumentation();
663
664   float cost() const;
665   bool checkAndInstallInstrumentation();
666
667   float originalCost() const { return originalCost_; }
668
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, 
679                       callOrder o,
680                       bool manuallyTrigger);
681
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);  
685
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.
700
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.
707
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
713      // the system.
714
715   // remove an instance from an aggregate metric
716   void removeThisInstance();
717
718   bool anythingToManuallyTrigger() const;
719
720   void manuallyTrigger();
721
722 private:
723   // Since we don't define these, make sure they're not used:
724   metricDefinitionNode &operator=(const metricDefinitionNode &src);
725   metricDefinitionNode(const metricDefinitionNode &src);
726
727   void removeComponent(metricDefinitionNode *comp);
728   void endOfDataCollection();
729   void removeFromAggregate(metricDefinitionNode *comp);
730
731   void updateAggregateComponent();
732
733   bool                  aggregate_;
734   int aggOp; // the aggregate operator
735   bool                  inserted_;
736   bool                  installed_;
737   string met_;                  // what type of metric
738   vector< vector<string> > focus_;
739   vector< vector<string> > component_focus; // defined for component mdn's only
740   string flat_name_;
741
742   /* for aggregate metrics */
743   vector<metricDefinitionNode*>   components;   
744   aggregateSample aggSample;    // current aggregate value
745
746   /* for non-aggregate metrics */
747   vector<dataReqNode*>  dataRequests;
748
749   vector<instReqNode> instRequests;
750   vector<returnInstance *> returnInsts;
751
752   sampleValue cumulativeValue; // cumulative value for this metric
753
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).
759
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].
764
765   int id_;                              // unique id for this one 
766   float originalCost_;
767
768   process *proc_;
769
770   string metric_name_;
771   metricStyle style_; 
772
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.
776 };
777
778 inline void metricDefinitionNode::addInst(instPoint *point, AstNode *ast,
779                                           callWhen when,
780                                           callOrder o,
781                                           bool manuallyTrigger) {
782   if (!point) return;
783
784   instReqNode temp(point, ast, when, o, manuallyTrigger);
785   instRequests += temp;
786 };
787
788 // allMIs: all aggregate (as opposed to component) metricDefinitionNodes
789 extern dictionary_hash<unsigned, metricDefinitionNode*> allMIs;
790
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;
794
795 extern double currentPredictedCost;
796
797 #ifndef SHM_SAMPLING
798 extern void processCost(process *proc, traceHeader *h, costUpdate *s);
799 #endif
800
801 extern void reportInternalMetrics(bool force);
802
803 /*
804  * Routines to control data collection.
805  *
806  * focus                - a list of resources
807  * metricName           - what metric to collect data for
808  * id                   - metric id
809  * procsToContinue      - a list of processes that had to be stopped to insert
810  *                        instrumentation. The caller must continue these processes.
811  */
812 int startCollecting(string& metricName, vector<u_int>& focus, int id,
813                     vector<process *> &procsToContinue); 
814
815 /*
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).
819  */
820 float guessCost(string& metric_name, vector<u_int>& focus);
821
822
823 /*
824  * process a sample ariving from an inferior process
825  *
826  */
827 #ifndef SHM_SAMPLING
828 void processSample(int pid, traceHeader*, traceSample *);
829 #endif
830
831 #endif