Added instReqNode method triggeredInStackFrame, which calls the process
[dyninst.git] / paradynd / src / metricFocusNode.C
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.C,v 1.170 2000/03/20 22:57:58 chambrea Exp $
43
44 #include "util/h/headers.h"
45 #include <limits.h>
46 #include <assert.h>
47
48 #include "rtinst/h/rtinst.h"
49 #include "rtinst/h/trace.h"
50 #include "util/h/aggregateSample.h"
51 #include "dyninstAPI/src/symtab.h"
52 #include "dyninstAPI/src/pdThread.h"
53 #include "dyninstAPI/src/process.h"
54 #include "dyninstAPI/src/inst.h"
55 #include "dyninstAPI/src/instP.h"
56 #include "dyninstAPI/src/dyninstP.h"
57 #include "dyninstAPI/src/ast.h"
58 #include "dyninstAPI/src/util.h"
59 #include "paradynd/src/comm.h"
60 #include "paradynd/src/internalMetrics.h"
61 #include "paradynd/src/init.h"
62 #include "paradynd/src/perfStream.h"
63 #include "paradynd/src/main.h"
64 #include "dyninstAPI/src/stats.h"
65 #include "paradynd/src/dynrpc.h"
66 #include "paradynd/src/mdld.h"
67 #include "util/h/Timer.h"
68 #include "dyninstAPI/src/showerror.h"
69 #include "paradynd/src/costmetrics.h"
70 #include "paradynd/src/metric.h"
71 #include "util/h/debugOstream.h"
72
73 #include "dyninstAPI/src/instPoint.h"
74
75 // The following vrbles were defined in process.C:
76 extern debug_ostream attach_cerr;
77 extern debug_ostream inferiorrpc_cerr;
78 extern debug_ostream shmsample_cerr;
79 extern debug_ostream forkexec_cerr;
80 extern debug_ostream metric_cerr;
81
82 extern unsigned inferiorMemAvailable;
83 extern vector<Address> getAllTrampsAtPoint(instInstance *instance);
84 static unsigned internalMetricCounterId = 0;
85
86 static unsigned numOfActCounters_all=0;
87 static unsigned numOfActProcTimers_all=0;
88 static unsigned numOfActWallTimers_all=0;
89 #if defined(MT_THREAD)
90 static unsigned numOfCurrentLevels_all=0;
91 static unsigned numOfCurrentThreads_all=0;
92 static unsigned numOfActiveThreads=0;
93 #endif
94
95 void flush_batch_buffer();
96 void batchSampleData(int mid, double startTimeStamp, double endTimeStamp,
97                      double value, unsigned val_weight, bool internal_metric);
98
99 double currentPredictedCost = 0.0;
100
101 dictionary_hash <unsigned, metricDefinitionNode*> midToMiMap(uiHash);
102    // maps low-level counter-ids to metricDefinitionNodes
103
104 unsigned mdnHash(const metricDefinitionNode *&mdn) {
105   return ((unsigned)(Address)mdn) >> 2; // assume all addrs are 4-byte aligned
106 //  return ((unsigned) mdn);
107 }
108
109 unsigned componentMdnPtrHash(metricDefinitionNode * const &ptr) {
110    // maybe assert that "ptr" isn't for an aggregate mi
111    return string::hash(ptr->getFullName());
112 }
113
114
115 dictionary_hash<unsigned, metricDefinitionNode*> allMIs(uiHash);
116 dictionary_hash<string, metricDefinitionNode*> allMIComponents(string::hash);
117 vector<internalMetric*> internalMetric::allInternalMetrics;
118
119 // used to indicate the mi is no longer used.
120 #define DELETED_MI 1
121 #define MILLION 1000000.0
122
123 bool mdl_internal_metric_data(const string& metric_name, mdl_inst_data& result) {
124   unsigned size = internalMetric::allInternalMetrics.size();
125   for (unsigned u=0; u<size; u++) {
126     internalMetric *theIMetric = internalMetric::allInternalMetrics[u];
127     if (theIMetric->name() == metric_name) {
128       result.aggregate = theIMetric->aggregate();
129       result.style = theIMetric->style();
130       return true;
131     }
132   }
133
134   for (unsigned u2=0; u2< costMetric::allCostMetrics.size(); u2++) {
135     if (costMetric::allCostMetrics[u2]->name() == metric_name) {
136       result.aggregate = costMetric::allCostMetrics[u2]->aggregate();
137       result.style = costMetric::allCostMetrics[u2]->style();
138       return true;
139     }
140   }
141
142   return (mdl_metric_data(metric_name, result));
143 }
144
145 // for non-aggregate metrics
146 metricDefinitionNode::metricDefinitionNode(process *p, const string& met_name, 
147                                    const vector< vector<string> >& foc,
148                                    const vector< vector<string> >& component_foc,
149 #if defined(MT_THREAD)
150                                    const string& component_flat_name, int agg_style, AGG_LEVEL agg_level)
151 : aggLevel(agg_level), 
152 #else
153                                    const string& component_flat_name, int agg_style)
154 : aggregate_(false), 
155 #endif
156   aggOp(agg_style), // CM5 metrics need aggOp to be set
157   inserted_(false), installed_(false), met_(met_name),
158   focus_(foc), component_focus(component_foc),
159   flat_name_(component_flat_name),
160   aggSample(0),
161   cumulativeValue_float(0.0),
162   id_(-1), originalCost_(0.0), proc_(p)
163 {
164   mdl_inst_data md;
165   bool aflag;
166   aflag=mdl_internal_metric_data(met_name, md);
167   assert(aflag);
168   style_ = md.style;
169 #if defined(MT_THREAD)
170   needData_ = true ;
171 #endif
172 }
173
174 // for aggregate metrics
175 metricDefinitionNode::metricDefinitionNode(const string& metric_name,
176                                            const vector< vector<string> >& foc,
177                                            const string& cat_name, 
178                                            vector<metricDefinitionNode*>& parts,
179 #if defined(MT_THREAD)
180                                            int agg_op, AGG_LEVEL agg_level)
181 : aggLevel(agg_level),
182 #else
183                                            int agg_op)
184 : aggregate_(true), 
185 #endif
186   aggOp(agg_op), inserted_(false),  installed_(false),
187   met_(metric_name), focus_(foc),
188   flat_name_(cat_name), components(parts),
189   aggSample(agg_op),
190   cumulativeValue_float(0.0),
191   id_(-1), originalCost_(0.0), proc_(NULL)
192 {
193   unsigned p_size = parts.size();
194   for (unsigned u=0; u<p_size; u++) {
195     metricDefinitionNode *mi = parts[u];
196     mi->aggregators += this;
197     mi->samples += aggSample.newComponent();
198   }
199 #if defined(MT_THREAD)
200   needData_ = true ;
201 #endif
202 }
203
204 // check for "special" metrics that are computed directly by paradynd 
205 // if a cost of an internal metric is asked for, enable=false
206 metricDefinitionNode *doInternalMetric(vector< vector<string> >& canon_focus,
207                                        vector< vector<string> >& component_canon_focus,
208                                        string& metric_name, string& flat_name,
209                                        bool enable, bool& matched)
210 {
211   // called by createMetricInstance, below.
212   // return values:
213   //   a valid metricDefinitionNode* when successful
214   //   -1 --> enable was false
215   //   -2 --> not legal to instrument this focus
216   //   NULL --> a more serious error (probably metric-is-unknown)
217
218   matched = false;
219   metricDefinitionNode *mn = 0; 
220
221   // check to see if this is an internal metric
222   unsigned im_size = internalMetric::allInternalMetrics.size();
223   for (unsigned im_index=0; im_index<im_size; im_index++){
224     internalMetric *theIMetric = internalMetric::allInternalMetrics[im_index];
225     if (theIMetric->name() == metric_name) {
226       matched = true;
227       if (!enable)
228          return (metricDefinitionNode*)-1;
229
230       if (!theIMetric->legalToInst(canon_focus))
231          // Paradyn will handle this case and report appropriate error msg
232          return (metricDefinitionNode*)-2;
233
234       mn = new metricDefinitionNode(NULL, metric_name, canon_focus,
235                                     component_canon_focus,
236                                     flat_name, theIMetric->aggregate());
237       assert(mn);
238
239       theIMetric->enableNewInstance(mn);
240       return(mn);
241     }
242   }
243
244   // check to see if this is a cost metric
245   for (unsigned i=0; i < costMetric::allCostMetrics.size(); i++){
246      if(costMetric::allCostMetrics[i]->name() == metric_name){
247           matched = true;
248           if (!enable) return (metricDefinitionNode*)-1;
249           costMetric *nc = costMetric::allCostMetrics[i];
250           if (!nc->legalToInst(canon_focus)) return (metricDefinitionNode*)-2;
251
252           mn = new metricDefinitionNode(NULL, metric_name, canon_focus,
253                                         component_canon_focus,
254                                         flat_name, nc->aggregate());
255           assert(mn);
256
257           nc->enable(mn); 
258
259           return(mn);
260      }
261   }
262
263   // No matches found among internal or cost metrics
264   return NULL;
265 }
266
267 // the following should probably be made a public static member fn of class metric
268 string metricAndCanonFocus2FlatName(const string &metricName,
269                                     const vector< vector<string> > &canonFocus) {
270    string result = metricName;
271
272    for (unsigned hierarchy=0; hierarchy < canonFocus.size(); hierarchy++)
273       for (unsigned component=0; component < canonFocus[hierarchy].size();
274            component++)
275          result += canonFocus[hierarchy][component];
276
277    return result;
278 }
279
280 // the following should probably be made a public static member fn of class metric
281 static bool focus2CanonicalFocus(const vector<unsigned> &focus,
282                                  vector< vector<string> > &canonFocus,
283                                  bool important) {
284    // takes in "focus", writes to "canonFocus".  Returns true iff successful.
285    // if "important" is false, don't print error msg on failure (called by guessCost();
286    // no mi is really being created)
287
288    vector< vector<string> > unCanonFocus;
289    if (!resource::foc_to_strings(unCanonFocus, focus, important)) { // writes to unCanonFocus
290       if (important)
291          cerr << "focus2CanonicalFocus failed since resource::foc_to_strings failed" << endl;
292       return false;
293    }
294
295    resource::make_canonical(unCanonFocus, canonFocus);
296
297    return true;
298 }
299
300 static void print_focus(debug_ostream &os, vector< vector<string> > &focus) {
301    for (unsigned a=0; a < focus.size(); a++) {
302       for (unsigned b=0; b < focus[a].size(); b++)
303          os << '/' << focus[a][b];
304
305       if (a < focus.size()-1)
306          os << ',';
307    }
308    os << endl;
309 }
310
311 metricDefinitionNode *createMetricInstance(string& metric_name, 
312                                            vector<u_int>& focus,
313                                            bool enable, // true if for real; false for guessCost()
314                                            bool& internal)
315 {
316     vector< vector<string> > canonicalFocus;
317     // we make third parameter false to avoid printing warning messages in
318     // focus2CanonicalFocus ("enable" was here previously) - naim
319     if (!focus2CanonicalFocus(focus, canonicalFocus, false)) {
320        //if (enable) cerr << "createMetricInstance failed because focus2CanonicalFocus failed" << endl;
321        return NULL;
322     }
323
324     //cerr << "createMetricInstance called.  metric_name = "
325     //     << metric_name << endl;
326     //cerr << " canonicalFocus (derived from focus (u_int id array)) == "
327     //   << endl;
328     //for(unsigned z = 0; z < canonicalFocus.size(); z++) {
329     //    vector<string> temp_strings = canonicalFocus[z];
330     //  cerr << "  canonicalFocus[" << z << "] : " << endl;
331     //    for(unsigned y = 0; y < temp_strings.size(); y++) {
332     //        cerr << "   " << temp_strings[y] << endl;
333     //    }
334     //}
335
336     string flat_name = metricAndCanonFocus2FlatName(metric_name, canonicalFocus);
337     //cerr << "flat_name = " << flat_name << endl;
338
339
340     // first see if it is already defined.
341     dictionary_hash_iter<unsigned, metricDefinitionNode*> mdi(allMIs);
342
343 /*
344  * See if we can find the requested metric instance.
345  *   Currently this is only used to cache structs built for cost requests 
346  *   which are then instantiated.  This could be used as a general system
347  *   to request find sub-metrics that are already.defines and use them to
348  *   reduce cost.  This would require adding the componenets of an aggregate
349  *   into the allMIs list since searching tends to be top down, not bottom
350  *   up.  This would also require adding a ref count to many of the structures
351  *   so they only get deleted when we are really done with them.
352  *
353  */
354
355     // first see if it is already defined.
356     for (; mdi; mdi++) {
357        metricDefinitionNode *mi = mdi.currval();
358
359        if (mi->getFullName() == flat_name) {
360           metric_cerr << "createMetricInstance: mi with flat_name " << flat_name << " already exists! using it" << endl;
361           return mi; // this metricDefinitionNode has already been defined
362        }
363     }
364
365     //cerr << " previous instance of metric not found, trying to create"
366     //   << endl;
367
368     if (mdl_can_do(metric_name)) {
369       //cerr << " mdl_can_do(metrix_name) == TRUE" << endl;
370       internal = false;
371
372       /* select the processes that should be instrumented. We skip process
373          that have exited, and processes that have been created but are not
374          completely initialized yet.
375          If we try to insert instrumentation in a process that is not ready
376          yet, we get a core dump.
377          A process is ready when it is not in neonatal state and the 
378          isBootstrappedYet returns true.
379       */
380       vector<process*> procs;
381       vector< vector<pdThread *> > threadsVec;
382       
383       for (unsigned u = 0; u < processVec.size(); u++) {
384         if (processVec[u]->status()==exited 
385             || processVec[u]->status()==neonatal || processVec[u]->isBootstrappedYet()) 
386         {
387           procs += processVec[u];
388 #if defined(MT_THREAD)
389           threadsVec += processVec[u]->threads;
390 #endif
391         }
392       }
393
394 #if defined(MT_THREAD)
395       if (procs.size() == 0 || threadsVec.size() == 0) {
396         // there are no processes or threads to instrument
397 #else
398       if (procs.size() == 0) {
399        // there are no processes to instrument
400 #endif
401         //printf("createMetricInstance failed, no processes to instrument\n");
402         return NULL;
403       }
404
405       bool computingCost;
406       if (enable) computingCost = false;
407       else computingCost = true;
408       metricDefinitionNode *mi = mdl_do(canonicalFocus, metric_name, flat_name,
409                                         procs, threadsVec, false, computingCost);
410       //cerr << "  mdl_do returned ";
411       //if (mi == NULL) {
412       //    cerr << "NULL" << endl;
413       //} else {
414       //    cerr << "Non-NULL" << endl;
415       //}
416
417       if (mi == NULL) {
418          metric_cerr << "createMetricInstance failed since mdl_do failed" << endl;
419          metric_cerr << "metric name was " << metric_name << "; focus was ";
420          print_focus(metric_cerr, canonicalFocus);
421       }
422 #if defined(TEST_DEL_DEBUG)
423       // print mdn info
424       if (mi != NULL) {
425         logLine("*** AGGREGATE LEVEL\n");
426         sprintf(errorLine,"*** METRIC: %s\n",mi->getMetName().string_of());
427         logLine(errorLine);
428         sprintf(errorLine,"*** FLAT NAME: %s\n",mi->getFullName().string_of());
429         logLine(errorLine);
430         for (unsigned i=0;i<(mi->getComponents()).size();i++) {
431           metricDefinitionNode *proc_mi = (mi->getComponents())[i];
432           if (i==0) {
433             if (proc_mi->getLevel() == PROC_COMP)
434               logLine("****** PROCESS LEVEL\n");
435             if (proc_mi->getLevel() == THR_COMP)
436               logLine("****** THREAD LEVEL\n");
437           }
438           sprintf(errorLine,"****** METRIC: %s\n",proc_mi->getMetName().string_of());
439           logLine(errorLine);
440           sprintf(errorLine,"****** FLAT NAME: %s\n",proc_mi->getFullName().string_of());
441           logLine(errorLine);
442           for (unsigned j=0;j<(proc_mi->getComponents()).size();j++) {
443             metricDefinitionNode *thr_mi = (proc_mi->getComponents())[j];
444             if (j==0) {
445               if (thr_mi->getLevel() == PROC_COMP)
446                 logLine("********* PROCESS LEVEL\n");
447               if (thr_mi->getLevel() == THR_COMP)
448                 logLine("********* THREAD LEVEL\n");
449             }
450             sprintf(errorLine,"********* METRIC: %s\n",thr_mi->getMetName().string_of());
451             logLine(errorLine);
452             sprintf(errorLine,"********* FLAT NAME: %s\n",thr_mi->getFullName().string_of());
453             logLine(errorLine);   
454           }
455         }
456       }
457 #endif
458       return mi;
459     } else {
460       //cerr << " mdl_can_do(metrix_name) == FALSE" << endl;
461       bool matched;
462       metricDefinitionNode *mi=doInternalMetric(canonicalFocus,
463                           canonicalFocus, // is this right for component_canon_focus???
464                           metric_name,flat_name,enable,matched);
465          // NULL on serious error; -1 if enable was false; -2 if illegal to instr with
466          // given focus [many internal metrics work only for whole program]
467
468       if (mi == (metricDefinitionNode*)-2) {
469          metric_cerr << "createMetricInstance: internal metric " << metric_name << " isn't defined for focus: ";
470          print_focus(metric_cerr, canonicalFocus);
471          mi = NULL; // straighten up the return value
472       }
473       else if (mi == (metricDefinitionNode*)-1) {
474          assert(!enable); // no error msg needed
475          mi = NULL; // straighten up the return value
476       }
477       else if (mi == NULL) {
478          // more serious error...do a printout
479          metric_cerr << "createMetricInstance failed since doInternalMetric failed" << endl;
480          metric_cerr << "metric name was " << metric_name << "; focus was ";
481          print_focus(metric_cerr, canonicalFocus);
482       }
483
484       internal = true;
485       return mi;
486     }
487 }
488
489
490 // propagate this metric instance to process p.
491 // p is a process that started after the metric instance was created
492 // note: don't call this routine for a process started via fork or exec, just
493 // for processes started the "normal" way.
494 // "this" is an aggregate mi, not a component one.
495
496 void metricDefinitionNode::propagateToNewProcess(process *p) {
497   unsigned comp_size = components.size();
498
499   if (comp_size == 0)
500     return; // if there are no components, shouldn't the mi be fried?
501
502   for (unsigned u = 0; u < comp_size; u++) {
503     if (components[u]->proc() == p) {
504       // The metric is already enabled for this process. This case can 
505       // happen when we are starting several processes at the same time.
506       // (explain...?)
507       return;
508     }
509   }
510
511   bool internal = false;
512
513   metricDefinitionNode *mi = NULL;
514      // an aggregate (not component) mi, though we know that it'll contain just
515      // one component.  It's that one component that we're really interested in.
516   if (mdl_can_do(met_)) {
517       // Make the unique ID for this metric/focus visible in MDL.
518       string vname = "$globalId";
519       mdl_env::add(vname, false, MDL_T_INT);
520       mdl_env::set(this->getMId(), vname);
521
522       vector<process *> vp(1,p);
523       vector< vector<pdThread *> > threadsVec;
524 #if defined(MT_THREAD)
525       threadsVec += p->threads;
526 #endif
527       mi = mdl_do(focus_, met_, flat_name_, vp, threadsVec, false, false);
528   } else {
529     // internal and cost metrics don't need to be propagated (um, is this correct?)
530     mi = NULL;
531   }
532
533   if (mi) { // successfully created new mi
534     assert(mi->components.size() == 1);
535     metricDefinitionNode *theNewComponent = mi->components[0];
536
537     components += theNewComponent;
538     theNewComponent->aggregators[0] = this;
539     theNewComponent->samples[0] = aggSample.newComponent();
540     if (!internal) {
541       theNewComponent->insertInstrumentation();
542       theNewComponent->checkAndInstallInstrumentation();
543     }
544
545     // update cost
546     const float cost = mi->cost();
547     if (cost > originalCost_) {
548       currentPredictedCost += cost - originalCost_;
549       originalCost_ = cost;
550     }
551
552     mi->components.resize(0); // protect the new component
553     delete mi;
554   }
555 }
556
557 metricDefinitionNode* metricDefinitionNode::handleExec() {
558    // called by handleExec(), below.  See that routine for documentation.
559    // "this" is a component mi.
560
561    // If this component mi can be (re-)enabled in the new (post-exec) process, then do
562    // so.  Else, remove the component mi from aggregators, etc.  Returns new component
563    // mi if successful, NULL otherwise.
564
565 #if defined(MT_THREAD)
566    assert(aggLevel == PROC_COMP);
567 #else
568    assert(!aggregate_);
569 #endif
570
571    // How can we tell if the mi can be inserted into the "new" (post-exec) process?
572    // A component mi is basically a set of instReqNodes and dataReqNodes.  The latter
573    // don't restrict what can be inserted (is this right?); the instReqNodes hold the
574    // key -- we should look at the functions (instPoint's) where code (whose contents
575    // are in AstNode's) would be inserted.  Now clearly, the instPoint's must be
576    // checked -- if any one doesn't exist, then the instReqNode and hence the component
577    // mi doesn't belong in the post-exec process.  But what about the AstNode's?
578    // Should the code that gets inserted be subject to a similar test?  Probably, but
579    // we currently don't do it.
580
581    // BUT: Even if a process contains a function in both the pre-exec and post-exec
582    // stages, we must assume that the function is IN A DIFFERENT LOCATION IN
583    // THE ADDRESS SPACE.  Ick.  So the instPoint's can't be trusted and must
584    // be recalculated from scratch.  In that regard, this routine is similar to
585    // propagateToNewProcess(), which propagates aggregate mi's to a brand new
586    // process (but which doesn't work for processes started via fork or exec).
587    // The lesson learned is to (ick, ick, ick) call mdl_do() all over again.
588    // This gets really confusing when you consider that a component mi can belong
589    // to several aggregate mi's (e.g. if we represent cpu time for proc 100 then
590    // we can belong to cpu/whole and cpu/proc-100); for which aggregate mi should
591    // we run mdl_do?  Any will do, so we can pick arbitrarily (is this right?).
592
593    // QUESTION: What about internal or cost metrics???  They have aggregate and
594    //           component mi's just like normal metrics, right?  If that's so, then
595    //           they must be propagated too!   NOT YET IMPLEMENTED!!!
596
597    metricDefinitionNode *aggregateMI = this->aggregators[0];
598    metricDefinitionNode *resultCompMI = NULL; // so far...
599
600    const bool internal = !mdl_can_do(aggregateMI->met_);
601    if (internal)
602       return NULL; // NOT YET IMPLEMENTED
603
604    // try to propagate the mi
605    // note: the following code is mostly stolen from propagateToNewProcess(); blame
606    //       it for any bugs :)
607
608    // Make the unique ID for this metric/focus visible in MDL. (?)
609    string vname = "$globalId";
610    mdl_env::add(vname, false, MDL_T_INT);
611    mdl_env::set(aggregateMI->getMId(), vname);
612
613    vector<process*> vp(1, this->proc());
614    vector< vector<pdThread *> > threadsVec;
615 #if defined(MT_THREAD)
616    threadsVec += this->proc()->threads;
617 #endif
618    metricDefinitionNode *tempAggMI = mdl_do(aggregateMI->focus_,
619                                             aggregateMI->met_,
620                                             aggregateMI->flat_name_,
621                                             vp,
622                                             threadsVec,
623                                             true, // fry existing component MI
624                                             false);
625    if (tempAggMI == NULL)
626       return NULL; // failure
627
628 #if defined(MT_THREAD)
629    assert(tempAggMI->aggLevel == AGG_COMP);
630 #else
631    assert(tempAggMI->aggregate_);
632 #endif
633
634    // okay, it looks like we successfully created a new aggregate mi.
635    // Of course, we're just interested in the (single) component mi contained
636    // within it; it'll replace "this".
637
638    assert(tempAggMI->components.size() == 1);
639    resultCompMI = tempAggMI->components[0];
640
641    resultCompMI->aggregators.resize(0);
642    resultCompMI->samples.resize(0);
643
644    // For each aggregator, go back and find where "this" was a component mi.
645    // When found, replace the ptr to "this" with "theNewComponent".
646    unsigned num_aggregators = aggregators.size();
647    assert(num_aggregators > 0);
648    for (unsigned agglcv=0; agglcv < num_aggregators; agglcv++) {
649       metricDefinitionNode *aggMI = aggregators[agglcv];
650
651       bool found=false;
652       for (unsigned complcv=0; complcv < aggMI->components.size(); complcv++) {
653          if (aggMI->components[complcv] == this) {
654             aggMI->components[complcv] = resultCompMI;
655
656             resultCompMI->aggregators += aggMI;
657             resultCompMI->samples     += aggMI->aggSample.newComponent();
658             
659             aggMI->aggSample.removeComponent(this->samples[agglcv]);
660             
661             found=true;
662             break;
663          }
664       }
665       assert(found);
666    }
667
668    // Now let's actually insert the instrumentation:
669    if (!internal) {
670       resultCompMI->insertInstrumentation();
671       resultCompMI->checkAndInstallInstrumentation();
672    }
673
674    // And fry "tempAggMI", but make sure "resultCompMI" isn't fried when we do so
675    tempAggMI->components.resize(0); // protect resultCompMI
676    delete tempAggMI; // good riddance; you were an ugly hack to begin with
677
678    return resultCompMI;
679 }
680
681 void metricDefinitionNode::handleExec(process *proc) {
682    // a static member fn.
683    // handling exec is tricky.  At the time this routine is called, the "new" process
684    // has been bootstrapped and is ready for stuff to get inserted.  No mi's have yet
685    // been propagated, and the data structures (allMIs, allMIComponents, etc.) are still
686    // in their old, pre-exec state, so they show component mi's enabled for this
687    // process, even though they're not (at least not yet).  This routines brings things
688    // up-to-date.
689    //
690    // Algorithm: loop thru all component mi's for this process.  If it is possible to
691    // propagate it to the "new" (post-exec) process, then do so.  If not, fry the
692    // component mi.  An example where a component mi can no longer fit is an mi
693    // specific to, say, function foo(), which (thanks to the exec syscall) no longer
694    // exists in this process.  Note that the exec syscall changed the addr space enough
695    // so even if a given routine foo() is present in both the pre-exec and post-exec
696    // process, we must assume that it has MOVED TO A NEW LOCATION, thus making
697    // the component mi's instReqNode's instPoint out-of-date.  Ick.
698
699    // note the two loops; we can't safely combine into one since the second loop modifies
700    // the dictionary.
701    vector<metricDefinitionNode*> allcomps;
702    for (dictionary_hash_iter<string,metricDefinitionNode*> iter=allMIComponents; iter; iter++)
703       allcomps += iter.currval();
704    
705    for (unsigned i=0; i < allcomps.size(); i++) {
706       metricDefinitionNode* componentMI = allcomps[i];
707       if (componentMI->proc() != proc)
708          continue;
709
710       forkexec_cerr << "calling handleExec for component "
711                     << componentMI->flat_name_ << endl;
712
713       metricDefinitionNode *replaceWithComponentMI = componentMI->handleExec();
714
715       if (replaceWithComponentMI == NULL) {
716          forkexec_cerr << "handleExec for component " << componentMI->flat_name_
717                        << " failed, so not propagating it" << endl;
718          componentMI->removeThisInstance(); // propagation failed; fry component mi
719       }
720       else {
721          forkexec_cerr << "handleExec for component " << componentMI->flat_name_
722                        << " succeeded...it has been propagated" << endl;
723          // new component mi has already been inserted in place of old component mi
724          // in all of its aggregate's component lists.  So, not much left to do,
725          // except to update allMIComponents.
726
727          assert(replaceWithComponentMI->flat_name_ == componentMI->flat_name_);
728          delete componentMI; // old component mi (dtor removes it from allMIComponents)
729          // This is redundant, see mdl.C, apply_to_process 
730          // assert(!allMIComponents.defines(replaceWithComponentMI->flat_name_));
731          allMIComponents[replaceWithComponentMI->flat_name_] = replaceWithComponentMI;
732       }
733    }
734 }
735
736 // called when all components have been removed (because the processes have exited
737 // or exec'd) from "this".  "this" is an aggregate mi.
738 void metricDefinitionNode::endOfDataCollection() {
739   assert(components.size() == 0);
740
741   // flush aggregateSamples
742   sampleInterval ret = aggSample.aggregateValues();
743
744   while (ret.valid) {
745     assert(ret.end > ret.start);
746     assert(ret.start >= (firstRecordTime/MILLION));
747     assert(ret.end >= (firstRecordTime/MILLION));
748     batchSampleData(id_, ret.start, ret.end, ret.value,
749                     aggSample.numComponents(),false);
750     ret = aggSample.aggregateValues();
751   }
752   flush_batch_buffer();
753   // trace data streams
754   extern dictionary_hash<unsigned, unsigned> traceOn;
755   for (dictionary_hash_iter<unsigned,unsigned> iter=traceOn; iter; iter++) {
756      unsigned key = iter.currkey();
757      unsigned val = iter.currval();
758      
759      if (val) {
760           extern void batchTraceData(int, int, int, char *);
761           extern bool TRACE_BURST_HAS_COMPLETED;
762           TRACE_BURST_HAS_COMPLETED = true;
763           batchTraceData(0, key, 0, (char *)NULL);
764           traceOn[key] = 0;
765       }
766   }
767   tp->endOfDataCollection(id_);
768 }
769
770 // remove a component from an aggregate.
771 // "this" is an aggregate mi; "comp" is a component mi.
772 void metricDefinitionNode::removeFromAggregate(metricDefinitionNode *comp, 
773                                                int deleteComp) {
774   unsigned size = components.size();
775   for (unsigned u = 0; u < size; u++) {
776 #if defined(TEST_DEL_DEBUG)
777     sprintf(errorLine,"=====> size=%d, component's name = %s\n",size,components[u]->getFullName().string_of());
778     logLine(errorLine);
779 #endif
780     if (components[u] == comp) {
781       if (deleteComp) {
782 #if defined(TEST_DEL_DEBUG)
783         sprintf(errorLine,"=====> REMOVING component %s\n",components[u]->getFullName().string_of());
784         logLine(errorLine);
785 #endif
786         removeComponent(components[u]);
787         //delete components[u];
788       }
789 #if defined(TEST_DEL_DEBUG)
790       else logLine("=====> REMOVING couldn't happen, deleteComp is false\n");
791 #endif
792       components[u] = NULL;
793       components[u] = components[size-1];
794       components.resize(size-1);
795       if (size == 1 && id_ != -1) {
796 #if defined(TEST_DEL_DEBUG)
797         sprintf(errorLine,"-----> endOfDataCollection for mid = %d, level = %d\n",id_,aggLevel);
798         logLine(errorLine);
799 #endif
800         endOfDataCollection();
801       }
802       return;
803     }
804   }
805 //#if defined(TEST_DEL_DEBUG)
806   sprintf(errorLine,"=====> mid=%d, component_flat_name = %s, component to delete = %s\n",id_,flat_name_.string_of(),comp->getFullName().string_of());
807   logLine(errorLine);
808 //#endif
809   // should always find the right component 
810   //assert(0);
811 }
812
813 // remove this component mi from all aggregators it is a component of.
814 // if the aggregate mi no longer has any components then fry the mi aggregate mi.
815 // called by removeFromMetricInstances, below, when a process exits (or exec's)
816 void metricDefinitionNode::removeThisInstance() {
817 #if defined(MT_THREAD)
818   assert(aggLevel != AGG_COMP);
819 #else
820   assert(!aggregate_);
821 #endif
822
823 #if defined(TEST_DEL_DEBUG)
824   sprintf(errorLine,"-----> removeThisInstance, mid = %d, level = %d\n",id_,aggLevel);
825   logLine(errorLine);
826 #endif
827
828   // first, remove from allMIComponents (this is new --- is it right?)
829   if (allMIComponents.defines(flat_name_)) {
830     allMIComponents.undef(flat_name_);
831   }
832
833   assert(aggregators.size() == samples.size());
834
835   for (unsigned u = 0; u < aggregators.size() && u < samples.size(); u++) {
836     aggregators[u]->aggSample.removeComponent(samples[u]);
837 #if defined(MT_THREAD)
838     aggregators[u]->removeFromAggregate(this,true); //why was 0
839 #else
840     aggregators[u]->removeFromAggregate(this, 0); 
841 #endif
842   }
843 }
844
845
846 // Called when a process exits, to remove the component associated to proc 
847 // from all metric instances.  (If, after an exec, we never want to carry over
848 // mi's from the pre-exec, then this routine will work there, too.  But we try to
849 // carry over mi's whenever appropriate.)
850 // Remove the aggregate metric instances that don't have any components left
851 void removeFromMetricInstances(process *proc) {
852     // Loop through all of the _component_ mi's; for each with component process
853     // of "proc", remove the component mi from its aggregate mi.
854     // Note: imho, there should be a *per-process* vector of mi-components.
855
856    // note 2 loops for safety (2d loop may modify dictionary?)
857     vector<metricDefinitionNode *> MIs;
858     for (dictionary_hash_iter<string,metricDefinitionNode*> iter=allMIComponents; iter; iter++)
859        MIs += iter.currval();
860
861 #if defined(TEST_DEL_DEBUG)
862     sprintf(errorLine,"=====> removeFromMetricInstances, MIs size=%d\n",MIs.size());
863     logLine(errorLine);
864 #endif
865     for (unsigned j = 0; j < MIs.size(); j++) {
866       if (MIs[j]->proc() == proc) 
867         MIs[j]->removeThisInstance();
868     }
869     costMetric::removeProcessFromAll(proc); // what about internal metrics?
870 }
871
872 /* *************************************************************************** */
873
874 #if defined(MT_THREAD)
875 //
876 // reUseIndex only works at the presence of an aggregator.
877 // We always need a dummy aggregator for threads metrics, and it is 
878 // implemented in mdl.C apply_to_process
879 //
880 void metricDefinitionNode::reUseIndexAndLevel(unsigned &p_allocatedIndex, 
881                                               unsigned &p_allocatedLevel)
882 {
883   p_allocatedIndex = UINT_MAX;
884   p_allocatedLevel = UINT_MAX;
885   unsigned agg_size = aggregators.size();
886
887   metricDefinitionNode *proc_mn = NULL;
888   for (unsigned uu=0; uu < agg_size; uu++)
889     if (aggregators[uu]->aggLevel == PROC_COMP) {
890       proc_mn = aggregators[uu];
891       break;
892     }
893
894   if (proc_mn != NULL) {
895     unsigned c_size = proc_mn->components.size();
896     for (unsigned i=0;i<c_size;i++) {
897       if (proc_mn->components[i] != this) {
898         dataReqNode *p_dataRequest;
899         // Assume for all metrics, data are allocated in the same order
900         // we get the one that was created the earliest
901 #if defined(TEST_DEL_DEBUG)
902         sprintf(errorLine, "proc_mn->dataRequests.size=%d, this->dataRequests.size=%d",
903                 proc_mn->components[i]->dataRequests.size(),
904                 this->dataRequests.size());
905         cerr << errorLine << endl ;
906 #endif
907
908         if (proc_mn->components[i]->dataRequests.size()>this->dataRequests.size()) {
909           p_dataRequest = proc_mn->components[i]->dataRequests[this->dataRequests.size()];
910           p_allocatedIndex = p_dataRequest->getAllocatedIndex();
911           p_allocatedLevel = p_dataRequest->getAllocatedLevel();
912 #if defined(TEST_DEL_DEBUG)
913           sprintf(errorLine,"=====> re-using level=%d, index=%d\n",p_allocatedLevel,p_allocatedIndex);
914           cerr << errorLine << endl;
915 #endif
916           break;
917         }
918       }
919     } 
920   }
921 }
922 #endif //MT_THREAD
923
924 // obligatory definition of static member vrble:
925 int metricDefinitionNode::counterId=0;
926
927 #if defined(MT_THREAD)
928 dataReqNode *metricDefinitionNode::addSampledIntCounter(pdThread *thr, int initialValue,
929 #else
930 dataReqNode *metricDefinitionNode::addSampledIntCounter(int initialValue,
931 #endif
932                                                         bool computingCost,
933                                                         bool doNotSample)
934 {
935    dataReqNode *result=NULL;
936
937 #ifdef SHM_SAMPLING
938 #ifdef MT_THREAD
939    // shared memory sampling of a reported intCounter
940    unsigned p_allocatedIndex, p_allocatedLevel;
941    reUseIndexAndLevel(p_allocatedIndex, p_allocatedLevel);
942 #if defined(TEST_DEL_DEBUG)
943    sprintf(errorLine,"+++++ creating counter for mid=%d, name=%s\n",id_,flat_name_.string_of());
944    logLine(errorLine);
945 #endif
946    result = new sampledShmIntCounterReqNode(thr, initialValue,
947                                             metricDefinitionNode::counterId,
948                                             this, computingCost, doNotSample,
949                                             p_allocatedIndex,p_allocatedLevel);
950 #else
951    result = new sampledShmIntCounterReqNode(initialValue,
952                                             metricDefinitionNode::counterId,
953                                             this, computingCost, doNotSample);
954 #endif //MT_THREAD
955       // implicit conversion to base class
956 #else
957    // non-shared-memory sampling of a reported intCounter
958    result = new sampledIntCounterReqNode(initialValue,
959                                          metricDefinitionNode::counterId,
960                                          this, computingCost);
961       // implicit conversion to base class
962 #endif
963
964    assert(result);
965    
966    metricDefinitionNode::counterId++;
967    proc_->numOfActCounters_is++;
968
969    internalMetricCounterId = metricDefinitionNode::counterId;
970
971    dataRequests += result;
972    return result;
973 }
974
975 dataReqNode *metricDefinitionNode::addUnSampledIntCounter(int initialValue,
976                                                           bool computingCost) {
977    // sampling of a non-reported intCounter (probably just a predicate)
978    // NOTE: In the future, we should probably put un-sampled intcounters
979    // into shared-memory when SHM_SAMPLING is defined.  After all, the shared
980    // memory heap is faster.
981    dataReqNode *result = new nonSampledIntCounterReqNode
982                          (initialValue, metricDefinitionNode::counterId, 
983                           this, computingCost);
984       // implicit conversion to base class
985    assert(result);
986
987    metricDefinitionNode::counterId++;
988
989    internalMetricCounterId = metricDefinitionNode::counterId;
990
991    dataRequests += result;
992    return result;
993 };
994
995 #if defined(MT_THREAD)
996 dataReqNode *metricDefinitionNode::addWallTimer(bool computingCost, pdThread *thr) {
997 #else
998 dataReqNode *metricDefinitionNode::addWallTimer(bool computingCost) {
999 #endif
1000    dataReqNode *result = NULL;
1001
1002 #ifdef SHM_SAMPLING
1003 #if defined(MT_THREAD)
1004    unsigned p_allocatedIndex, p_allocatedLevel;
1005    reUseIndexAndLevel(p_allocatedIndex, p_allocatedLevel);
1006    result = new sampledShmWallTimerReqNode(thr, metricDefinitionNode::counterId, this, computingCost, p_allocatedIndex, p_allocatedLevel);
1007       // implicit conversion to base class
1008 #else
1009    result = new sampledShmWallTimerReqNode(metricDefinitionNode::counterId, this, computingCost);
1010 #endif //MT_THREAD
1011 #else
1012    result = new sampledTimerReqNode(wallTime, metricDefinitionNode::counterId, this, computingCost);
1013       // implicit conversion to base class
1014 #endif
1015
1016    assert(result);
1017
1018    metricDefinitionNode::counterId++;
1019    proc_->numOfActWallTimers_is++;
1020
1021    internalMetricCounterId = metricDefinitionNode::counterId;
1022
1023    dataRequests += result;
1024    return result;
1025 }
1026
1027 #if defined(MT_THREAD)
1028 dataReqNode *metricDefinitionNode::addProcessTimer(bool computingCost, pdThread *thr) {
1029 #else
1030 dataReqNode *metricDefinitionNode::addProcessTimer(bool computingCost) {
1031 #endif
1032    dataReqNode *result = NULL;
1033
1034 #ifdef SHM_SAMPLING
1035 #if defined(MT_THREAD)
1036    unsigned p_allocatedIndex, p_allocatedLevel;
1037    reUseIndexAndLevel(p_allocatedIndex, p_allocatedLevel);
1038    result = new sampledShmProcTimerReqNode(thr, metricDefinitionNode::counterId, this, computingCost, p_allocatedIndex, p_allocatedLevel);
1039       // implicit conversion to base class
1040 #else
1041    result = new sampledShmProcTimerReqNode(metricDefinitionNode::counterId, this, computingCost);
1042 #endif //MT_THREAD
1043 #else
1044    result = new sampledTimerReqNode(processTime, metricDefinitionNode::counterId, this, computingCost);
1045       // implicit conversion to base class
1046 #endif
1047
1048    assert(result);
1049
1050    metricDefinitionNode::counterId++;
1051    proc_->numOfActProcTimers_is++;
1052
1053    internalMetricCounterId = metricDefinitionNode::counterId;
1054
1055    dataRequests += result;
1056    return result;
1057 };
1058
1059 /* *************************************************************************** */
1060
1061 // called when a process forks (by handleFork(), below). "this" is a (component)
1062 // mi in the parent process. Duplicate it for the child, with appropriate
1063 // changes (i.e. the pid of the component focus name differs), and return the newly
1064 // created child mi.  "map" maps all instInstance's of the parent to those copied into
1065 // the child.
1066 // 
1067 // Note how beautifully everything falls into place.  Consider the case of alarm
1068 // sampling with cpu/whole program.  Then comes the fork.  The parent process has
1069 // (0) a tTimer structure allocated in a specific location in the inferior heap,
1070 // (1) instrumentation @ main to call startTimer on that ptr, (2) instrumentation in
1071 // DYNINSTsampleValues() to call DYNINSTreportTimer on that ptr.
1072 // The child process of fork will have ALL of these things in the exact same locations,
1073 // which is correct.  We want the timer to be located in the same spot; we want
1074 // DYNINSTreportTimer to be called on the same pointer; and main() hasn't moved.
1075 //
1076 // So there's not much to do here.  We create a new component mi (with same flat name
1077 // as in the parent, except for a different pid), and call "forkProcess" for all
1078 // dataReqNodes and instReqNodes, none of which have to do anything titanic.
1079
1080 metricDefinitionNode *metricDefinitionNode::forkProcess(process *child,
1081                         const dictionary_hash<instInstance*,instInstance*> &map) const {
1082     // The "focus_" member vrble stays the same, because it was always for the
1083     // metric as a whole, and not for some component.
1084     //
1085     // But two things must change, because they were component-specific (and the
1086     // component has changed processes):
1087     // (1) the flat name
1088     // (2) the component focus (not to be confused with plain focus_)
1089     //
1090     // For example, instead of
1091     // "/Code/foo.c/myfunc, /Process/100, ...", we should have
1092     // "/Code/foo.c/myfunc, /Process/101, ...", because the pid of the child
1093     // differs from that of the parent.
1094
1095     // The resource structure of a given process is found in the "rid"
1096     // field of class process.
1097     const resource *parentResource = child->getParent()->rid;
1098     const string &parentPartName = parentResource->part_name();
1099
1100     const resource *childResource = child->rid;
1101     const string &childPartName = childResource->part_name();
1102
1103     vector< vector<string> > newComponentFocus = this->component_focus;
1104        // we'll change the process, but not the machine name.
1105     bool foundProcess = false;
1106
1107     for (unsigned hier=0; hier < component_focus.size(); hier++) {
1108        if (component_focus[hier][0] == "Machine") {
1109           foundProcess = true;
1110           assert(component_focus[hier].size() >= 3);
1111              // since a component focus is by definition specific to some process
1112
1113           //assert(component_focus[hier][2] == parentPartName); -- DAN
1114           if( component_focus[hier][2] != parentPartName )
1115                   return NULL;
1116
1117           // change the process:
1118           newComponentFocus[hier][2] = childPartName;
1119
1120           break;
1121        }
1122     }
1123     assert(foundProcess);
1124     
1125     string newComponentFlatName = metricAndCanonFocus2FlatName(met_, newComponentFocus);
1126
1127     metricDefinitionNode *mi =
1128         new metricDefinitionNode(child,
1129                          met_, // metric name doesn't change
1130                          focus_, // focus doesn't change (tho component focus will)
1131                          newComponentFocus, // this is a change
1132                          newComponentFlatName, // this is a change
1133                          aggOp // no change
1134                          );
1135     assert(mi);
1136
1137     metricDefinitionNode::counterId++;
1138
1139     forkexec_cerr << "metricDefinitionNode::forkProcess -- component flat name for parent is " << flat_name_ << "; for child is " << mi->flat_name_ << endl;
1140
1141     internalMetricCounterId = metricDefinitionNode::counterId;
1142
1143     assert(!allMIComponents.defines(newComponentFlatName));
1144     allMIComponents[newComponentFlatName] = mi;
1145
1146     // Duplicate the dataReqNodes:
1147     for (unsigned u1 = 0; u1 < dataRequests.size(); u1++) {
1148        // must add to midToMiMap[] before dup() to avoid some assert fails
1149        const int newCounterId = metricDefinitionNode::counterId++;
1150           // no relation to mi->getMId();
1151        forkexec_cerr << "forked dataReqNode going into midToMiMap with id " << newCounterId << endl;
1152        assert(!midToMiMap.defines(newCounterId));
1153        midToMiMap[newCounterId] = mi;
1154        
1155        dataReqNode *newNode = dataRequests[u1]->dup(child, mi, newCounterId, map);
1156          // remember, dup() is a virtual fn, so the right dup() and hence the
1157          // right fork-ctor is called.
1158        assert(newNode);
1159
1160        mi->dataRequests += newNode;
1161     }
1162
1163     // Duplicate the instReqNodes:
1164     for (unsigned u2 = 0; u2 < instRequests.size(); u2++) {
1165       mi->instRequests += instReqNode::forkProcess(instRequests[u2], map);
1166     }
1167
1168     mi->inserted_ = true;
1169
1170     return mi;
1171 }
1172
1173 bool metricDefinitionNode::unFork(dictionary_hash<instInstance*, instInstance*> &map,
1174                                   bool unForkInstRequests,
1175                                   bool unForkDataRequests) {
1176    // see below handleFork() for explanation of why this routine is needed.
1177    // "this" is a component mi for the parent process; we need to remove copied
1178    // instrumentation from the _child_ process.
1179    // Returns true iff the instrumentation was removed in the child (would be false
1180    // if it's not safe to remove the instrumentation in the child because it was
1181    // active.)
1182
1183    // "map" maps instInstances from the parent process to instInstances in the child
1184    // process.
1185
1186    // We loop thru the instReqNodes of the parent process, unforking each.
1187    // In addition, we need to unfork the dataReqNodes, because the alarm-sampled
1188    // ones instrument DYNINSTsampleValues.
1189
1190    bool result = true;
1191
1192    if (unForkInstRequests)
1193       for (unsigned lcv=0; lcv < instRequests.size(); lcv++)
1194          if (!instRequests[lcv].unFork(map))
1195             result = false; // failure
1196
1197    if (unForkDataRequests)
1198       for (unsigned lcv=0; lcv < dataRequests.size(); lcv++)
1199          if (!dataRequests[lcv]->unFork(map))
1200             result = false; // failure
1201
1202    return result;
1203 }
1204
1205
1206 // called by forkProcess of context.C, just after the fork-constructor was
1207 // called for the child process.
1208 void metricDefinitionNode::handleFork(const process *parent, process *child,
1209                               dictionary_hash<instInstance*,instInstance*> &map) {
1210    // "map" defines a mapping from all instInstance's of the parent process to
1211    // the copied one in the child process.  Some of the child process's ones may
1212    // get fried by this routine, as it detects that instrumentation has been copied
1213    // (by the fork syscall, which we have no control over) which doesn't belong in
1214    // the child process and therefore gets deleted manually.
1215   
1216    // Remember that a given component can be shared by multiple aggregator-mi's,
1217    // so be careful about duplicating a component twice.  Since we loop through
1218    // component mi's instead of aggregate mi's, it's no problem.  Note that it's
1219    // possible that only a subset of a component-mi's aggregators should get the newly
1220    // created child component mi.
1221
1222    // 2 loops for safety (2d loop may modify dictionary?)
1223    vector<metricDefinitionNode *> allComponents;
1224    for (dictionary_hash_iter<string,metricDefinitionNode*> iter=allMIComponents; iter; iter++)
1225       allComponents += iter.currval();
1226
1227    for (unsigned complcv=0; complcv < allComponents.size(); complcv++) {
1228       metricDefinitionNode *comp = allComponents[complcv];
1229
1230       // duplicate the component (create a new one) if it belongs in the
1231       // child process.  It belongs if any of its aggregate mi's should be
1232       // propagated to the child process.  An aggregate mi should be propagated
1233       // if it wasn't refined to some process.
1234
1235       bool shouldBePropagated = false; // so far
1236       bool shouldBeUnforkedIfNotPropagated = false; // so far
1237       assert(comp->aggregators.size() > 0);
1238       for (unsigned agglcv1=0; agglcv1 < comp->aggregators.size(); agglcv1++) {
1239          metricDefinitionNode *aggMI = comp->aggregators[agglcv1];
1240
1241          if (aggMI->focus_[resource::machine].size() <= 2) {
1242             // wasn't specific to any process
1243             shouldBeUnforkedIfNotPropagated = false; // we'll definitely be using it
1244             shouldBePropagated = true;
1245             break;
1246          }
1247          else if (comp->proc() == parent)
1248             // was specific to parent process, so fork() copied it into the child,
1249             // unless it was an internal or cost metric, in which case there was nothing
1250             // for fork to copy.
1251             if (!internalMetric::isInternalMetric(aggMI->getMetName()) &&
1252                 !costMetric::isCostMetric(aggMI->getMetName()))
1253                shouldBeUnforkedIfNotPropagated = true;
1254          else
1255             // was specific to other process, so nothing is in the child for it yet
1256             ;
1257       }
1258
1259       if (!shouldBePropagated && shouldBeUnforkedIfNotPropagated) {
1260          // this component mi isn't gonna be propagated to the child process, but
1261          // the fork syscall left some residue in the child.  Delete that residue now.
1262          assert(comp->proc() == parent);
1263          comp->unFork(map, true, true); // also modifies 'map' to remove items
1264       }
1265
1266       if (!shouldBePropagated)
1267          continue;
1268
1269       // Okay, it's time to propagate this component mi to the subset of its aggregate
1270       // mi's which weren't refined to a specific process.  If we've gotten to this
1271       // point, then there _is_ at least one such aggregate.
1272       assert(shouldBePropagated);
1273       metricDefinitionNode *newComp = comp->forkProcess(child, map);
1274
1275           if( !newComp )
1276                   continue;
1277          // copies instr (well, fork() does this for us), allocs ctr/timer space,
1278          // initializes.  Basically, copies dataReqNode's and instReqNode's.
1279
1280       bool foundAgg = false;
1281       for (unsigned agglcv2=0; agglcv2 < comp->aggregators.size(); agglcv2++) {
1282          metricDefinitionNode *aggMI = comp->aggregators[agglcv2];
1283          if (aggMI->focus_[resource::machine].size() <= 2) {
1284             // this aggregate mi wasn't specific to any process, so it gets the new
1285             // child component.
1286             aggMI->components += newComp;
1287             newComp->aggregators += aggMI;
1288             newComp->samples     += aggMI->aggSample.newComponent();
1289             foundAgg = true;
1290          }
1291       }
1292       assert(foundAgg);
1293    }
1294 }
1295
1296 bool metricDefinitionNode::anythingToManuallyTrigger() const {
1297 #if defined(MT_THREAD)
1298    if (aggLevel != PROC_COMP) {
1299 #else
1300    if (aggregate_) {
1301 #endif
1302       for (unsigned i=0; i < components.size(); i++)
1303          if (components[i]->anythingToManuallyTrigger())
1304             return true;
1305       return false;
1306    }
1307    else {
1308            // Should we do this?
1309            //
1310            if( manuallyTriggerNodes.size() > 0 )
1311                    return true;
1312            return false;
1313    }
1314
1315    assert(false);
1316 }
1317
1318 //
1319 // Added to allow metrics affecting a function F to be triggered when
1320 //  a program is executing (in a stack frame) under F:
1321 // The basic idea here is similar to Ari's(?) hack to start "whole 
1322 //  program" metrics requested while the program is executing 
1323 //  (see T_dyninstRPC::mdl_instr_stmt::apply in mdl.C).  However,
1324 //  in this case, the manuallyTrigger flag is set based on the 
1325 //  program stack (the call sequence implied by the sequence of PCs
1326 //  in the program stack), and the types of the set of inst points 
1327 //  which the metricDefinitionNode corresponds to, as opposed to
1328 //  a hacked interpretation of the original MDL statement syntax.
1329 // The basic algorithm is as follows:
1330 //  1. Construct function call sequence leading to the current 
1331 //     stack frame (yields vector of pf_Function hopefully equivalent
1332 //     to yield of "backtrace" functionality in gdb.
1333 //  2. Look at each instReqNode in *this (call it node n):
1334 //     Does n correspond to a function currently on the stack?
1335 //       No -> don't manually trigger n's instrumentation.
1336 //       Yes ->
1337 //         
1338 void metricDefinitionNode::adjustManuallyTrigger()
1339 {
1340   vector<instPoint*> instPts;
1341   unsigned i, j, k, l;
1342   pd_Function *stack_func;
1343   instPoint *point;
1344   Address stack_pc;
1345   
1346   // aggregate metricDefinitionNode - decide whether to manually trigger 
1347   //  instrumentation corresponding to each component node individually.
1348 #if defined(MT_THREAD)
1349   if (aggLevel == AGG_COMP || aggLevel == THR_COMP)
1350 #else
1351   if (aggregate_) 
1352 #endif
1353   {
1354     for (i=0; i < components.size(); i++) {
1355       components[i]->adjustManuallyTrigger();
1356     }
1357   } 
1358   // non-aggregate:
1359   else {
1360
1361     string prettyName;
1362     if (pd_debug_catchup) {
1363       prettyName = met_ + string(": <");;
1364
1365       bool first = true;
1366       for (unsigned h=0; h<focus_.size(); h++) {
1367         if (focus_[h].size() > 1) {
1368           if (!first) prettyName += string(",");
1369           first = false;
1370           for (unsigned c=0; c< focus_[h].size(); c++) {
1371             prettyName += string("/");
1372             prettyName += focus_[h][c];
1373           }
1374         }
1375       }
1376       prettyName += string(">");
1377       cerr << "metricDefinitionNode::adjustManuallyTrigger() called. "
1378            << prettyName << ", instRequests.size = "
1379            << instRequests.size() << endl;
1380     }
1381     assert(proc_); // proc_ should always be correct for non-aggregates
1382     const function_base *mainFunc = proc_->getMainFunction();
1383     assert(mainFunc); // processes should always have mainFunction defined
1384                       // Instead of asserting we could call adjustManuallyTrigger0,
1385                       // which could handle a pseudo function.
1386 #ifndef OLD_CATCHUP
1387 //
1388 #if defined(MT_THREAD)
1389     vector<Address> stack_pcs;
1390     vector<vector<Address> > pc_s = proc_->walkAllStack();
1391     for (i=0; i< pc_s.size(); i++) {
1392       stack_pcs += pc_s[i];
1393     }
1394 //
1395 #else
1396     vector<Address> stack_pcs = proc_->walkStack();
1397 #endif
1398     if( stack_pcs.size() == 0 )
1399       cerr << "WARNING -- process::walkStack returned an empty stack" << endl;
1400     vector<pd_Function *> stack_funcs = proc_->convertPCsToFuncs(stack_pcs);
1401     proc_->correctStackFuncsForTramps( stack_pcs, stack_funcs );
1402     bool badReturnInst = false;
1403     
1404     unsigned i = stack_funcs.size();
1405     //for(i=0;i<stack_funcs.size();i++) {
1406     if (i!=0)
1407     do {
1408       --i;
1409       stack_func = stack_funcs[i];
1410       stack_pc = stack_pcs[i];
1411       if (pd_debug_catchup) {
1412         if( stack_func != NULL ) {
1413           instPoint *ip = findInstPointFromAddress(proc_, stack_pc);
1414           if (ip) {// this is an inst point
1415             cerr << i << ": " << stack_func->prettyName() << "@" << (void*) ip->iPgetAddress() << "[iP]"
1416                       << "@" << (void*)stack_pc << endl;
1417           } else 
1418             cerr << i << ": " << stack_func->prettyName() << "@" << (void*)stack_pc << endl;
1419         } else
1420           cerr << i << ": skipped (unknown function) @" << (void*)stack_pc << endl;
1421       }
1422       if (stack_func == NULL) continue;
1423       instPts.resize(0);
1424       instPts += const_cast<instPoint*>( stack_func->funcEntry(proc_) );
1425       instPts += stack_func->funcCalls(proc_);
1426       instPts += stack_func->funcExits(proc_);
1427       
1428 #if !(defined(i386_unknown_nt4_0) \
1429   || defined(i386_unknown_solaris2_5) \
1430   || defined(i386_unknown_linux2_0))
1431       // If there is a function on the stack with relevant instPoints which we were
1432       // not able to install return instances for, we don't want to manually trigger
1433       // anything else further on the stack, as it could cause inconsistencies with
1434       // metrics which rely on matching pairs of actions. - DAN
1435       // **NOTE** we don't do this on x86, because we can always immediately insert
1436       // a 'jump' to base tramp via. trap.  In addition, when we use a trap rather
1437       // than a branch, the return instance is still NULL, and this code breaks. - DAN
1438
1439       //
1440       // If any instrumentation attempt failed for this function, we shouldn't
1441       // be doing catchup instrumentation for this function. - ZHICHEN
1442       //
1443       for(j=1;j<instPts.size()&&!badReturnInst;j++) {
1444         for(k=0;k<instRequests.size();k++) {
1445           if( instPts[j] == instRequests[k].Point() ) {
1446             if( instRequests[k].getRInstance() != NULL
1447                 && !(instRequests[k].getRInstance()->Installed())
1448         //&& instPts[j]->triggeredExitingStackFrame(stack_func, stack_pc,
1449         // instRequests[k].When(), proc_ ) 
1450             )
1451             {
1452               if (pd_debug_catchup) {
1453                 cerr << "AdjustManuallyTrigger -- Bad return instance in "
1454                      << stack_func->prettyName()
1455                      << ", not manually triggering for this stack frame." << endl;
1456               }
1457               badReturnInst = true;
1458               break;
1459             }
1460           }
1461         }
1462       }
1463 #endif
1464       if( badReturnInst )
1465         continue;
1466       
1467       for(j=0;j<instPts.size();j++) {
1468         point = instPts[j];
1469         for(k=0;k<instRequests.size();k++) {
1470           if (point == instRequests[k].Point()) {
1471             if (instRequests[k].triggeredInStackFrame(stack_func, stack_pc, proc_))
1472             {
1473
1474               if (pd_debug_catchup) {
1475                 instReqNode &iRN = instRequests[k];
1476                 cerr << "--- catch-up needed for "
1477                      << prettyName << " @ " << stack_func->prettyName() 
1478                      << " @ " << (void*) stack_pc << endl;
1479 //
1480 //
1481                 switch (iRN.When()) {
1482                   case callPreInsn:
1483                     cerr << " callPreInsn for ";
1484                     break;
1485                   case callPostInsn:
1486                     cerr << " callPostInsn for ";
1487                     break;
1488                 }
1489 #if defined(mips_sgi_irix6_4)
1490               if( iRN.Point()->type() == IPT_ENTRY )
1491                 cerr << " FunctionEntry " << endl;
1492               else if (iRN.Point()->type() == IPT_EXIT )
1493                 cerr << " FunctionExit " << endl;
1494               else if (iRN.Point()->type() == IPT_CALL )
1495                 cerr << " callSite " << endl;
1496
1497 #elif defined(sparc_sun_solaris2_4) || defined(alpha_dec_osf4_0)
1498               if( iRN.Point()->ipType == functionEntry )
1499                 cerr << " Function Entry " << endl;
1500               else if( iRN.Point()->ipType == functionExit )
1501                 cerr << " FunctionExit " << endl;
1502               else if( iRN.Point()->ipType == callSite )
1503                 cerr << " callSite " << endl;
1504
1505 #elif defined(rs6000_ibm_aix4_1)
1506               if( iRN.Point()->ipLoc == ipFuncEntry )
1507                 cerr << " FunctionEntry " << endl;
1508               if( iRN.Point()->ipLoc == ipFuncReturn )
1509                 cerr << " FunctionExit " << endl;
1510               if( iRN.Point()->ipLoc == ipFuncCallPoint )
1511                 cerr << " callSite " << endl;
1512
1513 #elif defined(i386_unknown_nt4_0) || defined(i386_unknown_solaris2_5) \
1514       || defined(i386_unknown_linux2_0)
1515               if( iRN.Point()->iPgetAddress() == iRN.Point()->iPgetFunction()->addr() )
1516                 cerr << " FunctionEntry " << endl;
1517               else if ( iRN.Point()->insnAtPoint().isCall() ) 
1518                 cerr << " calSite " << endl;
1519               else
1520                  cerr << " FunctionExit " << endl;
1521 #else
1522 #error Check for instPoint type == entry not implemented on this platform
1523 #endif
1524
1525 //
1526 //
1527               }
1528               manuallyTriggerNodes += &(instRequests[k]);
1529             }
1530           }
1531         }
1532       }
1533     } while (i!=0);
1534
1535 #else // !OLD_CATCHUP
1536
1537     // The following code is used in the case where the new catchup code is disabled.
1538     // It is replicated in the adjustManuallyTrigger0 function and at some point in the
1539     // future could be moved into a single separate function.  This code could also
1540     // useful in the case where mainFunc is undefined.
1541
1542     // This code is a kludge which will catch the case where the WHOLE_PROGRAM metrics
1543     // have not been set to manjually trigger by the above code.  Look at the 
1544     // component_focus for the "Code" element, and see if there is any contraint.
1545     // Then, for each InstReqNode in this MetricDefinitionNode which is at the entry
1546     // point of main, and which has not been added to the manuallyTriggerNodes list,
1547     // add it to the list.
1548     for( j = 0; j < component_focus.size(); ++j )
1549       if( component_focus[j][0] == "Code" && ( component_focus[j].size() == 1 ||
1550                                                ( component_focus[j].size() == 2 && component_focus[j][1] == "" ) ) )
1551         for( k = 0; k < instRequests.size(); ++k ) {
1552           if( instRequests[ k ].Point()->iPgetFunction() == mainFunc ) {
1553             if( !find( manuallyTriggerNodes, &(instRequests[k]), l ) ) {
1554 #if defined(mips_sgi_irix6_4)
1555               if( instRequests[ k ].Point()->type() == IPT_ENTRY )
1556 #elif defined(sparc_sun_solaris2_4) || defined(alpha_dec_osf4_0)
1557               if( instRequests[ k ].Point()->ipType == functionEntry )
1558 #elif defined(rs6000_ibm_aix4_1)
1559               if( instRequests[ k ].Point()->ipLoc == ipFuncEntry )
1560 #elif defined(i386_unknown_nt4_0) || defined(i386_unknown_solaris2_5) \
1561       || defined(i386_unknown_linux2_0)
1562               if( instRequests[ k ].Point()->iPgetAddress() == mainFunc->addr() )
1563 #else
1564 #error Check for instPoint type == entry not implemented on this platform
1565 #endif
1566               {
1567                 if ( pd_debug_catchup ) {
1568                   metric_cerr << "AdjustManuallyTrigger -- (WHOLE_PROGRAM kludge) catch-up needed for "
1569                             << flat_name_ << " @ " << mainFunc->prettyName() << endl;
1570                 }
1571                 manuallyTriggerNodes.insert( 0, &(instRequests[k]) );
1572               }
1573             }
1574           }
1575         }
1576 #endif  // OLD_CATCHUP
1577   }
1578 }
1579
1580 //
1581 // degenerated version
1582 //
1583 void metricDefinitionNode::adjustManuallyTrigger0()
1584 {
1585   vector<instPoint*> instPts;
1586   unsigned i, j, k, l;
1587   
1588   // aggregate metricDefinitionNode - decide whether to manually trigger 
1589   //  instrumentation corresponding to each component node individually.
1590 #if defined(MT_THREAD)
1591   if (aggLevel == AGG_COMP || aggLevel == THR_COMP)
1592 #else
1593   if (aggregate_) 
1594 #endif
1595   {
1596     //cerr << "metricDefinitionNode::adjustManuallyTrigger() called, flat_name = "
1597     // << flat_name_.string_of() << endl;
1598     //cerr << " (metricDefinitionNode::adjustManuallyTrigger()) aggregate = true" << endl;
1599     for (i=0; i < components.size(); i++) {
1600       components[i]->adjustManuallyTrigger();
1601     }
1602   } 
1603   // non-aggregate:
1604   else {
1605     //cerr << "metricDefinitionNode::adjustManuallyTrigger() called, flat_name = "
1606     //   << flat_name_.string_of() << "aggregate = false, instRequests.size = "
1607     //   << instRequests.size() << endl;
1608     assert(proc_); // proc_ should always be correct for non-aggregates
1609     const function_base *mainFunc = proc_->getMainFunction();
1610     assert(mainFunc); // processes should always have mainFunction defined
1611     
1612     // This code is a kludge which will catch the case where the WHOLE_PROGRAM metrics
1613     // have not been set to manjually trigger by the above code.  Look at the 
1614     // component_focus for the "Code" element, and see if there is any contraint.
1615     // Then, for each InstReqNode in this MetricDefinitionNode which is at the entry
1616     // point of main, and which has not been added to the manuallyTriggerNodes list,
1617     // add it to the list.
1618     for( j = 0; j < component_focus.size(); ++j )
1619       if( component_focus[j][0] == "Code" && ( component_focus[j].size() == 1 ||
1620                                                ( component_focus[j].size() == 2 && component_focus[j][1] == "" ) ) )
1621         for( k = 0; k < instRequests.size(); ++k ) {
1622           if( instRequests[ k ].Point()->iPgetFunction() == mainFunc ) {
1623             if( !find( manuallyTriggerNodes, &(instRequests[k]), l ) ) {
1624 #if defined(mips_sgi_irix6_4)
1625               if( instRequests[ k ].Point()->type() == IPT_ENTRY )
1626 #elif defined(sparc_sun_solaris2_4) || defined(alpha_dec_osf4_0)
1627               if( instRequests[ k ].Point()->ipType == functionEntry )
1628 #elif defined(rs6000_ibm_aix4_1)
1629               if( instRequests[ k ].Point()->ipLoc == ipFuncEntry )
1630 #elif defined(i386_unknown_nt4_0) || defined(i386_unknown_solaris2_5) \
1631       || defined(i386_unknown_linux2_0)
1632               if( instRequests[ k ].Point()->iPgetAddress() == mainFunc->addr() )
1633 #else
1634 #error Check for instPoint type == entry not implemented on this platform
1635 #endif
1636               {
1637                 metric_cerr << "AdjustManuallyTrigger -- (WHOLE_PROGRAM kludge) catch-up needed for "
1638                             << flat_name_ << " @ " << mainFunc->prettyName() << endl;
1639                 manuallyTriggerNodes.insert( 0, &(instRequests[k]) );
1640               }
1641             }
1642           }
1643         }   
1644   }
1645 }
1646  
1647  
1648 // Look at the inst point corresponding to *this, and the stack.
1649 // If inst point corresponds a location which is conceptually "over"
1650 // the current execution frame, then set the manuallyTrigger flag
1651 // (of *this) to true, (hopefully) causing the AST corresponding
1652 // to the inst point to be executed (before the process resumes
1653 // execution).
1654 // What does conceptually "over" mean?
1655 // An inst point is "over" the current execution state if that inst
1656 //  point would have had to have been traversed to get to the current
1657 //  execution state, had the inst point existed since before the
1658 //  program began execution.
1659 // In practise, inst points are categorized as function entry, exit, and call
1660 //  site instrumentation.  entry instrumentation is "over" the current 
1661 //  execution frame if the function it is applied to appears anywhere
1662 //  on the stack.  exit instrumentation is never "over" the current 
1663 //  execution frame.  call site instrumentation is "over" the current
1664 //  execution frame if   
1665
1666
1667 void metricDefinitionNode::manuallyTrigger(int parentMId) {
1668    assert(anythingToManuallyTrigger());
1669
1670    bool aggr = true;
1671
1672 #if defined(MT_THREAD)
1673    if (aggLevel == PROC_COMP)
1674            aggr = false;
1675 #else
1676    if (!aggregate_)
1677            aggr = false;
1678 #endif
1679
1680    if( aggr ) {
1681            for ( unsigned i=0; i < components.size(); ++i )
1682                    if (components[i]->anythingToManuallyTrigger())
1683                            components[i]->manuallyTrigger(parentMId);
1684            return;
1685    }
1686
1687    for ( unsigned i=0; i < manuallyTriggerNodes.size(); ++i ) {
1688 #if !defined(MT_THREAD)
1689            if (!manuallyTriggerNodes[i]->triggerNow(proc(),parentMId)) {
1690                    cerr << "manual trigger failed for an inst request" << endl;
1691            }
1692 #else
1693            if (aggLevel == PROC_COMP) {
1694                for( unsigned u=0; u < proc()->threads.size(); ++u ) {
1695                    if (!manuallyTriggerNodes[i]->triggerNow( proc(), parentMId,
1696                         proc()->threads[u]->get_tid() )) {
1697                            cerr << "manual trigger failed for an inst request" << endl;
1698                    }
1699                }
1700            }
1701 #endif
1702    }
1703    manuallyTriggerNodes.resize( 0 );
1704 }
1705
1706 void metricDefinitionNode::manuallyTrigger(int parentMId, int thrId) {
1707    assert(anythingToManuallyTrigger());
1708
1709    bool aggr = true;
1710
1711 #if defined(MT_THREAD)
1712    if (aggLevel == PROC_COMP)
1713            aggr = false;
1714 #else
1715    if (!aggregate_)
1716            aggr = false;
1717 #endif
1718
1719    if( aggr ) {
1720            for ( unsigned i=0; i < components.size(); ++i )
1721                    if (components[i]->anythingToManuallyTrigger())
1722                            components[i]->manuallyTrigger(parentMId);
1723            return;
1724    }
1725
1726    for ( unsigned i=0; i < manuallyTriggerNodes.size(); ++i ) {
1727 #if !defined(MT_THREAD)
1728            if (!manuallyTriggerNodes[i]->triggerNow(proc(),parentMId)) {
1729                    cerr << "manual trigger failed for an inst request" << endl;
1730            }
1731 #else
1732            if (aggLevel == PROC_COMP) {
1733                    if (!manuallyTriggerNodes[i]->triggerNow( proc(), parentMId, thrId)) {
1734                            cerr << "manual trigger failed for an inst request" << endl;
1735                    }
1736            }
1737 #endif
1738    }
1739    manuallyTriggerNodes.resize( 0 );
1740 }
1741
1742 #if defined(MT_THREAD)
1743 void metricDefinitionNode::propagateId(int id) {
1744   if (aggLevel != THR_COMP) {
1745     for (unsigned i=0;i<components.size();i++) 
1746       if (components[i])
1747         components[i]->propagateId(id);
1748   }
1749   if (id_ == -1) id_ = id;
1750 }
1751 #endif
1752
1753 // startCollecting is called by dynRPC::enableDataCollection (or enableDataCollection2)
1754 // in dynrpc.C
1755 // startCollecting is a friend of metricDefinitionNode; can it be
1756 // made a member function of metricDefinitionNode instead?
1757 // Especially since it clearly is an integral part of the class;
1758 // in particular, it sets the crucial vrble "id_"
1759 int startCollecting(string& metric_name, vector<u_int>& focus, int id,
1760                     vector<process *> &procsToCont)
1761 {
1762     bool internal = false;
1763
1764     //cerr << "startCollecting called for metric " << metric_name.string_of() << endl;
1765
1766     // Make the unique ID for this metric/focus visible in MDL.
1767     string vname = "$globalId";
1768     mdl_env::add(vname, false, MDL_T_INT);
1769     mdl_env::set(id, vname);
1770
1771     metricDefinitionNode *mi = createMetricInstance(metric_name, focus,
1772                                                     true, internal);
1773        // calls mdl_do()
1774     if (!mi) {
1775        //cerr << "startCollecting for " << metric_name << " failed because createMetricInstance failed" << endl;
1776        return(-1);
1777     }
1778
1779     mi->id_ = id;
1780 #if defined(MT_THREAD)
1781     mi->propagateId(id);
1782 #endif
1783
1784 #if defined(TEST_DEL_DEBUG)
1785     sprintf(errorLine,"-----> in startCollecting, id=%d\n",mi->id_);
1786     logLine(errorLine);
1787 #endif
1788
1789     assert(!allMIs.defines(mi->id_));
1790     allMIs[mi->id_] = mi;
1791
1792     const float cost = mi->cost();
1793     mi->originalCost_ = cost;
1794
1795     currentPredictedCost += cost;
1796
1797 #ifdef ndef
1798     // enable timing stuff: also code in insertInstrumentation()
1799     u_int start_size = test_heapsize;
1800     printf("ENABLE: %d %s %s\n",start_size,
1801         (mi->getMetName()).string_of(),
1802         (mi->getFullName()).string_of());
1803     static timer inTimer;
1804     inTimer.start();
1805 #endif
1806
1807
1808     if (!internal) {
1809
1810         // pause processes that are running and add them to procsToCont.
1811         // We don't rerun the processes after we insert instrumentation,
1812         // this will be done by our caller, after all instrumentation
1813         // has been inserted.
1814                 //cerr << "startCollecting -- pausing processes" << endl;
1815         for (unsigned u = 0; u < mi->components.size(); u++) {
1816           process *p = mi->components[u]->proc();
1817           if (p->status() == running && p->pause()) {
1818             procsToCont += p;
1819           }
1820         }
1821
1822
1823         metricDefinitionNode *inst_mdn = mi;
1824 #if defined(MT_THREAD)
1825         while (inst_mdn->getLevel() != PROC_COMP)
1826           inst_mdn = inst_mdn->components[0];
1827 #else
1828         while (inst_mdn->is_aggregate())
1829           inst_mdn = inst_mdn->components[0];
1830 #endif
1831         bool alreadyThere = inst_mdn->inserted() && inst_mdn->installed(); 
1832            // shouldn't manually trigger if already there
1833
1834         mi->insertInstrumentation(); // calls pause and unpause (this could be a bug, since the next line should be allowed to execute before the unpause!!!)
1835         mi->checkAndInstallInstrumentation();
1836
1837         //
1838     // Now that the timers and counters have been allocated on the heap, and
1839         // the instrumentation added, we can manually execute instrumentation
1840         // we may have missed at function entry points and pre-instruction call 
1841         // sites which have already executed.
1842         //
1843
1844         // Adjust mi's manuallyTrigger fields to try to execute function entry and call
1845         //  site instrumentation according to the program stack....
1846         //cerr << " (startCollecting) about to call mi->adjustManuallyTrigger" << endl;
1847         if (!alreadyThere) // trigger only if it is fresh request
1848           mi->adjustManuallyTrigger();
1849         else {
1850           if (pd_debug_catchup)
1851             cerr << "SKIPPED  adjustManuallyTrigger for "
1852                  << mi->getFullName().string_of()
1853                  << ", instrumentation is already there" << endl;
1854         }
1855
1856         if (mi->anythingToManuallyTrigger()) {
1857            process *theProc = mi->components[0]->proc();
1858            assert(theProc);
1859
1860            bool alreadyRunning = (theProc->status_ == running);
1861
1862            if (alreadyRunning)
1863               theProc->pause();
1864
1865            mi->manuallyTrigger(id);
1866
1867            if (alreadyRunning) 
1868              theProc->continueProc();
1869         }
1870     }
1871
1872 #ifdef ndef
1873     inTimer.stop();
1874     if(!start_size) start_size = test_heapsize;
1875     printf("It took %f:user %f:system %f:wall seconds heap_left: %d used %d\n"
1876                 , inTimer.usecs(), inTimer.ssecs(), inTimer.wsecs(),
1877                 test_heapsize,start_size-test_heapsize);
1878 #endif
1879
1880     metResPairsEnabled++;
1881         //cerr << "startCollecting -- exiting" << endl;
1882     return(mi->id_);
1883 }
1884
1885 float guessCost(string& metric_name, vector<u_int>& focus) {
1886    // called by dynrpc.C (getPredictedDataCost())
1887     bool internal;
1888     metricDefinitionNode *mi = createMetricInstance(metric_name, focus, false, internal);
1889     if (!mi) {
1890        metric_cerr << "guessCost returning 0.0 since createMetricInstance failed" << endl;
1891        return(0.0);
1892     }
1893
1894     float cost = mi->cost();
1895     // delete the metric instance, if it is not being used 
1896     if (!allMIs.defines(mi->getMId()) && mi->aggregators.size()==0) {
1897       metric_cerr << "guessCost deletes <" <<  mi->getFullName().string_of()
1898                   << ">  since it is not being used" << endl ;
1899       delete mi;
1900     }
1901
1902     return(cost);
1903 }
1904
1905 bool metricDefinitionNode::insertInstrumentation()
1906 {
1907     // returns true iff successful
1908     if (inserted_)
1909        return true;
1910
1911     inserted_ = true;
1912
1913 #if defined(MT_THREAD)
1914     if (aggLevel == AGG_COMP) { //if (aggLevel != THR_COMP) {
1915 #else
1916     if (aggregate_) {
1917 #endif
1918         unsigned c_size = components.size();
1919         for (unsigned u=0; u<c_size; u++)
1920           if (!components[u]->insertInstrumentation())
1921              return false; // shouldn't we try to undo what's already put in?
1922     } else {
1923 #if defined(TEST_DEL_DEBUG)
1924       sprintf(errorLine,"=====> insertInstrumentation, dataRequests=%d, instRequests=%d\n",dataRequests.size(),instRequests.size());
1925       logLine(errorLine);
1926 #endif
1927       bool needToCont = proc_->status() == running;
1928       bool res = proc_->pause();
1929       if (!res)
1930         return false;
1931
1932       // Loop thru "dataRequests", an array of (ptrs to) dataReqNode:
1933       // Here we allocate ctrs/timers in the inferior heap but don't
1934       // stick in any code, except (if appropriate) that we'll instrument the
1935       // application's alarm-handler when not shm sampling.
1936       unsigned size = dataRequests.size();
1937       for (unsigned u=0; u<size; u++) {
1938         // the following allocs an object in inferior heap and arranges for
1939         // it to be alarm sampled, if appropriate.
1940         // Note: this is not necessary anymore because we are allocating the
1941         // space when the constructor for dataReqNode is called. This was
1942         // done for the dyninstAPI - naim 2/18/97
1943         //if (!dataRequests[u]->insertInstrumentation(proc_, this))
1944         //  return false; // shouldn't we try to undo what's already put in?
1945
1946         unsigned mid = dataRequests[u]->getSampleId();
1947         if (midToMiMap.defines(mid))
1948           assert(midToMiMap[mid] == this);
1949         else
1950           midToMiMap[mid] = this;
1951       }
1952
1953       // Loop thru "instRequests", an array of instReqNode:
1954       // (Here we insert code instrumentation, tramps, etc. via addInstFunc())
1955       for (unsigned u1=0; u1<instRequests.size(); u1++) {
1956           // code executed later (adjustManuallyTrigger) may also manually trigger 
1957           // the instrumentation via inferiorRPC.
1958           returnInstance *retInst=NULL;
1959           if (!instRequests[u1].insertInstrumentation(proc_, retInst))
1960              return false; // shouldn't we try to undo what's already put in?
1961
1962           if (retInst)
1963             returnInsts += retInst;
1964       }
1965       
1966 #if defined(MT_THREAD)
1967         unsigned c_size = components.size();
1968         for (unsigned u=0; u<c_size; u++)
1969           if (!components[u]->insertInstrumentation())
1970              return false; // shouldn't we try to undo what's already put in?
1971 #endif
1972
1973       if (needToCont)
1974          proc_->continueProc();
1975     }
1976
1977     return(true);
1978 }
1979
1980 bool metricDefinitionNode::checkAndInstallInstrumentation() {
1981    // Patch up the application to make it jump to the base trampoline(s) of this
1982    // metric.  (The base trampoline and mini-tramps have already been installed
1983    // in the inferior heap).  We must first check to see if it's safe to install by
1984    // doing a stack walk, and determining if anything on it overlaps with any of our
1985    // desired jumps to base tramps.
1986    // The key variable is "returnsInsts", which was created for us when the base
1987    // tramp(s) were created.  Essentially, it contains the details of how we'll jump
1988    // to the base tramp (where in the code to patch, how many instructions, the
1989    // instructions themselves).
1990    // Note that it seems this routine is misnamed: it's not instrumentation that needs
1991    // to be installed (the base & mini tramps are already in place); it's just the
1992    // last step that is still needed: the jump to the base tramp.
1993    // If one or more can't be added, then a TRAP insn is inserted in the closest
1994    // common safe return point along the stack walk, and some structures are appended
1995    // to the process' "wait list", which is then checked when a TRAP signal arrives.
1996    // At that time, the jump to the base tramp is finally done.  WARNING: It seems to
1997    // me that such code isn't thread-safe...just because one thread hits the TRAP,
1998    // there may still be other threads that are unsafe.  It seems to me that we should
1999    // be doing this check again when a TRAP arrives...but for each thread (right now,
2000    // there's no stack walk for other threads).  --ari
2001  
2002    bool needToCont = false;
2003
2004     if (installed_) return(true);
2005
2006     installed_ = true;
2007
2008 #if defined(MT_THREAD)
2009     if (aggLevel != PROC_COMP) {//if (aggLevel != THR_COMP) {
2010 #else
2011     if (aggregate_) {
2012 #endif
2013         unsigned c_size = components.size();
2014         for (unsigned u=0; u<c_size; u++)
2015             components[u]->checkAndInstallInstrumentation();
2016             // why no checking of the return value?
2017     } else {
2018         needToCont = proc_->status() == running;
2019         if (!proc_->pause()) {
2020             cerr << "checkAndInstallInstrumentation -- pause failed" << endl; cerr.flush();
2021             return false;
2022         }
2023
2024         // NOTE: walkStack should walk all the threads' staks! It doesn't do
2025         // that right now... naim 1/28/98
2026         vector<Address> pc = proc_->walkStack();
2027            // ndx 0 is where the pc is now; ndx 1 is the call site;
2028            // ndx 2 is the call site's call site, etc...
2029
2030         // for(u_int i=0; i < pc.size(); i++){
2031         //     printf("frame %d: pc = 0x%x\n",i,pc[i]);
2032         // }
2033
2034 #ifdef WALK_ALL_STACKS
2035         //
2036         // We do stack walk conservatively, stacks include all LWP stacks, and
2037         // stacks for all user-level threads
2038         //
2039         vector<vector<Address> > pc_s = proc_->walkAllStack();
2040         for (unsigned i=0; i< pc_s.size(); i++) {
2041           vector<Address>& pc = pc_s[i];
2042           for (unsigned j=0; j<pc.size(); j++) {
2043             Address a = pc[j] ;
2044
2045             if (a) {
2046               function_base *func = proc_->findFunctionIn(a);
2047               if (func) {
2048                  sprintf(errorLine, "[%d] <0x%lx> %s\n", 
2049                    i, a, func->prettyName().string_of());
2050                  logLine(errorLine);
2051               }
2052             }
2053           }
2054         }
2055         unsigned rsize = returnInsts.size();
2056         for (unsigned u=0; u<rsize; u++) {
2057           bool delay_install = false ;
2058           unsigned pc_s_size = pc_s.size();
2059           vector<u_int> max_index(pc_s_size) ;
2060
2061           //walk staks of all threads (kernel or user-level)
2062           for (unsigned i=0; i<pc_s_size; i++) {
2063             vector<Address>& pc = pc_s[i];
2064             max_index[i] = 0 ;
2065             u_int index=0 ;
2066             bool installSafe = returnInsts[u]->checkReturnInstance(pc,index);
2067             if (!installSafe && index > max_index[i]) {
2068               max_index[i] = index;
2069               delay_install = true ;
2070             }
2071           }
2072
2073           if (!delay_install) {
2074             //it is safe to install only when all threads are safe to install
2075             //returnInsts[u] -> installReturnInstance(proc_);
2076             sprintf(errorLine, "returnInsts[%u] -> installReturnInstance(proc_)\n", u);
2077             logLine(errorLine);
2078           } else {
2079             //put traps everywhere
2080             for (unsigned j=0; j<pc_s_size; j++) {
2081               //returnInsts[u]->addToReturnWaitingList(pc2, proc_);
2082               sprintf(errorLine, "returnInsts[%u]->addToReturnWaitingList(pc, proc_)\n", u);
2083               logLine(errorLine);
2084             }
2085           }
2086         }
2087 #endif
2088         ///////////////////////
2089
2090         unsigned rsize = returnInsts.size();
2091         u_int max_index = 0;  // first frame where it is safe to install instr
2092         bool delay_install = false; // true if some instr. needs to be delayed 
2093         vector<bool> delay_elm(rsize); // wch instr. to delay
2094         // for each inst point walk the stack to determine if it can be
2095         // inserted now (it can if it is not currently on the stack)
2096         // If some can not be inserted, then find the first safe point on
2097         // the stack where all can be inserted, and set a break point  
2098         for (unsigned u=0; u<rsize; u++) {
2099             u_int index = 0;
2100 #if defined(MT_THREAD)
2101             bool installSafe = true; 
2102 #else
2103             bool installSafe = returnInsts[u] -> checkReturnInstance(pc,index);
2104 #endif
2105                // if unsafe, index will be set to the first unsafe stack walk ndx
2106                // (0 being top of stack; i.e. the current pc)
2107
2108             if (!installSafe && index > max_index)
2109                max_index = index;
2110             
2111             if (installSafe) {
2112                 returnInsts[u] -> installReturnInstance(proc_);
2113                 delay_elm[u] = false;
2114             } else {
2115                 delay_install = true;
2116                 delay_elm[u] = true;
2117             }
2118         }
2119
2120         if (delay_install) {
2121             // get rid of pathological cases...caused by threaded applications 
2122             // TODO: this should be fixed to do something smarter
2123             if(max_index > 0 && max_index+1 >= pc.size()){
2124                max_index--;
2125                //printf("max_index changed: %d\n",max_index);
2126             }
2127             if(max_index > 0 && pc[max_index+1] == 0){
2128                max_index--;
2129                //printf("max_index changed: %d\n",max_index);
2130             }
2131             Address pc2 = pc[max_index+1];
2132             for (u_int i=0; i < rsize; i++)
2133                 if (delay_elm[i]) {
2134                     returnInsts[i]->addToReturnWaitingList(pc2, proc_);
2135                 }
2136         }
2137
2138         if (needToCont) proc_->continueProc();
2139     }
2140     return(true);
2141 }
2142
2143 float metricDefinitionNode::cost() const
2144 {
2145     float ret = 0.0;
2146 #if defined(MT_THREAD)
2147     if (aggLevel != THR_COMP) {
2148 #else
2149     if (aggregate_) {
2150 #endif
2151         unsigned c_size = components.size();
2152         for (unsigned u=0; u<c_size; u++) {
2153           float nc = components[u]->cost();
2154           if (nc > ret) ret = nc;
2155         }
2156     } else {
2157       for (unsigned u=0; u<instRequests.size(); u++)
2158         ret += instRequests[u].cost(proc_);
2159     }
2160     return(ret);
2161 }
2162
2163 #if !defined(MT_THREAD)
2164 void metricDefinitionNode::disable()
2165 {
2166     // check for internal metrics
2167
2168     unsigned ai_size = internalMetric::allInternalMetrics.size();
2169     for (unsigned u=0; u<ai_size; u++) {
2170       internalMetric *theIMetric = internalMetric::allInternalMetrics[u];
2171       if (theIMetric->disableByMetricDefinitionNode(this)) {
2172         //logLine("disabled internal metric\n");
2173         return;
2174       }
2175     }
2176
2177     // check for cost metrics
2178     for (unsigned i=0; i<costMetric::allCostMetrics.size(); i++){
2179       if (costMetric::allCostMetrics[i]->node == this) {
2180         costMetric::allCostMetrics[i]->disable();
2181         //logLine("disabled cost metric\n");
2182         return;
2183     }}
2184     if (!inserted_) return;
2185
2186     inserted_ = false;
2187     if (aggregate_) {
2188         /* disable components of aggregate metrics */
2189         for (unsigned u=0; u<components.size(); u++) {
2190           metricDefinitionNode *m = components[u];
2191           unsigned aggr_size = m->aggregators.size();
2192           assert(aggr_size == m->samples.size());
2193           for (unsigned u1=0; u1 < aggr_size; u1++) {
2194             if (m->aggregators[u1] == this) {
2195               m->aggregators[u1] = m->aggregators[aggr_size-1];
2196               m->aggregators.resize(aggr_size-1);
2197               m->samples[u1] = m->samples[aggr_size-1];
2198               m->samples.resize(aggr_size-1);
2199               break;
2200             }
2201           }
2202           if (aggr_size!=0) {
2203             assert(m->aggregators.size() == aggr_size-1);
2204           }
2205           // disable component only if it is not being shared
2206           if (aggr_size == 1) {
2207             m->disable();
2208           }
2209         }
2210
2211     } else {
2212       vector<addrVecType> pointsToCheck;
2213       for (unsigned u1=0; u1<instRequests.size(); u1++) {
2214         addrVecType pointsForThisRequest =
2215             getAllTrampsAtPoint(instRequests[u1].getInstance());
2216
2217         pointsToCheck += pointsForThisRequest;
2218
2219         instRequests[u1].disable(pointsForThisRequest); // calls deleteInst()
2220       }
2221
2222       for (unsigned u=0; u<dataRequests.size(); u++) {
2223         unsigned mid = dataRequests[u]->getSampleId();
2224         dataRequests[u]->disable(proc_, pointsToCheck); // deinstrument
2225         assert(midToMiMap.defines(mid));
2226         midToMiMap.undef(mid);
2227       }
2228     }
2229 }
2230 #else //!defined(MT_THREAD)
2231 void metricDefinitionNode::disable()
2232 {
2233     // check for internal metrics
2234
2235     unsigned ai_size = internalMetric::allInternalMetrics.size();
2236     for (unsigned u=0; u<ai_size; u++) {
2237       internalMetric *theIMetric = internalMetric::allInternalMetrics[u];
2238       if (theIMetric->disableByMetricDefinitionNode(this)) {
2239         //logLine("disabled internal metric\n");
2240         return;
2241       }
2242     }
2243
2244     // check for cost metrics
2245     for (unsigned i=0; i<costMetric::allCostMetrics.size(); i++){
2246       if (costMetric::allCostMetrics[i]->node == this) {
2247         costMetric::allCostMetrics[i]->disable();
2248         //logLine("disabled cost metric\n");
2249         return;
2250     }}
2251
2252     if (!inserted_) return;
2253
2254 #if defined(MT_THREAD)
2255     bool disable = false ;
2256     if (aggregators.size()==0)
2257        disable = true ;
2258
2259     if (aggregators.size()==0) 
2260 #endif
2261       inserted_ = false;
2262
2263 #if defined(MT_THREAD)
2264     if (aggLevel == AGG_COMP) {
2265 #else
2266     if (aggregate_) {
2267 #endif
2268         /* disable components of aggregate metrics */
2269         for (unsigned u=0; u<components.size(); u++) {
2270           metricDefinitionNode *m = components[u];
2271           unsigned aggr_size = m->aggregators.size();
2272           assert(aggr_size == m->samples.size());
2273           for (unsigned u1=0; u1 < aggr_size; u1++) {
2274             if (m->aggregators[u1] == this) {
2275               m->aggregators[u1] = m->aggregators[aggr_size-1];
2276               m->aggregators.resize(aggr_size-1);
2277               m->samples[u1] = m->samples[aggr_size-1];
2278               m->samples.resize(aggr_size-1);
2279               break;
2280             }
2281           }
2282           if (aggr_size!=0) {
2283             assert(m->aggregators.size() == aggr_size-1);
2284           }
2285           // disable component only if it is not being shared
2286           if (aggr_size == 1) {
2287             m->disable();
2288           }
2289 #if defined(MT_THREAD)
2290           // the above has removed the AGG_COMP from m's aggregators list
2291           // in the case that m is THR_COMP, we want to do the following
2292           if ( THR_COMP == m->aggLevel && 
2293                AGG_COMP == aggLevel    && 
2294                2        == aggr_size ) 
2295              m->disable();
2296 #endif
2297         }
2298
2299     } else {
2300       vector<addrVecType> pointsToCheck;
2301 #if defined(MT_THREAD)
2302       if (aggLevel == PROC_COMP) {
2303 #endif
2304         for (unsigned u1=0; u1<instRequests.size(); u1++) {
2305           addrVecType pointsForThisRequest =
2306               getAllTrampsAtPoint(instRequests[u1].getInstance());
2307
2308           pointsToCheck += pointsForThisRequest;
2309
2310           instRequests[u1].disable(pointsForThisRequest); // calls deleteInst()
2311         }
2312
2313 #if defined(MT_THREAD)
2314         for (unsigned u=0; u<components.size(); u++) {
2315           metricDefinitionNode *m = components[u];
2316           unsigned aggr_size = m->aggregators.size();
2317           assert(aggr_size == m->samples.size());
2318           for (unsigned u1=0; u1 < aggr_size; u1++) {
2319               if (m->aggregators[u1] == this) {
2320                 m->aggregators[u1] = m->aggregators[aggr_size-1];
2321                 m->aggregators.resize(aggr_size-1);
2322                 m->samples[u1] = m->samples[aggr_size-1];
2323                 m->samples.resize(aggr_size-1);
2324                 break;
2325               }
2326           }
2327           if (aggr_size == 1) 
2328               m->disable();
2329         }//for
2330       }
2331
2332       if (aggLevel == THR_COMP) {
2333         if (components.size() == 1 && components[0] != NULL) {
2334           metricDefinitionNode *m = components[0];
2335           unsigned aggr_size = m->aggregators.size();
2336           assert(aggr_size == m->samples.size());
2337           for (unsigned u1=0; u1 < aggr_size; u1++) {
2338             if (m->aggregators[u1] == this) {
2339               m->aggregators[u1] = m->aggregators[aggr_size-1];
2340               m->aggregators.resize(aggr_size-1);
2341               m->samples[u1] = m->samples[aggr_size-1];
2342               m->samples.resize(aggr_size-1);
2343               break;
2344             }
2345           }
2346           // if (aggr_size!=0) 
2347           //   assert(m->aggregators.size() == aggr_size-1);
2348           // disable component only if it is not being shared
2349           if (aggr_size == 1) m->disable();
2350         } 
2351
2352         if (disable) {
2353 #endif
2354         for (unsigned u=0; u<dataRequests.size(); u++) {
2355           unsigned mid = dataRequests[u]->getSampleId();
2356           dataRequests[u]->disable(proc_, pointsToCheck); // deinstrument
2357           assert(midToMiMap.defines(mid));
2358           midToMiMap.undef(mid);
2359         }
2360 #if defined(MT_THREAD)
2361       }}
2362 #endif
2363     }
2364 }
2365 #endif
2366
2367 void metricDefinitionNode::removeComponent(metricDefinitionNode *comp) {
2368 #if defined(MT_THREAD)
2369     if ( !comp ) return;
2370     //assert(comp->aggLevel != AGG_COMP);
2371 #else
2372     assert(!comp->aggregate_);
2373 #endif
2374     unsigned aggr_size = comp->aggregators.size();
2375     unsigned found = aggr_size;
2376
2377     if (aggr_size == 0) {
2378       delete comp;
2379       return;
2380     }
2381
2382     // component has more than one aggregator. Remove this from list of aggregators
2383     for (unsigned u = 0; u < aggr_size; u++) {
2384       if (comp->aggregators[u] == this) {
2385         found = u;
2386         break;
2387       }
2388     }
2389     if (found == aggr_size) 
2390        return;
2391     assert(found < aggr_size);
2392     assert(aggr_size == comp->samples.size());
2393     comp->aggregators[found] = comp->aggregators[aggr_size-1];
2394     comp->aggregators.resize(aggr_size-1);
2395     comp->samples[found] = comp->samples[aggr_size-1];
2396     comp->samples.resize(aggr_size-1);
2397
2398     if (aggr_size == 1) {
2399       delete comp;
2400       return;
2401     }
2402
2403 #if defined(MT_THREAD)
2404    if (AGG_COMP==aggLevel && THR_COMP==comp->aggLevel && 2>=aggr_size){
2405       if (comp->components.size()>0) {
2406         metricDefinitionNode *pcomp = comp->components[0];
2407         comp->components.resize(0);
2408         comp->removeComponent(pcomp);
2409       }
2410    }
2411 #endif
2412 }
2413
2414 metricDefinitionNode::~metricDefinitionNode()
2415 {
2416 #if defined(MT_THREAD)
2417    // sprintf(errorLine, "delete 0x%x:%s: mid=%d, aggLevel=%d", this, flat_name_.string_of(), id_, aggLevel);
2418    // metric_cerr << errorLine << endl;
2419 #endif
2420
2421 #if defined(MT_THREAD)
2422     if (aggLevel == PROC_COMP && proc_) {
2423       unsigned tSize = proc_->allMIComponentsWithThreads.size();
2424       for (unsigned u=0; u<tSize; u++) 
2425         if (proc_->allMIComponentsWithThreads[u] == this) {
2426           proc_->allMIComponentsWithThreads[u] = proc_->allMIComponentsWithThreads[tSize-1];
2427           proc_->allMIComponentsWithThreads.resize(tSize-1);
2428           break ;
2429         }
2430     }
2431 #endif
2432
2433     /* delete components of aggregate metrics */
2434     unsigned c_size = components.size();
2435     for (unsigned u=0; u<c_size; u++)
2436       if (components[u] != NULL) {
2437 #if defined(MT_THREAD) // remove circles which  could exist 
2438          unsigned cc_size = components[u]->components.size();
2439          for (unsigned v=0; v < cc_size; v++) 
2440            if (components[u]->components[v] == this)
2441              components[u]->components[v] = NULL ;
2442 #endif
2443          removeComponent(components[u]);
2444       }
2445     components.resize(0);
2446
2447     if (allMIComponents.defines(flat_name_) && this==allMIComponents[flat_name_])
2448       allMIComponents.undef(flat_name_);
2449     for (unsigned u2=0; u2<dataRequests.size(); u2++) 
2450       delete dataRequests[u2];
2451     dataRequests.resize(0);
2452 }
2453
2454 void metricDefinitionNode::cleanup_drn()
2455 {
2456       // we assume that it is safe to delete a dataReqNode at this point, 
2457       // otherwise, we would need to do something similar as in the disable
2458       // method for metricDefinitionNode - naim
2459       vector<addrVecType> pointsToCheck;
2460       for (unsigned u=0; u<dataRequests.size(); u++) {
2461         dataRequests[u]->disable(proc_, pointsToCheck); // deinstrument
2462       }
2463 }
2464
2465 // NOTE: This stuff (flush_batch_buffer() and batchSampleData()) belongs
2466 //       in perfStream.C; this is an inappropriate file.
2467
2468 //////////////////////////////////////////////////////////////////////////////
2469 // Buffer the samples before we actually send it                            //
2470 //      Send it when the buffers are full                                   //
2471 //      or, send it when the last sample in the interval has arrived.       //
2472 //////////////////////////////////////////////////////////////////////////////
2473
2474 const unsigned SAMPLE_BUFFER_SIZE = (1*1024)/sizeof(T_dyninstRPC::batch_buffer_entry);
2475 bool BURST_HAS_COMPLETED = false;
2476    // set to true after a burst (after a processTraceStream(), or sampleNodes for
2477    // the CM5), which will force the buffer to be flushed before it fills up
2478    // (if not, we'd have bad response time)
2479
2480 vector<T_dyninstRPC::batch_buffer_entry> theBatchBuffer (SAMPLE_BUFFER_SIZE);
2481 unsigned int batch_buffer_next=0;
2482
2483 // The following routines (flush_batch_buffer() and batchSampleData() are
2484 // in an inappropriate src file...move somewhere more appropriate)
2485 void flush_batch_buffer() {
2486    // don't need to flush if the batch had no data (this does happen; see
2487    // perfStream.C)
2488    if (batch_buffer_next == 0)
2489       return;
2490
2491    // alloc buffer of the exact size to make communication
2492    // more efficient.  Why don't we send theBatchBuffer with a count?
2493    // This would work but would always (in the igen call) copy the entire
2494    // vector.  This solution has the downside of calling new but is not too bad
2495    // and is clean.
2496    vector<T_dyninstRPC::batch_buffer_entry> copyBatchBuffer(batch_buffer_next);
2497    assert(copyBatchBuffer.size() <= theBatchBuffer.size());
2498    for (unsigned i=0; i< batch_buffer_next; i++) {
2499       copyBatchBuffer[i] = theBatchBuffer[i];
2500    }
2501
2502 #ifdef FREEDEBUG
2503 timeStamp t1,t2;
2504 t1=getCurrentTime(false);
2505 #endif
2506
2507    // Now let's do the actual igen call!
2508    tp->batchSampleDataCallbackFunc(0, copyBatchBuffer);
2509
2510 #ifdef FREEDEBUG
2511 t2=getCurrentTime(false);
2512 if ((float)(t2-t1) > 15.0) {
2513 sprintf(errorLine,"++--++ TEST ++--++ batchSampleDataCallbackFunc took %5.2f secs, size=%d, Kbytes=%5.2f\n",(float)(t2-t1),sizeof(T_dyninstRPC::batch_buffer_entry),(float)(sizeof(T_dyninstRPC::batch_buffer_entry)*copyBatchBuffer.size()/1024.0));
2514 logLine(errorLine);
2515 }
2516 #endif
2517
2518    BURST_HAS_COMPLETED = false;
2519    batch_buffer_next = 0;
2520 }
2521
2522 void batchSampleData(int mid, double startTimeStamp,
2523                      double endTimeStamp, double value, unsigned val_weight,
2524                      bool internal_metric) 
2525 {
2526    // This routine is called where we used to call tp->sampleDataCallbackFunc.
2527    // We buffer things up and eventually call tp->batchSampleDataCallbackFunc
2528
2529 #ifdef notdef
2530    char myLogBuffer[120] ;
2531    sprintf(myLogBuffer, "mid %d, value %g\n", mid, value) ;
2532    logLine(myLogBuffer) ;
2533 #endif
2534
2535    // Flush the buffer if (1) it is full, or (2) for good response time, after
2536    // a burst of data:
2537    if (batch_buffer_next >= SAMPLE_BUFFER_SIZE || BURST_HAS_COMPLETED)
2538       flush_batch_buffer();
2539
2540    // Now let's batch this entry.
2541    T_dyninstRPC::batch_buffer_entry &theEntry = theBatchBuffer[batch_buffer_next];
2542    theEntry.mid = mid;
2543    theEntry.startTimeStamp = startTimeStamp;
2544    theEntry.endTimeStamp = endTimeStamp;
2545    theEntry.value = value;
2546    theEntry.weight = val_weight;
2547    theEntry.internal_met = internal_metric;
2548    batch_buffer_next++;
2549 }
2550
2551 //////////////////////////////////////////////////////////////////////////////
2552 // Buffer the traces before we actually send it                            //
2553 //      Send it when the buffers are full                                   //
2554 //      or, send it when the last sample in the interval has arrived.       //
2555 //////////////////////////////////////////////////////////////////////////////
2556
2557 const unsigned TRACE_BUFFER_SIZE = 10;
2558 bool TRACE_BURST_HAS_COMPLETED = false;
2559    // set to true after a burst (after a processTraceStream(), or sampleNodes for
2560    // the CM5), which will force the buffer to be flushed before it fills up
2561    // (if not, we'd have bad response time)
2562
2563 vector<T_dyninstRPC::trace_batch_buffer_entry> theTraceBatchBuffer (TRACE_BUFFER_SIZE);
2564 unsigned int trace_batch_buffer_next=0;
2565
2566 void flush_trace_batch_buffer(int program) {
2567    // don't need to flush if the batch had no data (this does happen; see
2568    // perfStream.C)
2569    if (trace_batch_buffer_next == 0)
2570       return;
2571
2572    vector<T_dyninstRPC::trace_batch_buffer_entry> copyTraceBatchBuffer(trace_batch_buffer_next);
2573    for (unsigned i=0; i< trace_batch_buffer_next; i++)
2574       copyTraceBatchBuffer[i] = theTraceBatchBuffer[i];
2575
2576
2577    // Now let's do the actual igen call!
2578
2579    tp->batchTraceDataCallbackFunc(program, copyTraceBatchBuffer);
2580
2581    TRACE_BURST_HAS_COMPLETED = false;
2582    trace_batch_buffer_next = 0;
2583 }
2584
2585 void batchTraceData(int program, int mid, int recordLength,
2586                      char *recordPtr)
2587 {
2588    // Now let's batch this entry.
2589    T_dyninstRPC::trace_batch_buffer_entry &theEntry = theTraceBatchBuffer[trace_batch_buffer_next];
2590    theEntry.mid = mid;
2591    theEntry.length = recordLength;
2592    theEntry.traceRecord = byteArray(recordPtr,recordLength);
2593    trace_batch_buffer_next++;
2594
2595    // We buffer things up and eventually call tp->batchTraceDataCallbackFunc
2596
2597    // Flush the buffer if (1) it is full, or (2) for good response time, after
2598    // a burst of data:
2599    if (trace_batch_buffer_next >= TRACE_BUFFER_SIZE || TRACE_BURST_HAS_COMPLETED) {
2600       flush_trace_batch_buffer(program);
2601    }
2602
2603 }
2604
2605 void metricDefinitionNode::forwardSimpleValue(timeStamp start, timeStamp end,
2606                                        sampleValue value, unsigned weight,
2607                                        bool internal_met)
2608 {
2609   // TODO mdc
2610     assert(start + 0.000001 >= (firstRecordTime/MILLION));
2611     assert(end >= (firstRecordTime/MILLION));
2612     assert(end > start);
2613
2614     batchSampleData(id_, start, end, value, weight, internal_met);
2615 }
2616
2617 void metricDefinitionNode::updateValue(time64 wallTime, int new_cumulative_value) {
2618    // This is an alternative to updateValue(time64, sampleValue); this
2619    // integer-only version should be faster (fewer int-->float conversions)
2620    // and possibly more accurate (since int-->float conversions lose precision)
2621    
2622    const timeStamp sampleTime = wallTime / 1000000.0;
2623       // yuck; fp division is expensive!!!
2624    
2625 #if defined(TEST_DEL_DEBUG)
2626    if (new_cumulative_value < cumulativeValue_float) {
2627      sprintf(errorLine,"=====> in updateValue, flat_name = %s\n",flat_name_.string_of());
2628      logLine(errorLine);
2629    }
2630 #endif
2631    // report only the delta from the last sample, if style is EventCounter
2632    if (style_ == EventCounter )
2633       assert(new_cumulative_value >= cumulativeValue_float);
2634
2635    // note: right now, cumulativeValue is a float; we should change it to a union
2636    // of {float, int, long, long long, double}
2637    float delta_value ;
2638    if (style_ == EventCounter)
2639      delta_value = new_cumulative_value - cumulativeValue_float;
2640    else
2641      delta_value = new_cumulative_value ;
2642
2643    // note: change delta_value to "int" once we get cumulativeValue_int implemented;
2644
2645    // updating cumulativeValue_float is much easier than the float version of
2646    // updateValue():
2647    cumulativeValue_float = new_cumulative_value;
2648
2649    assert(samples.size() == aggregators.size());
2650    for (unsigned lcv=0; lcv < samples.size(); lcv++) {
2651       // call sampleInfo::newValue().  sampleInfo is in the util lib
2652       // (aggregateSample.h/.C)
2653       if (samples[lcv]->firstValueReceived()) {
2654          samples[lcv]->newValue(sampleTime, delta_value);
2655       } else {
2656          samples[lcv]->firstTimeAndValue(sampleTime, delta_value);
2657             // formerly startTime()
2658       }
2659
2660       // call sampleInfo::updateAggregateComponent()
2661       aggregators[lcv]->updateAggregateComponent();  // metricDefinitionNode::updateAggregateComponent()
2662    }
2663 }
2664
2665 void metricDefinitionNode::updateValue(time64 wallTime, 
2666                                        sampleValue value)
2667 {
2668     timeStamp sampleTime = wallTime / 1000000.0;
2669        // note: we can probably do integer division by million quicker
2670
2671     assert(value >= -0.01);
2672
2673     // TODO -- is this ok?
2674     // TODO -- do sampledFuncs work ?
2675     if (style_ == EventCounter) { 
2676
2677       // only use delta from last sample.
2678       if (value < cumulativeValue_float) {
2679         if ((value/cumulativeValue_float) < 0.99999) {
2680            //assert((value + 0.0001)  >= cumulativeValue_float);
2681 #if defined(TEST_DEL_DEBUG)
2682           // for now, just keep going and avoid the assertion - naim
2683           sprintf(errorLine,"***** avoiding assertion failure, value=%e, cumulativeValue_float=%e\n",value,cumulativeValue_float);
2684           logLine(errorLine);
2685 #endif
2686           value = cumulativeValue_float;
2687           // for now, we avoid executing this assertion failure - naim
2688           //assert((value + 0.0001)  >= cumulativeValue_float);
2689         } else {
2690           // floating point rounding error ignore
2691           cumulativeValue_float = value;
2692         }
2693       }
2694
2695       //        if (value + 0.0001 < cumulativeValue_float)
2696       //           printf ("WARNING:  sample went backwards!!!!!\n");
2697       value -= cumulativeValue_float;
2698       cumulativeValue_float += value;
2699     } 
2700
2701     //
2702     // If style==EventCounter then value is changed. Otherwise, it keeps the
2703     // the current "value" (e.g. SampledFunction case). That's why it is not
2704     // necessary to have an special case for SampledFunction.
2705     //
2706
2707     unsigned samples_size = samples.size();
2708     unsigned aggregators_size = aggregators.size();
2709     if (aggregators_size!=samples_size) {
2710       metric_cerr << "++++++++ <" << flat_name_.string_of() 
2711            << ">, samples_size=" << samples_size
2712            << ", aggregators_size=" << aggregators_size << endl;
2713     }
2714     assert(samples.size() == aggregators.size());
2715     for (unsigned u = 0; u < samples.size(); u++) {
2716       if (samples[u]->firstValueReceived())
2717          samples[u]->newValue(sampleTime, value);
2718       else {
2719          samples[u]->firstTimeAndValue(sampleTime, value);
2720          //samples[u]->startTime(sampleTime);
2721       }
2722       aggregators[u]->updateAggregateComponent();
2723     }
2724 }
2725
2726 // There are several problems here. We can not deal with cases that, two levels of
2727 // aggregations are needed in the daemon
2728 void metricDefinitionNode::updateAggregateComponent()
2729 {
2730     // currently called (only) by the above routine
2731     sampleInterval ret = aggSample.aggregateValues();
2732        // class aggregateSample is in util lib (aggregateSample.h)
2733        // warning: method aggregateValues() is complex
2734
2735     if (ret.valid) {
2736         assert(ret.end > ret.start);
2737         assert(ret.start + 0.000001 >= (firstRecordTime/MILLION));
2738         assert(ret.end >= (firstRecordTime/MILLION));
2739 #if defined(MT_THREAD)
2740         if (aggLevel == AGG_COMP) {
2741 #else
2742         if (aggregate_) {
2743 #endif
2744           batchSampleData(id_, ret.start, ret.end, ret.value,
2745                         aggSample.numComponents(),false);
2746         }
2747
2748         assert(samples.size() == aggregators.size());
2749         for (unsigned lcv=0; lcv < aggregators.size(); lcv++) {
2750 #if defined(MT_THREAD)
2751           if ( !(aggLevel == PROC_COMP && aggregators[lcv]->aggLevel == THR_COMP) ) {
2752 #endif
2753             if (samples[lcv]->firstValueReceived()) {
2754               samples[lcv]->newValue(ret.start, ret.value);
2755             } else {
2756               samples[lcv]->firstTimeAndValue(ret.start, ret.value);
2757             }
2758             aggregators[lcv]->updateAggregateComponent();  // metricDefinitionNode::updateAggregateComponent()
2759 #if defined(MT_THREAD)
2760           }
2761 #endif
2762        }
2763     }
2764 }
2765
2766 //
2767 // Costs are now reported to paradyn like other metrics (ie. we are not
2768 // calling reportInternalMetrics to deliver cost values, instead we wait
2769 // until we have received a new interval of cost data from each process)
2770 // note: this only works for the CM5 because all cost metrics are sumed
2771 // at the daemons and at paradyn, otherwise the CM5 needs its own version
2772 // of this routine that uses the same aggregate method as the one for paradyn 
2773 //
2774 #ifndef SHM_SAMPLING
2775 void processCost(process *proc, traceHeader *h, costUpdate *s)
2776 {
2777     // we can probably do integer division by million quicker.
2778     timeStamp newSampleTime = (h->wall / 1000000.0);
2779     timeStamp newProcessTime = (h->process / 1000000.0);
2780
2781     timeStamp lastProcessTime = 
2782                         totalPredictedCost->getLastSampleProcessTime(proc); 
2783
2784     // find the portion of uninstrumented time for this interval
2785     double unInstTime = ((newProcessTime - lastProcessTime) 
2786                          / (1+currentPredictedCost));
2787     // update predicted cost
2788     // note: currentPredictedCost is the same for all processes 
2789     //       this should be changed to be computed on a per process basis
2790     sampleValue newPredCost = totalPredictedCost->getCumulativeValue(proc);
2791     newPredCost += (float)(currentPredictedCost*unInstTime); 
2792     totalPredictedCost->updateValue(proc,newPredCost,
2793                                     newSampleTime,newProcessTime);
2794     // update observed cost 
2795     observed_cost->updateValue(proc,s->obsCostIdeal,
2796                                newSampleTime,newProcessTime);
2797
2798     // update smooth observed cost
2799     smooth_obs_cost->updateSmoothValue(proc,s->obsCostIdeal,
2800                                  newSampleTime,newProcessTime);
2801 }
2802 #endif
2803
2804 #ifndef SHM_SAMPLING
2805 void processSample(int /* pid */, traceHeader *h, traceSample *s)
2806 {
2807     // called from processTraceStream (perfStream.C) when a TR_SAMPLE record
2808     // has arrived from the appl.
2809
2810     unsigned mid = s->id.id; // low-level counterId (see primitives.C)
2811
2812     static time64 firstWall = 0;
2813
2814     static bool firstTime = true;
2815
2816     if (firstTime) {
2817        firstWall = h->wall;
2818     }
2819
2820     metricDefinitionNode *mi; // filled in by find() if found
2821     if (!midToMiMap.find(mid, mi)) { // low-level counterId to metricDefinitionNode
2822        metric_cerr << "TR_SAMPLE id " << s->id.id << " not for valid mi...discarding" << endl;
2823        return;
2824     }
2825
2826 //    metric_cerr << "FROM pid " << pid << " got value " << s->value << " for id " << s->id.id << endl;
2827
2828     //    sprintf(errorLine, "sample id %d at time %8.6f = %f\n", s->id.id, 
2829     //  ((double) *(int*) &h->wall) + (*(((int*) &h->wall)+1))/1000000.0, s->value);
2830     //    logLine(errorLine);
2831     mi->updateValue(h->wall, s->value);
2832     samplesDelivered++;
2833 }
2834 #endif
2835
2836 /*
2837  * functions to operate on inst request graph.
2838  *
2839  */
2840 instReqNode::instReqNode(instPoint *iPoint,
2841                          AstNode *iAst,
2842                          callWhen  iWhen,
2843                          callOrder o) {
2844     point = iPoint;
2845     when = iWhen;
2846     order = o;
2847     instance = NULL; // set when insertInstrumentation() calls addInstFunc()
2848     ast = assignAst(iAst);
2849     assert(point);
2850 }
2851
2852 instReqNode instReqNode::forkProcess(const instReqNode &parentNode,
2853                              const dictionary_hash<instInstance*,instInstance*> &map) {
2854     instReqNode ret = instReqNode(parentNode.point, parentNode.ast, parentNode.when,
2855                                   parentNode.order
2856                                   );
2857
2858     if (!map.find(parentNode.instance, ret.instance)) // writes to ret.instance
2859        assert(false);
2860
2861     return ret;
2862 }
2863
2864 bool instReqNode::unFork(dictionary_hash<instInstance*,instInstance*> &map) const {
2865    // The fork syscall duplicates all trampolines from the parent into the child. For
2866    // those mi's which we don't want to propagate to the child, this creates a
2867    // problem.  We need to remove instrumentation code from the child.  This routine
2868    // does that.
2869    //
2870    // "this" represents an instReqNode in the PARENT process.
2871    // "map" maps all instInstance*'s of the parent process to instInstance*'s in the
2872    // child process.  We modify "map" by setting a value to NULL.
2873
2874    instInstance *parentInstance = getInstance();
2875    
2876    instInstance *childInstance;
2877    if (!map.find(parentInstance, childInstance)) // writes to childInstance
2878       assert(false);
2879
2880    vector<Address> pointsToCheck; // is it right leaving this empty on a fork()???
2881    deleteInst(childInstance, pointsToCheck);
2882
2883    map[parentInstance] = NULL; // since we've deleted...
2884
2885    return true; // success
2886 }
2887
2888 bool instReqNode::insertInstrumentation(process *theProc,
2889                                         returnInstance *&retInstance) 
2890 {
2891     // NEW: We may manually trigger the instrumentation, via a call to postRPCtoDo()
2892
2893     // addInstFunc() is one of the key routines in all paradynd.
2894     // It installs a base tramp at the point (if needed), generates code
2895     // for the tramp, calls inferiorMalloc() in the text heap to get space for it,
2896     // and actually inserts the instrumentation.
2897     instance = addInstFunc(theProc, point, ast, when, order,
2898                            false, // false --> don't exclude cost
2899                            retInstance,
2900                            false // false --> do not allow recursion
2901                            );
2902
2903     //if( !retInstance )
2904         //cerr << "addInstFunc returned a NULL retInstance" << endl;
2905     rinstance = retInstance;
2906
2907     return (instance != NULL);
2908 }
2909
2910 void instReqNode::disable(const vector<Address> &pointsToCheck)
2911 {
2912 #if defined(MT_THREAD)
2913     if (instance) 
2914       deleteInst(instance, pointsToCheck);
2915 #else
2916     deleteInst(instance, pointsToCheck);
2917 #endif
2918     instance = NULL;
2919 }
2920
2921 instReqNode::~instReqNode()
2922 {
2923     instance = NULL;
2924     removeAst(ast);
2925 }
2926
2927 float instReqNode::cost(process *theProc) const
2928 {
2929     float value;
2930     float unitCost;
2931     float frequency;
2932     int unitCostInCycles;
2933
2934     unitCostInCycles = ast->cost() + getPointCost(theProc, point) +
2935                        getInsnCost(trampPreamble) + getInsnCost(trampTrailer);
2936     // printf("unit cost = %d cycles\n", unitCostInCycles);
2937     unitCost = unitCostInCycles/ cyclesPerSecond;
2938     frequency = getPointFrequency(point);
2939     value = unitCost * frequency;
2940     return(value);
2941 }
2942
2943 extern void checkProcStatus();
2944
2945 #if defined(MT_THREAD)
2946 bool instReqNode::triggerNow(process *theProc, int mid, int thrId) {
2947 #else
2948 bool instReqNode::triggerNow(process *theProc, int mid) {
2949 #endif
2950    bool needToCont = theProc->status() == running;
2951    if ( !theProc->pause() ) {
2952            cerr << "instReqNode::triggerNow -- pause failed" << endl;
2953            return false;
2954    }
2955
2956    // trigger the instrumentation
2957 #if defined(MT_THREAD)
2958    for (unsigned i=0;i<manuallyTriggerTIDs.size();i++) {
2959      if (manuallyTriggerTIDs[i]==thrId) {
2960        // inferiorRPC has been launched already for this thread - naim
2961        return true;
2962      }
2963    }
2964    manuallyTriggerTIDs += thrId;
2965
2966 #if defined(TEST_DEL_DEBUG)
2967    sprintf(errorLine,"***** posting inferiorRPC for mid=%d and tid=%d\n",mid,thrId);
2968    logLine(errorLine);
2969 #endif
2970 #endif
2971    theProc->postRPCtoDo(ast, false, // don't skip cost
2972                         instReqNode::triggerNowCallbackDispatch, this,
2973 #if defined(MT_THREAD)
2974                         mid,
2975                         thrId,
2976                         false); //false --> regular RPC, true-->SAFE RPC
2977 #else
2978                         mid);
2979 #endif
2980
2981    rpcCount = 0;
2982
2983    if (pd_debug_catchup)
2984      cerr << "launched catchup instrumentation, waiting rpc to finish ..." << endl;
2985
2986    do {
2987        // Make sure that we are not currently in an RPC to avoid race
2988        // conditions between catchup instrumentation and waitProcs()
2989        // loops
2990        if ( !theProc->isRPCwaitingForSysCallToComplete() )
2991            theProc->launchRPCifAppropriate(false, false);
2992        checkProcStatus();
2993        
2994    } while ( !rpcCount && theProc->status() != exited );
2995
2996    if ( pd_debug_catchup )
2997      cerr << "catchup instrumentation finished ..." << endl;
2998
2999    if( needToCont && (theProc->status() != running))
3000            theProc->continueProc();
3001    else if ( !needToCont && theProc->status()==running )
3002           theProc->pause();
3003
3004    return true;
3005 }
3006
3007 void instReqNode::triggerNowCallback(void * /*returnValue*/ ) {
3008         ++rpcCount;
3009 }
3010
3011
3012 bool instReqNode::triggeredInStackFrame(pd_Function *stack_fn,
3013                                       Address pc,
3014                                       process *p)
3015 {
3016     return p->triggeredInStackFrame(point, stack_fn, pc, when, order);
3017 }
3018
3019 /* ************************************************************************* */
3020
3021 #ifndef SHM_SAMPLING
3022 sampledIntCounterReqNode::sampledIntCounterReqNode(int iValue, int iCounterId,
3023                                                    metricDefinitionNode *iMi, 
3024                                                    bool computingCost) :
3025                                                    dataReqNode() {
3026    theSampleId = iCounterId;
3027    initialValue = iValue;
3028
3029    // The following fields are NULL until insertInstrumentation()
3030    counterPtr = NULL;
3031    sampler = NULL;
3032
3033    if (!computingCost) {
3034      bool isOk=false;
3035      isOk = insertInstrumentation(iMi->proc(), iMi);
3036      assert(isOk && counterPtr!=NULL); 
3037    }
3038 }
3039
3040 sampledIntCounterReqNode::sampledIntCounterReqNode(const sampledIntCounterReqNode &src,
3041                                                    process *childProc,
3042                                                    metricDefinitionNode *,
3043                                                    int iCounterId,
3044                                                    const dictionary_hash<instInstance*,instInstance*> &map) {
3045    // a dup() routine (call after a fork())
3046    counterPtr = src.counterPtr; // assumes addr spaces have been dup()d.
3047
3048    if (!map.find(src.sampler, this->sampler)) // writes to this->sampler
3049       assert(false);
3050
3051    theSampleId = iCounterId;
3052  
3053    intCounter temp;
3054    temp.id.id = this->theSampleId;
3055    temp.value = initialValue;
3056    writeToInferiorHeap(childProc, temp);
3057 }
3058
3059 dataReqNode *
3060 sampledIntCounterReqNode::dup(process *childProc,
3061                               metricDefinitionNode *mi,
3062                               int iCounterId,
3063                               const dictionary_hash<instInstance*,instInstance*> &map
3064                               ) const {
3065    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
3066
3067    sampledIntCounterReqNode *tmp;
3068    tmp = new sampledIntCounterReqNode(*this, childProc, mi, iCounterId, map);
3069       // fork ctor
3070   
3071    return tmp;
3072 }
3073
3074 bool sampledIntCounterReqNode::insertInstrumentation(process *theProc,
3075                                                      metricDefinitionNode *,
3076                                                      bool) {
3077    // Remember counterPtr and sampler are NULL until this routine
3078    // gets called.
3079    counterPtr = (intCounter*)inferiorMalloc(theProc, sizeof(intCounter), dataHeap);
3080    if (counterPtr == NULL)
3081       return false; // failure!
3082
3083    // initialize the intCounter in the inferior heap
3084    intCounter temp;
3085    temp.id.id = this->theSampleId;
3086    temp.value = this->initialValue;
3087
3088    writeToInferiorHeap(theProc, temp);
3089
3090    function_base *sampleFunction = 
3091         theProc->findOneFunction("DYNINSTsampleValues");
3092    if (!sampleFunction) 
3093      sampleFunction = theProc->findOneFunction("_DYNINSTsampleValues");
3094    assert(sampleFunction);
3095
3096    AstNode *ast, *tmp;
3097    tmp = new AstNode(AstNode::Constant, counterPtr);
3098    ast = new AstNode("DYNINSTreportCounter", tmp);
3099    removeAst(tmp);
3100
3101    instPoint *func_entry = const_cast<instPoint*>(sampleFunction->funcEntry(theProc));
3102    sampler = addInstFunc(theProc, func_entry,
3103                          ast, callPreInsn, orderLastAtPoint, false, false);
3104    removeAst(ast);
3105
3106    return true; // success
3107 }
3108
3109 void sampledIntCounterReqNode::disable(process *theProc,
3110                                        const vector<addrVecType> &pointsToCheck) {
3111    // We used to remove the sample id from midToMiMap here but now the caller is
3112    // responsible for that.
3113
3114    // Remove instrumentation added to DYNINSTsampleValues(), if necessary:
3115    if (sampler != NULL)
3116       ::deleteInst(sampler, getAllTrampsAtPoint(sampler));
3117
3118    // Deallocate space for intCounter in the inferior heap:
3119    assert(counterPtr != NULL);
3120    inferiorFree(theProc, (unsigned)counterPtr, pointsToCheck);
3121 }
3122
3123 void sampledIntCounterReqNode::writeToInferiorHeap(process *theProc,
3124                                                    const intCounter &dataSrc) const {
3125    // using the contents of "dataSrc", write to the inferior heap at loc
3126    // "counterPtr" via proc->writeDataSpace()
3127    assert(counterPtr);
3128    theProc->writeDataSpace(counterPtr, sizeof(intCounter), &dataSrc);
3129 }
3130
3131 bool sampledIntCounterReqNode::
3132 unFork(dictionary_hash<instInstance*,instInstance*> &map) {
3133    instInstance *parentSamplerInstance = this->sampler;
3134
3135    instInstance *childSamplerInstance;
3136    if (!map.find(parentSamplerInstance, childSamplerInstance))
3137       assert(false);
3138
3139    addrVecType pointsToCheck; // empty on purpose
3140    deleteInst(childSamplerInstance, pointsToCheck);
3141
3142    map[parentSamplerInstance] = NULL;
3143
3144    return true;
3145 }
3146                                       
3147 #endif
3148
3149 /* ************************************************************************* */
3150
3151 #ifdef SHM_SAMPLING
3152 #if defined(MT_THREAD)
3153 int sampledShmIntCounterReqNode::getThreadId() const {
3154   assert(thr_);
3155   return(thr_->get_tid());
3156 }
3157 #endif
3158
3159 #if defined(MT_THREAD)
3160 sampledShmIntCounterReqNode::sampledShmIntCounterReqNode(pdThread *thr,
3161                                                          int iValue, 
3162                                                          int iCounterId, 
3163                                                          metricDefinitionNode *iMi,
3164                                                          bool computingCost,
3165                                                          bool doNotSample,
3166                                                          unsigned p_allocatedIndex,
3167                                                          unsigned p_allocatedLevel) :
3168 #else
3169 sampledShmIntCounterReqNode::sampledShmIntCounterReqNode(int iValue, 
3170                                                     int iCounterId, 
3171                                                     metricDefinitionNode *iMi,
3172                                                     bool computingCost,
3173                                                     bool doNotSample) :
3174 #endif
3175                                                          dataReqNode() {
3176    theSampleId = iCounterId;
3177    initialValue = iValue;
3178 #if defined(MT_THREAD)
3179    thr_ = thr;
3180 #endif
3181 #if defined(TEST_DEL_DEBUG)
3182    sprintf(errorLine,"=====> creating counter, theSampleId = %d\n",theSampleId);
3183    logLine(errorLine);
3184 #endif
3185
3186    // The following fields are NULL until insertInstrumentation()
3187 #if defined(MT_THREAD)
3188    allocatedIndex = p_allocatedIndex;
3189    allocatedLevel = p_allocatedLevel;
3190 #else
3191    allocatedIndex = UINT_MAX;
3192    allocatedLevel = UINT_MAX;
3193 #endif
3194
3195    position_=0;
3196
3197    if (!computingCost) {
3198      bool isOk=false;
3199 #if defined(MT_THREAD)
3200      isOk = insertInstrumentation(thr, iMi->proc(), iMi, doNotSample);
3201 #else
3202      isOk = insertInstrumentation(iMi->proc(), iMi, doNotSample);
3203 #endif
3204      assert(isOk); 
3205    }
3206 }
3207
3208 sampledShmIntCounterReqNode::
3209 sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &src,
3210                             process *childProc, metricDefinitionNode *mi,
3211                             int iCounterId, const process *parentProc) {
3212    // a dup() routine (call after a fork())
3213    // Assumes that "childProc" has been copied already (e.g., the shm seg was copied).
3214
3215    // Note that the index w/in the inferior heap remains the same, so setting the
3216    // new inferiorCounterPtr isn't too hard.  Actually, it's trivial, since other code
3217    // ensures that the new shm segment is placed in exactly the same virtual mem loc
3218    // as the previous one.
3219    //
3220    // Note that the fastInferiorHeap class's fork ctor will have already copied the
3221    // actual data; we need to fill in new meta-data (new houseKeeping entries).
3222
3223    this->allocatedIndex = src.allocatedIndex;
3224    this->allocatedLevel = src.allocatedLevel;
3225
3226    this->theSampleId = iCounterId;  // this is different from the parent's value
3227    this->initialValue = src.initialValue;
3228
3229    superTable &theTable = childProc->getTable();
3230
3231    // since the new shm seg is placed in exactly the same memory location as
3232    // the old one, nothing here should change.
3233    const superTable &theParentTable = parentProc->getTable();
3234    assert(theTable.index2InferiorAddr(0,childProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel)==theParentTable.index2InferiorAddr(0,parentProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel));
3235
3236    for (unsigned i=0; i<childProc->threads.size(); i++) {
3237      // write to the raw item in the inferior heap:
3238      intCounter *localCounterPtr = (intCounter *) theTable.index2LocalAddr(0,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
3239      const intCounter *localSrcCounterPtr = (const intCounter *) childProc->getParent()->getTable().index2LocalAddr(0,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
3240      localCounterPtr->value = initialValue;
3241      localCounterPtr->id.id = theSampleId;
3242      localCounterPtr->theSpinner = localSrcCounterPtr->theSpinner;
3243         // in case we're in the middle of an operation
3244    }
3245
3246    // write HK for this intCounter:
3247    // Note: we don't assert anything about mi->getMId(), because that id has no
3248    // relation to the ids we work with (theSampleId).  In fact, we (the sampling code)
3249    // just don't ever care what mi->getMId() is.
3250    assert(theSampleId >= 0);
3251    assert(midToMiMap.defines(theSampleId));
3252    assert(midToMiMap[theSampleId] == mi);
3253    intCounterHK iHKValue(theSampleId, mi);
3254       // the mi differs from the mi of the parent; theSampleId differs too.
3255    theTable.initializeHKAfterForkIntCounter(allocatedIndex, allocatedLevel, iHKValue);
3256
3257    position_=0;
3258 }
3259
3260 dataReqNode *
3261 sampledShmIntCounterReqNode::dup(process *childProc,
3262                                  metricDefinitionNode *mi,
3263                                  int iCounterId,
3264                                  const dictionary_hash<instInstance*,instInstance*> &
3265                                  ) const {
3266    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
3267
3268    sampledShmIntCounterReqNode *tmp;
3269    tmp = new sampledShmIntCounterReqNode(*this, childProc, mi, iCounterId, childProc->getParent());
3270       // fork ctor
3271
3272    return tmp;
3273 }
3274
3275 #if defined(MT_THREAD)
3276 bool sampledShmIntCounterReqNode::insertInstrumentation(pdThread *thr, process *theProc,
3277 #else
3278 bool sampledShmIntCounterReqNode::insertInstrumentation(process *theProc,
3279 #endif
3280                                                         metricDefinitionNode *iMi, bool doNotSample) {
3281    // Remember counterPtr is NULL until this routine gets called.
3282    // WARNING: there will be an assert failure if the applic hasn't yet attached to the
3283    //          shm segment!!!
3284
3285    // initialize the intCounter in the inferior heap
3286    intCounter iValue;
3287    iValue.id.id = this->theSampleId;
3288    iValue.value = this->initialValue; // what about initializing 'theSpinner'???
3289
3290    intCounterHK iHKValue(this->theSampleId, iMi);
3291
3292    superTable &theTable = theProc->getTable();
3293 #if defined(MT_THREAD)
3294    if (thr==NULL) thr = theProc->threads[0]; // default value for thread - naim
3295    assert(thr!=NULL);
3296    unsigned thr_pos = thr->get_pd_pos();
3297 #endif
3298
3299 #if defined(MT_THREAD)
3300    if (!theTable.allocIntCounter(thr_pos, iValue, iHKValue, this->allocatedIndex, this->allocatedLevel, doNotSample))
3301 #else
3302    if (!theTable.allocIntCounter(iValue, iHKValue, this->allocatedIndex, this->allocatedLevel, doNotSample))
3303 #endif
3304       return false; // failure
3305
3306    return true; // success
3307 }
3308
3309 void sampledShmIntCounterReqNode::disable(process *theProc,
3310                                           const vector<addrVecType> &pointsToCheck) {
3311    // We used to remove the sample id from midToMiMap here but now the caller is
3312    // responsible for that.
3313
3314    superTable &theTable = theProc->getTable();
3315
3316    // Remove from inferior heap; make sure we won't be sampled any more:
3317    vector<Address> trampsMaybeUsing;
3318    for (unsigned pointlcv=0; pointlcv < pointsToCheck.size(); pointlcv++)
3319       for (unsigned tramplcv=0; tramplcv < pointsToCheck[pointlcv].size(); tramplcv++)
3320          trampsMaybeUsing += pointsToCheck[pointlcv][tramplcv];
3321
3322 #if defined(MT_THREAD)
3323    theTable.makePendingFree(thr_,0,allocatedIndex,allocatedLevel,trampsMaybeUsing);
3324    if (theProc->numOfActCounters_is>0) theProc->numOfActCounters_is--;
3325 #else
3326    theTable.makePendingFree(0,allocatedIndex,allocatedLevel,trampsMaybeUsing);
3327 #endif
3328 }
3329
3330 #endif
3331
3332 /* ************************************************************************* */
3333
3334 nonSampledIntCounterReqNode::nonSampledIntCounterReqNode(int iValue, 
3335                                                     int iCounterId,
3336                                                     metricDefinitionNode *iMi, 
3337                                                     bool computingCost) :
3338                                                     dataReqNode() {
3339    theSampleId = iCounterId;
3340    initialValue = iValue;
3341
3342    // The following fields are NULL until insertInstrumentation()
3343    counterPtr = NULL;
3344
3345    if (!computingCost) {
3346      bool isOk=false;
3347 #if defined(MT_THREAD)
3348      isOk = insertInstrumentation(NULL, iMi->proc(), iMi);
3349 #else
3350      isOk = insertInstrumentation(iMi->proc(), iMi);
3351 #endif
3352      assert(isOk && counterPtr!=NULL); 
3353    }
3354 }
3355
3356 nonSampledIntCounterReqNode::
3357 nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &src,
3358                             process *childProc, metricDefinitionNode *,
3359                             int iCounterId) {
3360    // a dup() routine (call after a fork())
3361    counterPtr = src.counterPtr; // assumes addr spaces have been dup()d.
3362    initialValue = src.initialValue;
3363    theSampleId = iCounterId;
3364  
3365    intCounter temp;
3366    temp.id.id = this->theSampleId;
3367    temp.value = this->initialValue;
3368    writeToInferiorHeap(childProc, temp);
3369 }
3370
3371 dataReqNode *
3372 nonSampledIntCounterReqNode::dup(process *childProc,
3373                                  metricDefinitionNode *mi,
3374                                  int iCounterId,
3375                                  const dictionary_hash<instInstance*,instInstance*> &
3376                                  ) const {
3377    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
3378
3379    nonSampledIntCounterReqNode *tmp;
3380    tmp = new nonSampledIntCounterReqNode(*this, childProc, mi, iCounterId);
3381       // fork ctor
3382
3383    return tmp;
3384 }
3385
3386 #if defined(MT_THREAD)
3387 bool nonSampledIntCounterReqNode::insertInstrumentation(pdThread *, process *theProc,
3388 #else
3389 bool nonSampledIntCounterReqNode::insertInstrumentation(process *theProc,
3390 #endif
3391                                                         metricDefinitionNode *,
3392                                                         bool) {
3393    // Remember counterPtr is NULL until this routine gets called.
3394    counterPtr = (intCounter*)inferiorMalloc(theProc, sizeof(intCounter), dataHeap);
3395    if (counterPtr == NULL)
3396       return false; // failure!
3397
3398    // initialize the intCounter in the inferior heap
3399    intCounter temp;
3400 #ifdef PURE_BUILD
3401    // explicitly initialize "theUsage" struct (to pacify Purify)
3402    memset(&temp, '\0', sizeof(intCounter));
3403 #endif
3404    temp.id.id = this->theSampleId;
3405    temp.value = this->initialValue;
3406
3407    writeToInferiorHeap(theProc, temp);
3408
3409    return true; // success
3410 }
3411
3412 void nonSampledIntCounterReqNode::disable(process *theProc,
3413                                           const vector<addrVecType> &pointsToCheck) {
3414    // We used to remove the sample id from midToMiMap here but now the caller is
3415    // responsible for that.
3416
3417    // Deallocate space for intCounter in the inferior heap:
3418    assert(counterPtr != NULL);
3419    inferiorFree(theProc, (Address)counterPtr, pointsToCheck);
3420 }
3421
3422 void nonSampledIntCounterReqNode::writeToInferiorHeap(process *theProc,
3423                                                       const intCounter &dataSrc) const {
3424    // using the contents of "dataSrc", write to the inferior heap at loc
3425    // "counterPtr" via proc->writeDataSpace()
3426    assert(counterPtr);
3427    theProc->writeDataSpace(counterPtr, sizeof(intCounter), &dataSrc);
3428 }
3429
3430 /* ****************************************************************** */
3431
3432 #ifndef SHM_SAMPLING
3433 sampledTimerReqNode::sampledTimerReqNode(timerType iType, int iCounterId, 
3434                                          metricDefinitionNode *iMi,
3435                                          bool computingCost) :
3436                                          dataReqNode() {
3437    theSampleId = iCounterId;
3438    theTimerType = iType;
3439
3440    // The following fields are NULL until insertInstrumentatoin():
3441    timerPtr = NULL;
3442    sampler  = NULL;
3443
3444    if (!computingCost) {
3445      bool isOk=false;
3446      isOk = insertInstrumentation(iMi->proc(), iMi);
3447      assert(isOk && timerPtr!=NULL); 
3448    }
3449 }
3450
3451 sampledTimerReqNode::sampledTimerReqNode(const sampledTimerReqNode &src,
3452                                          process *childProc,
3453                                          metricDefinitionNode *,
3454                                          int iCounterId,
3455                                          const dictionary_hash<instInstance*,instInstance*> &map) {
3456    // a dup()-like routine; call after a fork()
3457    timerPtr = src.timerPtr; // assumes addr spaces have been dup()'d
3458
3459    if (!map.find(src.sampler, this->sampler)) // writes to this->sampler
3460       assert(false);
3461
3462    assert(sampler); // makes sense; timers are always sampled, whereas intCounters
3463                     // might be just non-sampled predicates.
3464    
3465    theSampleId = iCounterId;
3466    theTimerType = src.theTimerType;
3467
3468    tTimer temp;
3469    P_memset(&temp, '\0', sizeof(tTimer)); /* is this needed? */
3470    temp.id.id = this->theSampleId;
3471    temp.type = this->theTimerType;
3472    temp.normalize = 1000000;
3473    writeToInferiorHeap(childProc, temp);
3474