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