change initialization variable for int counter metrics to a 64 bit integer
[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 // $Id: metricFocusNode.h,v 1.66 2001/01/16 22:26:21 schendel Exp $ 
43
44 #ifndef METRIC_H
45 #define METRIC_H
46
47 #include "common/h/String.h"
48 // trace data streams
49 #include "pdutil/h/ByteArray.h"
50 #include "common/h/Vector.h"
51 #include "common/h/Dictionary.h"
52 #include "pdutil/h/aggregateSample.h"
53 #include "dyninstAPI/src/ast.h"
54 #include "dyninstAPI/src/util.h"
55 #include "rtinst/h/trace.h"
56 #include "dyninstAPI/src/inst.h" // for "enum callWhen"
57 #include "dyninstRPC.xdr.SRVR.h" // for flag_cons
58 #include "common/h/Time.h"
59
60 class instInstance; // enough since we only use instInstance* in this file
61 #if defined(MT_THREAD)
62 class pdThread; // enough since we only use pdThread* in this file
63 #endif
64
65 #if defined(SHM_SAMPLING)
66 #include "paradynd/src/superTable.h"
67 #endif
68
69 class dataReqNode {
70  private:
71   // Since we don't define these, make sure they're not used:
72   dataReqNode &operator=(const dataReqNode &src);
73   dataReqNode (const dataReqNode &src);
74
75  protected:
76   dataReqNode() {}
77
78  public:
79   virtual ~dataReqNode() {};
80
81   virtual Address getInferiorPtr(process *proc=NULL) const = 0;
82   virtual unsigned getAllocatedIndex() const = 0;
83   virtual unsigned getAllocatedLevel() const = 0;
84
85   virtual int getSampleId() const = 0;
86
87 #if defined(MT_THREAD)
88   virtual int getThreadId() const = 0;
89   virtual bool insertInstrumentation(pdThread *, process *, metricDefinitionNode *, bool) = 0;
90 #else 
91   virtual bool insertInstrumentation(process *, metricDefinitionNode *, bool) = 0;
92 #endif
93      // Allocates stuff from inferior heap, instrumenting DYNINSTreportCounter
94      // as appropriate.  
95      // Returns true iff successful.
96
97   virtual void disable(process *,
98                        const vector< vector<Address> > &pointsToCheck) = 0;
99      // the opposite of insertInstrumentation.  Deinstruments, deallocates
100      // from inferior heap, etc.
101
102   virtual dataReqNode *dup(process *childProc, metricDefinitionNode *,
103                            int iCounterId,
104                            const dictionary_hash<instInstance*,instInstance*> &map
105                            ) const = 0;
106      // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
107
108      // "map" provides a dictionary that maps instInstance's of the parent process to
109      // those in the child process; dup() may find it useful. (for now, the shm
110      // dataReqNodes have no need for it; the alarm sampled ones need it).
111
112   virtual bool unFork(dictionary_hash<instInstance*,instInstance*> &map) = 0;
113      // the fork syscall duplicates all instrumentation (except on AIX), which is a
114      // problem when we determine that a certain mi shouldn't be propagated to the child
115      // process.  Hence this routine.
116 };
117
118 /*
119  * Classes derived from dataReqNode
120  *
121  * There are a lot of classes derived from dataReqNode, so things can get a little
122  * confusing.  Most of them are used in either shm_sampling mode or not; few are
123  * used in both.  Here's a bit of documentation that should sort things out:
124  *
125  * A) classes used in _both_ shm_sampling and non-shm-sampling
126  *
127  *    nonSampledIntCounterReqNode --
128  *       provides an intCounter value that is never sampled.  Currently useful
129  *       for predicates (constraint booleans).  The intCounter is allocated from
130  *       the "conventional" heap (where tramps are allocated) using good old
131  *       inferiorMalloc(), even when shm_sampling.
132  *       (In the future, we may provide a separate shm_sampling version, to make
133  *       allocation faster [allocation in the shm seg heap is always faster])
134  *
135  * B) classes used only when shm_sampling
136  *
137  *    shmSampledIntCounterReqNode --
138  *       provides an intCounter value that is sampled with shm sampling.  The
139  *       intCounter is allocated from the shm segment (i.e., not with inferiorMalloc).
140  *
141  *    shmSampledWallTimerReqNode --
142  *       provides a wall timer value that is sampled with shm sampling.  The tTimer is
143  *       allocated from the shm segment (i.e., not with inferiorMalloc)
144  *    
145  *    shmSampledProcTimerReqNode --
146  *       provides a process timer value that is sampled with shm sampling.  The tTimer
147  *       is allocated from the shm segment (i.e., not with inferiorMalloc)
148  *    
149  * C) classes used only when _not_ shm-sampling
150  *    
151  *    alarmSampledIntCounterReqNode --
152  *       provides an intCounter value that is sampled.  The intCounter is allocated
153  *       in the conventional heap with inferiorMalloc().  Sampling is done the
154  *       old-fasioned SIGALRM way: by instrumenting DYNINSTsampleValues to call
155  *       DYNINSTreportTimer
156  *
157  *    alarmSampledTimerReqNode --
158  *       provides a tTimer value (can be wall or process timer) that is sampled.  The
159  *       tTimer is allocated in the conventional heap with inferiorMalloc().  Sampling
160  *       is done the old-fasioned SIGALRM way: by instrumenting DYNINSTsampleValues to
161  *       call DYNINSTreportTimer.
162  *
163  */
164
165 #ifndef SHM_SAMPLING
166 class sampledIntCounterReqNode : public dataReqNode {
167  // intCounter for use when not shm sampling.  Allocated in the conventional heap
168  // with inferiorMalloc().  Sampled the old-fasioned way: by instrumenting
169  // DYNINSTsampleValues() to call DYNINSTreportCounter.
170  private:
171    // The following fields are always properly initialized in ctor:
172    int theSampleId;
173    rawTime64 initialValue; // needed when dup()'ing
174
175    // The following fields are NULL until insertInstrumentation() called:   
176    intCounter *counterPtr;              /* NOT in our address space !!!! */
177    instInstance *sampler;               /* function to sample value */
178
179    // Since we don't use these, disallow:
180    sampledIntCounterReqNode &operator=(const sampledIntCounterReqNode &);
181    sampledIntCounterReqNode(const sampledIntCounterReqNode &);
182
183    // private fork-ctor called by dup():
184    sampledIntCounterReqNode(const sampledIntCounterReqNode &src,
185                             process *childProc, metricDefinitionNode *, int iCounterId,
186                             const dictionary_hash<instInstance*,instInstance*> &map);
187
188    void writeToInferiorHeap(process *theProc, const intCounter &src) const;
189
190  public:
191    sampledIntCounterReqNode(rawTime64 iValue, int iCounterId,
192                             metricDefinitionNode *iMi, bool computingCost);
193   ~sampledIntCounterReqNode() {}
194       // Hopefully, disable() has already been called.  A bit of a complication
195       // since disable() needs an arg passed, which we can't do here.  Too bad.
196
197    dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
198                     const dictionary_hash<instInstance*,instInstance*> &map) const;
199
200 #if defined(MT_THREAD)
201    bool insertInstrumentation(pdThread *, process *, metricDefinitionNode *, bool doNotSample=false);
202 #else
203    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
204 #endif
205       // allocates from inferior heap; initializes it; instruments
206       // DYNINSTsampleValues
207
208    void disable(process *, const vector< vector<Address> > &);
209
210    Address getInferiorPtr(process *) const {
211       // counterPtr could be NULL if we are building AstNodes just to compute
212       // the cost - naim 2/18/97
213       //assert(counterPtr != NULL); // NULL until insertInstrumentation()
214       return (Address)counterPtr;
215    }
216
217    unsigned getAllocatedIndex() const {assert(0); return 0;}
218    unsigned getAllocatedLevel() const {assert(0); return 0;}
219
220    int getSampleId() const {return theSampleId;}
221 #if defined(MT_THREAD)
222    int getThreadId() const {assert(0); return 0;}
223 #endif
224
225    bool unFork(dictionary_hash<instInstance*,instInstance*> &map);
226      // the fork syscall duplicates all instrumentation (except on AIX), which is a
227      // problem when we determine that a certain mi shouldn't be propagated to the child
228      // process.  Hence this routine (to remove unwanted instr of DYNINSTsampleValues())
229 };
230 #endif
231
232 #ifdef SHM_SAMPLING
233 class sampledShmIntCounterReqNode : public dataReqNode {
234  // intCounter for use when shm-sampling.  Allocated in the shm segment heap.
235  // Sampled using shm sampling.
236  private:
237    // The following fields are always properly initialized in ctor:
238    int theSampleId; // obsolete with shm sampling; can be removed.
239 #if defined(MT_THREAD)
240    pdThread *thr_;
241 #endif
242
243    rawTime64 initialValue; // needed when dup()'ing
244
245    // The following fields are NULL until insertInstrumentation() called:
246    unsigned allocatedIndex;
247    unsigned allocatedLevel;
248
249    unsigned position_;
250
251    // Since we don't use these, making them privates ensures they're not used.
252    sampledShmIntCounterReqNode &operator=(const sampledShmIntCounterReqNode &);
253    sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &);
254
255    // private fork-ctor called by dup():
256    sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &src,
257                                process *childProc, metricDefinitionNode *,
258                                int iCounterId, const process *parentProc);
259
260  public:
261 #if defined(MT_THREAD)
262    sampledShmIntCounterReqNode(pdThread *thr, rawTime64 iValue, int iCounterId,
263                                metricDefinitionNode *iMi, bool computingCost,
264                                bool doNotSample, unsigned, unsigned);
265 #else
266    sampledShmIntCounterReqNode(rawTime64 iValue, int iCounterId,
267                                 metricDefinitionNode *iMi, bool computingCost,
268                                 bool doNotSample);
269 #endif
270   ~sampledShmIntCounterReqNode() {}
271       // Hopefully, disable() has already been called.
272       // A bit of a complication since disable() needs an
273       // arg passed, which we can't do here.  Too bad.
274
275    dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
276                     const dictionary_hash<instInstance*,instInstance*> &) const;
277
278 #if defined(MT_THREAD)
279    bool insertInstrumentation(pdThread *, process *, metricDefinitionNode *, bool);
280 #else
281    bool insertInstrumentation(process *, metricDefinitionNode *, bool);
282 #endif
283       // allocates from inferior heap; initializes it, etc.
284
285    void disable(process *, const vector< vector<Address> > &);
286
287    Address getInferiorPtr(process *) const;
288
289    unsigned getAllocatedIndex() const {return allocatedIndex;}
290    unsigned getAllocatedLevel() const {return allocatedLevel;}
291
292    unsigned getPosition() const {return position_;}
293    int getSampleId() const {return theSampleId;}
294 #if defined(MT_THREAD)
295    int getThreadId() const;
296    pdThread *getThread() {return thr_;}
297 #endif
298
299    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
300 };
301 #endif
302
303 class nonSampledIntCounterReqNode : public dataReqNode {
304  // intCounter for predicates (because they don't need to be sampled).
305  // Allocated in the conventional heap with inferiorMalloc().
306  private:
307    // The following fields are always properly initialized in ctor:
308    int theSampleId;
309    rawTime64 initialValue; // needed when dup()'ing
310
311    // The following is NULL until insertInstrumentation() called:   
312    intCounter *counterPtr;              /* NOT in our address space !!!! */
313
314    // Since we don't use these, disallow:
315    nonSampledIntCounterReqNode &operator=(const nonSampledIntCounterReqNode &);
316    nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &);
317
318    // private fork-ctor called by dup():
319    nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &src,
320                                process *childProc, metricDefinitionNode *,
321                                int iCounterId);
322
323    void writeToInferiorHeap(process *theProc, const intCounter &src) const;
324
325  public:
326    nonSampledIntCounterReqNode(rawTime64 iValue, int iCounterId,
327                                metricDefinitionNode *iMi, bool computingCost);
328   ~nonSampledIntCounterReqNode() {}
329       // Hopefully, disable() has already been called.
330       // A bit of a complication since disable() needs an
331       // arg passed, which we can't do here.  Too bad.
332
333    dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
334                     const dictionary_hash<instInstance*,instInstance*> &) const;
335
336 #if defined(MT_THREAD)
337    bool insertInstrumentation(pdThread *, process *, metricDefinitionNode *, bool doNotSample=false);
338 #else
339    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
340 #endif
341       // allocates from inferior heap; initializes it
342
343    void disable(process *, const vector< vector<Address> > &);
344
345    Address getInferiorPtr(process *) const {
346       //assert(counterPtr != NULL); // NULL until insertInstrumentation()
347       // counterPtr could be NULL if we are building AstNodes just to compute
348       // the cost - naim 2/18/97
349       return (Address)counterPtr;
350    }
351
352    unsigned getAllocatedIndex() const {assert(0); return 0;}
353    unsigned getAllocatedLevel() const {assert(0); return 0;}
354
355    int getSampleId() const {return theSampleId;}
356 #if defined(MT_THREAD)
357    int getThreadId() const {assert(0); return 0;}
358 #endif
359
360    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
361 };
362
363 #ifndef SHM_SAMPLING
364 class sampledTimerReqNode : public dataReqNode {
365  // tTimer for use when not shm sampling.  Allocated in the conventional heap with
366  // inferiorMalloc().  Sampled the old-fasioned way: by instrumenting
367  // DYNINSTsampleValues to call DYNINSTreportTimer.
368  private:
369    // The following fields are always initialized in the ctor:   
370    int theSampleId;
371    timerType theTimerType;
372
373    // The following fields are NULL until insertInstrumentation():
374    tTimer *timerPtr;                    /* NOT in our address space !!!! */
375    instInstance *sampler;               /* function to sample value */
376
377    // since we don't use these, disallow:
378    sampledTimerReqNode(const sampledTimerReqNode &);
379    sampledTimerReqNode &operator=(const sampledTimerReqNode &);
380
381    // fork ctor:
382    sampledTimerReqNode(const sampledTimerReqNode &src, process *childProc,
383                        metricDefinitionNode *, int iCounterId,
384                        const dictionary_hash<instInstance*,instInstance*> &map);
385
386    void writeToInferiorHeap(process *theProc, const tTimer &dataSrc) const;
387
388  public:
389    sampledTimerReqNode(timerType iType, int iCounterId,
390                        metricDefinitionNode *iMi, bool computingCost);
391   ~sampledTimerReqNode() {}
392       // hopefully, freeInInferior() has already been called
393       // a bit of a complication since freeInInferior() needs an
394       // arg passed, which we can't do here.  Too bad.
395
396    dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
397                     const dictionary_hash<instInstance*,instInstance*> &map) const;
398
399 #if defined(MT_THREAD)
400    bool insertInstrumentation(pdThread *, process *, metricDefinitionNode *, bool doNotSample=false);
401 #else
402    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
403 #endif
404    void disable(process *, const vector< vector<Address> > &);
405
406    Address getInferiorPtr(process *) const {
407       // counterPtr could be NULL if we are building AstNodes just to compute
408       // the cost - naim 2/18/97
409       //assert(timerPtr != NULL); // NULL until insertInstrumentation()
410       return (Address)timerPtr;
411    }
412
413    unsigned getAllocatedIndex() const {assert(0); return 0;}
414    unsigned getAllocatedLevel() const {assert(0); return 0;}
415
416    int getSampleId() const {return theSampleId;}
417 #if defined(MT_THREAD)
418    int getThreadId() const {assert(0); return 0;}
419 #endif
420
421    bool unFork(dictionary_hash<instInstance*,instInstance*> &map);
422      // the fork syscall duplicates all instrumentation (except on AIX), which is a
423      // problem when we determine that a certain mi shouldn't be propagated to the child
424      // process.  Hence this routine (to remove unwanted instr of DYNINSTsampleValues())
425 };
426 #endif
427
428 #ifdef SHM_SAMPLING
429 class sampledShmWallTimerReqNode : public dataReqNode {
430  // wall tTimer for use when shm sampling.  Allocated in the shm segment heap.
431  // Sampled using shm-sampling.
432  private:
433    // The following fields are always initialized in the ctor:   
434    int theSampleId;
435 #if defined(MT_THREAD)
436    pdThread *thr_;
437 #endif
438
439    // The following fields are NULL until insertInstrumentatoin():
440    unsigned allocatedIndex;
441    unsigned allocatedLevel;
442
443    unsigned position_;
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, 
451                               process *childProc,
452                               metricDefinitionNode *, int iCounterId,
453                               const process *parentProc);
454
455  public:
456 #if defined(MT_THREAD)
457    sampledShmWallTimerReqNode(pdThread *thr, int iCounterId,
458                               metricDefinitionNode *iMi, bool computingCost,
459                               unsigned, unsigned);
460 #else
461    sampledShmWallTimerReqNode(int iCounterId,
462                               metricDefinitionNode *iMi, bool computingCost);
463 #endif
464   ~sampledShmWallTimerReqNode() {}
465       // hopefully, freeInInferior() has already been called
466       // a bit of a complication since freeInInferior() needs an
467       // arg passed, which we can't do here.  Too bad.
468
469    dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
470                     const dictionary_hash<instInstance*,instInstance*> &) const;
471
472 #if defined(MT_THREAD)
473    bool insertInstrumentation(pdThread *, process *, metricDefinitionNode *, bool doNotSample=false);
474 #else
475    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
476 #endif
477    void disable(process *, const vector< vector<Address> > &);
478
479    Address getInferiorPtr(process *) const;
480
481    unsigned getAllocatedIndex() const {return allocatedIndex;}
482    unsigned getAllocatedLevel() const {return allocatedLevel;}
483
484    unsigned getPosition() const {return position_;}
485
486    int getSampleId() const {return theSampleId;}
487 #if defined(MT_THREAD)
488    int getThreadId() const;
489    pdThread *getThread() {return thr_;}
490 #endif
491
492    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
493 };
494
495 class sampledShmProcTimerReqNode : public dataReqNode {
496  // process tTimer for use when shm sampling.  Allocated in the shm segment heap.
497  // Sampled using shm-sampling.
498  private:
499    // The following fields are always initialized in the ctor:   
500    int theSampleId;
501 #if defined(MT_THREAD)
502    pdThread *thr_;
503 #endif
504
505    // The following fields are NULL until insertInstrumentatoin():
506    unsigned allocatedIndex;
507    unsigned allocatedLevel;
508
509    unsigned position_;
510
511    // since we don't use these, disallow:
512    sampledShmProcTimerReqNode(const sampledShmProcTimerReqNode &);
513    sampledShmProcTimerReqNode &operator=(const sampledShmProcTimerReqNode &);
514
515    // fork ctor:
516    sampledShmProcTimerReqNode(const sampledShmProcTimerReqNode &src, 
517                               process *childProc,
518                               metricDefinitionNode *, int iCounterId,
519                               const process *parentProc);
520
521  public:
522 #if defined(MT_THREAD)
523    sampledShmProcTimerReqNode(pdThread *thr, int iCounterId,
524                               metricDefinitionNode *iMi, bool computingCost,
525                               unsigned, unsigned);
526 #else
527    sampledShmProcTimerReqNode(int iCounterId,
528                              metricDefinitionNode *iMi, bool computingCost);
529 #endif
530   ~sampledShmProcTimerReqNode() {}
531       // hopefully, freeInInferior() has already been called
532       // a bit of a complication since freeInInferior() needs an
533       // arg passed, which we can't do here.  Too bad.
534
535    dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
536                     const dictionary_hash<instInstance*,instInstance*> &) const;
537
538 #if defined(MT_THREAD)
539    bool insertInstrumentation(pdThread *, process *, metricDefinitionNode *, bool doNotSample=false);
540 #else
541    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
542 #endif
543    void disable(process *, const vector< vector<Address> > &);
544
545    Address getInferiorPtr(process *) const;
546
547    unsigned getAllocatedIndex() const {return allocatedIndex;}
548    unsigned getAllocatedLevel() const {return allocatedLevel;}
549
550    unsigned getPosition() const {return position_;}
551
552    int getSampleId() const {return theSampleId;}
553 #if defined(MT_THREAD)
554    int getThreadId() const;
555    pdThread *getThread() {return thr_;}
556 #endif
557
558    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
559 };
560 #endif
561
562 /* ************************************************************************ */
563
564 class instReqNode {
565 public:
566   instReqNode(instPoint*, AstNode *, callWhen, callOrder order);
567  ~instReqNode();
568
569   instReqNode() {
570      // needed by Vector class
571      ast = NULL; point=NULL; instance = NULL; rinstance = NULL;
572   }
573
574   instReqNode(const instReqNode &src) {
575      point = src.point;
576      when = src.when;
577      order = src.order;
578      instance = src.instance;
579      rinstance = src.rinstance;
580      ast = assignAst(src.ast);
581   }
582   instReqNode &operator=(const instReqNode &src) {
583      if (this == &src)
584         return *this;
585
586      point = src.point;
587      ast = assignAst(src.ast);
588      when = src.when;
589      order = src.order;
590      instance = src.instance;
591      rinstance = src.rinstance;
592
593      return *this;
594   }
595
596   bool insertInstrumentation(process *theProc,
597                              returnInstance *&retInstance);
598
599   void disable(const vector<Address> &pointsToCheck);
600   timeLength cost(process *theProc) const;
601
602   static instReqNode forkProcess(const instReqNode &parent,
603                                  const dictionary_hash<instInstance*,instInstance*> &);
604      // should become a copy-ctor...or at least, a non-static member fn.
605
606   bool unFork(dictionary_hash<instInstance*, instInstance*> &map) const;
607      // The fork syscall duplicates all trampolines from the parent into the child. For
608      // those mi's which we don't want to propagate to the child, this creates a
609      // problem.  We need to remove instrumentation code from the child.  This routine
610      // does that.  "map" maps instInstances of the parent to those in the child.
611
612   instInstance *getInstance() const { return instance; }
613   returnInstance *getRInstance() const { return rinstance; }
614
615 #if defined(MT_THREAD)
616   bool triggerNow(process *theProc, int mid, int thrId);
617 #else
618   bool triggerNow(process *theProc, int mid);
619 #endif
620   static void triggerNowCallbackDispatch(process * /*theProc*/,
621                                                     void *userData, void *returnValue)
622           { ((instReqNode*)userData)->triggerNowCallback( returnValue ); }
623   void triggerNowCallback(void *returnValue);
624
625   bool triggeredInStackFrame(pd_Function *stack_fn,
626                              Address pc,
627                              process *p);
628   
629   instPoint *Point() {return point;}
630   AstNode* Ast()  {return ast;}
631   callWhen When() {return when;}
632
633 private:
634   instPoint     *point;
635   AstNode       *ast;
636   callWhen      when;
637   callOrder     order;
638   instInstance  *instance; // undefined until insertInstrumentation() calls addInstFunc
639   returnInstance *rinstance;
640
641   // Counts the number of rpcs which have successfully completed 
642   // for this node.  This is needed because we may need to manually 
643   // trigger multiple times for recursive functions.
644   int rpcCount;
645 #if defined(MT_THREAD)
646   vector<int> manuallyTriggerTIDs;
647 #endif
648 };
649
650 #if defined(MT_THREAD)
651 typedef enum {AGG_COMP, PROC_COMP, THR_COMP} AGG_LEVEL;
652 #endif
653
654 /*
655    metricDefinitionNode describe metric instances. There are two types of
656    nodes: aggregates and non-aggregates (Maybe this class should be divided in
657    two).
658    Aggregate nodes represent a metric instance with one or more components.
659    Each component is represented by a non-aggregate metricDefinitionNode, and
660    is associated with a different process.
661    All metric instance have an aggregate metricDefinitionNode, even if it has 
662    only one component (this simplifies doing metric propagation when new 
663    processes start).
664    Components can be shared by two or more aggregate metricDefinitionNodes, 
665    so for example if there are two metric/focus pairs enabled, cpu time for
666    the whole program and cpu time for process p, there will be one non-aggregate
667    instance shared between two aggregate metricDefinitionNodes.
668 */
669 class metricDefinitionNode {
670 friend timeLength guessCost(string& metric_name, vector<u_int>& focus) ;
671 friend int startCollecting(string&, vector<u_int>&, int id, 
672                            vector<process *> &procsToContinue); // called by dynrpc.C
673
674  private:
675    /* unique id for a counter or timer */
676    static int counterId;
677
678 public:
679   // styles are enumerated in aggregation.h
680 #if defined(MT_THREAD)
681   metricDefinitionNode(process *p, const string& metric_name, 
682                        const vector< vector<string> >& foc,
683                        const vector< vector<string> >& component_foc,
684                        const string& component_flat_name, 
685                        metricStyle metric_style, int agg_style = aggSum,
686                        AGG_LEVEL agg_level = PROC_COMP);
687 #else
688   metricDefinitionNode(process *p, const string& metric_name, 
689                        const vector< vector<string> >& foc,
690                        const vector< vector<string> >& component_foc,
691                        const string& component_flat_name, 
692                        metricStyle metric_style, int agg_style = aggSum);
693 #endif
694      // for component (per-process) (non-aggregate) mdn's
695
696 #if defined(MT_THREAD)
697   metricDefinitionNode(const string& metric_name, 
698                        const vector< vector<string> >& foc,
699                        const string& cat_name,
700                        vector<metricDefinitionNode*>& parts,
701                        metricStyle metric_style, int agg_op, 
702                        AGG_LEVEL agg_level = AGG_COMP);
703 #else
704   metricDefinitionNode(const string& metric_name, const vector< vector<string> >& foc,
705                        const string& cat_name,
706                        vector<metricDefinitionNode*>& parts,
707                        metricStyle metric_style, int agg_op);
708 #endif
709      // for aggregate (not component) mdn's
710
711   ~metricDefinitionNode();
712   void disable();
713   void cleanup_drn();
714   void updateValue(timeStamp, pdSample);
715   void forwardSimpleValue(timeStamp, timeStamp, pdSample,unsigned,bool);
716
717   int getMId() const { return id_; }
718   const string &getMetName() const { return met_; }
719   const string &getFullName() const { return flat_name_; }
720   const vector< vector<string> > &getFocus() const {return focus_;}
721   const vector< vector<string> > &getComponentFocus() const {
722 #if defined(MT_THREAD)
723      assert(aggLevel != AGG_COMP);
724 #else
725      assert(!aggregate_); // defined for component mdn's only
726 #endif
727      return component_focus;
728   }
729
730   process *proc() const { return proc_; }
731
732 #if defined(MT_THREAD)
733   void reUseIndexAndLevel(unsigned &p_allocatedIndex, unsigned &p_allocatedLevel);
734   void addParts(vector<metricDefinitionNode*>& parts);
735   void addPart(metricDefinitionNode* part);
736   vector<metricDefinitionNode *>& getComponents() { return components; }
737   AGG_LEVEL getLevel() { return aggLevel; }
738   vector<dataReqNode *> getDataRequests() { return dataRequests; }
739   void addThread(pdThread *thr);
740   void deleteThread(pdThread *thr);
741   void duplicateInst(metricDefinitionNode *from, metricDefinitionNode *to);
742   void duplicateInst(metricDefinitionNode *mn) ;
743
744   // data required to add threads - naim
745   unsigned type_thr;
746   vector<string> *temp_ctr_thr;
747   vector<T_dyninstRPC::mdl_constraint*> flag_cons_thr;
748   bool computingCost_thr;
749   T_dyninstRPC::mdl_constraint*  base_use_thr;
750 #else
751   bool is_aggregate(void) { return aggregate_; } 
752 #endif
753   bool nonNull() const { return (instRequests.size() || dataRequests.size()); }
754   bool insertInstrumentation();
755
756   timeLength cost() const;
757   bool checkAndInstallInstrumentation();
758
759   timeLength originalCost() const { return originalCost_; }
760
761   // The following routines are (from the outside world's viewpoint)
762   // the heart of it all.  They append to dataRequets or instRequests, so that
763   // a future call to metricDefinitionNode::insertInstrumentation() will
764   // "do their thing".  The MDL calls these routines.
765 #if defined(MT_THREAD)
766   dataReqNode *addSampledIntCounter(pdThread *thr, rawTime64 initialValue, 
767                                     bool computingCost,
768                                     bool doNotSample=false);
769 #else
770   dataReqNode *addSampledIntCounter(rawTime64 initialValue, bool computingCost,
771                                      bool doNotSample=false);
772 #endif
773   dataReqNode *addUnSampledIntCounter(rawTime64 initialValue, bool computingCost);
774 #if defined(MT_THREAD)
775   dataReqNode *addWallTimer(bool computingCost, pdThread *thr=NULL);
776   dataReqNode *addProcessTimer(bool computingCost, pdThread *thr=NULL);
777 #else
778   dataReqNode *addWallTimer(bool computingCost);
779   dataReqNode *addProcessTimer(bool computingCost);
780 #endif
781   inline void addInst(instPoint *point, AstNode *, callWhen when, 
782                       callOrder o);
783
784   // propagate this aggregate mi to a newly started process p (not for processes
785   // started via fork or exec, just for those started "normally")
786   void propagateToNewProcess(process *p);  
787
788   metricDefinitionNode *forkProcess(process *child,
789                                     const dictionary_hash<instInstance*,instInstance*> &map) const;
790      // called when it's determined that an mi should be propagated from the
791      // parent to the child.  "this" is a component mi, not an aggregator mi.
792   bool unFork(dictionary_hash<instInstance*, instInstance*> &map,
793               bool unForkInstRequests, bool unForkDataRequests);
794      // the fork() sys call copies all trampoline code, so the child process can be
795      // left with code that writes to counters/timers that don't exist (in the case
796      // where we don't propagate the mi to the new process).  In such cases, we must
797      // remove instrumentation from the child process.  That's what this routine is
798      // for.  It looks at the instReqNodes of the mi, which are in place in the parent
799      // process, and removes them from the child process.  "this" is a component mi
800      // representing the parent process.  "map" maps instInstance's of the parent to
801      // those of the child.
802
803   static void handleFork(const process *parent, process *child,
804                          dictionary_hash<instInstance*, instInstance*> &map);
805      // called once per fork.  "map" maps all instInstance's of the parent
806      // process to the corresponding copy in the child process...we'll delete some
807      // instrumentation in the child process if we find that some instrumentation
808      // in the parent doesn't belong in the child.
809
810   static void handleExec(process *);
811      // called once per exec, once the "new" process has been bootstrapped.
812      // We decide which mi's that were present in the pre-exec process should be
813      // carried over to the new process.  For those that should, the instrumentation
814      // is actually inserted.  For others, the component mi in question is removed from
815      // the system.
816
817   // remove an instance from an aggregate metric
818   void removeThisInstance();
819
820   bool anythingToManuallyTrigger() const;
821
822   void adjustManuallyTrigger();
823   void adjustManuallyTrigger0();
824   void manuallyTrigger(int);
825   void manuallyTrigger(int, int);
826
827 #if defined(MT_THREAD)
828   void propagateId(int);
829   bool& needData(void) { return needData_; }
830 #endif
831   bool inserted(void)     { return inserted_; }
832   bool installed(void)    { return installed_; }
833 private:
834   // Since we don't define these, make sure they're not used:
835   metricDefinitionNode &operator=(const metricDefinitionNode &src);
836   metricDefinitionNode(const metricDefinitionNode &src);
837
838   void removeComponent(metricDefinitionNode *comp);
839   void endOfDataCollection();
840   void removeFromAggregate(metricDefinitionNode *comp, int deleteComp = 1);
841
842   void updateAggregateComponent();
843
844   metricStyle metStyle() { return style_; }
845
846 #if defined(MT_THREAD)
847   AGG_LEVEL              aggLevel;// level of aggregation.
848                                   // AGG_COMP:  top level (aggregate)
849                                   // PROC_COMP: process component level (pre-
850                                   //            viously non aggregate but now
851                                   //            aggregate)
852                                   // THR_COMP:  thread component level. It has
853                                   //            no instrumentation associated,
854                                   //            only dataReqNodes and sampling
855                                   //            data
856   bool                  needData_ ;
857 #else
858   bool                  aggregate_;
859 #endif
860   int aggOp; // the aggregate operator
861   bool                  inserted_;
862   bool                  installed_;
863   string met_;                  // what type of metric
864   vector< vector<string> > focus_;
865   vector< vector<string> > component_focus; // defined for component mdn's only
866   string flat_name_;
867
868   /* for aggregate metrics */
869   vector<metricDefinitionNode*>   components;   
870   aggregateSample aggSample;    // current aggregate value
871
872   /* for non-aggregate metrics */
873   vector<dataReqNode*>  dataRequests;
874
875   vector<instReqNode> instRequests;
876   vector<returnInstance *> returnInsts;
877
878   vector<instReqNode *> manuallyTriggerNodes;
879
880 //  sampleValue cumulativeValue; // cumulative value for this metric
881   pdSample cumulativeValue;
882
883   // which metricDefinitionNode depend on this value.
884   vector<metricDefinitionNode*>   aggregators;
885      // remember, there can be more than one.  E.g. if cpu for whole program and
886      // cpu for process 100 are chosen, then we'll have just one component mi which is
887      // present in two aggregate mi's (cpu/whole and cpu/proc-100).
888
889   vector<sampleInfo *> samples;
890      // defined for component mi's only -- one sample for each aggregator, usually
891      // allocated with "aggregateMI.aggSample.newComponent()".
892      // samples[i] is the sample of aggregators[i].
893
894   int id_;                              // unique id for this one 
895   timeLength originalCost_;
896
897   process *proc_;
898
899   string metric_name_;
900   metricStyle style_; 
901
902   metricDefinitionNode* handleExec();
903      // called by static void handleExec(process *), for each component mi
904      // returns new component mi if propagation succeeded; NULL if not.
905 };
906
907 inline void metricDefinitionNode::addInst(instPoint *point, AstNode *ast,
908                                           callWhen when,
909                                           callOrder o) {
910   if (!point) return;
911
912   instReqNode temp(point, ast, when, o);
913   instRequests += temp;
914 };
915
916 // allMIs: all aggregate (as opposed to component) metricDefinitionNodes
917 extern dictionary_hash<unsigned, metricDefinitionNode*> allMIs;
918
919 // allMIComponents: all component (as opposed to aggregate) metricDefinitionNodes,
920 // indexed by the component's unique flat_name.
921 extern dictionary_hash<string, metricDefinitionNode*> allMIComponents;
922 #if defined(MT_THREAD)
923 extern dictionary_hash<string, metricDefinitionNode*> allMIinstalled;
924 #endif
925
926 // don't access this directly, consider private
927 extern timeLength currentPredictedCost;
928
929 // Access currentPredictedCost through these functions, should probably
930 // be included in some class or namespace in the future
931 inline timeLength &getCurrentPredictedCost() {
932   return currentPredictedCost;
933 }
934 inline void setCurrentPredictedCost(const timeLength &tl) {
935   currentPredictedCost = tl;
936 }
937 inline void addCurrentPredictedCost(const timeLength &tl) {
938   currentPredictedCost += tl;
939 }
940 inline void subCurrentPredictedCost(const timeLength &tl) {
941   currentPredictedCost -= tl;
942 }
943
944 #ifndef SHM_SAMPLING
945 extern void processCost(process *proc, traceHeader *h, costUpdate *s);
946 #endif
947
948 extern void reportInternalMetrics(bool force);
949
950 /*
951  * Routines to control data collection.
952  *
953  * focus                - a list of resources
954  * metricName           - what metric to collect data for
955  * id                   - metric id
956  * procsToContinue      - a list of processes that had to be stopped to insert
957  *                        instrumentation. The caller must continue these processes.
958  */
959 int startCollecting(string& metricName, vector<u_int>& focus, int id,
960                     vector<process *> &procsToContinue); 
961
962 /*
963  * Return the expected cost of collecting performance data for a single
964  *    metric at a given focus.  The value returned is the fraction of
965  *    perturbation expected (i.e. 0.10 == 10% slow down expected).
966  */
967 timeLength guessCost(string& metric_name, vector<u_int>& focus);
968
969
970 /*
971  * process a sample ariving from an inferior process
972  *
973  */
974 #ifndef SHM_SAMPLING
975 void processSample(int pid, traceHeader*, traceSample *);
976 #endif
977
978 #endif