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