Removing warning message - naim
[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 #include "util/h/headers.h"
43 #include <limits.h>
44 #include <assert.h>
45
46 #include "rtinst/h/rtinst.h"
47 #include "rtinst/h/trace.h"
48 #include "util/h/aggregateSample.h"
49 #include "dyninstAPI/src/symtab.h"
50 #include "dyninstAPI/src/pdThread.h"
51 #include "dyninstAPI/src/process.h"
52 #include "dyninstAPI/src/inst.h"
53 #include "dyninstAPI/src/instP.h"
54 #include "dyninstAPI/src/dyninstP.h"
55 #include "dyninstAPI/src/ast.h"
56 #include "dyninstAPI/src/util.h"
57 #include "paradynd/src/comm.h"
58 #include "paradynd/src/internalMetrics.h"
59 #include "paradynd/src/init.h"
60 #include "paradynd/src/perfStream.h"
61 #include "paradynd/src/main.h"
62 #include "dyninstAPI/src/stats.h"
63 #include "paradynd/src/dynrpc.h"
64 #include "paradynd/src/mdld.h"
65 #include "util/h/Timer.h"
66 #include "paradynd/src/showerror.h"
67 #include "paradynd/src/costmetrics.h"
68 #include "paradynd/src/metric.h"
69 #include "util/h/debugOstream.h"
70
71 // The following vrbles were defined in process.C:
72 extern debug_ostream attach_cerr;
73 extern debug_ostream inferiorrpc_cerr;
74 extern debug_ostream shmsample_cerr;
75 extern debug_ostream forkexec_cerr;
76 extern debug_ostream metric_cerr;
77
78 extern unsigned inferiorMemAvailable;
79 extern vector<unsigned> getAllTrampsAtPoint(instInstance *instance);
80 static unsigned internalMetricCounterId = 0;
81
82 static unsigned numOfActCounters_all=0;
83 static unsigned numOfActProcTimers_all=0;
84 static unsigned numOfActWallTimers_all=0;
85
86 void flush_batch_buffer();
87 void batchSampleData(int mid, double startTimeStamp, double endTimeStamp,
88                      double value, unsigned val_weight, bool internal_metric);
89
90 double currentPredictedCost = 0.0;
91
92 dictionary_hash <unsigned, metricDefinitionNode*> midToMiMap(uiHash);
93    // maps low-level counter-ids to metricDefinitionNodes
94
95 unsigned mdnHash(const metricDefinitionNode *&mdn) {
96   return ((unsigned)mdn) >> 2; // assume all addrs are 4-byte aligned
97 //  return ((unsigned) mdn);
98 }
99
100 unsigned componentMdnPtrHash(metricDefinitionNode * const &ptr) {
101    // maybe assert that "ptr" isn't for an aggregate mi
102    return string::hash(ptr->getFullName());
103 }
104
105
106 dictionary_hash<unsigned, metricDefinitionNode*> allMIs(uiHash);
107 dictionary_hash<string, metricDefinitionNode*> allMIComponents(string::hash);
108 vector<internalMetric*> internalMetric::allInternalMetrics;
109
110 // used to indicate the mi is no longer used.
111 #define DELETED_MI 1
112 #define MILLION 1000000.0
113
114 bool mdl_internal_metric_data(const string& metric_name, mdl_inst_data& result) {
115   unsigned size = internalMetric::allInternalMetrics.size();
116   for (unsigned u=0; u<size; u++) {
117     internalMetric *theIMetric = internalMetric::allInternalMetrics[u];
118     if (theIMetric->name() == metric_name) {
119       result.aggregate = theIMetric->aggregate();
120       result.style = theIMetric->style();
121       return true;
122     }
123   }
124
125   for (unsigned u2=0; u2< costMetric::allCostMetrics.size(); u2++) {
126     if (costMetric::allCostMetrics[u2]->name() == metric_name) {
127       result.aggregate = costMetric::allCostMetrics[u2]->aggregate();
128       result.style = costMetric::allCostMetrics[u2]->style();
129       return true;
130     }
131   }
132
133   return (mdl_metric_data(metric_name, result));
134 }
135
136 // for non-aggregate metrics
137 metricDefinitionNode::metricDefinitionNode(process *p, const string& met_name, 
138                                    const vector< vector<string> >& foc,
139                                    const vector< vector<string> >& component_foc,
140                                    const string& component_flat_name, int agg_style)
141 : aggregate_(false), 
142   aggOp(agg_style), // CM5 metrics need aggOp to be set
143   inserted_(false), installed_(false), met_(met_name),
144   focus_(foc), component_focus(component_foc),
145   flat_name_(component_flat_name),
146   aggSample(0),
147   cumulativeValue(0.0), samples(0),
148   id_(-1), originalCost_(0.0), proc_(p)
149 {
150   mdl_inst_data md;
151   bool aflag;
152   aflag=mdl_internal_metric_data(met_name, md);
153   assert(aflag);
154   style_ = md.style;
155 }
156
157 // for aggregate metrics
158 metricDefinitionNode::metricDefinitionNode(const string& metric_name,
159                                            const vector< vector<string> >& foc,
160                                            const string& cat_name, 
161                                            vector<metricDefinitionNode*>& parts,
162                                            int agg_op)
163 : aggregate_(true), aggOp(agg_op), inserted_(false),  installed_(false),
164   met_(metric_name), focus_(foc),
165   flat_name_(cat_name), components(parts),
166   aggSample(agg_op),
167   id_(-1), originalCost_(0.0), proc_(NULL)
168 {
169   unsigned p_size = parts.size();
170   for (unsigned u=0; u<p_size; u++) {
171     metricDefinitionNode *mi = parts[u];
172     mi->aggregators += this;
173     mi->samples += aggSample.newComponent();
174   }
175 }
176
177 // check for "special" metrics that are computed directly by paradynd 
178 // if a cost of an internal metric is asked for, enable=false
179 metricDefinitionNode *doInternalMetric(vector< vector<string> >& canon_focus,
180                                        vector< vector<string> >& component_canon_focus,
181                                        string& metric_name, string& flat_name,
182                                        bool enable, bool& matched)
183 {
184   // called by createMetricInstance, below.
185   // return values:
186   //   a valid metricDefinitionNode* when successful
187   //   -1 --> enable was false
188   //   -2 --> not legal to instrument this focus
189   //   NULL --> a more serious error (probably metric-is-unknown)
190
191   matched = false;
192   metricDefinitionNode *mn = 0; 
193
194   // check to see if this is an internal metric
195   unsigned im_size = internalMetric::allInternalMetrics.size();
196   for (unsigned im_index=0; im_index<im_size; im_index++){
197     internalMetric *theIMetric = internalMetric::allInternalMetrics[im_index];
198     if (theIMetric->name() == metric_name) {
199       matched = true;
200       if (!enable)
201          return (metricDefinitionNode*)-1;
202
203       if (!theIMetric->legalToInst(canon_focus))
204          // Paradyn will handle this case and report appropriate error msg
205          return (metricDefinitionNode*)-2;
206
207       mn = new metricDefinitionNode(NULL, metric_name, canon_focus,
208                                     component_canon_focus,
209                                     flat_name, theIMetric->aggregate());
210       assert(mn);
211
212       theIMetric->enableNewInstance(mn);
213       return(mn);
214     }
215   }
216
217   // check to see if this is a cost metric
218   for (unsigned i=0; i < costMetric::allCostMetrics.size(); i++){
219      if(costMetric::allCostMetrics[i]->name() == metric_name){
220           matched = true;
221           if (!enable) return (metricDefinitionNode*)-1;
222           costMetric *nc = costMetric::allCostMetrics[i];
223           if (!nc->legalToInst(canon_focus)) return (metricDefinitionNode*)-2;
224
225           mn = new metricDefinitionNode(NULL, metric_name, canon_focus,
226                                         component_canon_focus,
227                                         flat_name, nc->aggregate());
228           assert(mn);
229
230           nc->enable(mn); 
231
232           return(mn);
233      }
234   }
235
236   // No matches found among internal or cost metrics
237   return NULL;
238 }
239
240 // the following should probably be made a public static member fn of class metric
241 string metricAndCanonFocus2FlatName(const string &metricName,
242                                     const vector< vector<string> > &canonFocus) {
243    string result = metricName;
244
245    for (unsigned hierarchy=0; hierarchy < canonFocus.size(); hierarchy++)
246       for (unsigned component=0; component < canonFocus[hierarchy].size();
247            component++)
248          result += canonFocus[hierarchy][component];
249
250    return result;
251 }
252
253 // the following should probably be made a public static member fn of class metric
254 static bool focus2CanonicalFocus(const vector<unsigned> &focus,
255                                  vector< vector<string> > &canonFocus,
256                                  bool important) {
257    // takes in "focus", writes to "canonFocus".  Returns true iff successful.
258    // if "important" is false, don't print error msg on failure (called by guessCost();
259    // no mi is really being created)
260
261    vector< vector<string> > unCanonFocus;
262    if (!resource::foc_to_strings(unCanonFocus, focus, important)) { // writes to unCanonFocus
263       if (important)
264          cerr << "focus2CanonicalFocus failed since resource::foc_to_strings failed" << endl;
265       return false;
266    }
267
268    resource::make_canonical(unCanonFocus, canonFocus);
269
270    return true;
271 }
272
273 static void print_focus(debug_ostream &os, vector< vector<string> > &focus) {
274    for (unsigned a=0; a < focus.size(); a++) {
275       for (unsigned b=0; b < focus[a].size(); b++)
276          os << '/' << focus[a][b];
277
278       if (a < focus.size()-1)
279          os << ',';
280    }
281    os << endl;
282 }
283
284 metricDefinitionNode *createMetricInstance(string& metric_name, 
285                                            vector<u_int>& focus,
286                                            bool enable, // true if for real; false for guessCost()
287                                            bool& internal)
288 {
289     vector< vector<string> > canonicalFocus;
290     // we make third parameter false to avoid printing warning messages in
291     // focus2CanonicalFocus ("enable" was here previously) - naim
292     if (!focus2CanonicalFocus(focus, canonicalFocus, false)) {
293        //if (enable) cerr << "createMetricInstance failed because focus2CanonicalFocus failed" << endl;
294        return NULL;
295     }
296
297     string flat_name = metricAndCanonFocus2FlatName(metric_name, canonicalFocus);
298
299     // first see if it is already defined.
300     dictionary_hash_iter<unsigned, metricDefinitionNode*> mdi(allMIs);
301
302 /*
303  * See if we can find the requested metric instance.
304  *   Currently this is only used to cache structs built for cost requests 
305  *   which are then instantiated.  This could be used as a general system
306  *   to request find sub-metrics that are already.defines and use them to
307  *   reduce cost.  This would require adding the componenets of an aggregate
308  *   into the allMIs list since searching tends to be top down, not bottom
309  *   up.  This would also require adding a ref count to many of the structures
310  *   so they only get deleted when we are really done with them.
311  *
312  */
313
314     unsigned key;
315     metricDefinitionNode *mi= NULL;
316
317     // TODO -- a dictionary search here will be much faster
318     while (mdi.next(key, mi)) {
319       if (mi->getFullName() == flat_name) {
320         metric_cerr << "createMetricInstance: mi with flat_name " << flat_name << " already exists! using it" << endl;
321         return mi; // this metricDefinitionNode has already been defined
322       }
323     }
324
325     if (mdl_can_do(metric_name)) {
326       internal = false;
327
328       /* select the processes that should be instrumented. We skip process
329          that have exited, and processes that have been created but are not
330          completely initialized yet.
331          If we try to insert instrumentation in a process that is not ready
332          yet, we get a core dump.
333          A process is ready when it is not in neonatal state and the 
334          isBootstrappedYet returns true.
335       */
336       vector<process*> procs;
337
338       for (unsigned u = 0; u < processVec.size(); u++) {
339         if (processVec[u]->status()==exited || processVec[u]->status()==neonatal
340             || processVec[u]->isBootstrappedYet())
341           procs += processVec[u];
342       }
343
344       if (procs.size() == 0) {
345         // there are no processes to instrument
346         //printf("createMetricInstance failed, no processes to instrument\n");
347         return NULL;
348       }
349
350       bool computingCost;
351       if (enable) computingCost = false;
352       else computingCost = true;
353       mi = mdl_do(canonicalFocus, metric_name, flat_name, procs, false,
354                   computingCost);
355       if (mi == NULL) {
356          metric_cerr << "createMetricInstance failed since mdl_do failed" << endl;
357          metric_cerr << "metric name was " << metric_name << "; focus was ";
358          print_focus(metric_cerr, canonicalFocus);
359       }
360     } else {
361       bool matched;
362       mi=doInternalMetric(canonicalFocus,
363                           canonicalFocus, // is this right for component_canon_focus???
364                           metric_name,flat_name,enable,matched);
365          // NULL on serious error; -1 if enable was false; -2 if illegal to instr with
366          // given focus [many internal metrics work only for whole program]
367
368       if (mi == (metricDefinitionNode*)-2) {
369          metric_cerr << "createMetricInstance: internal metric " << metric_name << " isn't defined for focus: ";
370          print_focus(metric_cerr, canonicalFocus);
371          mi = NULL; // straighten up the return value
372       }
373       else if (mi == (metricDefinitionNode*)-1) {
374          assert(!enable); // no error msg needed
375          mi = NULL; // straighten up the return value
376       }
377       else if (mi == NULL) {
378          // more serious error...do a printout
379          metric_cerr << "createMetricInstance failed since doInternalMetric failed" << endl;
380          metric_cerr << "metric name was " << metric_name << "; focus was ";
381          print_focus(metric_cerr, canonicalFocus);
382       }
383
384       internal = true;
385     }
386
387     return mi;
388 }
389
390
391 // propagate this metric instance to process p.
392 // p is a process that started after the metric instance was created
393 // note: don't call this routine for a process started via fork or exec, just
394 // for processes started the "normal" way.
395 // "this" is an aggregate mi, not a component one.
396
397 void metricDefinitionNode::propagateToNewProcess(process *p) {
398   unsigned comp_size = components.size();
399
400   if (comp_size == 0)
401     return; // if there are no components, shouldn't the mi be fried?
402
403   for (unsigned u = 0; u < comp_size; u++) {
404     if (components[u]->proc() == p) {
405       // The metric is already enabled for this process. This case can 
406       // happen when we are starting several processes at the same time.
407       // (explain...?)
408       return;
409     }
410   }
411
412   bool internal = false;
413
414   metricDefinitionNode *mi = NULL;
415      // an aggregate (not component) mi, though we know that it'll contain just
416      // one component.  It's that one component that we're really interested in.
417   if (mdl_can_do(met_)) {
418       // Make the unique ID for this metric/focus visible in MDL.
419       string vname = "$globalId";
420       mdl_env::add(vname, false, MDL_T_INT);
421       mdl_env::set(this->getMId(), vname);
422
423       vector<process *> vp(1,p);
424       mi = mdl_do(focus_, met_, flat_name_, vp, false, false);
425   } else {
426     // internal and cost metrics don't need to be propagated (um, is this correct?)
427     mi = NULL;
428   }
429
430   if (mi) { // successfully created new mi
431     assert(mi->components.size() == 1);
432     metricDefinitionNode *theNewComponent = mi->components[0];
433
434     components += theNewComponent;
435     theNewComponent->aggregators[0] = this;
436     theNewComponent->samples[0] = aggSample.newComponent();
437     if (!internal) {
438       theNewComponent->insertInstrumentation();
439       theNewComponent->checkAndInstallInstrumentation();
440     }
441
442     // update cost
443     const float cost = mi->cost();
444     if (cost > originalCost_) {
445       currentPredictedCost += cost - originalCost_;
446       originalCost_ = cost;
447     }
448
449     mi->components.resize(0); // protect the new component
450     delete mi;
451   }
452 }
453
454 metricDefinitionNode* metricDefinitionNode::handleExec() {
455    // called by handleExec(), below.  See that routine for documentation.
456    // "this" is a component mi.
457
458    // If this component mi can be (re-)enabled in the new (post-exec) process, then do
459    // so.  Else, remove the component mi from aggregators, etc.  Returns new component
460    // mi if successful, NULL otherwise.
461
462    assert(!aggregate_);
463
464    // How can we tell if the mi can be inserted into the "new" (post-exec) process?
465    // A component mi is basically a set of instReqNodes and dataReqNodes.  The latter
466    // don't restrict what can be inserted (is this right?); the instReqNodes hold the
467    // key -- we should look at the functions (instPoint's) where code (whose contents
468    // are in AstNode's) would be inserted.  Now clearly, the instPoint's must be
469    // checked -- if any one doesn't exist, then the instReqNode and hence the component
470    // mi doesn't belong in the post-exec process.  But what about the AstNode's?
471    // Should the code that gets inserted be subject to a similar test?  Probably, but
472    // we currently don't do it.
473
474    // BUT: Even if a process contains a function in both the pre-exec and post-exec
475    // stages, we must assume that the function is IN A DIFFERENT LOCATION IN
476    // THE ADDRESS SPACE.  Ick.  So the instPoint's can't be trusted and must
477    // be recalculated from scratch.  In that regard, this routine is similar to
478    // propagateToNewProcess(), which propagates aggregate mi's to a brand new
479    // process (but which doesn't work for processes started via fork or exec).
480    // The lesson learned is to (ick, ick, ick) call mdl_do() all over again.
481    // This gets really confusing when you consider that a component mi can belong
482    // to several aggregate mi's (e.g. if we represent cpu time for proc 100 then
483    // we can belong to cpu/whole and cpu/proc-100); for which aggregate mi should
484    // we run mdl_do?  Any will do, so we can pick arbitrarily (is this right?).
485
486    // QUESTION: What about internal or cost metrics???  They have aggregate and
487    //           component mi's just like normal metrics, right?  If that's so, then
488    //           they must be propagated too!   NOT YET IMPLEMENTED!!!
489
490    metricDefinitionNode *aggregateMI = this->aggregators[0];
491    metricDefinitionNode *resultCompMI = NULL; // so far...
492
493    const bool internal = !mdl_can_do(aggregateMI->met_);
494    if (internal)
495       return NULL; // NOT YET IMPLEMENTED
496
497    // try to propagate the mi
498    // note: the following code is mostly stolen from propagateToNewProcess(); blame
499    //       it for any bugs :)
500
501    // Make the unique ID for this metric/focus visible in MDL. (?)
502    string vname = "$globalId";
503    mdl_env::add(vname, false, MDL_T_INT);
504    mdl_env::set(aggregateMI->getMId(), vname);
505
506    vector<process*> vp(1, this->proc());
507    metricDefinitionNode *tempAggMI = mdl_do(aggregateMI->focus_,
508                                             aggregateMI->met_,
509                                             aggregateMI->flat_name_,
510                                             vp,
511                                             true, // fry existing component MI
512                                             false);
513    if (tempAggMI == NULL)
514       return NULL; // failure
515
516    assert(tempAggMI->aggregate_);
517
518    // okay, it looks like we successfully created a new aggregate mi.
519    // Of course, we're just interested in the (single) component mi contained
520    // within it; it'll replace "this".
521
522    assert(tempAggMI->components.size() == 1);
523    resultCompMI = tempAggMI->components[0];
524
525    resultCompMI->aggregators.resize(0);
526    resultCompMI->samples.resize(0);
527
528    // For each aggregator, go back and find where "this" was a component mi.
529    // When found, replace the ptr to "this" with "theNewComponent".
530    unsigned num_aggregators = aggregators.size();
531    assert(num_aggregators > 0);
532    for (unsigned agglcv=0; agglcv < num_aggregators; agglcv++) {
533       metricDefinitionNode *aggMI = aggregators[agglcv];
534
535       bool found=false;
536       for (unsigned complcv=0; complcv < aggMI->components.size(); complcv++) {
537          if (aggMI->components[complcv] == this) {
538             aggMI->components[complcv] = resultCompMI;
539
540             resultCompMI->aggregators += aggMI;
541             resultCompMI->samples     += aggMI->aggSample.newComponent();
542             
543             aggMI->aggSample.removeComponent(this->samples[agglcv]);
544             
545             found=true;
546             break;
547          }
548       }
549       assert(found);
550    }
551
552    // Now let's actually insert the instrumentation:
553    if (!internal) {
554       resultCompMI->insertInstrumentation();
555       resultCompMI->checkAndInstallInstrumentation();
556    }
557
558    // And fry "tempAggMI", but make sure "resultCompMI" isn't fried when we do so
559    tempAggMI->components.resize(0); // protect resultCompMI
560    delete tempAggMI; // good riddance; you were an ugly hack to begin with
561
562    return resultCompMI;
563 }
564
565 void metricDefinitionNode::handleExec(process *proc) {
566    // a static member fn.
567    // handling exec is tricky.  At the time this routine is called, the "new" process
568    // has been bootstrapped and is ready for stuff to get inserted.  No mi's have yet
569    // been propagated, and the data structures (allMIs, allMIComponents, etc.) are still
570    // in their old, pre-exec state, so they show component mi's enabled for this
571    // process, even though they're not (at least not yet).  This routines brings things
572    // up-to-date.
573    //
574    // Algorithm: loop thru all component mi's for this process.  If it is possible to
575    // propagate it to the "new" (post-exec) process, then do so.  If not, fry the
576    // component mi.  An example where a component mi can no longer fit is an mi
577    // specific to, say, function foo(), which (thanks to the exec syscall) no longer
578    // exists in this process.  Note that the exec syscall changed the addr space enough
579    // so even if a given routine foo() is present in both the pre-exec and post-exec
580    // process, we must assume that it has MOVED TO A NEW LOCATION, thus making
581    // the component mi's instReqNode's instPoint out-of-date.  Ick.
582
583    vector<metricDefinitionNode*> miComponents = allMIComponents.values();
584    for (unsigned lcv=0; lcv < miComponents.size(); lcv++) {
585       metricDefinitionNode *componentMI = miComponents[lcv];
586       if (componentMI->proc() != proc)
587          continue;
588
589       forkexec_cerr << "calling handleExec for component "
590                     << componentMI->flat_name_ << endl;
591
592       metricDefinitionNode *replaceWithComponentMI = componentMI->handleExec();
593
594       if (replaceWithComponentMI == NULL) {
595          forkexec_cerr << "handleExec for component " << componentMI->flat_name_
596                        << " failed, so not propagating it" << endl;
597          componentMI->removeThisInstance(); // propagation failed; fry component mi
598       }
599       else {
600          forkexec_cerr << "handleExec for component " << componentMI->flat_name_
601                        << " succeeded...it has been propagated" << endl;
602          // new component mi has already been inserted in place of old component mi
603          // in all of its aggregate's component lists.  So, not much left to do,
604          // except to update allMIComponents.
605
606          assert(replaceWithComponentMI->flat_name_ == componentMI->flat_name_);
607
608          delete componentMI; // old component mi (dtor removes it from allMIComponents)
609          assert(!allMIComponents.defines(replaceWithComponentMI->flat_name_));
610          allMIComponents[replaceWithComponentMI->flat_name_] = replaceWithComponentMI;
611       }
612    }
613 }
614
615 // called when all components have been removed (because the processes have exited
616 // or exec'd) from "this".  "this" is an aggregate mi.
617 void metricDefinitionNode::endOfDataCollection() {
618   assert(components.size() == 0);
619
620   // flush aggregateSamples
621   sampleInterval ret = aggSample.aggregateValues();
622
623   while (ret.valid) {
624     assert(ret.end > ret.start);
625     assert(ret.start >= (firstRecordTime/MILLION));
626     assert(ret.end >= (firstRecordTime/MILLION));
627     batchSampleData(id_, ret.start, ret.end, ret.value,
628                     aggSample.numComponents(),false);
629     ret = aggSample.aggregateValues();
630   }
631   flush_batch_buffer();
632   // trace data streams
633   extern dictionary_hash<unsigned, unsigned> traceOn;
634   for (unsigned w = 0; w<traceOn.keys().size(); w++) {
635       if (traceOn.values()[w]) {
636           extern void batchTraceData(int, int, int, char *);
637           int k;
638           extern bool TRACE_BURST_HAS_COMPLETED;
639           TRACE_BURST_HAS_COMPLETED = true;
640           batchTraceData(0, (k = traceOn.keys()[w]), 0, (char *)NULL);
641           traceOn[k] = 0;
642       }
643   }
644   tp->endOfDataCollection(id_);
645 }
646
647 // remove a component from an aggregate.
648 // "this" is an aggregate mi; "comp" is a component mi.
649 void metricDefinitionNode::removeFromAggregate(metricDefinitionNode *comp) {
650   unsigned size = components.size();
651   for (unsigned u = 0; u < size; u++) {
652     if (components[u] == comp) {
653       delete components[u];
654       components[u] = NULL;
655       components[u] = components[size-1];
656       components.resize(size-1);
657       if (size == 1) {
658         endOfDataCollection();
659       }
660       return;
661     }
662   }
663   // should always find the right component 
664   assert(0);
665 }
666
667 // remove this component mi from all aggregators it is a component of.
668 // if the aggregate mi no longer has any components then fry the mi aggregate mi.
669 // called by removeFromMetricInstances, below, when a process exits (or exec's)
670 void metricDefinitionNode::removeThisInstance() {
671   assert(!aggregate_);
672
673   // first, remove from allMIComponents (this is new --- is it right?)
674   assert(allMIComponents.defines(flat_name_));
675   allMIComponents.undef(flat_name_);
676
677   assert(aggregators.size() == samples.size());
678   unsigned aggr_size = aggregators.size();
679   assert(aggr_size > 0);
680
681   //for (unsigned u = 0; u < aggr_size; u++) {
682   for (unsigned u = 0; u < aggregators.size() && u < samples.size(); u++) {
683     aggregators[u]->aggSample.removeComponent(samples[u]);
684     aggregators[u]->removeFromAggregate(this); 
685   }
686 }
687
688
689 // Called when a process exits, to remove the component associated to proc 
690 // from all metric instances.  (If, after an exec, we never want to carry over
691 // mi's from the pre-exec, then this routine will work there, too.  But we try to
692 // carry over mi's whenever appropriate.)
693 // Remove the aggregate metric instances that don't have any components left
694 void removeFromMetricInstances(process *proc) {
695     // Loop through all of the _component_ mi's; for each with component process
696     // of "proc", remove the component mi from its aggregate mi.
697     // Note: imho, there should be a *per-process* vector of mi-components.
698
699     vector<metricDefinitionNode *> MIs = allMIComponents.values();
700     for (unsigned j = 0; j < MIs.size(); j++) {
701       if (MIs[j]->proc() == proc)
702         MIs[j]->removeThisInstance();
703     }
704     costMetric::removeProcessFromAll(proc); // what about internal metrics?
705 }
706
707 /* *************************************************************************** */
708
709 // obligatory definition of static member vrble:
710 int metricDefinitionNode::counterId=0;
711
712 dataReqNode *metricDefinitionNode::addSampledIntCounter(int initialValue,
713                                                         bool computingCost,
714                                                         bool doNotSample) 
715 {
716    dataReqNode *result=NULL;
717
718 #ifdef SHM_SAMPLING
719    // shared memory sampling of a reported intCounter
720    result = new sampledShmIntCounterReqNode(initialValue,
721                                             metricDefinitionNode::counterId,
722                                             this, computingCost, doNotSample);
723       // implicit conversion to base class
724 #else
725    // non-shared-memory sampling of a reported intCounter
726    result = new sampledIntCounterReqNode(initialValue,
727                                          metricDefinitionNode::counterId,
728                                          this, computingCost);
729       // implicit conversion to base class
730 #endif
731
732    assert(result);
733    
734    metricDefinitionNode::counterId++;
735
736    internalMetricCounterId = metricDefinitionNode::counterId;
737
738    dataRequests += result;
739    return result;
740 }
741
742 dataReqNode *metricDefinitionNode::addUnSampledIntCounter(int initialValue,
743                                                           bool computingCost) {
744    // sampling of a non-reported intCounter (probably just a predicate)
745    // NOTE: In the future, we should probably put un-sampled intcounters
746    // into shared-memory when SHM_SAMPLING is defined.  After all, the shared
747    // memory heap is faster.
748    dataReqNode *result = new nonSampledIntCounterReqNode
749                          (initialValue, metricDefinitionNode::counterId, 
750                           this, computingCost);
751       // implicit conversion to base class
752    assert(result);
753
754    metricDefinitionNode::counterId++;
755
756    internalMetricCounterId = metricDefinitionNode::counterId;
757
758    dataRequests += result;
759    return result;
760 };
761
762 dataReqNode *metricDefinitionNode::addWallTimer(bool computingCost) {
763    dataReqNode *result = NULL;
764
765 #ifdef SHM_SAMPLING
766    result = new sampledShmWallTimerReqNode(metricDefinitionNode::counterId, this, computingCost);
767       // implicit conversion to base class
768 #else
769    result = new sampledTimerReqNode(wallTime, metricDefinitionNode::counterId, this, computingCost);
770       // implicit conversion to base class
771 #endif
772
773    assert(result);
774
775    metricDefinitionNode::counterId++;
776
777    internalMetricCounterId = metricDefinitionNode::counterId;
778
779    dataRequests += result;
780    return result;
781 }
782
783 dataReqNode *metricDefinitionNode::addProcessTimer(bool computingCost) {
784    dataReqNode *result = NULL;
785
786 #ifdef SHM_SAMPLING
787    result = new sampledShmProcTimerReqNode(metricDefinitionNode::counterId, this, computingCost);
788       // implicit conversion to base class
789 #else
790    result = new sampledTimerReqNode(processTime, metricDefinitionNode::counterId, this, computingCost);
791       // implicit conversion to base class
792 #endif
793
794    assert(result);
795
796    metricDefinitionNode::counterId++;
797
798    internalMetricCounterId = metricDefinitionNode::counterId;
799
800    dataRequests += result;
801    return result;
802 };
803
804 /* *************************************************************************** */
805
806 // called when a process forks (by handleFork(), below). "this" is a (component)
807 // mi in the parent process. Duplicate it for the child, with appropriate
808 // changes (i.e. the pid of the component focus name differs), and return the newly
809 // created child mi.  "map" maps all instInstance's of the parent to those copied into
810 // the child.
811 // 
812 // Note how beautifully everything falls into place.  Consider the case of alarm
813 // sampling with cpu/whole program.  Then comes the fork.  The parent process has
814 // (0) a tTimer structure allocated in a specific location in the inferior heap,
815 // (1) instrumentation @ main to call startTimer on that ptr, (2) instrumentation in
816 // DYNINSTsampleValues() to call DYNINSTreportTimer on that ptr.
817 // The child process of fork will have ALL of these things in the exact same locations,
818 // which is correct.  We want the timer to be located in the same spot; we want
819 // DYNINSTreportTimer to be called on the same pointer; and main() hasn't moved.
820 //
821 // So there's not much to do here.  We create a new component mi (with same flat name
822 // as in the parent, except for a different pid), and call "forkProcess" for all
823 // dataReqNodes and instReqNodes, none of which have to do anything titanic.
824
825 metricDefinitionNode *metricDefinitionNode::forkProcess(process *child,
826                         const dictionary_hash<instInstance*,instInstance*> &map) const {
827     // The "focus_" member vrble stays the same, because it was always for the
828     // metric as a whole, and not for some component.
829     //
830     // But two things must change, because they were component-specific (and the
831     // component has changed processes):
832     // (1) the flat name
833     // (2) the component focus (not to be confused with plain focus_)
834     //
835     // For example, instead of
836     // "/Code/foo.c/myfunc, /Process/100, ...", we should have
837     // "/Code/foo.c/myfunc, /Process/101, ...", because the pid of the child
838     // differs from that of the parent.
839
840     // The resource structure of a given process is found in the "rid"
841     // field of class process.
842     const resource *parentResource = child->getParent()->rid;
843     const string &parentPartName = parentResource->part_name();
844
845     const resource *childResource = child->rid;
846     const string &childPartName = childResource->part_name();
847
848     vector< vector<string> > newComponentFocus = this->component_focus;
849        // we'll change the process, but not the machine name.
850     bool foundProcess = false;
851
852     for (unsigned hier=0; hier < component_focus.size(); hier++) {
853        if (component_focus[hier][0] == "Process") {
854           foundProcess = true;
855           assert(component_focus[hier].size() == 2);
856              // since a component focus is by definition specific to some process
857
858           assert(component_focus[hier][1] == parentPartName);
859
860           // change the process:
861           newComponentFocus[hier][1] = childPartName;
862           break;
863        }
864     }
865     assert(foundProcess);
866     
867     string newComponentFlatName = metricAndCanonFocus2FlatName(met_, newComponentFocus);
868
869     metricDefinitionNode *mi =
870         new metricDefinitionNode(child,
871                          met_, // metric name doesn't change
872                          focus_, // focus doesn't change (tho component focus will)
873                          newComponentFocus, // this is a change
874                          newComponentFlatName, // this is a change
875                          aggOp // no change
876                          );
877     assert(mi);
878
879     metricDefinitionNode::counterId++;
880
881     forkexec_cerr << "metricDefinitionNode::forkProcess -- component flat name for parent is " << flat_name_ << "; for child is " << mi->flat_name_ << endl;
882
883     internalMetricCounterId = metricDefinitionNode::counterId;
884
885     assert(!allMIComponents.defines(newComponentFlatName));
886     allMIComponents[newComponentFlatName] = mi;
887
888     // Duplicate the dataReqNodes:
889     for (unsigned u1 = 0; u1 < dataRequests.size(); u1++) {
890        // must add to midToMiMap[] before dup() to avoid some assert fails
891        const int newCounterId = metricDefinitionNode::counterId++;
892           // no relation to mi->getMId();
893        forkexec_cerr << "forked dataReqNode going into midToMiMap with id " << newCounterId << endl;
894        assert(!midToMiMap.defines(newCounterId));
895        midToMiMap[newCounterId] = mi;
896        
897        dataReqNode *newNode = dataRequests[u1]->dup(child, mi, newCounterId, map);
898          // remember, dup() is a virtual fn, so the right dup() and hence the
899          // right fork-ctor is called.
900        assert(newNode);
901
902        mi->dataRequests += newNode;
903     }
904
905     // Duplicate the instReqNodes:
906     for (unsigned u2 = 0; u2 < instRequests.size(); u2++) {
907       mi->instRequests += instReqNode::forkProcess(instRequests[u2], map);
908     }
909
910     mi->inserted_ = true;
911
912     return mi;
913 }
914
915 bool metricDefinitionNode::unFork(dictionary_hash<instInstance*, instInstance*> &map,
916                                   bool unForkInstRequests,
917                                   bool unForkDataRequests) {
918    // see below handleFork() for explanation of why this routine is needed.
919    // "this" is a component mi for the parent process; we need to remove copied
920    // instrumentation from the _child_ process.
921    // Returns true iff the instrumentation was removed in the child (would be false
922    // if it's not safe to remove the instrumentation in the child because it was
923    // active.)
924
925    // "map" maps instInstances from the parent process to instInstances in the child
926    // process.
927
928    // We loop thru the instReqNodes of the parent process, unforking each.
929    // In addition, we need to unfork the dataReqNodes, because the alarm-sampled
930    // ones instrument DYNINSTsampleValues.
931
932    bool result = true;
933
934    if (unForkInstRequests)
935       for (unsigned lcv=0; lcv < instRequests.size(); lcv++)
936          if (!instRequests[lcv].unFork(map))
937             result = false; // failure
938
939    if (unForkDataRequests)
940       for (unsigned lcv=0; lcv < dataRequests.size(); lcv++)
941          if (!dataRequests[lcv]->unFork(map))
942             result = false; // failure
943
944    return result;
945 }
946
947
948 // called by forkProcess of context.C, just after the fork-constructor was
949 // called for the child process.
950 void metricDefinitionNode::handleFork(const process *parent, process *child,
951                               dictionary_hash<instInstance*,instInstance*> &map) {
952    // "map" defines a mapping from all instInstance's of the parent process to
953    // the copied one in the child process.  Some of the child process's ones may
954    // get fried by this routine, as it detects that instrumentation has been copied
955    // (by the fork syscall, which we have no control over) which doesn't belong in
956    // the child process and therefore gets deleted manually.
957   
958    // Remember that a given component can be shared by multiple aggregator-mi's,
959    // so be careful about duplicating a component twice.  Since we loop through
960    // component mi's instead of aggregate mi's, it's no problem.  Note that it's
961    // possible that only a subset of a component-mi's aggregators should get the newly
962    // created child component mi.
963
964    vector<metricDefinitionNode *> allComponents = allMIComponents.values();
965    for (unsigned complcv=0; complcv < allComponents.size(); complcv++) {
966       metricDefinitionNode *comp = allComponents[complcv];
967
968       // duplicate the component (create a new one) if it belongs in the
969       // child process.  It belongs if any of its aggregate mi's should be
970       // propagated to the child process.  An aggregate mi should be propagated
971       // if it wasn't refined to some process.
972
973       bool shouldBePropagated = false; // so far
974       bool shouldBeUnforkedIfNotPropagated = false; // so far
975       assert(comp->aggregators.size() > 0);
976       for (unsigned agglcv1=0; agglcv1 < comp->aggregators.size(); agglcv1++) {
977          metricDefinitionNode *aggMI = comp->aggregators[agglcv1];
978
979          if (aggMI->focus_[resource::process].size() == 1) {
980             // wasn't specific to any process
981             shouldBeUnforkedIfNotPropagated = false; // we'll definitely be using it
982             shouldBePropagated = true;
983             break;
984          }
985          else if (comp->proc() == parent)
986             // was specific to parent process, so fork() copied it into the child,
987             // unless it was an internal or cost metric, in which case there was nothing
988             // for fork to copy.
989             if (!internalMetric::isInternalMetric(aggMI->getMetName()) &&
990                 !costMetric::isCostMetric(aggMI->getMetName()))
991                shouldBeUnforkedIfNotPropagated = true;
992          else
993             // was specific to other process, so nothing is in the child for it yet
994             ;
995       }
996
997       if (!shouldBePropagated && shouldBeUnforkedIfNotPropagated) {
998          // this component mi isn't gonna be propagated to the child process, but
999          // the fork syscall left some residue in the child.  Delete that residue now.
1000          assert(comp->proc() == parent);
1001          comp->unFork(map, true, true); // also modifies 'map' to remove items
1002       }
1003
1004       if (!shouldBePropagated)
1005          continue;
1006
1007       // Okay, it's time to propagate this component mi to the subset of its aggregate
1008       // mi's which weren't refined to a specific process.  If we've gotten to this
1009       // point, then there _is_ at least one such aggregate.
1010       assert(shouldBePropagated);
1011       metricDefinitionNode *newComp = comp->forkProcess(child, map);
1012          // copies instr (well, fork() does this for us), allocs ctr/timer space,
1013          // initializes.  Basically, copies dataReqNode's and instReqNode's.
1014
1015       bool foundAgg = false;
1016       for (unsigned agglcv2=0; agglcv2 < comp->aggregators.size(); agglcv2++) {
1017          metricDefinitionNode *aggMI = comp->aggregators[agglcv2];
1018          if (aggMI->focus_[resource::process].size() == 1) {
1019             // this aggregate mi wasn't specific to any process, so it gets the new
1020             // child component.
1021             aggMI->components += newComp;
1022             newComp->aggregators += aggMI;
1023             newComp->samples     += aggMI->aggSample.newComponent();
1024             foundAgg = true;
1025          }
1026       }
1027       assert(foundAgg);
1028    }
1029 }
1030
1031 bool metricDefinitionNode::anythingToManuallyTrigger() const {
1032    if (aggregate_) {
1033       for (unsigned i=0; i < components.size(); i++)
1034          if (components[i]->anythingToManuallyTrigger())
1035             return true;
1036       return false;
1037    }
1038    else {
1039       for (unsigned i=0; i < instRequests.size(); i++)
1040          if (instRequests[i].anythingToManuallyTrigger())
1041             return true;
1042       return false;
1043    }
1044
1045    assert(false);
1046 }
1047
1048 void metricDefinitionNode::manuallyTrigger() {
1049    assert(anythingToManuallyTrigger());
1050
1051    if (aggregate_) {
1052       for (unsigned i=0; i < components.size(); i++)
1053          components[i]->manuallyTrigger();
1054    }
1055    else {
1056       for (unsigned i=0; i < instRequests.size(); i++)
1057          if (instRequests[i].anythingToManuallyTrigger())
1058             if (!instRequests[i].triggerNow(proc())) {
1059                cerr << "manual trigger failed for an inst request" << endl;
1060             }
1061    }
1062 }
1063
1064
1065 // startCollecting is called by dynRPC::enableDataCollection (or enableDataCollection2)
1066 // in dynrpc.C
1067 // startCollecting is a friend of metricDefinitionNode; can it be
1068 // made a member function of metricDefinitionNode instead?
1069 // Especially since it clearly is an integral part of the class;
1070 // in particular, it sets the crucial vrble "id_"
1071 int startCollecting(string& metric_name, vector<u_int>& focus, int id,
1072                     vector<process *> &procsToCont)
1073 {
1074     bool internal = false;
1075
1076     // Make the unique ID for this metric/focus visible in MDL.
1077     string vname = "$globalId";
1078     mdl_env::add(vname, false, MDL_T_INT);
1079     mdl_env::set(id, vname);
1080
1081     metricDefinitionNode *mi = createMetricInstance(metric_name, focus,
1082                                                     true, internal);
1083        // calls mdl_do()
1084     if (!mi) {
1085        //cerr << "startCollecting for " << metric_name << " failed because createMetricInstance failed" << endl;
1086        return(-1);
1087     }
1088
1089     mi->id_ = id;
1090
1091     assert(!allMIs.defines(mi->id_));
1092     allMIs[mi->id_] = mi;
1093
1094     const float cost = mi->cost();
1095     mi->originalCost_ = cost;
1096
1097     currentPredictedCost += cost;
1098
1099 #ifdef ndef
1100     // enable timing stuff: also code in insertInstrumentation()
1101     u_int start_size = test_heapsize;
1102     printf("ENABLE: %d %s %s\n",start_size,
1103         (mi->getMetName()).string_of(),
1104         (mi->getFullName()).string_of());
1105     static timer inTimer;
1106     inTimer.start();
1107 #endif
1108
1109
1110     if (!internal) {
1111
1112         // pause processes that are running and add them to procsToCont.
1113         // We don't rerun the processes after we insert instrumentation,
1114         // this will be done by our caller, after all instrumentation
1115         // has been inserted.
1116         for (unsigned u = 0; u < mi->components.size(); u++) {
1117           process *p = mi->components[u]->proc();
1118           if (p->status() == running && p->pause()) {
1119             procsToCont += p;
1120           }
1121         }
1122
1123
1124         mi->insertInstrumentation(); // calls pause and unpause (this could be a bug, since the next line should be allowed to execute before the unpause!!!)
1125         mi->checkAndInstallInstrumentation();
1126
1127         // Now that the timers and counters have been allocated on the heap, and
1128         // the instrumentation added, we can manually execute instrumentation
1129         // we may have missed at $start.entry.  But has the process been paused
1130         // all this time?  Hopefully so; otherwise things can get screwy.
1131
1132         if (mi->anythingToManuallyTrigger()) {
1133            process *theProc = mi->components[0]->proc();
1134            assert(theProc);
1135
1136            bool alreadyRunning = (theProc->status_ == running);
1137
1138            if (alreadyRunning)
1139               theProc->pause();
1140
1141            mi->manuallyTrigger();
1142
1143            if (alreadyRunning)
1144               theProc->continueProc(); // the continue will trigger our code
1145            else
1146               ; // the next time the process continues, we'll trigger our code
1147         }
1148     }
1149
1150 #ifdef ndef
1151     inTimer.stop();
1152     if(!start_size) start_size = test_heapsize;
1153     printf("It took %f:user %f:system %f:wall seconds heap_left: %d used %d\n"
1154                 , inTimer.usecs(), inTimer.ssecs(), inTimer.wsecs(),
1155                 test_heapsize,start_size-test_heapsize);
1156 #endif
1157
1158     metResPairsEnabled++;
1159     return(mi->id_);
1160 }
1161
1162 float guessCost(string& metric_name, vector<u_int>& focus) {
1163    // called by dynrpc.C (getPredictedDataCost())
1164     bool internal;
1165     metricDefinitionNode *mi = createMetricInstance(metric_name, focus, false, internal);
1166     if (!mi) {
1167        //metric_cerr << "guessCost returning 0.0 since createMetricInstance failed" << endl;
1168        return(0.0);
1169     }
1170
1171     float cost = mi->cost();
1172     // delete the metric instance, if it is not being used 
1173     if (!allMIs.defines(mi->getMId()))
1174       delete mi;
1175
1176     return(cost);
1177 }
1178
1179 bool metricDefinitionNode::insertInstrumentation()
1180 {
1181     // returns true iff successful
1182     if (inserted_)
1183        return true;
1184
1185     inserted_ = true;
1186
1187     if (aggregate_) {
1188         unsigned c_size = components.size();
1189         for (unsigned u=0; u<c_size; u++)
1190           if (!components[u]->insertInstrumentation())
1191              return false; // shouldn't we try to undo what's already put in?
1192     } else {
1193       bool needToCont = proc_->status() == running;
1194       bool res = proc_->pause();
1195       if (!res)
1196         return false;
1197
1198       // Loop thru "dataRequests", an array of (ptrs to) dataReqNode:
1199       // Here we allocate ctrs/timers in the inferior heap but don't
1200       // stick in any code, except (if appropriate) that we'll instrument the
1201       // application's alarm-handler when not shm sampling.
1202       unsigned size = dataRequests.size();
1203       for (unsigned u=0; u<size; u++) {
1204         // the following allocs an object in inferior heap and arranges for
1205         // it to be alarm sampled, if appropriate.
1206         // Note: this is not necessary anymore because we are allocating the
1207         // space when the constructor for dataReqNode is called. This was
1208         // done for the dyninstAPI - naim 2/18/97
1209         //if (!dataRequests[u]->insertInstrumentation(proc_, this))
1210         //  return false; // shouldn't we try to undo what's already put in?
1211
1212         unsigned mid = dataRequests[u]->getSampleId();
1213         assert(!midToMiMap.defines(mid));
1214         midToMiMap[mid] = this;
1215       }
1216
1217       // Loop thru "instRequests", an array of instReqNode:
1218       // (Here we insert code instrumentation, tramps, etc. via addInstFunc())
1219       for (unsigned u1=0; u1<instRequests.size(); u1++) {
1220           // NEW: the following may also manually trigger the instrumentation
1221           // via inferiorRPC.
1222           returnInstance *retInst=NULL;
1223           if (!instRequests[u1].insertInstrumentation(proc_, retInst))
1224              return false; // shouldn't we try to undo what's already put in?
1225
1226           if (retInst)
1227             returnInsts += retInst;
1228       }
1229
1230       if (needToCont)
1231          proc_->continueProc();
1232     }
1233
1234     return(true);
1235 }
1236
1237 bool metricDefinitionNode::checkAndInstallInstrumentation() {
1238     bool needToCont = false;
1239
1240     if (installed_) return(true);
1241
1242     installed_ = true;
1243
1244     if (aggregate_) {
1245         unsigned c_size = components.size();
1246         for (unsigned u=0; u<c_size; u++)
1247             components[u]->checkAndInstallInstrumentation();
1248     } else {
1249         needToCont = proc_->status() == running;
1250         if (!proc_->pause()) {
1251             cerr << "checkAnd... pause failed" << endl; cerr.flush();
1252             return false;
1253         }
1254
1255         vector<Address> pc = proc_->walkStack();
1256
1257         // for(u_int i=0; i < pc.size(); i++){
1258         //     printf("frame %d: pc = 0x%x\n",i,pc[i]);
1259         // }
1260
1261         unsigned rsize = returnInsts.size();
1262         u_int max_index = 0;  // first frame where it is safe to install instr
1263         bool delay_install = false; // true if some instr. needs to be delayed 
1264         vector<bool> delay_elm(rsize); // wch instr. to delay
1265         // for each inst point walk the stack to determine if it can be
1266         // inserted now (it can if it is not currently on the stack)
1267         // If some can not be inserted, then find the first safe point on
1268         // the stack where all can be inserted, and set a break point  
1269         for (unsigned u=0; u<rsize; u++) {
1270             u_int index = 0;
1271             bool installSafe = returnInsts[u] -> checkReturnInstance(pc,index);
1272             if ((!installSafe) && (index > max_index)) max_index = index;
1273             
1274             if (installSafe) {
1275                 //cerr << "installSafe!" << endl;
1276                 returnInsts[u] -> installReturnInstance(proc_);
1277                 delay_elm[u] = false;
1278             } else {
1279                 delay_install = true;
1280                 delay_elm[u] = true;
1281             }
1282         }
1283         if(delay_install){
1284             // get rid of pathological cases...caused by threaded applications 
1285             // TODO: this should be fixed to do something smarter
1286             if((max_index > 0) && ((max_index+1) >= pc.size())){
1287                max_index--;
1288                //printf("max_index changed: %d\n",max_index);
1289             }
1290             if((max_index > 0) && (pc[max_index+1] == 0)){
1291                max_index--;
1292                //printf("max_index changed: %d\n",max_index);
1293             }
1294             Address pc2 = pc[max_index+1];
1295             for(u_int i=0; i < rsize; i++){
1296                 if(delay_elm[i]){
1297                     returnInsts[i]->addToReturnWaitingList(pc2, proc_);
1298                 }
1299             }
1300         }
1301
1302         if (needToCont) proc_->continueProc();
1303     }
1304     return(true);
1305 }
1306
1307 float metricDefinitionNode::cost() const
1308 {
1309     float ret = 0.0;
1310     if (aggregate_) {
1311         unsigned c_size = components.size();
1312         for (unsigned u=0; u<c_size; u++) {
1313           float nc = components[u]->cost();
1314           if (nc > ret) ret = nc;
1315         }
1316     } else {
1317       for (unsigned u=0; u<instRequests.size(); u++)
1318         ret += instRequests[u].cost(proc_);
1319     }
1320     return(ret);
1321 }
1322
1323 void metricDefinitionNode::disable()
1324 {
1325     // check for internal metrics
1326
1327     unsigned ai_size = internalMetric::allInternalMetrics.size();
1328     for (unsigned u=0; u<ai_size; u++) {
1329       internalMetric *theIMetric = internalMetric::allInternalMetrics[u];
1330       if (theIMetric->disableByMetricDefinitionNode(this)) {
1331         //logLine("disabled internal metric\n");
1332         return;
1333       }
1334     }
1335
1336     // check for cost metrics
1337     for (unsigned i=0; i<costMetric::allCostMetrics.size(); i++){
1338       if (costMetric::allCostMetrics[i]->node == this) {
1339         costMetric::allCostMetrics[i]->disable();
1340         //logLine("disabled cost metric\n");
1341         return;
1342     }}
1343
1344     if (!inserted_) return;
1345
1346     inserted_ = false;
1347     if (aggregate_) {
1348         /* disable components of aggregate metrics */
1349         // unsigned c_size = components.size();
1350         //for (unsigned u=0; u<c_size; u++) {
1351         for (unsigned u=0; u<components.size(); u++) {
1352           //components[u]->disable();
1353           metricDefinitionNode *m = components[u];
1354           unsigned aggr_size = m->aggregators.size();
1355           assert(aggr_size == m->samples.size());
1356           for (unsigned u1=0; u1 < aggr_size; u1++) {
1357             if (m->aggregators[u1] == this) {
1358               m->aggregators[u1] = m->aggregators[aggr_size-1];
1359               m->aggregators.resize(aggr_size-1);
1360               m->samples[u1] = m->samples[aggr_size-1];
1361               m->samples.resize(aggr_size-1);
1362               break;
1363             }
1364           }
1365           assert(m->aggregators.size() == aggr_size-1);
1366           // disable component only if it is not being shared
1367           if (aggr_size == 1) {
1368             m->disable();
1369           }
1370         }
1371
1372     } else {
1373       vector<unsigVecType> pointsToCheck;
1374       for (unsigned u1=0; u1<instRequests.size(); u1++) {
1375         unsigVecType pointsForThisRequest = 
1376             getAllTrampsAtPoint(instRequests[u1].getInstance());
1377         pointsToCheck += pointsForThisRequest;
1378
1379         instRequests[u1].disable(pointsForThisRequest); // calls deleteInst()
1380       }
1381
1382       for (unsigned u=0; u<dataRequests.size(); u++) {
1383         unsigned mid = dataRequests[u]->getSampleId();
1384         dataRequests[u]->disable(proc_, pointsToCheck); // deinstrument
1385         assert(midToMiMap.defines(mid));
1386         midToMiMap.undef(mid);
1387       }
1388     }
1389 }
1390
1391 void metricDefinitionNode::removeComponent(metricDefinitionNode *comp) {
1392     assert(!comp->aggregate_);
1393     unsigned aggr_size = comp->aggregators.size();
1394     unsigned found = aggr_size;
1395
1396     if (aggr_size == 0) {
1397       delete comp;
1398       return;
1399     }
1400
1401     // component has more than one aggregator. Remove this from list of aggregators
1402     for (unsigned u = 0; u < aggr_size; u++) {
1403       if (comp->aggregators[u] == this) {
1404         found = u;
1405         break;
1406       }
1407     }
1408     if (found == aggr_size)
1409      return;
1410     assert(found < aggr_size);
1411     assert(aggr_size == comp->samples.size());
1412     comp->aggregators[found] = comp->aggregators[aggr_size-1];
1413     comp->aggregators.resize(aggr_size-1);
1414     comp->samples[found] = comp->samples[aggr_size-1];
1415     comp->samples.resize(aggr_size-1);
1416
1417     if (aggr_size == 1) {
1418       delete comp;
1419       return;
1420     }
1421
1422 }
1423
1424 metricDefinitionNode::~metricDefinitionNode()
1425 {
1426     if (aggregate_) {
1427         /* delete components of aggregate metrics */
1428         unsigned c_size = components.size();
1429         for (unsigned u=0; u<c_size; u++)
1430           removeComponent(components[u]);
1431           //delete components[u];
1432         components.resize(0);
1433     } else {
1434       allMIComponents.undef(flat_name_);
1435       unsigned size = dataRequests.size();
1436       for (unsigned u=0; u<size; u++)
1437         delete dataRequests[u];
1438     }
1439 }
1440
1441 // NOTE: This stuff (flush_batch_buffer() and batchSampleData()) belongs
1442 //       in perfStream.C; this is an inappropriate file.
1443
1444 //////////////////////////////////////////////////////////////////////////////
1445 // Buffer the samples before we actually send it                            //
1446 //      Send it when the buffers are full                                   //
1447 //      or, send it when the last sample in the interval has arrived.       //
1448 //////////////////////////////////////////////////////////////////////////////
1449
1450 const unsigned SAMPLE_BUFFER_SIZE = (1*1024)/sizeof(T_dyninstRPC::batch_buffer_entry);
1451 bool BURST_HAS_COMPLETED = false;
1452    // set to true after a burst (after a processTraceStream(), or sampleNodes for
1453    // the CM5), which will force the buffer to be flushed before it fills up
1454    // (if not, we'd have bad response time)
1455
1456 vector<T_dyninstRPC::batch_buffer_entry> theBatchBuffer (SAMPLE_BUFFER_SIZE);
1457 unsigned int batch_buffer_next=0;
1458
1459 // The following routines (flush_batch_buffer() and batchSampleData() are
1460 // in an inappropriate src file...move somewhere more appropriate)
1461 void flush_batch_buffer() {
1462    // don't need to flush if the batch had no data (this does happen; see
1463    // perfStream.C)
1464    if (batch_buffer_next == 0)
1465       return;
1466
1467    // alloc buffer of the exact size to make communication
1468    // more efficient.  Why don't we send theBatchBuffer with a count?
1469    // This would work but would always (in the igen call) copy the entire
1470    // vector.  This solution has the downside of calling new but is not too bad
1471    // and is clean.
1472    vector<T_dyninstRPC::batch_buffer_entry> copyBatchBuffer(batch_buffer_next);
1473    assert(copyBatchBuffer.size() <= theBatchBuffer.size());
1474    for (unsigned i=0; i< batch_buffer_next; i++) {
1475       copyBatchBuffer[i] = theBatchBuffer[i];
1476    }
1477
1478 #ifdef FREEDEBUG
1479 timeStamp t1,t2;
1480 t1=getCurrentTime(false);
1481 #endif
1482
1483    // Now let's do the actual igen call!
1484    tp->batchSampleDataCallbackFunc(0, copyBatchBuffer);
1485
1486 #ifdef FREEDEBUG
1487 t2=getCurrentTime(false);
1488 if ((float)(t2-t1) > 15.0) {
1489 sprintf(errorLine,"++--++ TEST ++--++ batchSampleDataCallbackFunc took %5.2f secs, size=%d, Kbytes=%5.2f\n",(float)(t2-t1),sizeof(T_dyninstRPC::batch_buffer_entry),(float)(sizeof(T_dyninstRPC::batch_buffer_entry)*copyBatchBuffer.size()/1024.0));
1490 logLine(errorLine);
1491 }
1492 #endif
1493
1494    BURST_HAS_COMPLETED = false;
1495    batch_buffer_next = 0;
1496 }
1497
1498 void batchSampleData(int mid, double startTimeStamp,
1499                      double endTimeStamp, double value, unsigned val_weight,
1500                      bool internal_metric) 
1501 {
1502    // This routine is called where we used to call tp->sampleDataCallbackFunc.
1503    // We buffer things up and eventually call tp->batchSampleDataCallbackFunc
1504
1505 #ifdef notdef
1506    char myLogBuffer[120] ;
1507    sprintf(myLogBuffer, "mid %d, value %g\n", mid, value) ;
1508    logLine(myLogBuffer) ;
1509 #endif
1510
1511    // Flush the buffer if (1) it is full, or (2) for good response time, after
1512    // a burst of data:
1513    if (batch_buffer_next >= SAMPLE_BUFFER_SIZE || BURST_HAS_COMPLETED)
1514       flush_batch_buffer();
1515
1516    // Now let's batch this entry.
1517    T_dyninstRPC::batch_buffer_entry &theEntry = theBatchBuffer[batch_buffer_next];
1518    theEntry.mid = mid;
1519    theEntry.startTimeStamp = startTimeStamp;
1520    theEntry.endTimeStamp = endTimeStamp;
1521    theEntry.value = value;
1522    theEntry.weight = val_weight;
1523    theEntry.internal_met = internal_metric;
1524    batch_buffer_next++;
1525 }
1526
1527 //////////////////////////////////////////////////////////////////////////////
1528 // Buffer the traces before we actually send it                            //
1529 //      Send it when the buffers are full                                   //
1530 //      or, send it when the last sample in the interval has arrived.       //
1531 //////////////////////////////////////////////////////////////////////////////
1532
1533 const unsigned TRACE_BUFFER_SIZE = 10;
1534 bool TRACE_BURST_HAS_COMPLETED = false;
1535    // set to true after a burst (after a processTraceStream(), or sampleNodes for
1536    // the CM5), which will force the buffer to be flushed before it fills up
1537    // (if not, we'd have bad response time)
1538
1539 vector<T_dyninstRPC::trace_batch_buffer_entry> theTraceBatchBuffer (TRACE_BUFFER_SIZE);
1540 unsigned int trace_batch_buffer_next=0;
1541
1542 void flush_trace_batch_buffer(int program) {
1543    // don't need to flush if the batch had no data (this does happen; see
1544    // perfStream.C)
1545    if (trace_batch_buffer_next == 0)
1546       return;
1547
1548    vector<T_dyninstRPC::trace_batch_buffer_entry> copyTraceBatchBuffer(trace_batch_buffer_next);
1549    for (unsigned i=0; i< trace_batch_buffer_next; i++)
1550       copyTraceBatchBuffer[i] = theTraceBatchBuffer[i];
1551
1552
1553    // Now let's do the actual igen call!
1554
1555    tp->batchTraceDataCallbackFunc(program, copyTraceBatchBuffer);
1556
1557    TRACE_BURST_HAS_COMPLETED = false;
1558    trace_batch_buffer_next = 0;
1559 }
1560
1561 void batchTraceData(int program, int mid, int recordLength,
1562                      char *recordPtr)
1563 {
1564    // Now let's batch this entry.
1565    T_dyninstRPC::trace_batch_buffer_entry &theEntry = theTraceBatchBuffer[trace_batch_buffer_next];
1566    theEntry.mid = mid;
1567    theEntry.length = recordLength;
1568    theEntry.traceRecord = byteArray(recordPtr,recordLength);
1569    trace_batch_buffer_next++;
1570
1571    // We buffer things up and eventually call tp->batchTraceDataCallbackFunc
1572
1573    // Flush the buffer if (1) it is full, or (2) for good response time, after
1574    // a burst of data:
1575    if (trace_batch_buffer_next >= TRACE_BUFFER_SIZE || TRACE_BURST_HAS_COMPLETED) {
1576       flush_trace_batch_buffer(program);
1577    }
1578
1579 }
1580
1581 void metricDefinitionNode::forwardSimpleValue(timeStamp start, timeStamp end,
1582                                        sampleValue value, unsigned weight,
1583                                        bool internal_met)
1584 {
1585   // TODO mdc
1586     assert(start + 0.000001 >= (firstRecordTime/MILLION));
1587     assert(end >= (firstRecordTime/MILLION));
1588     assert(end > start);
1589
1590     batchSampleData(id_, start, end, value, weight, internal_met);
1591 }
1592
1593 void metricDefinitionNode::updateValue(time64 wallTime, 
1594                                        sampleValue value)
1595 {
1596     timeStamp sampleTime = wallTime / 1000000.0;
1597        // note: we can probably do integer division by million quicker
1598
1599     assert(value >= -0.01);
1600
1601     // TODO -- is this ok?
1602     // TODO -- do sampledFuncs work ?
1603     if (style_ == EventCounter) { 
1604
1605       // only use delta from last sample.
1606       if (value < cumulativeValue) {
1607         if ((value/cumulativeValue) < 0.99999) {
1608           assert((value + 0.0001)  >= cumulativeValue);
1609         } else {
1610           // floating point rounding error ignore
1611           cumulativeValue = value;
1612         }
1613       }
1614
1615       //        if (value + 0.0001 < cumulativeValue)
1616       //           printf ("WARNING:  sample went backwards!!!!!\n");
1617       value -= cumulativeValue;
1618       cumulativeValue += value;
1619     } 
1620
1621     //
1622     // If style==EventCounter then value is changed. Otherwise, it keeps the
1623     // the current "value" (e.g. SampledFunction case). That's why it is not
1624     // necessary to have an special case for SampledFunction.
1625     //
1626
1627     assert(samples.size() == aggregators.size());
1628     for (unsigned u = 0; u < samples.size(); u++) {
1629       if (samples[u]->firstValueReceived())
1630         samples[u]->newValue(sampleTime, value);
1631       else {
1632         samples[u]->startTime(sampleTime);
1633       }
1634       aggregators[u]->updateAggregateComponent();
1635     }
1636 }
1637
1638 void metricDefinitionNode::updateAggregateComponent()
1639 {
1640     // currently called (only) by the above routine
1641     sampleInterval ret = aggSample.aggregateValues();
1642     if (ret.valid) {
1643         assert(ret.end > ret.start);
1644         assert(ret.start + 0.000001 >= (firstRecordTime/MILLION));
1645         assert(ret.end >= (firstRecordTime/MILLION));
1646         batchSampleData(id_, ret.start, ret.end, ret.value,
1647                         aggSample.numComponents(),false);
1648     }
1649 //    else {
1650 //        metric_cerr << "sorry, ret.valid false so not batching sample data" << endl;
1651 //    }
1652 }
1653
1654 //
1655 // Costs are now reported to paradyn like other metrics (ie. we are not
1656 // calling reportInternalMetrics to deliver cost values, instead we wait
1657 // until we have received a new interval of cost data from each process)
1658 // note: this only works for the CM5 because all cost metrics are sumed
1659 // at the daemons and at paradyn, otherwise the CM5 needs its own version
1660 // of this routine that uses the same aggregate method as the one for paradyn 
1661 //
1662 #ifndef SHM_SAMPLING
1663 void processCost(process *proc, traceHeader *h, costUpdate *s)
1664 {
1665     // we can probably do integer division by million quicker.
1666     timeStamp newSampleTime = (h->wall / 1000000.0);
1667     timeStamp newProcessTime = (h->process / 1000000.0);
1668
1669     timeStamp lastProcessTime = 
1670                         totalPredictedCost->getLastSampleProcessTime(proc); 
1671
1672     // find the portion of uninstrumented time for this interval
1673     double unInstTime = ((newProcessTime - lastProcessTime) 
1674                          / (1+currentPredictedCost));
1675     // update predicted cost
1676     // note: currentPredictedCost is the same for all processes 
1677     //       this should be changed to be computed on a per process basis
1678     sampleValue newPredCost = totalPredictedCost->getCumulativeValue(proc);
1679     newPredCost += (float)(currentPredictedCost*unInstTime); 
1680     totalPredictedCost->updateValue(proc,newPredCost,
1681                                     newSampleTime,newProcessTime);
1682     // update observed cost 
1683     observed_cost->updateValue(proc,s->obsCostIdeal,
1684                                newSampleTime,newProcessTime);
1685
1686     // update smooth observed cost
1687     smooth_obs_cost->updateSmoothValue(proc,s->obsCostIdeal,
1688                                  newSampleTime,newProcessTime);
1689 }
1690 #endif
1691
1692 #ifndef SHM_SAMPLING
1693 void processSample(int /* pid */, traceHeader *h, traceSample *s)
1694 {
1695     // called from processTraceStream (perfStream.C) when a TR_SAMPLE record
1696     // has arrived from the appl.
1697
1698     unsigned mid = s->id.id; // low-level counterId (see primitives.C)
1699
1700     static time64 firstWall = 0;
1701
1702     static bool firstTime = true;
1703
1704     if (firstTime) {
1705        firstWall = h->wall;
1706     }
1707
1708     metricDefinitionNode *mi; // filled in by find() if found
1709     if (!midToMiMap.find(mid, mi)) { // low-level counterId to metricDefinitionNode
1710        metric_cerr << "TR_SAMPLE id " << s->id.id << " not for valid mi...discarding" << endl;
1711        return;
1712     }
1713
1714 //    metric_cerr << "FROM pid " << pid << " got value " << s->value << " for id " << s->id.id << endl;
1715
1716     //    sprintf(errorLine, "sample id %d at time %8.6f = %f\n", s->id.id, 
1717     //  ((double) *(int*) &h->wall) + (*(((int*) &h->wall)+1))/1000000.0, s->value);
1718     //    logLine(errorLine);
1719     mi->updateValue(h->wall, s->value);
1720     samplesDelivered++;
1721 }
1722 #endif
1723
1724 /*
1725  * functions to operate on inst request graph.
1726  *
1727  */
1728 instReqNode::instReqNode(instPoint *iPoint,
1729                          AstNode *iAst,
1730                          callWhen  iWhen,
1731                          callOrder o, bool iManuallyTrigger) {
1732     point = iPoint;
1733     when = iWhen;
1734     order = o;
1735     instance = NULL; // set when insertInstrumentation() calls addInstFunc()
1736     ast = assignAst(iAst);
1737     manuallyTrigger = iManuallyTrigger;
1738     assert(point);
1739 }
1740
1741 instReqNode instReqNode::forkProcess(const instReqNode &parentNode,
1742                              const dictionary_hash<instInstance*,instInstance*> &map) {
1743     instReqNode ret = instReqNode(parentNode.point, parentNode.ast, parentNode.when,
1744                                   parentNode.order,
1745                                   false // don't manually trigger
1746                                   );
1747
1748     if (!map.find(parentNode.instance, ret.instance)) // writes to ret.instance
1749        assert(false);
1750
1751     return ret;
1752 }
1753
1754 bool instReqNode::unFork(dictionary_hash<instInstance*,instInstance*> &map) const {
1755    // The fork syscall duplicates all trampolines from the parent into the child. For
1756    // those mi's which we don't want to propagate to the child, this creates a
1757    // problem.  We need to remove instrumentation code from the child.  This routine
1758    // does that.
1759    //
1760    // "this" represents an instReqNode in the PARENT process.
1761    // "map" maps all instInstance*'s of the parent process to instInstance*'s in the
1762    // child process.  We modify "map" by setting a value to NULL.
1763
1764    instInstance *parentInstance = getInstance();
1765    
1766    instInstance *childInstance;
1767    if (!map.find(parentInstance, childInstance)) // writes to childInstance
1768       assert(false);
1769
1770    vector<unsigned> pointsToCheck; // is it right leaving this empty on a fork()???
1771    deleteInst(childInstance, pointsToCheck);
1772
1773    map[parentInstance] = NULL; // since we've deleted...
1774
1775    return true; // success
1776 }
1777
1778 bool instReqNode::insertInstrumentation(process *theProc,
1779                                         returnInstance *&retInstance) 
1780 {
1781     // NEW: We may manually trigger the instrumentation, via a call to postRPCtoDo()
1782
1783     // addInstFunc() is one of the key routines in all paradynd.
1784     // It installs a base tramp at the point (if needed), generates code
1785     // for the tramp, calls inferiorMalloc() in the text heap to get space for it,
1786     // and actually inserts the instrumentation.
1787     instance = addInstFunc(theProc, point, ast, when, order,
1788                            false, // false --> don't exclude cost
1789                            retInstance);
1790
1791     return (instance != NULL);
1792 }
1793
1794 void instReqNode::disable(const vector<unsigned> &pointsToCheck)
1795 {
1796     deleteInst(instance, pointsToCheck);
1797     instance = NULL;
1798 }
1799
1800 instReqNode::~instReqNode()
1801 {
1802     instance = NULL;
1803     removeAst(ast);
1804 }
1805
1806 float instReqNode::cost(process *theProc) const
1807 {
1808     float value;
1809     float unitCost;
1810     float frequency;
1811     int unitCostInCycles;
1812
1813     unitCostInCycles = ast->cost() + getPointCost(theProc, point) +
1814                        getInsnCost(trampPreamble) + getInsnCost(trampTrailer);
1815     // printf("unit cost = %d cycles\n", unitCostInCycles);
1816     unitCost = unitCostInCycles/ cyclesPerSecond;
1817     frequency = getPointFrequency(point);
1818     value = unitCost * frequency;
1819     return(value);
1820 }
1821
1822 bool instReqNode::triggerNow(process *theProc) {
1823    assert(manuallyTrigger);
1824
1825    theProc->postRPCtoDo(ast, false, // don't skip cost
1826                         NULL, // no callback fn needed
1827                         NULL
1828                         );
1829       // the rpc will be launched with a call to launchRPCifAppropriate()
1830       // in the main loop (perfStream.C)
1831
1832    return true;
1833 }
1834
1835 /* ************************************************************************* */
1836
1837 #ifndef SHM_SAMPLING
1838 sampledIntCounterReqNode::sampledIntCounterReqNode(int iValue, int iCounterId,
1839                                                    metricDefinitionNode *iMi, 
1840                                                    bool computingCost) :
1841                                                    dataReqNode() {
1842    theSampleId = iCounterId;
1843    initialValue = iValue;
1844
1845    // The following fields are NULL until insertInstrumentation()
1846    counterPtr = NULL;
1847    sampler = NULL;
1848
1849    if (!computingCost) {
1850      bool isOk=false;
1851      isOk = insertInstrumentation(iMi->proc(), iMi);
1852      assert(isOk && counterPtr!=NULL); 
1853    }
1854 }
1855
1856 sampledIntCounterReqNode::sampledIntCounterReqNode(const sampledIntCounterReqNode &src,
1857                                                    process *childProc,
1858                                                    metricDefinitionNode *,
1859                                                    int iCounterId,
1860                                                    const dictionary_hash<instInstance*,instInstance*> &map) {
1861    // a dup() routine (call after a fork())
1862    counterPtr = src.counterPtr; // assumes addr spaces have been dup()d.
1863
1864    if (!map.find(src.sampler, this->sampler)) // writes to this->sampler
1865       assert(false);
1866
1867    theSampleId = iCounterId;
1868  
1869    intCounter temp;
1870    temp.id.id = this->theSampleId;
1871    temp.value = initialValue;
1872    writeToInferiorHeap(childProc, temp);
1873 }
1874
1875 dataReqNode *
1876 sampledIntCounterReqNode::dup(process *childProc,
1877                               metricDefinitionNode *mi,
1878                               int iCounterId,
1879                               const dictionary_hash<instInstance*,instInstance*> &map
1880                               ) const {
1881    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
1882
1883    sampledIntCounterReqNode *tmp;
1884    tmp = new sampledIntCounterReqNode(*this, childProc, mi, iCounterId, map);
1885       // fork ctor
1886   
1887    return tmp;
1888 }
1889
1890 bool sampledIntCounterReqNode::insertInstrumentation(process *theProc,
1891                                                      metricDefinitionNode *,
1892                                                      bool) {
1893    // Remember counterPtr and sampler are NULL until this routine
1894    // gets called.
1895    counterPtr = (intCounter*)inferiorMalloc(theProc, sizeof(intCounter), dataHeap);
1896    if (counterPtr == NULL)
1897       return false; // failure!
1898
1899    // initialize the intCounter in the inferior heap
1900    intCounter temp;
1901    temp.id.id = this->theSampleId;
1902    temp.value = this->initialValue;
1903
1904    writeToInferiorHeap(theProc, temp);
1905
1906    function_base *sampleFunction = 
1907         theProc->findOneFunction("DYNINSTsampleValues");
1908    assert(sampleFunction);
1909
1910    AstNode *ast, *tmp;
1911    tmp = new AstNode(AstNode::Constant, counterPtr);
1912    ast = new AstNode("DYNINSTreportCounter", tmp);
1913    removeAst(tmp);
1914
1915    instPoint *func_entry = (instPoint *)sampleFunction->funcEntry(theProc);
1916    sampler = addInstFunc(theProc, func_entry,
1917                          ast, callPreInsn, orderLastAtPoint, false);
1918    removeAst(ast);
1919
1920    return true; // success
1921 }
1922
1923 void sampledIntCounterReqNode::disable(process *theProc,
1924                                        const vector<unsigVecType> &pointsToCheck) {
1925    // We used to remove the sample id from midToMiMap here but now the caller is
1926    // responsible for that.
1927
1928    // Remove instrumentation added to DYNINSTsampleValues(), if necessary:
1929    if (sampler != NULL)
1930       ::deleteInst(sampler, getAllTrampsAtPoint(sampler));
1931
1932    // Deallocate space for intCounter in the inferior heap:
1933    assert(counterPtr != NULL);
1934    inferiorFree(theProc, (unsigned)counterPtr, dataHeap, pointsToCheck);
1935 }
1936
1937 void sampledIntCounterReqNode::writeToInferiorHeap(process *theProc,
1938                                                    const intCounter &dataSrc) const {
1939    // using the contents of "dataSrc", write to the inferior heap at loc
1940    // "counterPtr" via proc->writeDataSpace()
1941    assert(counterPtr);
1942    theProc->writeDataSpace(counterPtr, sizeof(intCounter), &dataSrc);
1943 }
1944
1945 bool sampledIntCounterReqNode::
1946 unFork(dictionary_hash<instInstance*,instInstance*> &map) {
1947    instInstance *parentSamplerInstance = this->sampler;
1948
1949    instInstance *childSamplerInstance;
1950    if (!map.find(parentSamplerInstance, childSamplerInstance))
1951       assert(false);
1952
1953    vector<unsigned> pointsToCheck; // empty on purpose
1954    deleteInst(childSamplerInstance, pointsToCheck);
1955
1956    map[parentSamplerInstance] = NULL;
1957
1958    return true;
1959 }
1960                                       
1961 #endif
1962
1963 /* ************************************************************************* */
1964
1965 #ifdef SHM_SAMPLING
1966
1967 sampledShmIntCounterReqNode::sampledShmIntCounterReqNode(int iValue, 
1968                                                      int iCounterId, 
1969                                                      metricDefinitionNode *iMi,
1970                                                      bool computingCost,
1971                                                      bool doNotSample) :
1972                                                      dataReqNode() {
1973    theSampleId = iCounterId;
1974    initialValue = iValue;
1975
1976    // The following fields are NULL until insertInstrumentation()
1977    allocatedIndex = UINT_MAX;
1978    allocatedLevel = UINT_MAX;
1979
1980    position_=0;
1981
1982    if (!computingCost) {
1983      bool isOk=false;
1984      isOk = insertInstrumentation(iMi->proc(), iMi, doNotSample);
1985      assert(isOk); 
1986    }
1987 }
1988
1989 sampledShmIntCounterReqNode::
1990 sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &src,
1991                             process *childProc, metricDefinitionNode *mi,
1992                             int iCounterId, const process *parentProc) {
1993    // a dup() routine (call after a fork())
1994    // Assumes that "childProc" has been copied already (e.g., the shm seg was copied).
1995
1996    // Note that the index w/in the inferior heap remains the same, so setting the
1997    // new inferiorCounterPtr isn't too hard.  Actually, it's trivial, since other code
1998    // ensures that the new shm segment is placed in exactly the same virtual mem location
1999    // as the previous one.
2000    //
2001    // Note that the fastInferiorHeap class's fork ctor will have already copied the
2002    // actual data; we need to fill in new meta-data (new houseKeeping entries).
2003
2004    this->allocatedIndex = src.allocatedIndex;
2005    this->allocatedLevel = src.allocatedLevel;
2006
2007    this->theSampleId = iCounterId;  // this is different from the parent's value
2008    this->initialValue = src.initialValue;
2009
2010    superTable &theTable = childProc->getTable();
2011
2012    // since the new shm seg is placed in exactly the same memory location as
2013    // the old one, nothing here should change.
2014    const superTable &theParentTable = parentProc->getTable();
2015    assert(theTable.index2InferiorAddr(0,childProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel)==theParentTable.index2InferiorAddr(0,parentProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel));
2016
2017    for (unsigned i=0; i<childProc->threads.size(); i++) {
2018      // write to the raw item in the inferior heap:
2019      intCounter *localCounterPtr = (intCounter *) theTable.index2LocalAddr(0,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2020      const intCounter *localSrcCounterPtr = (const intCounter *) childProc->getParent()->getTable().index2LocalAddr(0,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2021      localCounterPtr->value = initialValue;
2022      localCounterPtr->id.id = theSampleId;
2023      localCounterPtr->theSpinner = localSrcCounterPtr->theSpinner;
2024         // in case we're in the middle of an operation
2025    }
2026
2027    // write HK for this intCounter:
2028    // Note: we don't assert anything about mi->getMId(), because that id has no
2029    // relation to the ids we work with (theSampleId).  In fact, we (the sampling code)
2030    // just don't ever care what mi->getMId() is.
2031    assert(theSampleId >= 0);
2032    assert(midToMiMap.defines(theSampleId));
2033    assert(midToMiMap[theSampleId] == mi);
2034    intCounterHK iHKValue(theSampleId, mi);
2035       // the mi differs from the mi of the parent; theSampleId differs too.
2036    theTable.initializeHKAfterForkIntCounter(allocatedIndex, allocatedLevel, iHKValue);
2037
2038    position_=0;
2039 }
2040
2041 dataReqNode *
2042 sampledShmIntCounterReqNode::dup(process *childProc,
2043                                  metricDefinitionNode *mi,
2044                                  int iCounterId,
2045                                  const dictionary_hash<instInstance*,instInstance*> &
2046                                  ) const {
2047    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2048
2049    sampledShmIntCounterReqNode *tmp;
2050    tmp = new sampledShmIntCounterReqNode(*this, childProc, mi, iCounterId, childProc->getParent());
2051       // fork ctor
2052
2053    return tmp;
2054 }
2055
2056 bool sampledShmIntCounterReqNode::insertInstrumentation(process *theProc,
2057                                                         metricDefinitionNode *iMi, bool doNotSample) {
2058    // Remember counterPtr is NULL until this routine gets called.
2059    // WARNING: there will be an assert failure if the applic hasn't yet attached to the
2060    //          shm segment!!!
2061
2062    // initialize the intCounter in the inferior heap
2063    intCounter iValue;
2064    iValue.id.id = this->theSampleId;
2065    iValue.value = this->initialValue; // what about initializing 'theSpinner'???
2066
2067    intCounterHK iHKValue(this->theSampleId, iMi);
2068
2069    superTable &theTable = theProc->getTable();
2070
2071    if (!theTable.allocIntCounter(iValue, iHKValue, this->allocatedIndex, this->allocatedLevel, doNotSample))
2072       return false; // failure
2073
2074    return true; // success
2075 }
2076
2077 void sampledShmIntCounterReqNode::disable(process *theProc,
2078                                           const vector<unsigVecType> &pointsToCheck) {
2079    // We used to remove the sample id from midToMiMap here but now the caller is
2080    // responsible for that.
2081
2082    superTable &theTable = theProc->getTable();
2083
2084    // Remove from inferior heap; make sure we won't be sampled any more:
2085    vector<unsigned> trampsMaybeUsing;
2086    for (unsigned pointlcv=0; pointlcv < pointsToCheck.size(); pointlcv++)
2087       for (unsigned tramplcv=0; tramplcv < pointsToCheck[pointlcv].size(); tramplcv++)
2088          trampsMaybeUsing += pointsToCheck[pointlcv][tramplcv];
2089
2090    theTable.makePendingFree(0,allocatedIndex,allocatedLevel,trampsMaybeUsing);
2091
2092 #if defined(MT_THREAD)
2093 //NOTE: Not yet implemented for shm sampling! naim 4/23/97
2094 //    pdThread *thr = theProc->threads[0];
2095 //    thr->CTvector->remove(this->theSampleId, this->position_);
2096 //    theProc->updateActiveCT(false,counter);
2097 #endif
2098 }
2099
2100 #endif
2101
2102 /* ************************************************************************* */
2103
2104 nonSampledIntCounterReqNode::nonSampledIntCounterReqNode(int iValue, 
2105                                                     int iCounterId,
2106                                                     metricDefinitionNode *iMi, 
2107                                                     bool computingCost) :
2108                                                     dataReqNode() {
2109    theSampleId = iCounterId;
2110    initialValue = iValue;
2111
2112    // The following fields are NULL until insertInstrumentation()
2113    counterPtr = NULL;
2114
2115    if (!computingCost) {
2116      bool isOk=false;
2117      isOk = insertInstrumentation(iMi->proc(), iMi);
2118      assert(isOk && counterPtr!=NULL); 
2119    }
2120 }
2121
2122 nonSampledIntCounterReqNode::
2123 nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &src,
2124                             process *childProc, metricDefinitionNode *,
2125                             int iCounterId) {
2126    // a dup() routine (call after a fork())
2127    counterPtr = src.counterPtr; // assumes addr spaces have been dup()d.
2128    initialValue = src.initialValue;
2129    theSampleId = iCounterId;
2130  
2131    intCounter temp;
2132    temp.id.id = this->theSampleId;
2133    temp.value = this->initialValue;
2134    writeToInferiorHeap(childProc, temp);
2135 }
2136
2137 dataReqNode *
2138 nonSampledIntCounterReqNode::dup(process *childProc,
2139                                  metricDefinitionNode *mi,
2140                                  int iCounterId,
2141                                  const dictionary_hash<instInstance*,instInstance*> &
2142                                  ) const {
2143    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2144
2145    nonSampledIntCounterReqNode *tmp;
2146    tmp = new nonSampledIntCounterReqNode(*this, childProc, mi, iCounterId);
2147       // fork ctor
2148
2149    return tmp;
2150 }
2151
2152 bool nonSampledIntCounterReqNode::insertInstrumentation(process *theProc,
2153                                                         metricDefinitionNode *,
2154                                                         bool) {
2155    // Remember counterPtr is NULL until this routine gets called.
2156    counterPtr = (intCounter*)inferiorMalloc(theProc, sizeof(intCounter), dataHeap);
2157    if (counterPtr == NULL)
2158       return false; // failure!
2159
2160    // initialize the intCounter in the inferior heap
2161    intCounter temp;
2162    temp.id.id = this->theSampleId;
2163    temp.value = this->initialValue;
2164
2165    writeToInferiorHeap(theProc, temp);
2166
2167    return true; // success
2168 }
2169
2170 void nonSampledIntCounterReqNode::disable(process *theProc,
2171                                           const vector<unsigVecType> &pointsToCheck) {
2172    // We used to remove the sample id from midToMiMap here but now the caller is
2173    // responsible for that.
2174
2175    // Deallocate space for intCounter in the inferior heap:
2176    assert(counterPtr != NULL);
2177    inferiorFree(theProc, (unsigned)counterPtr, dataHeap, pointsToCheck);
2178 }
2179
2180 void nonSampledIntCounterReqNode::writeToInferiorHeap(process *theProc,
2181                                                       const intCounter &dataSrc) const {
2182    // using the contents of "dataSrc", write to the inferior heap at loc
2183    // "counterPtr" via proc->writeDataSpace()
2184    assert(counterPtr);
2185    theProc->writeDataSpace(counterPtr, sizeof(intCounter), &dataSrc);
2186 }
2187
2188 /* ****************************************************************** */
2189
2190 #ifndef SHM_SAMPLING
2191 sampledTimerReqNode::sampledTimerReqNode(timerType iType, int iCounterId, 
2192                                          metricDefinitionNode *iMi,
2193                                          bool computingCost) :
2194                                          dataReqNode() {
2195    theSampleId = iCounterId;
2196    theTimerType = iType;
2197
2198    // The following fields are NULL until insertInstrumentatoin():
2199    timerPtr = NULL;
2200    sampler  = NULL;
2201
2202    if (!computingCost) {
2203      bool isOk=false;
2204      isOk = insertInstrumentation(iMi->proc(), iMi);
2205      assert(isOk && timerPtr!=NULL); 
2206    }
2207 }
2208
2209 sampledTimerReqNode::sampledTimerReqNode(const sampledTimerReqNode &src,
2210                                          process *childProc,
2211                                          metricDefinitionNode *,
2212                                          int iCounterId,
2213                                          const dictionary_hash<instInstance*,instInstance*> &map) {
2214    // a dup()-like routine; call after a fork()
2215    timerPtr = src.timerPtr; // assumes addr spaces have been dup()'d
2216
2217    if (!map.find(src.sampler, this->sampler)) // writes to this->sampler
2218       assert(false);
2219
2220    assert(sampler); // makes sense; timers are always sampled, whereas intCounters
2221                     // might be just non-sampled predicates.
2222    
2223    theSampleId = iCounterId;
2224    theTimerType = src.theTimerType;
2225
2226    tTimer temp;
2227    P_memset(&temp, '\0', sizeof(tTimer)); /* is this needed? */
2228    temp.id.id = this->theSampleId;
2229    temp.type = this->theTimerType;
2230    temp.normalize = 1000000;
2231    writeToInferiorHeap(childProc, temp);
2232
2233    // WARNING: shouldn't we be resetting the raw value to count=0, start=0,
2234    //          total = src.initialValue ???  On the other hand, it's not that
2235    //          simple -- if the timer is active in the parent, then it'll be active
2236    //          in the child.  So how about setting count to src.count, start=now,
2237    //          total=0 ???
2238 }
2239
2240 dataReqNode *
2241 sampledTimerReqNode::dup(process *childProc, metricDefinitionNode *mi,
2242                          int iCounterId,
2243                          const dictionary_hash<instInstance*,instInstance*> &map
2244                          ) const {
2245    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2246
2247    sampledTimerReqNode *result = new sampledTimerReqNode(*this, childProc, mi, iCounterId, map);
2248       // fork ctor
2249    if (!result)
2250       return NULL; // on failure, return w/o incrementing counterId
2251
2252    return result;
2253 }
2254
2255 bool sampledTimerReqNode::insertInstrumentation(process *theProc,
2256                                                 metricDefinitionNode *,
2257                                                 bool) {
2258    timerPtr = (tTimer *)inferiorMalloc(theProc, sizeof(tTimer), dataHeap);
2259    if (timerPtr == NULL)
2260       return false; // failure!
2261
2262    // Now let's initialize the newly allocated tTimer in the inferior heap:
2263    tTimer temp;
2264    P_memset(&temp, '\0', sizeof(tTimer));
2265    temp.id.id = this->theSampleId;
2266    temp.type = this->theTimerType;
2267    temp.normalize = 1000000;
2268    writeToInferiorHeap(theProc, temp);
2269
2270    // Now instrument DYNINSTreportTimer:
2271    function_base *sampleFunction = 
2272         theProc->findOneFunction("DYNINSTsampleValues");
2273    assert(sampleFunction);
2274
2275    AstNode *ast, *tmp;
2276    tmp = new AstNode(AstNode::Constant, timerPtr);
2277    ast = new AstNode("DYNINSTreportTimer", tmp);
2278    removeAst(tmp);
2279
2280    instPoint *func_entry = (instPoint *)sampleFunction->funcEntry(theProc);
2281    sampler = addInstFunc(theProc, func_entry, ast,
2282                          callPreInsn, orderLastAtPoint, false);
2283    removeAst(ast);
2284
2285    return true; // successful
2286 }
2287
2288 void sampledTimerReqNode::disable(process *theProc,
2289                                   const vector<unsigVecType> &pointsToCheck) {
2290    // We used to remove the sample id from midToMiMap here but now the caller is
2291    // responsible for that.
2292
2293    // Remove instrumentation added to DYNINSTsampleValues(), if necessary:
2294    if (sampler != NULL)
2295       ::deleteInst(sampler, getAllTrampsAtPoint(sampler));
2296
2297    // Deallocate space for tTimer in the inferior heap:
2298    assert(timerPtr);
2299    inferiorFree(theProc, (unsigned)timerPtr, dataHeap, pointsToCheck);
2300 }
2301
2302 void sampledTimerReqNode::writeToInferiorHeap(process *theProc,
2303                                               const tTimer &dataSrc) const {
2304    // using contents of "dataSrc", a local copy of the data,
2305    // write to inferior heap at loc "timerPtr" via proc->writeDataSpace()
2306    assert(timerPtr);
2307    theProc->writeDataSpace(timerPtr, sizeof(tTimer), &dataSrc);
2308 }
2309
2310 bool sampledTimerReqNode::
2311 unFork(dictionary_hash<instInstance*,instInstance*> &map) {
2312    instInstance *parentSamplerInstance = sampler;
2313
2314    instInstance *childSamplerInstance;
2315    if (!map.find(parentSamplerInstance, childSamplerInstance))
2316       assert(false);
2317
2318    vector<unsigned> pointsToCheck; // empty
2319    deleteInst(childSamplerInstance, pointsToCheck);
2320
2321    map[parentSamplerInstance] = NULL; // since we've deleted...
2322
2323    return true;
2324 }
2325                                  
2326 #endif
2327
2328 /* ****************************************************************** */
2329
2330 #ifdef SHM_SAMPLING
2331 sampledShmWallTimerReqNode::sampledShmWallTimerReqNode(int iCounterId,
2332                                                      metricDefinitionNode *iMi,
2333                                                      bool computingCost) :
2334                                                      dataReqNode() {
2335    theSampleId = iCounterId;
2336
2337    // The following fields are NULL until insertInstrumentation():
2338    allocatedIndex = UINT_MAX;
2339    allocatedLevel = UINT_MAX;
2340
2341    position_=0;
2342
2343    if (!computingCost) {
2344      bool isOk=false;
2345      isOk = insertInstrumentation(iMi->proc(), iMi);
2346      assert(isOk); 
2347    }
2348 }
2349
2350 sampledShmWallTimerReqNode::
2351 sampledShmWallTimerReqNode(const sampledShmWallTimerReqNode &src,
2352                            process *childProc,
2353                            metricDefinitionNode *mi,
2354                            int iCounterId, const process *parentProc) {
2355    // a dup()-like routine; call after a fork().
2356    // Assumes that the "childProc" has been duplicated already
2357
2358    // Note that the index w/in the inferior heap remains the same, so setting the new
2359    // inferiorTimerPtr isn't too hard.  Actually, it's trivial, since other code
2360    // ensures that the new shm segment is placed in exactly the same virtual mem loc
2361    // as the previous one.
2362    //
2363    // Note that the fastInferiorHeap class's fork ctor will have already copied the
2364    // actual data; we need to fill in new meta-data (new houseKeeping entries).
2365
2366    allocatedIndex = src.allocatedIndex;
2367    allocatedLevel = src.allocatedLevel;
2368
2369    theSampleId = iCounterId;
2370    assert(theSampleId != src.theSampleId);
2371
2372    superTable &theTable = childProc->getTable();
2373
2374    // since the new shm seg is placed in exactly the same memory location as
2375    // the old one, nothing here should change.
2376    const superTable &theParentTable = parentProc->getTable();
2377    assert(theTable.index2InferiorAddr(1,childProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel)==theParentTable.index2InferiorAddr(1,parentProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel));
2378
2379    // Write new raw value in the inferior heap:
2380    // we set localTimerPtr as follows: protector1 and procetor2 should be copied from
2381    //    src. total should be reset to 0.  start should be set to now if active else 0.
2382    //    counter should be copied from the source.
2383    // NOTE: SINCE WE COPY FROM THE SOURCE, IT'S IMPORTANT THAT ON A FORK, BOTH THE
2384    //       PARENT AND CHILD ARE PAUSED UNTIL WE COPY THINGS OVER.  THAT THE CHILD IS
2385    //       PAUSED IS NOTHING NEW; THAT THE PARENT SHOULD BE PAUSED IS NEW NEWS!
2386
2387    for (unsigned i=0; i<childProc->threads.size(); i++) {
2388      tTimer *localTimerPtr = (tTimer *) theTable.index2LocalAddr(1,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2389      const tTimer *srcTimerPtr = (const tTimer *) childProc->getParent()->getTable().index2LocalAddr(1,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2390
2391      localTimerPtr->total = 0;
2392      localTimerPtr->counter = srcTimerPtr->counter;
2393      localTimerPtr->id.id   = theSampleId;
2394      localTimerPtr->protector1 = srcTimerPtr->protector1;
2395      localTimerPtr->protector2 = srcTimerPtr->protector2;
2396
2397      if (localTimerPtr->counter == 0)
2398         // inactive timer...this is the easy case to copy
2399         localTimerPtr->start = 0; // undefined, really
2400      else
2401         // active timer...don't copy the start time from the source...make it 'now'
2402         localTimerPtr->start = getCurrWallTime();
2403    }
2404
2405    // write new HK for this tTimer:
2406    // Note: we don't assert anything about mi->getMId(), because that id has no
2407    // relation to the ids we work with (theSampleId).  In fact, we (the sampling code)
2408    // just don't ever care what mi->getMId() is.
2409    assert(theSampleId >= 0);
2410    assert(midToMiMap.defines(theSampleId));
2411    assert(midToMiMap[theSampleId] == mi);
2412    wallTimerHK iHKValue(theSampleId, mi, 0); // is last param right?
2413       // the mi should differ from the mi of the parent; theSampleId differs too.
2414    theTable.initializeHKAfterForkWallTimer(allocatedIndex, allocatedLevel, iHKValue);
2415
2416    position_=0;
2417 }
2418
2419 dataReqNode *
2420 sampledShmWallTimerReqNode::dup(process *childProc,
2421                                 metricDefinitionNode *mi,
2422                                 int iCounterId,
2423                                 const dictionary_hash<instInstance*,instInstance*> &
2424                                 ) const {
2425    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2426
2427    sampledShmWallTimerReqNode *tmp;
2428    tmp = new sampledShmWallTimerReqNode(*this, childProc, mi, iCounterId, childProc->getParent());
2429       // fork constructor
2430
2431    return tmp;
2432 }
2433
2434 bool sampledShmWallTimerReqNode::insertInstrumentation(process *theProc,
2435                                                        metricDefinitionNode *iMi, bool) {
2436    // Remember inferiorTimerPtr is NULL until this routine gets called.
2437    // WARNING: there will be an assert failure if the applic hasn't yet attached to the
2438    //          shm segment!!!
2439
2440    // initialize the tTimer in the inferior heap
2441    tTimer iValue;
2442    P_memset(&iValue, '\0', sizeof(tTimer));
2443    iValue.id.id = this->theSampleId;
2444
2445    wallTimerHK iHKValue(this->theSampleId, iMi, 0);
2446
2447    superTable &theTable = theProc->getTable();
2448
2449    if (!theTable.allocWallTimer(iValue, iHKValue, this->allocatedIndex, this->allocatedLevel))
2450       return false; // failure
2451
2452    return true;
2453 }
2454
2455 void sampledShmWallTimerReqNode::disable(process *theProc,
2456                                          const vector<unsigVecType> &pointsToCheck) {
2457    // We used to remove the sample id from midToMiMap here but now the caller is
2458    // responsible for that.
2459
2460    superTable &theTable = theProc->getTable();
2461
2462    // Remove from inferior heap; make sure we won't be sampled any more:
2463    vector<unsigned> trampsMaybeUsing;
2464    for (unsigned pointlcv=0; pointlcv < pointsToCheck.size(); pointlcv++)
2465       for (unsigned tramplcv=0; tramplcv < pointsToCheck[pointlcv].size(); tramplcv++)
2466          trampsMaybeUsing += pointsToCheck[pointlcv][tramplcv];
2467
2468    theTable.makePendingFree(1,allocatedIndex,allocatedLevel,trampsMaybeUsing);
2469
2470 #if defined(MT_THREAD)
2471 //NOTE: Not yet implemented for shm sampling! naim 4/23/97
2472 //    pdThread *thr = theProc->threads[0];
2473 //    thr->CTvector->remove(this->theSampleId, this->position_);
2474 //    theProc->updateActiveCT(false,wallTimer);
2475 #endif
2476 }
2477
2478 /* ****************************************************************** */
2479
2480 sampledShmProcTimerReqNode::sampledShmProcTimerReqNode(int iCounterId,
2481                                                      metricDefinitionNode *iMi,
2482                                                      bool computingCost) :
2483                                                      dataReqNode() {
2484    theSampleId = iCounterId;
2485
2486    // The following fields are NULL until insertInstrumentatoin():
2487    allocatedIndex = UINT_MAX;
2488    allocatedLevel = UINT_MAX;
2489
2490    position_=0;
2491
2492    if (!computingCost) {
2493      bool isOk=false;
2494      isOk = insertInstrumentation(iMi->proc(), iMi);
2495      assert(isOk); 
2496    }
2497 }
2498
2499 sampledShmProcTimerReqNode::
2500 sampledShmProcTimerReqNode(const sampledShmProcTimerReqNode &src,
2501                            process *childProc,
2502                            metricDefinitionNode *mi,
2503                            int iCounterId, const process *parentProc) {
2504    // a dup()-like routine; call after a fork()
2505    // Assumes that the "childProc" has been duplicated already
2506
2507    // Note that the index w/in the inferior heap remains the same, so setting the new
2508    // inferiorTimerPtr isn't too hard.  Actually, it's trivial, since other code
2509    // ensures that the new shm segment is placed in exactly the same virtual mem loc
2510    // as the previous one.
2511    //
2512    // Note that the fastInferiorHeap class's fork ctor will have already copied the
2513    // actual data; we need to fill in new meta-data (new houseKeeping entries).
2514
2515    allocatedIndex = src.allocatedIndex;
2516    theSampleId = iCounterId;
2517    assert(theSampleId != src.theSampleId);
2518
2519    superTable &theTable = childProc->getTable();
2520
2521    // since the new shm seg is placed in exactly the same memory location as
2522    // the old one, nothing here should change.
2523    const superTable &theParentTable = parentProc->getTable();
2524    assert(theTable.index2InferiorAddr(2,childProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel)==theParentTable.index2InferiorAddr(2,parentProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel));
2525
2526    // Write new raw value:
2527    // we set localTimerPtr as follows: protector1 and procetor2 should be copied from
2528    //    src. total should be reset to 0.  start should be set to now if active else 0.
2529    //    counter should be copied from the source.
2530    // NOTE: SINCE WE COPY FROM THE SOURCE, IT'S IMPORTANT THAT ON A FORK, BOTH THE
2531    //       PARENT AND CHILD ARE PAUSED UNTIL WE COPY THINGS OVER.  THAT THE CHILD IS
2532    //       PAUSED IS NOTHING NEW; THAT THE PARENT SHOULD BE PAUSED IS NEW NEWS!
2533
2534    for (unsigned i=0; i<childProc->threads.size(); i++) {
2535      tTimer *localTimerPtr = (tTimer *) theTable.index2LocalAddr(2,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2536      const tTimer *srcTimerPtr = (const tTimer *) childProc->getParent()->getTable().index2LocalAddr(2,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2537
2538      localTimerPtr->total = 0;
2539      localTimerPtr->counter = srcTimerPtr->counter;
2540      localTimerPtr->id.id   = theSampleId;
2541      localTimerPtr->protector1 = srcTimerPtr->protector1;
2542      localTimerPtr->protector2 = srcTimerPtr->protector2;
2543
2544      if (localTimerPtr->counter == 0)
2545         // inactive timer...this is the easy case to copy
2546         localTimerPtr->start = 0; // undefined, really
2547      else
2548         // active timer...don't copy the start time from the source...make it 'now'
2549         localTimerPtr->start = childProc->getInferiorProcessCPUtime();
2550    }
2551
2552    // Write new HK for this tTimer:
2553    // Note: we don't assert anything about mi->getMId(), because that id has no
2554    // relation to the ids we work with (theSampleId).  In fact, we (the sampling code)
2555    // just don't ever care what mi->getMId() is.
2556    assert(theSampleId >= 0);
2557    assert(midToMiMap.defines(theSampleId));
2558    assert(midToMiMap[theSampleId] == mi);
2559    processTimerHK iHKValue(theSampleId, mi, 0); // is last param right?
2560       // the mi differs from the mi of the parent; theSampleId differs too.
2561    theTable.initializeHKAfterForkProcTimer(allocatedIndex, allocatedLevel, iHKValue);
2562
2563    position_=0;
2564 }
2565
2566 dataReqNode *
2567 sampledShmProcTimerReqNode::dup(process *childProc,
2568                                 metricDefinitionNode *mi,
2569                                 int iCounterId,
2570                                 const dictionary_hash<instInstance*,instInstance*> &
2571                                 ) const {
2572    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2573
2574    sampledShmProcTimerReqNode *tmp;
2575    tmp = new sampledShmProcTimerReqNode(*this, childProc, mi, iCounterId, childProc->getParent());
2576       // fork constructor
2577
2578    return tmp;
2579 }
2580
2581 bool sampledShmProcTimerReqNode::insertInstrumentation(process *theProc,
2582                                                        metricDefinitionNode *iMi, bool) {
2583    // Remember inferiorTimerPtr is NULL until this routine gets called.
2584    // WARNING: there will be an assert failure if the applic hasn't yet attached to the
2585    //          shm segment!!!
2586
2587    // initialize the tTimer in the inferior heap
2588    tTimer iValue;
2589    P_memset(&iValue, '\0', sizeof(tTimer));
2590    iValue.id.id = this->theSampleId;
2591
2592    processTimerHK iHKValue(this->theSampleId, iMi, 0);
2593
2594    superTable &theTable = theProc->getTable();
2595
2596    if (!theTable.allocProcTimer(iValue, iHKValue, this->allocatedIndex,this->allocatedLevel))
2597       return false; // failure
2598
2599    return true;
2600 }
2601
2602 void sampledShmProcTimerReqNode::disable(process *theProc,
2603                                          const vector<unsigVecType> &pointsToCheck) {
2604    // We used to remove the sample id from midToMiMap here but now the caller is
2605    // responsible for that.
2606
2607    superTable &theTable = theProc->getTable();
2608
2609    // Remove from inferior heap; make sure we won't be sampled any more:
2610    vector<unsigned> trampsMaybeUsing;
2611    for (unsigned pointlcv=0; pointlcv < pointsToCheck.size(); pointlcv++)
2612       for (unsigned tramplcv=0; tramplcv < pointsToCheck[pointlcv].size(); tramplcv++)
2613          trampsMaybeUsing += pointsToCheck[pointlcv][tramplcv];
2614
2615    theTable.makePendingFree(2,allocatedIndex,allocatedLevel,trampsMaybeUsing);
2616
2617 #if defined(MT_THREAD)
2618 //NOTE: Not yet implemented for shm sampling! naim 4/23/97
2619 //   pdThread *thr = theProc->threads[0];
2620 //   thr->CTvector->remove(this->theSampleId, this->position_);
2621 //   theProc->updateActiveCT(false,procTimer);
2622 #endif
2623 }
2624 #endif
2625
2626 /* **************************** */
2627
2628 void reportInternalMetrics(bool force) 
2629 {
2630     if (isApplicationPaused())
2631        return; // we don't sample when paused (is this right?)
2632
2633     static timeStamp end=0.0;
2634
2635     // see if we have a sample to establish time base.
2636     if (!firstRecordTime) {
2637        //cerr << "reportInternalMetrics: no because firstRecordTime==0" << endl;
2638        return;
2639     }
2640
2641     if (end==0.0)
2642         end = (timeStamp)firstRecordTime/MILLION;
2643
2644     const timeStamp now = getCurrentTime(false);
2645
2646     //  check if it is time for a sample
2647     if (!force && now < end + samplingRate)  {
2648 //        cerr << "reportInternalMetrics: no because now < end + samplingRate (end=" << end << "; samplingRate=" << samplingRate << "; now=" << now << ")" << endl;
2649 //      cerr << "difference is " << (end+samplingRate-now) << endl;
2650         return;
2651     }
2652
2653     timeStamp start = end;
2654     end = now;
2655
2656     // TODO -- clean me up, please
2657
2658     unsigned max1=0;
2659     unsigned max2=0;
2660     unsigned max3=0;
2661     for (unsigned u1 = 0; u1 < processVec.size(); u1++) {
2662       if (processVec[u1]->numOfActCounters_is > max1)
2663         max1=processVec[u1]->numOfActCounters_is;
2664       if (processVec[u1]->numOfActProcTimers_is > max2)
2665         max2=processVec[u1]->numOfActProcTimers_is;
2666       if (processVec[u1]->numOfActWallTimers_is > max3)
2667         max3=processVec[u1]->numOfActWallTimers_is;
2668     }
2669     numOfActCounters_all=max1;
2670     numOfActProcTimers_all=max2;
2671     numOfActWallTimers_all=max3;
2672
2673     unsigned ai_size = internalMetric::allInternalMetrics.size();
2674     for (unsigned u2=0; u2<ai_size; u2++) {
2675       internalMetric *theIMetric = internalMetric::allInternalMetrics[u2];
2676       // Loop thru all enabled instances of this internal metric...
2677
2678       for (unsigned v=0; v < theIMetric->num_enabled_instances(); v++) {
2679         internalMetric::eachInstance &theInstance = theIMetric->getEnabledInstance(v);
2680            // not "const" since bumpCumulativeValueBy() may be called
2681
2682         sampleValue value = (sampleValue) 0;
2683         if (theIMetric->name() == "active_processes") {
2684           //value = (end - start) * activeProcesses;
2685           value = (end - start) * theInstance.getValue();
2686         } else if (theIMetric->name() == "bucket_width") {
2687           //value = (end - start)* theInstance.getValue();
2688           // I would prefer to use (end-start) * theInstance.getValue(); however,
2689           // we've had some problems getting setValue() called in time, thus
2690           // leaving us with getValues() of 0 sometimes.  See longer comment in dynrpc.C --ari
2691           extern float currSamplingRate;
2692           value = (end - start) * currSamplingRate;
2693         } else if (theIMetric->name() == "number_of_cpus") {
2694           value = (end - start) * numberOfCPUs;
2695         } else if (theIMetric->name() == "total_CT") {
2696           value = (end - start) * internalMetricCounterId;
2697           assert(value>=0.0);
2698         } else if (theIMetric->name() == "numOfActCounters") {
2699           value = (end - start) * numOfActCounters_all;
2700           assert(value>=0.0);
2701         } else if (theIMetric->name() == "numOfActProcTimers") {
2702           value = (end - start) * numOfActProcTimers_all;
2703           assert(value>=0.0);
2704         } else if (theIMetric->name() == "numOfActWallTimers") {
2705           value = (end - start) * numOfActWallTimers_all;
2706           assert(value>=0.0);
2707         } else if (theIMetric->name() == "active_CT") {
2708           value = (end - start) * (numOfActCounters_all+numOfActProcTimers_all+numOfActWallTimers_all);
2709           assert(value>=0.0);
2710         } else if (theIMetric->name() == "infHeapMemAvailable") {
2711           value = (end - start) * inferiorMemAvailable;
2712           assert(value>=0.0);
2713         } else if (theIMetric->style() == EventCounter) {
2714           value = theInstance.getValue();
2715           // assert((value + 0.0001)  >= imp->cumulativeValue);
2716           value -= theInstance.getCumulativeValue();
2717           theInstance.bumpCumulativeValueBy(value);
2718         } else if (theIMetric->style() == SampledFunction) {
2719           value = theInstance.getValue();
2720         }
2721
2722         theInstance.report(start, end, value);
2723            // calls metricDefinitionNode->forwardSimpleValue()
2724       }
2725     }
2726 }
2727
2728 void disableAllInternalMetrics() {
2729     for (unsigned u=0; u < internalMetric::allInternalMetrics.size(); u++) {
2730       internalMetric *theIMetric = internalMetric::allInternalMetrics[u];
2731
2732       // Now loop thru all the enabled instances of this internal metric...
2733       while (theIMetric->num_enabled_instances() > 0) {
2734         internalMetric::eachInstance &theInstance = theIMetric->getEnabledInstance(0);
2735         tp->endOfDataCollection(theInstance.getMId());
2736         theIMetric->disableInstance(0);
2737       }
2738     }  
2739 }
2740
2741 #ifdef SHM_SAMPLING
2742
2743 unsigned sampledShmIntCounterReqNode::getInferiorPtr(process *proc) const {
2744     // counterPtr could be NULL if we are building AstNodes just to compute
2745     // the cost - naim 2/18/97
2746     // NOTE:
2747     // this routine will dissapear because we can't compute the address
2748     // of the counter/timer without knowing the thread id - naim 3/17/97
2749     //
2750     if (allocatedIndex == UINT_MAX || allocatedLevel == UINT_MAX) return(0);
2751     assert(proc != NULL);
2752     superTable &theTable = proc->getTable();
2753     // we assume there is only one thread
2754     return((unsigned) theTable.index2InferiorAddr(0,0,allocatedIndex,allocatedLevel));
2755 }
2756
2757 unsigned sampledShmWallTimerReqNode::getInferiorPtr(process *proc) const {
2758     // counterPtr could be NULL if we are building AstNodes just to compute
2759     // the cost - naim 2/18/97
2760     // NOTE:
2761     // this routine will dissapear because we can't compute the address
2762     // of the counter/timer without knowing the thread id - naim 3/17/97
2763     //
2764     if (allocatedIndex == UINT_MAX || allocatedLevel == UINT_MAX) return(0);
2765     assert(proc != NULL);
2766     superTable &theTable = proc->getTable();
2767     // we assume there is only one thread
2768     return((unsigned) theTable.index2InferiorAddr(1,0,allocatedIndex,allocatedLevel));
2769 }
2770
2771 unsigned sampledShmProcTimerReqNode::getInferiorPtr(process *proc) const {
2772     // counterPtr could be NULL if we are building AstNodes just to compute
2773     // the cost - naim 2/18/97
2774     // NOTE:
2775     // this routine will dissapear because we can't compute the address
2776     // of the counter/timer without knowing the thread id - naim 3/17/97
2777     //
2778     if (allocatedIndex == UINT_MAX || allocatedLevel == UINT_MAX) return(0);
2779     assert(proc != NULL);
2780     superTable &theTable = proc->getTable();
2781     // we assume there is only one thread
2782     return((unsigned) theTable.index2InferiorAddr(2,0,allocatedIndex,allocatedLevel));
2783 }
2784
2785 #endif