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