This commit merges the AGG_LEV enumeration into the MDN_TYPE enumeration.
[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 v * 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.75 2001/09/04 19:48:48 gurari 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/sampleAggregator.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 #include "pdutil/h/metricStyle.h"
60
61 #define OPT_VERSION 1
62
63 class instInstance; // enough since we only use instInstance* in this file
64 #if defined(MT_THREAD)
65 class pdThread; // enough since we only use pdThread* in this file
66 #endif
67
68 #if defined(SHM_SAMPLING)
69 #include "paradynd/src/superTable.h"
70 #endif
71
72 class dataReqNode {
73  private:
74   // Since we don't define these, make sure they're not used:
75   dataReqNode &operator=(const dataReqNode &src);
76   dataReqNode (const dataReqNode &src);
77
78  protected:
79   dataReqNode() {}
80
81  public:
82   virtual ~dataReqNode() {};
83
84   virtual Address getInferiorPtr(process *proc=NULL) const = 0;
85   virtual unsigned getAllocatedIndex() const = 0;
86   virtual unsigned getAllocatedLevel() const = 0;
87
88   virtual int getSampleId() const = 0;
89
90 #if defined(MT_THREAD)
91   virtual int getThreadId() const = 0;
92   virtual bool insertInstrumentation(pdThread *, process *, metricDefinitionNode *, bool) = 0;
93 #else 
94   virtual bool insertInstrumentation(process *, metricDefinitionNode *, bool) = 0;
95 #endif
96      // Allocates stuff from inferior heap, instrumenting DYNINSTreportCounter
97      // as appropriate.  
98      // Returns true iff successful.
99
100   virtual void disable(process *,
101                        const vector< vector<Address> > &pointsToCheck) = 0;
102      // the opposite of insertInstrumentation.  Deinstruments, deallocates
103      // from inferior heap, etc.
104
105   virtual dataReqNode *dup(process *childProc, metricDefinitionNode *,
106                            int iCounterId,
107                            const dictionary_hash<instInstance*,instInstance*> &map
108                            ) const = 0;
109      // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
110
111      // "map" provides a dictionary that maps instInstance's of the parent process to
112      // those in the child process; dup() may find it useful. (for now, the shm
113      // dataReqNodes have no need for it; the alarm sampled ones need it).
114
115   virtual bool unFork(dictionary_hash<instInstance*,instInstance*> &map) = 0;
116      // the fork syscall duplicates all instrumentation (except on AIX), which is a
117      // problem when we determine that a certain mi shouldn't be propagated to the child
118      // process.  Hence this routine.
119 };
120
121 /*
122  * Classes derived from dataReqNode
123  *
124  * There are a lot of classes derived from dataReqNode, so things can get a little
125  * confusing.  Most of them are used in either shm_sampling mode or not; few are
126  * used in both.  Here's a bit of documentation that should sort things out:
127  *
128  * A) classes used in _both_ shm_sampling and non-shm-sampling
129  *
130  *    nonSampledIntCounterReqNode --
131  *       provides an intCounter value that is never sampled.  Currently useful
132  *       for predicates (constraint booleans).  The intCounter is allocated from
133  *       the "conventional" heap (where tramps are allocated) using good old
134  *       inferiorMalloc(), even when shm_sampling.
135  *       (In the future, we may provide a separate shm_sampling version, to make
136  *       allocation faster [allocation in the shm seg heap is always faster])
137  *
138  * B) classes used only when shm_sampling
139  *
140  *    sampledShmIntCounterReqNode --
141  *       provides an intCounter value that is sampled with shm sampling.  The
142  *       intCounter is allocated from the shm segment (i.e., not with inferiorMalloc).
143  *
144  *    sampledShmWallTimerReqNode --
145  *       provides a wall timer value that is sampled with shm sampling.  The tTimer is
146  *       allocated from the shm segment (i.e., not with inferiorMalloc)
147  *    
148  *    sampledShmProcTimerReqNode --
149  *       provides a process timer value that is sampled with shm sampling.  The tTimer
150  *       is allocated from the shm segment (i.e., not with inferiorMalloc)
151  *    
152  * C) classes used only when _not_ shm-sampling
153  *    
154  *    sampledIntCounterReqNode --
155  *       provides an intCounter value that is sampled.  The intCounter is allocated
156  *       in the conventional heap with inferiorMalloc().  Sampling is done the
157  *       old-fasioned SIGALRM way: by instrumenting DYNINSTsampleValues to call
158  *       DYNINSTreportTimer
159  *
160  *    sampledTimerReqNode --
161  *       provides a tTimer value (can be wall or process timer) that is sampled.  The
162  *       tTimer is allocated in the conventional heap with inferiorMalloc().  Sampling
163  *       is done the old-fasioned SIGALRM way: by instrumenting DYNINSTsampleValues to
164  *       call DYNINSTreportTimer.
165  *
166  */
167
168 #ifndef SHM_SAMPLING
169 class sampledIntCounterReqNode : public dataReqNode {
170  // intCounter for use when not shm sampling.  Allocated in the conventional heap
171  // with inferiorMalloc().  Sampled the old-fasioned way: by instrumenting
172  // DYNINSTsampleValues() to call DYNINSTreportCounter.
173  private:
174    // The following fields are always properly initialized in ctor:
175    int theSampleId;
176    rawTime64 initialValue; // needed when dup()'ing
177
178    // The following fields are NULL until insertInstrumentation() called:   
179    intCounter *counterPtr;              /* NOT in our address space !!!! */
180    instInstance *sampler;               /* function to sample value */
181
182    // Since we don't use these, disallow:
183    sampledIntCounterReqNode &operator=(const sampledIntCounterReqNode &);
184    sampledIntCounterReqNode(const sampledIntCounterReqNode &);
185
186    // private fork-ctor called by dup():
187    sampledIntCounterReqNode(const sampledIntCounterReqNode &src,
188                             process *childProc, metricDefinitionNode *, int iCounterId,
189                             const dictionary_hash<instInstance*,instInstance*> &map);
190
191    void writeToInferiorHeap(process *theProc, const intCounter &src) const;
192
193  public:
194    sampledIntCounterReqNode(rawTime64 iValue, int iCounterId,
195                             metricDefinitionNode *iMi, bool computingCost);
196   ~sampledIntCounterReqNode() {}
197       // Hopefully, disable() has already been called.  A bit of a complication
198       // since disable() needs an arg passed, which we can't do here.  Too bad.
199
200    dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
201                     const dictionary_hash<instInstance*,instInstance*> &map) const;
202
203 #if defined(MT_THREAD)
204    bool insertInstrumentation(pdThread *, process *, metricDefinitionNode *, bool doNotSample=false);
205 #else
206    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
207 #endif
208       // allocates from inferior heap; initializes it; instruments
209       // DYNINSTsampleValues
210
211    void disable(process *, const vector< vector<Address> > &);
212
213    Address getInferiorPtr(process *) const {
214       // counterPtr could be NULL if we are building AstNodes just to compute
215       // the cost - naim 2/18/97
216       //assert(counterPtr != NULL); // NULL until insertInstrumentation()
217       return (Address)counterPtr;
218    }
219
220    unsigned getAllocatedIndex() const {assert(0); return 0;}
221    unsigned getAllocatedLevel() const {assert(0); return 0;}
222
223    int getSampleId() const {return theSampleId;}
224 #if defined(MT_THREAD)
225    int getThreadId() const {assert(0); return 0;}
226 #endif
227
228    bool unFork(dictionary_hash<instInstance*,instInstance*> &map);
229      // the fork syscall duplicates all instrumentation (except on AIX), which is a
230      // problem when we determine that a certain mi shouldn't be propagated to the child
231      // process.  Hence this routine (to remove unwanted instr of DYNINSTsampleValues())
232 };
233 #endif
234
235 #ifdef SHM_SAMPLING
236 class sampledShmIntCounterReqNode : public dataReqNode {
237  // intCounter for use when shm-sampling.  Allocated in the shm segment heap.
238  // Sampled using shm sampling.
239  private:
240    // The following fields are always properly initialized in ctor:
241    int theSampleId; // obsolete with shm sampling; can be removed.
242 #if defined(MT_THREAD)
243    pdThread *thr_;
244 #endif
245
246    rawTime64 initialValue; // needed when dup()'ing
247
248    // The following fields are NULL until insertInstrumentation() called:
249    unsigned allocatedIndex;
250    unsigned allocatedLevel;
251
252    unsigned position_;
253
254    // Since we don't use these, making them privates ensures they're not used.
255    sampledShmIntCounterReqNode &operator=(const sampledShmIntCounterReqNode &);
256    sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &);
257
258    // private fork-ctor called by dup():
259    sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &src,
260                                process *childProc, metricDefinitionNode *,
261                                int iCounterId, const process *parentProc);
262
263  public:
264 #if defined(MT_THREAD)
265    sampledShmIntCounterReqNode(pdThread *thr, rawTime64 iValue, int iCounterId,
266                                metricDefinitionNode *iMi, bool computingCost,
267                                bool doNotSample, unsigned, unsigned);
268 #else
269    sampledShmIntCounterReqNode(rawTime64 iValue, int iCounterId,
270                                 metricDefinitionNode *iMi, bool computingCost,
271                                 bool doNotSample);
272 #endif
273   ~sampledShmIntCounterReqNode() {}
274       // Hopefully, disable() has already been called.
275       // A bit of a complication since disable() needs an
276       // arg passed, which we can't do here.  Too bad.
277
278    dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
279                     const dictionary_hash<instInstance*,instInstance*> &) const;
280
281 #if defined(MT_THREAD)
282    bool insertInstrumentation(pdThread *, process *, metricDefinitionNode *, bool);
283 #else
284    bool insertInstrumentation(process *, metricDefinitionNode *, bool);
285 #endif
286       // allocates from inferior heap; initializes it, etc.
287
288    void disable(process *, const vector< vector<Address> > &);
289
290    Address getInferiorPtr(process *) const;
291
292    unsigned getAllocatedIndex() const {return allocatedIndex;}
293    unsigned getAllocatedLevel() const {return allocatedLevel;}
294
295    unsigned getPosition() const {return position_;}
296    int getSampleId() const {return theSampleId;}
297 #if defined(MT_THREAD)
298    int getThreadId() const;
299    pdThread *getThread() {return thr_;}
300 #endif
301
302    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
303 };
304 #endif
305
306 class nonSampledIntCounterReqNode : public dataReqNode {
307  // intCounter for predicates (because they don't need to be sampled).
308  // Allocated in the conventional heap with inferiorMalloc().
309  private:
310    // The following fields are always properly initialized in ctor:
311    int theSampleId;
312    rawTime64 initialValue; // needed when dup()'ing
313
314    // The following is NULL until insertInstrumentation() called:   
315    intCounter *counterPtr;              /* NOT in our address space !!!! */
316
317    // Since we don't use these, disallow:
318    nonSampledIntCounterReqNode &operator=(const nonSampledIntCounterReqNode &);
319    nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &);
320
321    // private fork-ctor called by dup():
322    nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &src,
323                                process *childProc, metricDefinitionNode *,
324                                int iCounterId);
325
326    void writeToInferiorHeap(process *theProc, const intCounter &src) const;
327
328  public:
329    nonSampledIntCounterReqNode(rawTime64 iValue, int iCounterId,
330                                metricDefinitionNode *iMi, bool computingCost);
331   ~nonSampledIntCounterReqNode() {}
332       // Hopefully, disable() has already been called.
333       // A bit of a complication since disable() needs an
334       // arg passed, which we can't do here.  Too bad.
335
336    dataReqNode *dup(process *, metricDefinitionNode *, int iCounterId,
337                     const dictionary_hash<instInstance*,instInstance*> &) const;
338
339 #if defined(MT_THREAD)
340    bool insertInstrumentation(pdThread *, process *, metricDefinitionNode *, bool doNotSample=false);
341 #else
342    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
343 #endif
344       // allocates from inferior heap; initializes it
345
346    void disable(process *, const vector< vector<Address> > &);
347
348    Address getInferiorPtr(process *) const {
349       //assert(counterPtr != NULL); // NULL until insertInstrumentation()
350       // counterPtr could be NULL if we are building AstNodes just to compute
351       // the cost - naim 2/18/97
352       return (Address)counterPtr;
353    }
354
355    unsigned getAllocatedIndex() const {assert(0); return 0;}
356    unsigned getAllocatedLevel() const {assert(0); return 0;}
357
358    int getSampleId() const {return theSampleId;}
359 #if defined(MT_THREAD)
360    int getThreadId() const {assert(0); return 0;}
361 #endif
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    // since we don't use these, disallow:
381    sampledTimerReqNode(const sampledTimerReqNode &);
382    sampledTimerReqNode &operator=(const sampledTimerReqNode &);
383
384    // fork ctor:
385    sampledTimerReqNode(const sampledTimerReqNode &src, process *childProc,
386                        metricDefinitionNode *, int iCounterId,
387                        const dictionary_hash<instInstance*,instInstance*> &map);
388
389    void writeToInferiorHeap(process *theProc, const tTimer &dataSrc) const;
390
391  public:
392    sampledTimerReqNode(timerType iType, int iCounterId,
393                        metricDefinitionNode *iMi, bool computingCost);
394   ~sampledTimerReqNode() {}
395       // hopefully, freeInInferior() has already been called
396       // a bit of a complication since freeInInferior() needs an
397       // arg passed, which we can't do here.  Too bad.
398
399    dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
400                     const dictionary_hash<instInstance*,instInstance*> &map) const;
401
402 #if defined(MT_THREAD)
403    bool insertInstrumentation(pdThread *, process *, metricDefinitionNode *, bool doNotSample=false);
404 #else
405    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
406 #endif
407    void disable(process *, const vector< vector<Address> > &);
408
409    Address getInferiorPtr(process *) 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 (Address)timerPtr;
414    }
415
416    unsigned getAllocatedIndex() const {assert(0); return 0;}
417    unsigned getAllocatedLevel() const {assert(0); return 0;}
418
419    int getSampleId() const {return theSampleId;}
420 #if defined(MT_THREAD)
421    int getThreadId() const {assert(0); return 0;}
422 #endif
423
424    bool unFork(dictionary_hash<instInstance*,instInstance*> &map);
425      // the fork syscall duplicates all instrumentation (except on AIX), which is a
426      // problem when we determine that a certain mi shouldn't be propagated to the child
427      // process.  Hence this routine (to remove unwanted instr of DYNINSTsampleValues())
428 };
429 #endif
430
431 #ifdef SHM_SAMPLING
432 class sampledShmWallTimerReqNode : public dataReqNode {
433  // wall tTimer for use when shm sampling.  Allocated in the shm segment heap.
434  // Sampled using shm-sampling.
435  private:
436    // The following fields are always initialized in the ctor:   
437    int theSampleId;
438 #if defined(MT_THREAD)
439    pdThread *thr_;
440 #endif
441
442    // The following fields are NULL until insertInstrumentatoin():
443    unsigned allocatedIndex;
444    unsigned allocatedLevel;
445
446    unsigned position_;
447
448    // since we don't use these, disallow:
449    sampledShmWallTimerReqNode(const sampledShmWallTimerReqNode &);
450    sampledShmWallTimerReqNode &operator=(const sampledShmWallTimerReqNode &);
451
452    // fork ctor:
453    sampledShmWallTimerReqNode(const sampledShmWallTimerReqNode &src, 
454                               process *childProc,
455                               metricDefinitionNode *, int iCounterId,
456                               const process *parentProc);
457
458  public:
459 #if defined(MT_THREAD)
460    sampledShmWallTimerReqNode(pdThread *thr, int iCounterId,
461                               metricDefinitionNode *iMi, bool computingCost,
462                               unsigned, unsigned);
463 #else
464    sampledShmWallTimerReqNode(int iCounterId,
465                               metricDefinitionNode *iMi, bool computingCost);
466 #endif
467   ~sampledShmWallTimerReqNode() {}
468       // hopefully, freeInInferior() has already been called
469       // a bit of a complication since freeInInferior() needs an
470       // arg passed, which we can't do here.  Too bad.
471
472    dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
473                     const dictionary_hash<instInstance*,instInstance*> &) const;
474
475 #if defined(MT_THREAD)
476    bool insertInstrumentation(pdThread *, process *, metricDefinitionNode *, bool doNotSample=false);
477 #else
478    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
479 #endif
480    void disable(process *, const vector< vector<Address> > &);
481
482    Address getInferiorPtr(process *) const;
483
484    unsigned getAllocatedIndex() const {return allocatedIndex;}
485    unsigned getAllocatedLevel() const {return allocatedLevel;}
486
487    unsigned getPosition() const {return position_;}
488
489    int getSampleId() const {return theSampleId;}
490 #if defined(MT_THREAD)
491    int getThreadId() const;
492    pdThread *getThread() {return thr_;}
493 #endif
494
495    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
496 };
497
498 class sampledShmProcTimerReqNode : public dataReqNode {
499  // process tTimer for use when shm sampling.  Allocated in the shm segment heap.
500  // Sampled using shm-sampling.
501  private:
502    // The following fields are always initialized in the ctor:   
503    int theSampleId;
504 #if defined(MT_THREAD)
505    pdThread *thr_;
506 #endif
507
508    // The following fields are NULL until insertInstrumentatoin():
509    unsigned allocatedIndex;
510    unsigned allocatedLevel;
511
512    unsigned position_;
513
514    // since we don't use these, disallow:
515    sampledShmProcTimerReqNode(const sampledShmProcTimerReqNode &);
516    sampledShmProcTimerReqNode &operator=(const sampledShmProcTimerReqNode &);
517
518    // fork ctor:
519    sampledShmProcTimerReqNode(const sampledShmProcTimerReqNode &src, 
520                               process *childProc,
521                               metricDefinitionNode *, int iCounterId,
522                               const process *parentProc);
523
524  public:
525 #if defined(MT_THREAD)
526    sampledShmProcTimerReqNode(pdThread *thr, int iCounterId,
527                               metricDefinitionNode *iMi, bool computingCost,
528                               unsigned, unsigned);
529 #else
530    sampledShmProcTimerReqNode(int iCounterId,
531                              metricDefinitionNode *iMi, bool computingCost);
532 #endif
533   ~sampledShmProcTimerReqNode() {}
534       // hopefully, freeInInferior() has already been called
535       // a bit of a complication since freeInInferior() needs an
536       // arg passed, which we can't do here.  Too bad.
537
538    dataReqNode *dup(process *childProc, metricDefinitionNode *, int iCounterId,
539                     const dictionary_hash<instInstance*,instInstance*> &) const;
540
541 #if defined(MT_THREAD)
542    bool insertInstrumentation(pdThread *, process *, metricDefinitionNode *, bool doNotSample=false);
543 #else
544    bool insertInstrumentation(process *, metricDefinitionNode *, bool doNotSample=false);
545 #endif
546    void disable(process *, const vector< vector<Address> > &);
547
548    Address getInferiorPtr(process *) const;
549
550    unsigned getAllocatedIndex() const {return allocatedIndex;}
551    unsigned getAllocatedLevel() const {return allocatedLevel;}
552
553    unsigned getPosition() const {return position_;}
554
555    int getSampleId() const {return theSampleId;}
556 #if defined(MT_THREAD)
557    int getThreadId() const;
558    pdThread *getThread() {return thr_;}
559 #endif
560
561    bool unFork(dictionary_hash<instInstance*,instInstance*> &) {return true;}
562 };
563 #endif
564
565 /* ************************************************************************ */
566
567 class instReqNode {
568 friend bool toDeletePrimitiveMDN(metricDefinitionNode *prim);
569
570 public:
571   instReqNode(instPoint*, AstNode *, callWhen, callOrder order);
572  ~instReqNode();
573
574   instReqNode() {
575      // needed by Vector class
576     ast = NULL; 
577     point=NULL; 
578     instance = NULL; 
579     rinstance = NULL; 
580   }
581
582   instReqNode(const instReqNode &src) {
583      point = src.point;
584      when = src.when;
585      order = src.order;
586      instance = src.instance;
587      rinstance = src.rinstance;
588      ast = assignAst(src.ast);
589   }
590   instReqNode &operator=(const instReqNode &src) {
591      if (this == &src)
592         return *this;
593
594      point = src.point;
595      ast = assignAst(src.ast);
596      when = src.when;
597      order = src.order;
598      instance = src.instance;
599      rinstance = src.rinstance;
600
601      return *this;
602   }
603
604   bool insertInstrumentation(process *theProc, 
605                              returnInstance *&retInstance,
606                              bool &deferred);
607
608   void disable(const vector<Address> &pointsToCheck);
609   timeLength cost(process *theProc) const;
610
611   static instReqNode forkProcess(const instReqNode &parent,
612                                  const dictionary_hash<instInstance*,instInstance*> &);
613      // should become a copy-ctor...or at least, a non-static member fn.
614
615   bool unFork(dictionary_hash<instInstance*, instInstance*> &map) const;
616      // The fork syscall duplicates all trampolines from the parent into the child. For
617      // those mi's which we don't want to propagate to the child, this creates a
618      // problem.  We need to remove instrumentation code from the child.  This routine
619      // does that.  "map" maps instInstances of the parent to those in the child.
620
621   instInstance *getInstance() const { return instance; }
622   returnInstance *getRInstance() const { return rinstance; }
623
624 #if defined(MT_THREAD)
625   bool triggerNow(process *theProc, int mid, int thrId);
626 #else
627   bool triggerNow(process *theProc, int mid);
628 #endif
629   static void triggerNowCallbackDispatch(process * /*theProc*/,
630                                                     void *userData, void *returnValue)
631           { ((instReqNode*)userData)->triggerNowCallback( returnValue ); }
632   void triggerNowCallback(void *returnValue);
633
634   bool triggeredInStackFrame(pd_Function *stack_fn,
635                              Address pc,
636                              process *p);
637   
638   instPoint *Point() {return point;}
639   AstNode* Ast()  {return ast;}
640   callWhen When() {return when;}
641
642 private:
643   instPoint     *point;
644   AstNode       *ast;
645   callWhen      when;
646   callOrder     order;
647   instInstance  *instance; // undefined until insertInstrumentation() calls addInstFunc
648   returnInstance *rinstance;
649
650   // Counts the number of rpcs which have successfully completed 
651   // for this node.  This is needed because we may need to manually 
652   // trigger multiple times for recursive functions.
653   int rpcCount;
654 #if defined(MT_THREAD)
655   vector<int> manuallyTriggerTIDs;
656 #endif
657 };
658
659 // A function which is called by the continue mechanism in the process
660 // object.  Used to determine the initialStartTime of a mdn.
661 void mdnContinueCallback(timeStamp timeOfCont);
662
663 // metricDefinitionNode type, AGG_MDN previously known as aggregate, 
664 // COMP_MDN previously known as component (non-aggregate), PRIM_MDN
665 // is new: COMP_MDN is decomposed into several constraint PRIM_MDN
666 // and one metric PRIM_MDN. One PRIM_MDN is the collection of modifications
667 // to ONE variable (constraint varaible or metric variable) except
668 // that in metric, several temp variables could also be modified.
669 //
670 // This is the best (smallest) unit to do reuse optimization 
671 // (instrumentation) because PRIM_MDN is about a variable and all
672 // modifications to that variable. We can reuse that variable
673 // instead of having a new one if the same modification snippets
674 // would be inserted at the same instrument points.
675 //
676 // BUT this is not true for "replace" constraints, in which case,
677 // metric could only be at COMP_MDN level instead of decomposing
678 // into PRIM_MDN level.
679
680 // ning: Should separate constraint prim from metric prim?
681 //   because even if we can reuse, constraint var is not sampled
682 //   while metric prim is sampled.  or have two separate
683 //   allMIPrimitives for them.
684 // THR_LEV is for threaded paradyn only
685 typedef enum {AGG_MDN, COMP_MDN, PRIM_MDN, THR_LEV} MDN_TYPE;
686
687
688 // metricDefinitionNode type for MT_THREAD version:
689 // AGG_LEV   is similar to AGG_MDN.
690 //
691 // PROC_COMP is similar to COMP_MDN, except that here, if metric
692 //   prim is the same, the same proc_comp will be shared;
693 //   multiple names should be memorized.
694 //
695 // PROC_PRIM is similar to PRIM_MDN, except that here, two
696 //   separate allMIPrimitives will be used for constraint and
697 //   metric respectively;  metric prim will have only one
698 //   aggregator.
699 //
700 // THR_LEV is new, it stores variables for each thread;
701 //   metric thr is registered in allMIComponents also;
702 //   thr_lev has only one aggregator -- a metric prim;
703 //   if it has component, it has only one -- the proc_
704 //   comp also for its metric prim.
705 #ifdef notdefined
706 #if defined(MT_THREAD)
707 typedef enum {AGG_LEV, PROC_COMP, PROC_PRIM, THR_LEV} AGG_LEVEL;
708 #endif
709 #endif
710
711 /*
712    metricDefinitionNode describe metric instances. There are two types of
713    nodes: aggregates and non-aggregates (Maybe this class should be divided in
714    two).
715    Aggregate nodes represent a metric instance with one or more components.
716    Each component is represented by a non-aggregate metricDefinitionNode, and
717    is associated with a different process.
718    All metric instance have an aggregate metricDefinitionNode, even if it has 
719    only one component (this simplifies doing metric propagation when new 
720    processes start).
721    Components can be shared by two or more aggregate metricDefinitionNodes, 
722    so for example if there are two metric/focus pairs enabled, cpu time for
723    the whole program and cpu time for process p, there will be one non-aggregate
724    instance shared between two aggregate metricDefinitionNodes.
725 */
726 class metricDefinitionNode {
727 friend timeLength guessCost(string& metric_name, vector<u_int>& focus) ;
728
729 friend int startCollecting(string&, vector<u_int>&, int id, 
730                            vector<process *> &procsToContinue); // called by dynrpc.C
731 friend bool toDeletePrimitiveMDN(metricDefinitionNode *prim); // used in mdl.C
732 #if defined(MT_THREAD)
733 friend bool checkMetricMIPrimitives(string metric_flat_name, metricDefinitionNode *& metric_prim,
734                              string name, vector< vector<string> >& comp_focus, int processIdx);
735 #endif
736
737 private:
738   /* unique id for a counter or timer */
739   static int counterId;
740
741 public:
742
743   // styles are enumerated in aggregation.h
744   metricDefinitionNode(process *p, const string& metric_name, 
745                        const vector< vector<string> >& foc,
746                        const vector< vector<string> >& component_foc,
747                        const string& component_flat_name, 
748                        aggregateOp agg_op, MDN_TYPE mdntype);
749
750   // NON_MT_THREAD version:
751   // for primitive (real non-aggregate, per constraint var or metric var) mdn's
752   // flat name should include process id
753   //
754   // for component (per-process) (non-aggregate, now aggregate) mdn's
755   // difference: it now has parts too (become aggregate)
756
757   metricDefinitionNode(const string& metric_name, 
758                        const vector< vector<string> >& foc,
759                        const string& cat_name,
760                        vector<metricDefinitionNode*>& parts,
761                        aggregateOp agg_op, MDN_TYPE mdntype = AGG_MDN);
762
763   // NON_MT_THREAD version:
764   // for aggregate (not component) mdn's
765
766   ~metricDefinitionNode();
767   void okayToSample();
768   void disable();
769   void cleanup_drn();
770   void updateValue(timeStamp, pdSample);
771   void forwardSimpleValue(timeStamp, timeStamp, pdSample);
772
773   int getMId() const { return id_; }
774
775   bool isTopLevelMDN() const {
776     return (mdn_type_ == AGG_MDN);
777   }
778
779   const string &getMetName() const { return met_; }
780   const string &getFullName() const { return flat_name_; }
781   const vector< vector<string> > &getFocus() const {return focus_;}
782   const vector< vector<string> > &getComponentFocus() const { return component_focus; }
783
784   process *proc() const { return proc_; }
785   
786   vector<dataReqNode *> getDataRequests();
787   vector<metricDefinitionNode *>& getComponents() { 
788     return components; 
789   }
790   void addPart(metricDefinitionNode* part);
791   void addPartDummySample(metricDefinitionNode* part);  // special purpose
792 #if defined(MT_THREAD)
793   void reUseIndexAndLevel(unsigned &p_allocatedIndex, unsigned &p_allocatedLevel);
794   void addParts(vector<metricDefinitionNode*>& parts);
795
796   //AGG_LEVEL getLevel() { return aggLevel; }
797   // vector<dataReqNode *> getDataRequests() { return dataRequests; }      
798   void addThread(pdThread *thr);
799   void deleteThread(pdThread *thr);
800   void duplicateInst(metricDefinitionNode *from, metricDefinitionNode *to);
801   void duplicateInst(metricDefinitionNode *mn) ;
802   
803   void setMetricRelated(unsigned type, bool computingCost, vector<string> * temp_ctr, 
804                         vector<T_dyninstRPC::mdl_constraint*> flag_cons,
805                         vector<T_dyninstRPC::mdl_constraint*> base_use) {
806     assert(COMP_MDN == mdn_type_);
807
808     type_thr          = type;
809     computingCost_thr = computingCost;
810     temp_ctr_thr      = temp_ctr;
811     flag_cons_thr     = flag_cons;
812     base_use_thr      = base_use;
813   }
814   //AGG_LEVEL getMdnType(void) const { return aggLevel; }
815 #endif
816
817   MDN_TYPE getMdnType(void) const { return mdn_type_; }
818
819
820   friend ostream& operator<<(ostream&s, const metricDefinitionNode &m);
821
822   // careful in use!
823   // NON_MT_THREAD version:  only for PRIM mdn
824   // MT_THREAD version:  only for PROC_PRIM or THR_LEV
825   bool nonNull() const { return (instRequests.size() || dataRequests.size()); }
826   int getSizeOfInstRequests() const { return instRequests.size(); }
827   void setStartTime(timeStamp t, bool resetCompStartTime = false);
828   bool insertInstrumentation(pd_Function *&func, bool &deferred);
829
830   void setInitialActualValue(pdSample s);
831   void sendInitialActualValue(pdSample s);
832   bool sentInitialActualValue() {  return _sentInitialActualValue; }
833   void sentInitialActualValue(bool v) {  _sentInitialActualValue = v; }
834   static void updateAllAggInterval(timeLength width);
835   void updateAggInterval(timeLength width) {
836     aggregator.changeAggIntervalWidth(width);
837   }
838
839   // needed
840   timeLength cost() const;
841   bool checkAndInstallInstrumentation();
842
843   timeLength originalCost() const { return originalCost_; }
844
845   // The following routines are (from the outside world's viewpoint)
846   // the heart of it all.  They append to dataRequets or instRequests, so that
847   // a future call to metricDefinitionNode::insertInstrumentation() will
848   // "do their thing".  The MDL calls these routines.
849 #if defined(MT_THREAD)
850   dataReqNode *addSampledIntCounter(pdThread *thr, rawTime64 initialValue, 
851                                     bool computingCost,
852                                     bool doNotSample=false);
853 #else
854   dataReqNode *addSampledIntCounter(rawTime64 initialValue, bool computingCost,
855                                      bool doNotSample=false);
856 #endif
857   dataReqNode *addUnSampledIntCounter(rawTime64 initialValue, bool computingCost);
858 #if defined(MT_THREAD)
859   dataReqNode *addWallTimer(bool computingCost, pdThread *thr=NULL);
860   dataReqNode *addProcessTimer(bool computingCost, pdThread *thr=NULL);
861 #else
862   dataReqNode *addWallTimer(bool computingCost);
863   dataReqNode *addProcessTimer(bool computingCost);
864 #endif
865   // inline void addInst(instPoint *point, AstNode *, callWhen when, 
866   //                     callOrder o);
867   void addInst(instPoint *point, AstNode *, callWhen when, 
868                callOrder o);
869
870   // propagate this aggregate mi to a newly started process p (not for processes
871   // started via fork or exec, just for those started "normally")
872   void propagateToNewProcess(process *p);  
873
874   metricDefinitionNode *forkProcess(process *child,
875                                     const dictionary_hash<instInstance*,instInstance*> &map) const;
876      // called when it's determined that an mi should be propagated from the
877      // parent to the child.  "this" is a component mi, not an aggregator mi.
878   bool unFork(dictionary_hash<instInstance*, instInstance*> &map,
879               bool unForkInstRequests, bool unForkDataRequests);
880      // the fork() sys call copies all trampoline code, so the child process can be
881      // left with code that writes to counters/timers that don't exist (in the case
882      // where we don't propagate the mi to the new process).  In such cases, we must
883      // remove instrumentation from the child process.  That's what this routine is
884      // for.  It looks at the instReqNodes of the mi, which are in place in the parent
885      // process, and removes them from the child process.  "this" is a component mi
886      // representing the parent process.  "map" maps instInstance's of the parent to
887      // those of the child.
888
889   static void handleFork(const process *parent, process *child,
890                          dictionary_hash<instInstance*, instInstance*> &map);
891      // called once per fork.  "map" maps all instInstance's of the parent
892      // process to the corresponding copy in the child process...we'll delete some
893      // instrumentation in the child process if we find that some instrumentation
894      // in the parent doesn't belong in the child.
895
896   static void handleExec(process *);
897      // called once per exec, once the "new" process has been bootstrapped.
898      // We decide which mi's that were present in the pre-exec process should be
899      // carried over to the new process.  For those that should, the instrumentation
900      // is actually inserted.  For others, the component mi in question is removed from
901      // the system.
902
903   // remove an instance from an aggregate metric
904   void removeThisInstance();
905
906   bool anythingToManuallyTrigger() const;
907
908   void adjustManuallyTrigger();
909   void adjustManuallyTrigger(vector<Address> stack_pcs); // should make it private
910 #if defined(MT_THREAD)
911   void adjustManuallyTrigger0();
912 #endif
913   void manuallyTrigger(int);
914   void manuallyTrigger(int, int);
915
916 #if defined(MT_THREAD)
917   void propagateId(int);
918   bool& needData(void) { return needData_; }
919 #endif
920   bool inserted(void)     { return inserted_; }
921   bool installed(void)    { return installed_; }
922
923   bool isInitialActualValueSet() { return !mdnInitActualVal.isNaN(); }
924   bool isStartTimeSet()    { return mdnStartTime.isInitialized(); }
925   timeStamp getStartTime() { return mdnStartTime; }
926
927   dataReqNode* getFlagDRN(void);
928
929   metricDefinitionNode* matchInMIPrimitives();
930   bool condMatch(metricDefinitionNode *mn,
931                  vector<dataReqNode*> &data_tuple1,
932                  vector<dataReqNode*> &data_tuple2);
933
934 #if defined(MT_THREAD)
935   metricDefinitionNode * getMetricPrim() {
936     // should be the last of its components
937     assert(mdn_type_ == COMP_MDN);
938     unsigned csize = components.size();
939     return (components[csize-1]);
940   }
941   metricDefinitionNode * getThrComp(string tname) {
942     assert(mdn_type_ == PRIM_MDN);
943     unsigned csize = components.size();
944     assert(csize == thr_names.size());
945
946     for (unsigned u=0; u<csize; u++)
947       if (tname == thr_names[u])
948         return components[u];
949
950     return NULL;
951   }
952   metricDefinitionNode * getProcComp() {
953     assert(mdn_type_ == PRIM_MDN);
954
955     return aggregators[0];
956   }
957   // --- ---
958   void rmCompFlatName(unsigned u) {
959     assert(COMP_MDN == mdn_type_);
960     unsigned size = comp_flat_names.size();
961     assert(u < size);
962     
963     extern dictionary_hash<string, metricDefinitionNode*> allMIComponents;
964     if (allMIComponents.defines(comp_flat_names[u])) {
965       allMIComponents.undef(comp_flat_names[u]);
966     }
967     
968     comp_flat_names[u] = comp_flat_names[size-1];
969     comp_flat_names.resize(size-1);
970   }
971
972   void addCompFlatName(string proc_flat_name) {
973     assert(COMP_MDN == mdn_type_);
974     comp_flat_names += proc_flat_name;
975   }
976
977   void addThrName(string thr_name) {
978     assert(PRIM_MDN == mdn_type_);
979     thr_names += thr_name;
980   }
981 #endif
982   
983 private:
984   // Since we don't define these, make sure they're not used:
985   metricDefinitionNode &operator=(const metricDefinitionNode &src);
986   metricDefinitionNode(const metricDefinitionNode &src);
987
988  public:
989   void removeComponent(metricDefinitionNode *comp);
990
991  private:
992   friend void mdnContinueCallback(timeStamp timeOfCont);
993
994   void updateWithDeltaValue(timeStamp startTime, timeStamp sampleTime, 
995                             pdSample value);
996   void tryAggregation();
997
998   void endOfDataCollection();
999   void removeFromAggregate(metricDefinitionNode *comp, int deleteComp = 1);
1000
1001   // this function checks if we need to do stack walk
1002   // if all returnInstance's overwrite only 1 instruction, no stack walk necessary
1003   bool needToWalkStack() const;
1004
1005   metricStyle metStyle() { return EventCounter; }
1006
1007   // @@ METRIC FIELD STARTS FROM HERE :
1008 #if defined(MT_THREAD)
1009   //  AGG_LEVEL              aggLevel;// level of aggregation.
1010                                   // AGG_LEV:    top level (aggregate)
1011                                   // THR_LEV:    same as below, only those for metric are added to allMIComponents
1012                                   // PROC_COMP:
1013                                   // PROC_PRIM:  process component level (previously non aggregate
1014                                   //             but now aggregate);  for constraint and metric
1015                                   // THR_LEV:    thread component level. It has no instrumentation associated,
1016                                   //             only dataReqNodes and sampling data;  for constraint and metric
1017   bool                  needData_ ;
1018 #endif
1019   MDN_TYPE              mdn_type_;
1020
1021   aggregateOp           aggOp;
1022   bool                  inserted_;
1023   bool                  installed_;
1024
1025   string met_;                       // what type of metric
1026   vector< vector<string> > focus_;
1027   vector< vector<string> > component_focus; // defined for component mdn's only
1028   string flat_name_;
1029
1030   // comments only for NON_MT_THREAD version:
1031   // for aggregate metrics and component (non-aggregate) metrics
1032   // for component metrics: the last is "base", others are all constraints
1033   vector<metricDefinitionNode*>   components;   
1034   sampleAggregator aggregator;    // current aggregate value
1035   //  aggregator should be consistent with components to some extents
1036   //  should be added or removed if necessary;
1037   //  also added in AGG_LEV constructor and addPart
1038   timeStamp mdnStartTime;    // the time that this metric started
1039
1040   pdSample mdnInitActualVal;  // the initial actual value for this mdn
1041
1042   // for component (non-aggregate) and primitive metrics
1043   vector<dataReqNode*>  dataRequests;  //  for THR_LEV only
1044
1045   vector<instReqNode> instRequests;    //  for PROC_PRIM only
1046   vector<returnInstance *> returnInsts;//  for PROC_PRIM only, follow instRequests
1047
1048   vector<instReqNode *> manuallyTriggerNodes;
1049                                        //  for PROC_PRIM only, follow instRequests
1050
1051   bool _sentInitialActualValue;        //  true when initial actual value has
1052                                        //  been sent to the front-end
1053   pdSample cumulativeValue;            //  seems only for THR_LEV, from which actual data is collected
1054
1055                                        //  aggregators and samples should always be consistent
1056                                        //  added in AGG_LEV constructor and addPart
1057   // which metricDefinitionNode depend on this value.
1058   vector<metricDefinitionNode*>   aggregators;
1059   // remember, there can be more than one.  E.g. if cpu for whole program and
1060   // cpu for process 100 are chosen, then we'll have just one component mi which is
1061   // present in two aggregate mi's (cpu/whole and cpu/proc-100).
1062   
1063   vector<aggComponent *> samples;
1064   // defined for component mi's only -- one sample for each aggregator, usually
1065   // allocated with "aggregateMI.aggregator.newComponent()".
1066   // samples[i] is the sample of aggregators[i].
1067
1068 #if defined(MT_THREAD)
1069                                        //  following 5 memorizing stuff --- for PROC_COMP only
1070   // data required to add threads - naim
1071   unsigned type_thr;
1072   bool computingCost_thr;
1073   vector<string> *temp_ctr_thr;
1074   vector<T_dyninstRPC::mdl_constraint*> flag_cons_thr;
1075   // could be multiple mdl_constraints
1076   vector<T_dyninstRPC::mdl_constraint*>  base_use_thr;
1077
1078                                        //  following 4 --- for PROC_COMP only
1079   vector<string> comp_flat_names;      //  should be consistent with PROC_COMP's aggregators
1080
1081   vector<string> thr_names;            //  for PROC_PRIM only, remember names of each of its threads (tid + start_func_name)
1082                                        //  should be consistent with PROC_PRIM's components
1083 #endif
1084   
1085   int id_;                             //  unique id for this "AGG_LEV" metricDefinitionNoe; no meaning for other kinds of mdn
1086   timeLength originalCost_;
1087   
1088   process *proc_;                      //  for NON_AGG_LEV (never changed once initialized)
1089
1090   metricStyle style_;                  //  never changed once initialized
1091
1092
1093   // CONSISTENCY GROUPS
1094   // aggregators, samples (comp_flat_names for PROC_COMP)  \  complicated relations between them
1095   // components, (aggregator) (thr_names for THR_LEV)           /  should be kept cleanly if possible
1096   // SPECIALS:  AGG_LEV  --- id_
1097   //          PROC_COMP  --- temp_ctr_thr... , comp_flat_names
1098   //          PROC_PRIM  --- instRequests... , thr_names
1099   //            THR_LEV  --- dataRequests, cumulativeValue
1100   
1101   metricDefinitionNode* handleExec();
1102   // called by static void handleExec(process *), for each component mi
1103   // returns new component mi if propagation succeeded; NULL if not.
1104   void oldCatchUp();
1105   bool checkAndInstallInstrumentation(vector<Address>& pc);
1106 };
1107
1108 class defInst {
1109  public:
1110   defInst(string& metric_name, vector<u_int>& focus, int id, 
1111           pd_Function *func, unsigned attempts);
1112
1113   string metric() { return metric_name_; }
1114   vector<u_int>& focus() { return focus_; }
1115   int id() { return id_; }
1116   pd_Function *func() { return func_; }
1117   unsigned numAttempts() { return attempts_; }
1118   void failedAttempt() { if (attempts_ > 0) attempts_--; }
1119   
1120  private:
1121   string metric_name_;
1122   vector<u_int> focus_; 
1123   int id_;
1124   pd_Function *func_;
1125   unsigned attempts_;
1126 };
1127
1128 ostream& operator<<(ostream&s, const metricDefinitionNode &m);
1129
1130 //class defInst {
1131 // public:
1132 //  defInst(unsigned, vector<T_dyninstRPC::focusStruct>&, vector<string>&,
1133 //        vector<u_int>&, u_int&, u_int&);
1134
1135 //  unsigned index() { return index_; }
1136 //  vector<T_dyninstRPC::focusStruct> focus() { return focus_; }
1137 //  vector<string>& metric() { return metric_; }
1138 //  vector<u_int>& ids() { return ids_; }
1139 //  u_int did() { return did_; }
1140 //  u_int rid() { return rid_; }
1141
1142 // private:
1143 //  unsigned index_;
1144 //  vector<T_dyninstRPC::focusStruct> focus_; 
1145 //  vector<string> metric_;
1146 //  vector<u_int> ids_; 
1147 //  u_int did_;
1148 //  u_int rid_;
1149 //};
1150
1151 // inline void metricDefinitionNode::addInst(instPoint *point, AstNode *ast,
1152 //                                        callWhen when,
1153 //                                        callOrder o) {
1154 //  if (!point) return;
1155 //
1156 //  instReqNode temp(point, ast, when, o);
1157 //  instRequests += temp;
1158 // };
1159
1160 // allMIs: all aggregate (as opposed to component) metricDefinitionNodes
1161 extern dictionary_hash<unsigned, metricDefinitionNode*> allMIs;
1162
1163 // allMIComponents: all component (as opposed to aggregate) metricDefinitionNodes,
1164 // indexed by the component's unique flat_name.
1165 extern dictionary_hash<string, metricDefinitionNode*> allMIComponents;
1166
1167 // allMIPrimitives: all primitives (variable with all its modifications) metricDefinitionNodes,
1168 // indexed by the primitive's unique flat_name (metric primitive should have the same unique
1169 // flat_name as its component
1170 extern dictionary_hash<string, metricDefinitionNode*> allMIPrimitives;
1171
1172 #if defined(MT_THREAD)
1173 extern dictionary_hash<string, metricDefinitionNode*> allMIinstalled;
1174 #endif
1175
1176 // don't access this directly, consider private
1177 extern timeLength currentPredictedCost;
1178
1179 // Access currentPredictedCost through these functions, should probably
1180 // be included in some class or namespace in the future
1181 inline timeLength &getCurrentPredictedCost() {
1182   return currentPredictedCost;
1183 }
1184 inline void setCurrentPredictedCost(const timeLength &tl) {
1185   currentPredictedCost = tl;
1186 }
1187 inline void addCurrentPredictedCost(const timeLength &tl) {
1188   currentPredictedCost += tl;
1189 }
1190 inline void subCurrentPredictedCost(const timeLength &tl) {
1191   currentPredictedCost -= tl;
1192 }
1193
1194 #ifndef SHM_SAMPLING
1195 extern void processCost(process *proc, traceHeader *h, costUpdate *s);
1196 #endif
1197
1198 extern void reportInternalMetrics(bool force);
1199
1200 bool toDeletePrimitiveMDN(metricDefinitionNode *prim);
1201
1202 /*
1203  * Routines to control data collection.
1204  *
1205  * focus                - a list of resources
1206  * metricName           - what metric to collect data for
1207  * id                   - metric id
1208  * procsToContinue      - a list of processes that had to be stopped to insert
1209  *                        instrumentation. The caller must continue these processes.
1210  */
1211 int startCollecting(string& metricName, vector<u_int>& focus, int id,
1212                     vector<process *> &procsToContinue); 
1213
1214 /*
1215  * Return the expected cost of collecting performance data for a single
1216  *    metric at a given focus.  The value returned is the fraction of
1217  *    perturbation expected (i.e. 0.10 == 10% slow down expected).
1218  */
1219 timeLength guessCost(string& metric_name, vector<u_int>& focus);
1220
1221
1222 /*
1223  * process a sample ariving from an inferior process
1224  *
1225  */
1226 #ifndef SHM_SAMPLING
1227 void processSample(int pid, traceHeader*, traceSample *);
1228 #endif
1229
1230 bool AstNode_condMatch(AstNode* a1, AstNode* a2,
1231                        vector<dataReqNode*> &data_tuple1, // initialization?
1232                        vector<dataReqNode*> &data_tuple2,
1233                        vector<dataReqNode*> datareqs1,
1234                        vector<dataReqNode*> datareqs2);
1235
1236 #endif
1237
1238
1239 // need to make dataReqNode return their type info
1240
1241
1242