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