Cleaning up dataReqNodes for certain cases of deletion of metricDefinitionNodes
[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       for (unsigned u=0; u<dataRequests.size(); u++) {
1436         delete dataRequests[u];
1437       }
1438       dataRequests.resize(0);
1439     }
1440 }
1441
1442 void metricDefinitionNode::cleanup_drn()
1443 {
1444       // we assume that it is safe to delete a dataReqNode at this point, 
1445       // otherwise, we would need to do something similar as in the disable
1446       // method for metricDefinitionNode - naim
1447       vector<unsigVecType> pointsToCheck;
1448       for (unsigned u=0; u<dataRequests.size(); u++) {
1449         dataRequests[u]->disable(proc_, pointsToCheck); // deinstrument
1450       }
1451 }
1452
1453 // NOTE: This stuff (flush_batch_buffer() and batchSampleData()) belongs
1454 //       in perfStream.C; this is an inappropriate file.
1455
1456 //////////////////////////////////////////////////////////////////////////////
1457 // Buffer the samples before we actually send it                            //
1458 //      Send it when the buffers are full                                   //
1459 //      or, send it when the last sample in the interval has arrived.       //
1460 //////////////////////////////////////////////////////////////////////////////
1461
1462 const unsigned SAMPLE_BUFFER_SIZE = (1*1024)/sizeof(T_dyninstRPC::batch_buffer_entry);
1463 bool BURST_HAS_COMPLETED = false;
1464    // set to true after a burst (after a processTraceStream(), or sampleNodes for
1465    // the CM5), which will force the buffer to be flushed before it fills up
1466    // (if not, we'd have bad response time)
1467
1468 vector<T_dyninstRPC::batch_buffer_entry> theBatchBuffer (SAMPLE_BUFFER_SIZE);
1469 unsigned int batch_buffer_next=0;
1470
1471 // The following routines (flush_batch_buffer() and batchSampleData() are
1472 // in an inappropriate src file...move somewhere more appropriate)
1473 void flush_batch_buffer() {
1474    // don't need to flush if the batch had no data (this does happen; see
1475    // perfStream.C)
1476    if (batch_buffer_next == 0)
1477       return;
1478
1479    // alloc buffer of the exact size to make communication
1480    // more efficient.  Why don't we send theBatchBuffer with a count?
1481    // This would work but would always (in the igen call) copy the entire
1482    // vector.  This solution has the downside of calling new but is not too bad
1483    // and is clean.
1484    vector<T_dyninstRPC::batch_buffer_entry> copyBatchBuffer(batch_buffer_next);
1485    assert(copyBatchBuffer.size() <= theBatchBuffer.size());
1486    for (unsigned i=0; i< batch_buffer_next; i++) {
1487       copyBatchBuffer[i] = theBatchBuffer[i];
1488    }
1489
1490 #ifdef FREEDEBUG
1491 timeStamp t1,t2;
1492 t1=getCurrentTime(false);
1493 #endif
1494
1495    // Now let's do the actual igen call!
1496    tp->batchSampleDataCallbackFunc(0, copyBatchBuffer);
1497
1498 #ifdef FREEDEBUG
1499 t2=getCurrentTime(false);
1500 if ((float)(t2-t1) > 15.0) {
1501 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));
1502 logLine(errorLine);
1503 }
1504 #endif
1505
1506    BURST_HAS_COMPLETED = false;
1507    batch_buffer_next = 0;
1508 }
1509
1510 void batchSampleData(int mid, double startTimeStamp,
1511                      double endTimeStamp, double value, unsigned val_weight,
1512                      bool internal_metric) 
1513 {
1514    // This routine is called where we used to call tp->sampleDataCallbackFunc.
1515    // We buffer things up and eventually call tp->batchSampleDataCallbackFunc
1516
1517 #ifdef notdef
1518    char myLogBuffer[120] ;
1519    sprintf(myLogBuffer, "mid %d, value %g\n", mid, value) ;
1520    logLine(myLogBuffer) ;
1521 #endif
1522
1523    // Flush the buffer if (1) it is full, or (2) for good response time, after
1524    // a burst of data:
1525    if (batch_buffer_next >= SAMPLE_BUFFER_SIZE || BURST_HAS_COMPLETED)
1526       flush_batch_buffer();
1527
1528    // Now let's batch this entry.
1529    T_dyninstRPC::batch_buffer_entry &theEntry = theBatchBuffer[batch_buffer_next];
1530    theEntry.mid = mid;
1531    theEntry.startTimeStamp = startTimeStamp;
1532    theEntry.endTimeStamp = endTimeStamp;
1533    theEntry.value = value;
1534    theEntry.weight = val_weight;
1535    theEntry.internal_met = internal_metric;
1536    batch_buffer_next++;
1537 }
1538
1539 //////////////////////////////////////////////////////////////////////////////
1540 // Buffer the traces before we actually send it                            //
1541 //      Send it when the buffers are full                                   //
1542 //      or, send it when the last sample in the interval has arrived.       //
1543 //////////////////////////////////////////////////////////////////////////////
1544
1545 const unsigned TRACE_BUFFER_SIZE = 10;
1546 bool TRACE_BURST_HAS_COMPLETED = false;
1547    // set to true after a burst (after a processTraceStream(), or sampleNodes for
1548    // the CM5), which will force the buffer to be flushed before it fills up
1549    // (if not, we'd have bad response time)
1550
1551 vector<T_dyninstRPC::trace_batch_buffer_entry> theTraceBatchBuffer (TRACE_BUFFER_SIZE);
1552 unsigned int trace_batch_buffer_next=0;
1553
1554 void flush_trace_batch_buffer(int program) {
1555    // don't need to flush if the batch had no data (this does happen; see
1556    // perfStream.C)
1557    if (trace_batch_buffer_next == 0)
1558       return;
1559
1560    vector<T_dyninstRPC::trace_batch_buffer_entry> copyTraceBatchBuffer(trace_batch_buffer_next);
1561    for (unsigned i=0; i< trace_batch_buffer_next; i++)
1562       copyTraceBatchBuffer[i] = theTraceBatchBuffer[i];
1563
1564
1565    // Now let's do the actual igen call!
1566
1567    tp->batchTraceDataCallbackFunc(program, copyTraceBatchBuffer);
1568
1569    TRACE_BURST_HAS_COMPLETED = false;
1570    trace_batch_buffer_next = 0;
1571 }
1572
1573 void batchTraceData(int program, int mid, int recordLength,
1574                      char *recordPtr)
1575 {
1576    // Now let's batch this entry.
1577    T_dyninstRPC::trace_batch_buffer_entry &theEntry = theTraceBatchBuffer[trace_batch_buffer_next];
1578    theEntry.mid = mid;
1579    theEntry.length = recordLength;
1580    theEntry.traceRecord = byteArray(recordPtr,recordLength);
1581    trace_batch_buffer_next++;
1582
1583    // We buffer things up and eventually call tp->batchTraceDataCallbackFunc
1584
1585    // Flush the buffer if (1) it is full, or (2) for good response time, after
1586    // a burst of data:
1587    if (trace_batch_buffer_next >= TRACE_BUFFER_SIZE || TRACE_BURST_HAS_COMPLETED) {
1588       flush_trace_batch_buffer(program);
1589    }
1590
1591 }
1592
1593 void metricDefinitionNode::forwardSimpleValue(timeStamp start, timeStamp end,
1594                                        sampleValue value, unsigned weight,
1595                                        bool internal_met)
1596 {
1597   // TODO mdc
1598     assert(start + 0.000001 >= (firstRecordTime/MILLION));
1599     assert(end >= (firstRecordTime/MILLION));
1600     assert(end > start);
1601
1602     batchSampleData(id_, start, end, value, weight, internal_met);
1603 }
1604
1605 void metricDefinitionNode::updateValue(time64 wallTime, 
1606                                        sampleValue value)
1607 {
1608     timeStamp sampleTime = wallTime / 1000000.0;
1609        // note: we can probably do integer division by million quicker
1610
1611     assert(value >= -0.01);
1612
1613     // TODO -- is this ok?
1614     // TODO -- do sampledFuncs work ?
1615     if (style_ == EventCounter) { 
1616
1617       // only use delta from last sample.
1618       if (value < cumulativeValue) {
1619         if ((value/cumulativeValue) < 0.99999) {
1620             assert((value + 0.0001)  >= cumulativeValue);
1621         } else {
1622           // floating point rounding error ignore
1623           cumulativeValue = value;
1624         }
1625       }
1626
1627       //        if (value + 0.0001 < cumulativeValue)
1628       //           printf ("WARNING:  sample went backwards!!!!!\n");
1629       value -= cumulativeValue;
1630       cumulativeValue += value;
1631     } 
1632
1633     //
1634     // If style==EventCounter then value is changed. Otherwise, it keeps the
1635     // the current "value" (e.g. SampledFunction case). That's why it is not
1636     // necessary to have an special case for SampledFunction.
1637     //
1638
1639     assert(samples.size() == aggregators.size());
1640     for (unsigned u = 0; u < samples.size(); u++) {
1641       if (samples[u]->firstValueReceived())
1642         samples[u]->newValue(sampleTime, value);
1643       else {
1644         samples[u]->startTime(sampleTime);
1645       }
1646       aggregators[u]->updateAggregateComponent();
1647     }
1648 }
1649
1650 void metricDefinitionNode::updateAggregateComponent()
1651 {
1652     // currently called (only) by the above routine
1653     sampleInterval ret = aggSample.aggregateValues();
1654     if (ret.valid) {
1655         assert(ret.end > ret.start);
1656         assert(ret.start + 0.000001 >= (firstRecordTime/MILLION));
1657         assert(ret.end >= (firstRecordTime/MILLION));
1658         batchSampleData(id_, ret.start, ret.end, ret.value,
1659                         aggSample.numComponents(),false);
1660     }
1661 //    else {
1662 //        metric_cerr << "sorry, ret.valid false so not batching sample data" << endl;
1663 //    }
1664 }
1665
1666 //
1667 // Costs are now reported to paradyn like other metrics (ie. we are not
1668 // calling reportInternalMetrics to deliver cost values, instead we wait
1669 // until we have received a new interval of cost data from each process)
1670 // note: this only works for the CM5 because all cost metrics are sumed
1671 // at the daemons and at paradyn, otherwise the CM5 needs its own version
1672 // of this routine that uses the same aggregate method as the one for paradyn 
1673 //
1674 #ifndef SHM_SAMPLING
1675 void processCost(process *proc, traceHeader *h, costUpdate *s)
1676 {
1677     // we can probably do integer division by million quicker.
1678     timeStamp newSampleTime = (h->wall / 1000000.0);
1679     timeStamp newProcessTime = (h->process / 1000000.0);
1680
1681     timeStamp lastProcessTime = 
1682                         totalPredictedCost->getLastSampleProcessTime(proc); 
1683
1684     // find the portion of uninstrumented time for this interval
1685     double unInstTime = ((newProcessTime - lastProcessTime) 
1686                          / (1+currentPredictedCost));
1687     // update predicted cost
1688     // note: currentPredictedCost is the same for all processes 
1689     //       this should be changed to be computed on a per process basis
1690     sampleValue newPredCost = totalPredictedCost->getCumulativeValue(proc);
1691     newPredCost += (float)(currentPredictedCost*unInstTime); 
1692     totalPredictedCost->updateValue(proc,newPredCost,
1693                                     newSampleTime,newProcessTime);
1694     // update observed cost 
1695     observed_cost->updateValue(proc,s->obsCostIdeal,
1696                                newSampleTime,newProcessTime);
1697
1698     // update smooth observed cost
1699     smooth_obs_cost->updateSmoothValue(proc,s->obsCostIdeal,
1700                                  newSampleTime,newProcessTime);
1701 }
1702 #endif
1703
1704 #ifndef SHM_SAMPLING
1705 void processSample(int /* pid */, traceHeader *h, traceSample *s)
1706 {
1707     // called from processTraceStream (perfStream.C) when a TR_SAMPLE record
1708     // has arrived from the appl.
1709
1710     unsigned mid = s->id.id; // low-level counterId (see primitives.C)
1711
1712     static time64 firstWall = 0;
1713
1714     static bool firstTime = true;
1715
1716     if (firstTime) {
1717        firstWall = h->wall;
1718     }
1719
1720     metricDefinitionNode *mi; // filled in by find() if found
1721     if (!midToMiMap.find(mid, mi)) { // low-level counterId to metricDefinitionNode
1722        metric_cerr << "TR_SAMPLE id " << s->id.id << " not for valid mi...discarding" << endl;
1723        return;
1724     }
1725
1726 //    metric_cerr << "FROM pid " << pid << " got value " << s->value << " for id " << s->id.id << endl;
1727
1728     //    sprintf(errorLine, "sample id %d at time %8.6f = %f\n", s->id.id, 
1729     //  ((double) *(int*) &h->wall) + (*(((int*) &h->wall)+1))/1000000.0, s->value);
1730     //    logLine(errorLine);
1731     mi->updateValue(h->wall, s->value);
1732     samplesDelivered++;
1733 }
1734 #endif
1735
1736 /*
1737  * functions to operate on inst request graph.
1738  *
1739  */
1740 instReqNode::instReqNode(instPoint *iPoint,
1741                          AstNode *iAst,
1742                          callWhen  iWhen,
1743                          callOrder o, bool iManuallyTrigger) {
1744     point = iPoint;
1745     when = iWhen;
1746     order = o;
1747     instance = NULL; // set when insertInstrumentation() calls addInstFunc()
1748     ast = assignAst(iAst);
1749     manuallyTrigger = iManuallyTrigger;
1750     assert(point);
1751 }
1752
1753 instReqNode instReqNode::forkProcess(const instReqNode &parentNode,
1754                              const dictionary_hash<instInstance*,instInstance*> &map) {
1755     instReqNode ret = instReqNode(parentNode.point, parentNode.ast, parentNode.when,
1756                                   parentNode.order,
1757                                   false // don't manually trigger
1758                                   );
1759
1760     if (!map.find(parentNode.instance, ret.instance)) // writes to ret.instance
1761        assert(false);
1762
1763     return ret;
1764 }
1765
1766 bool instReqNode::unFork(dictionary_hash<instInstance*,instInstance*> &map) const {
1767    // The fork syscall duplicates all trampolines from the parent into the child. For
1768    // those mi's which we don't want to propagate to the child, this creates a
1769    // problem.  We need to remove instrumentation code from the child.  This routine
1770    // does that.
1771    //
1772    // "this" represents an instReqNode in the PARENT process.
1773    // "map" maps all instInstance*'s of the parent process to instInstance*'s in the
1774    // child process.  We modify "map" by setting a value to NULL.
1775
1776    instInstance *parentInstance = getInstance();
1777    
1778    instInstance *childInstance;
1779    if (!map.find(parentInstance, childInstance)) // writes to childInstance
1780       assert(false);
1781
1782    vector<unsigned> pointsToCheck; // is it right leaving this empty on a fork()???
1783    deleteInst(childInstance, pointsToCheck);
1784
1785    map[parentInstance] = NULL; // since we've deleted...
1786
1787    return true; // success
1788 }
1789
1790 bool instReqNode::insertInstrumentation(process *theProc,
1791                                         returnInstance *&retInstance) 
1792 {
1793     // NEW: We may manually trigger the instrumentation, via a call to postRPCtoDo()
1794
1795     // addInstFunc() is one of the key routines in all paradynd.
1796     // It installs a base tramp at the point (if needed), generates code
1797     // for the tramp, calls inferiorMalloc() in the text heap to get space for it,
1798     // and actually inserts the instrumentation.
1799     instance = addInstFunc(theProc, point, ast, when, order,
1800                            false, // false --> don't exclude cost
1801                            retInstance);
1802
1803     return (instance != NULL);
1804 }
1805
1806 void instReqNode::disable(const vector<unsigned> &pointsToCheck)
1807 {
1808     deleteInst(instance, pointsToCheck);
1809     instance = NULL;
1810 }
1811
1812 instReqNode::~instReqNode()
1813 {
1814     instance = NULL;
1815     removeAst(ast);
1816 }
1817
1818 float instReqNode::cost(process *theProc) const
1819 {
1820     float value;
1821     float unitCost;
1822     float frequency;
1823     int unitCostInCycles;
1824
1825     unitCostInCycles = ast->cost() + getPointCost(theProc, point) +
1826                        getInsnCost(trampPreamble) + getInsnCost(trampTrailer);
1827     // printf("unit cost = %d cycles\n", unitCostInCycles);
1828     unitCost = unitCostInCycles/ cyclesPerSecond;
1829     frequency = getPointFrequency(point);
1830     value = unitCost * frequency;
1831     return(value);
1832 }
1833
1834 bool instReqNode::triggerNow(process *theProc) {
1835    assert(manuallyTrigger);
1836
1837    theProc->postRPCtoDo(ast, false, // don't skip cost
1838                         NULL, // no callback fn needed
1839                         NULL
1840                         );
1841       // the rpc will be launched with a call to launchRPCifAppropriate()
1842       // in the main loop (perfStream.C)
1843
1844    return true;
1845 }
1846
1847 /* ************************************************************************* */
1848
1849 #ifndef SHM_SAMPLING
1850 sampledIntCounterReqNode::sampledIntCounterReqNode(int iValue, int iCounterId,
1851                                                    metricDefinitionNode *iMi, 
1852                                                    bool computingCost) :
1853                                                    dataReqNode() {
1854    theSampleId = iCounterId;
1855    initialValue = iValue;
1856
1857    // The following fields are NULL until insertInstrumentation()
1858    counterPtr = NULL;
1859    sampler = NULL;
1860
1861    if (!computingCost) {
1862      bool isOk=false;
1863      isOk = insertInstrumentation(iMi->proc(), iMi);
1864      assert(isOk && counterPtr!=NULL); 
1865    }
1866 }
1867
1868 sampledIntCounterReqNode::sampledIntCounterReqNode(const sampledIntCounterReqNode &src,
1869                                                    process *childProc,
1870                                                    metricDefinitionNode *,
1871                                                    int iCounterId,
1872                                                    const dictionary_hash<instInstance*,instInstance*> &map) {
1873    // a dup() routine (call after a fork())
1874    counterPtr = src.counterPtr; // assumes addr spaces have been dup()d.
1875
1876    if (!map.find(src.sampler, this->sampler)) // writes to this->sampler
1877       assert(false);
1878
1879    theSampleId = iCounterId;
1880  
1881    intCounter temp;
1882    temp.id.id = this->theSampleId;
1883    temp.value = initialValue;
1884    writeToInferiorHeap(childProc, temp);
1885 }
1886
1887 dataReqNode *
1888 sampledIntCounterReqNode::dup(process *childProc,
1889                               metricDefinitionNode *mi,
1890                               int iCounterId,
1891                               const dictionary_hash<instInstance*,instInstance*> &map
1892                               ) const {
1893    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
1894
1895    sampledIntCounterReqNode *tmp;
1896    tmp = new sampledIntCounterReqNode(*this, childProc, mi, iCounterId, map);
1897       // fork ctor
1898   
1899    return tmp;
1900 }
1901
1902 bool sampledIntCounterReqNode::insertInstrumentation(process *theProc,
1903                                                      metricDefinitionNode *,
1904                                                      bool) {
1905    // Remember counterPtr and sampler are NULL until this routine
1906    // gets called.
1907    counterPtr = (intCounter*)inferiorMalloc(theProc, sizeof(intCounter), dataHeap);
1908    if (counterPtr == NULL)
1909       return false; // failure!
1910
1911    // initialize the intCounter in the inferior heap
1912    intCounter temp;
1913    temp.id.id = this->theSampleId;
1914    temp.value = this->initialValue;
1915
1916    writeToInferiorHeap(theProc, temp);
1917
1918    function_base *sampleFunction = 
1919         theProc->findOneFunction("DYNINSTsampleValues");
1920    assert(sampleFunction);
1921
1922    AstNode *ast, *tmp;
1923    tmp = new AstNode(AstNode::Constant, counterPtr);
1924    ast = new AstNode("DYNINSTreportCounter", tmp);
1925    removeAst(tmp);
1926
1927    instPoint *func_entry = (instPoint *)sampleFunction->funcEntry(theProc);
1928    sampler = addInstFunc(theProc, func_entry,
1929                          ast, callPreInsn, orderLastAtPoint, false);
1930    removeAst(ast);
1931
1932    return true; // success
1933 }
1934
1935 void sampledIntCounterReqNode::disable(process *theProc,
1936                                        const vector<unsigVecType> &pointsToCheck) {
1937    // We used to remove the sample id from midToMiMap here but now the caller is
1938    // responsible for that.
1939
1940    // Remove instrumentation added to DYNINSTsampleValues(), if necessary:
1941    if (sampler != NULL)
1942       ::deleteInst(sampler, getAllTrampsAtPoint(sampler));
1943
1944    // Deallocate space for intCounter in the inferior heap:
1945    assert(counterPtr != NULL);
1946    inferiorFree(theProc, (unsigned)counterPtr, dataHeap, pointsToCheck);
1947 }
1948
1949 void sampledIntCounterReqNode::writeToInferiorHeap(process *theProc,
1950                                                    const intCounter &dataSrc) const {
1951    // using the contents of "dataSrc", write to the inferior heap at loc
1952    // "counterPtr" via proc->writeDataSpace()
1953    assert(counterPtr);
1954    theProc->writeDataSpace(counterPtr, sizeof(intCounter), &dataSrc);
1955 }
1956
1957 bool sampledIntCounterReqNode::
1958 unFork(dictionary_hash<instInstance*,instInstance*> &map) {
1959    instInstance *parentSamplerInstance = this->sampler;
1960
1961    instInstance *childSamplerInstance;
1962    if (!map.find(parentSamplerInstance, childSamplerInstance))
1963       assert(false);
1964
1965    vector<unsigned> pointsToCheck; // empty on purpose
1966    deleteInst(childSamplerInstance, pointsToCheck);
1967
1968    map[parentSamplerInstance] = NULL;
1969
1970    return true;
1971 }
1972                                       
1973 #endif
1974
1975 /* ************************************************************************* */
1976
1977 #ifdef SHM_SAMPLING
1978
1979 sampledShmIntCounterReqNode::sampledShmIntCounterReqNode(int iValue, 
1980                                                      int iCounterId, 
1981                                                      metricDefinitionNode *iMi,
1982                                                      bool computingCost,
1983                                                      bool doNotSample) :
1984                                                      dataReqNode() {
1985    theSampleId = iCounterId;
1986    initialValue = iValue;
1987
1988    // The following fields are NULL until insertInstrumentation()
1989    allocatedIndex = UINT_MAX;
1990    allocatedLevel = UINT_MAX;
1991
1992    position_=0;
1993
1994    if (!computingCost) {
1995      bool isOk=false;
1996      isOk = insertInstrumentation(iMi->proc(), iMi, doNotSample);
1997      assert(isOk); 
1998    }
1999 }
2000
2001 sampledShmIntCounterReqNode::
2002 sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &src,
2003                             process *childProc, metricDefinitionNode *mi,
2004                             int iCounterId, const process *parentProc) {
2005    // a dup() routine (call after a fork())
2006    // Assumes that "childProc" has been copied already (e.g., the shm seg was copied).
2007
2008    // Note that the index w/in the inferior heap remains the same, so setting the
2009    // new inferiorCounterPtr isn't too hard.  Actually, it's trivial, since other code
2010    // ensures that the new shm segment is placed in exactly the same virtual mem location
2011    // as the previous one.
2012    //
2013    // Note that the fastInferiorHeap class's fork ctor will have already copied the
2014    // actual data; we need to fill in new meta-data (new houseKeeping entries).
2015
2016    this->allocatedIndex = src.allocatedIndex;
2017    this->allocatedLevel = src.allocatedLevel;
2018
2019    this->theSampleId = iCounterId;  // this is different from the parent's value
2020    this->initialValue = src.initialValue;
2021
2022    superTable &theTable = childProc->getTable();
2023
2024    // since the new shm seg is placed in exactly the same memory location as
2025    // the old one, nothing here should change.
2026    const superTable &theParentTable = parentProc->getTable();
2027    assert(theTable.index2InferiorAddr(0,childProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel)==theParentTable.index2InferiorAddr(0,parentProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel));
2028
2029    for (unsigned i=0; i<childProc->threads.size(); i++) {
2030      // write to the raw item in the inferior heap:
2031      intCounter *localCounterPtr = (intCounter *) theTable.index2LocalAddr(0,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2032      const intCounter *localSrcCounterPtr = (const intCounter *) childProc->getParent()->getTable().index2LocalAddr(0,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2033      localCounterPtr->value = initialValue;
2034      localCounterPtr->id.id = theSampleId;
2035      localCounterPtr->theSpinner = localSrcCounterPtr->theSpinner;
2036         // in case we're in the middle of an operation
2037    }
2038
2039    // write HK for this intCounter:
2040    // Note: we don't assert anything about mi->getMId(), because that id has no
2041    // relation to the ids we work with (theSampleId).  In fact, we (the sampling code)
2042    // just don't ever care what mi->getMId() is.
2043    assert(theSampleId >= 0);
2044    assert(midToMiMap.defines(theSampleId));
2045    assert(midToMiMap[theSampleId] == mi);
2046    intCounterHK iHKValue(theSampleId, mi);
2047       // the mi differs from the mi of the parent; theSampleId differs too.
2048    theTable.initializeHKAfterForkIntCounter(allocatedIndex, allocatedLevel, iHKValue);
2049
2050    position_=0;
2051 }
2052
2053 dataReqNode *
2054 sampledShmIntCounterReqNode::dup(process *childProc,
2055                                  metricDefinitionNode *mi,
2056                                  int iCounterId,
2057                                  const dictionary_hash<instInstance*,instInstance*> &
2058                                  ) const {
2059    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2060
2061    sampledShmIntCounterReqNode *tmp;
2062    tmp = new sampledShmIntCounterReqNode(*this, childProc, mi, iCounterId, childProc->getParent());
2063       // fork ctor
2064
2065    return tmp;
2066 }
2067
2068 bool sampledShmIntCounterReqNode::insertInstrumentation(process *theProc,
2069                                                         metricDefinitionNode *iMi, bool doNotSample) {
2070    // Remember counterPtr is NULL until this routine gets called.
2071    // WARNING: there will be an assert failure if the applic hasn't yet attached to the
2072    //          shm segment!!!
2073
2074    // initialize the intCounter in the inferior heap
2075    intCounter iValue;
2076    iValue.id.id = this->theSampleId;
2077    iValue.value = this->initialValue; // what about initializing 'theSpinner'???
2078
2079    intCounterHK iHKValue(this->theSampleId, iMi);
2080
2081    superTable &theTable = theProc->getTable();
2082
2083    if (!theTable.allocIntCounter(iValue, iHKValue, this->allocatedIndex, this->allocatedLevel, doNotSample))
2084       return false; // failure
2085
2086    return true; // success
2087 }
2088
2089 void sampledShmIntCounterReqNode::disable(process *theProc,
2090                                           const vector<unsigVecType> &pointsToCheck) {
2091    // We used to remove the sample id from midToMiMap here but now the caller is
2092    // responsible for that.
2093
2094    superTable &theTable = theProc->getTable();
2095
2096    // Remove from inferior heap; make sure we won't be sampled any more:
2097    vector<unsigned> trampsMaybeUsing;
2098    for (unsigned pointlcv=0; pointlcv < pointsToCheck.size(); pointlcv++)
2099       for (unsigned tramplcv=0; tramplcv < pointsToCheck[pointlcv].size(); tramplcv++)
2100          trampsMaybeUsing += pointsToCheck[pointlcv][tramplcv];
2101
2102    theTable.makePendingFree(0,allocatedIndex,allocatedLevel,trampsMaybeUsing);
2103
2104 #if defined(MT_THREAD)
2105 //NOTE: Not yet implemented for shm sampling! naim 4/23/97
2106 //    pdThread *thr = theProc->threads[0];
2107 //    thr->CTvector->remove(this->theSampleId, this->position_);
2108 //    theProc->updateActiveCT(false,counter);
2109 #endif
2110 }
2111
2112 #endif
2113
2114 /* ************************************************************************* */
2115
2116 nonSampledIntCounterReqNode::nonSampledIntCounterReqNode(int iValue, 
2117                                                     int iCounterId,
2118                                                     metricDefinitionNode *iMi, 
2119                                                     bool computingCost) :
2120                                                     dataReqNode() {
2121    theSampleId = iCounterId;
2122    initialValue = iValue;
2123
2124    // The following fields are NULL until insertInstrumentation()
2125    counterPtr = NULL;
2126
2127    if (!computingCost) {
2128      bool isOk=false;
2129      isOk = insertInstrumentation(iMi->proc(), iMi);
2130      assert(isOk && counterPtr!=NULL); 
2131    }
2132 }
2133
2134 nonSampledIntCounterReqNode::
2135 nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &src,
2136                             process *childProc, metricDefinitionNode *,
2137                             int iCounterId) {
2138    // a dup() routine (call after a fork())
2139    counterPtr = src.counterPtr; // assumes addr spaces have been dup()d.
2140    initialValue = src.initialValue;
2141    theSampleId = iCounterId;
2142  
2143    intCounter temp;
2144    temp.id.id = this->theSampleId;
2145    temp.value = this->initialValue;
2146    writeToInferiorHeap(childProc, temp);
2147 }
2148
2149 dataReqNode *
2150 nonSampledIntCounterReqNode::dup(process *childProc,
2151                                  metricDefinitionNode *mi,
2152                                  int iCounterId,
2153                                  const dictionary_hash<instInstance*,instInstance*> &
2154                                  ) const {
2155    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2156
2157    nonSampledIntCounterReqNode *tmp;
2158    tmp = new nonSampledIntCounterReqNode(*this, childProc, mi, iCounterId);
2159       // fork ctor
2160
2161    return tmp;
2162 }
2163
2164 bool nonSampledIntCounterReqNode::insertInstrumentation(process *theProc,
2165                                                         metricDefinitionNode *,
2166                                                         bool) {
2167    // Remember counterPtr is NULL until this routine gets called.
2168    counterPtr = (intCounter*)inferiorMalloc(theProc, sizeof(intCounter), dataHeap);
2169    if (counterPtr == NULL)
2170       return false; // failure!
2171
2172    // initialize the intCounter in the inferior heap
2173    intCounter temp;
2174    temp.id.id = this->theSampleId;
2175    temp.value = this->initialValue;
2176
2177    writeToInferiorHeap(theProc, temp);
2178
2179    return true; // success
2180 }
2181
2182 void nonSampledIntCounterReqNode::disable(process *theProc,
2183                                           const vector<unsigVecType> &pointsToCheck) {
2184    // We used to remove the sample id from midToMiMap here but now the caller is
2185    // responsible for that.
2186
2187    // Deallocate space for intCounter in the inferior heap:
2188    assert(counterPtr != NULL);
2189    inferiorFree(theProc, (unsigned)counterPtr, dataHeap, pointsToCheck);
2190 }
2191
2192 void nonSampledIntCounterReqNode::writeToInferiorHeap(process *theProc,
2193                                                       const intCounter &dataSrc) const {
2194    // using the contents of "dataSrc", write to the inferior heap at loc
2195    // "counterPtr" via proc->writeDataSpace()
2196    assert(counterPtr);
2197    theProc->writeDataSpace(counterPtr, sizeof(intCounter), &dataSrc);
2198 }
2199
2200 /* ****************************************************************** */
2201
2202 #ifndef SHM_SAMPLING
2203 sampledTimerReqNode::sampledTimerReqNode(timerType iType, int iCounterId, 
2204                                          metricDefinitionNode *iMi,
2205                                          bool computingCost) :
2206                                          dataReqNode() {
2207    theSampleId = iCounterId;
2208    theTimerType = iType;
2209
2210    // The following fields are NULL until insertInstrumentatoin():
2211    timerPtr = NULL;
2212    sampler  = NULL;
2213
2214    if (!computingCost) {
2215      bool isOk=false;
2216      isOk = insertInstrumentation(iMi->proc(), iMi);
2217      assert(isOk && timerPtr!=NULL); 
2218    }
2219 }
2220
2221 sampledTimerReqNode::sampledTimerReqNode(const sampledTimerReqNode &src,
2222                                          process *childProc,
2223                                          metricDefinitionNode *,
2224                                          int iCounterId,
2225                                          const dictionary_hash<instInstance*,instInstance*> &map) {
2226    // a dup()-like routine; call after a fork()
2227    timerPtr = src.timerPtr; // assumes addr spaces have been dup()'d
2228
2229    if (!map.find(src.sampler, this->sampler)) // writes to this->sampler
2230       assert(false);
2231
2232    assert(sampler); // makes sense; timers are always sampled, whereas intCounters
2233                     // might be just non-sampled predicates.
2234    
2235    theSampleId = iCounterId;
2236    theTimerType = src.theTimerType;
2237
2238    tTimer temp;
2239    P_memset(&temp, '\0', sizeof(tTimer)); /* is this needed? */
2240    temp.id.id = this->theSampleId;
2241    temp.type = this->theTimerType;
2242    temp.normalize = 1000000;
2243    writeToInferiorHeap(childProc, temp);
2244
2245    // WARNING: shouldn't we be resetting the raw value to count=0, start=0,
2246    //          total = src.initialValue ???  On the other hand, it's not that
2247    //          simple -- if the timer is active in the parent, then it'll be active
2248    //          in the child.  So how about setting count to src.count, start=now,
2249    //          total=0 ???
2250 }
2251
2252 dataReqNode *
2253 sampledTimerReqNode::dup(process *childProc, metricDefinitionNode *mi,
2254                          int iCounterId,
2255                          const dictionary_hash<instInstance*,instInstance*> &map
2256                          ) const {
2257    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2258
2259    sampledTimerReqNode *result = new sampledTimerReqNode(*this, childProc, mi, iCounterId, map);
2260       // fork ctor
2261    if (!result)
2262       return NULL; // on failure, return w/o incrementing counterId
2263
2264    return result;
2265 }
2266
2267 bool sampledTimerReqNode::insertInstrumentation(process *theProc,
2268                                                 metricDefinitionNode *,
2269                                                 bool) {
2270    timerPtr = (tTimer *)inferiorMalloc(theProc, sizeof(tTimer), dataHeap);
2271    if (timerPtr == NULL)
2272       return false; // failure!
2273
2274    // Now let's initialize the newly allocated tTimer in the inferior heap:
2275    tTimer temp;
2276    P_memset(&temp, '\0', sizeof(tTimer));
2277    temp.id.id = this->theSampleId;
2278    temp.type = this->theTimerType;
2279    temp.normalize = 1000000;
2280    writeToInferiorHeap(theProc, temp);
2281
2282    // Now instrument DYNINSTreportTimer:
2283    function_base *sampleFunction = 
2284         theProc->findOneFunction("DYNINSTsampleValues");
2285    assert(sampleFunction);
2286
2287    AstNode *ast, *tmp;
2288    tmp = new AstNode(AstNode::Constant, timerPtr);
2289    ast = new AstNode("DYNINSTreportTimer", tmp);
2290    removeAst(tmp);
2291
2292    instPoint *func_entry = (instPoint *)sampleFunction->funcEntry(theProc);
2293    sampler = addInstFunc(theProc, func_entry, ast,
2294                          callPreInsn, orderLastAtPoint, false);
2295    removeAst(ast);
2296
2297    return true; // successful
2298 }
2299
2300 void sampledTimerReqNode::disable(process *theProc,
2301                                   const vector<unsigVecType> &pointsToCheck) {
2302    // We used to remove the sample id from midToMiMap here but now the caller is
2303    // responsible for that.
2304
2305    // Remove instrumentation added to DYNINSTsampleValues(), if necessary:
2306    if (sampler != NULL)
2307       ::deleteInst(sampler, getAllTrampsAtPoint(sampler));
2308
2309    // Deallocate space for tTimer in the inferior heap:
2310    assert(timerPtr);
2311    inferiorFree(theProc, (unsigned)timerPtr, dataHeap, pointsToCheck);
2312 }
2313
2314 void sampledTimerReqNode::writeToInferiorHeap(process *theProc,
2315                                               const tTimer &dataSrc) const {
2316    // using contents of "dataSrc", a local copy of the data,
2317    // write to inferior heap at loc "timerPtr" via proc->writeDataSpace()
2318    assert(timerPtr);
2319    theProc->writeDataSpace(timerPtr, sizeof(tTimer), &dataSrc);
2320 }
2321
2322 bool sampledTimerReqNode::
2323 unFork(dictionary_hash<instInstance*,instInstance*> &map) {
2324    instInstance *parentSamplerInstance = sampler;
2325
2326    instInstance *childSamplerInstance;
2327    if (!map.find(parentSamplerInstance, childSamplerInstance))
2328       assert(false);
2329
2330    vector<unsigned> pointsToCheck; // empty
2331    deleteInst(childSamplerInstance, pointsToCheck);
2332
2333    map[parentSamplerInstance] = NULL; // since we've deleted...
2334
2335    return true;
2336 }
2337                                  
2338 #endif
2339
2340 /* ****************************************************************** */
2341
2342 #ifdef SHM_SAMPLING
2343 sampledShmWallTimerReqNode::sampledShmWallTimerReqNode(int iCounterId,
2344                                                      metricDefinitionNode *iMi,
2345                                                      bool computingCost) :
2346                                                      dataReqNode() {
2347    theSampleId = iCounterId;
2348
2349    // The following fields are NULL until insertInstrumentation():
2350    allocatedIndex = UINT_MAX;
2351    allocatedLevel = UINT_MAX;
2352
2353    position_=0;
2354
2355    if (!computingCost) {
2356      bool isOk=false;
2357      isOk = insertInstrumentation(iMi->proc(), iMi);
2358      assert(isOk); 
2359    }
2360 }
2361
2362 sampledShmWallTimerReqNode::
2363 sampledShmWallTimerReqNode(const sampledShmWallTimerReqNode &src,
2364                            process *childProc,
2365                            metricDefinitionNode *mi,
2366                            int iCounterId, const process *parentProc) {
2367    // a dup()-like routine; call after a fork().
2368    // Assumes that the "childProc" has been duplicated already
2369
2370    // Note that the index w/in the inferior heap remains the same, so setting the new
2371    // inferiorTimerPtr isn't too hard.  Actually, it's trivial, since other code
2372    // ensures that the new shm segment is placed in exactly the same virtual mem loc
2373    // as the previous one.
2374    //
2375    // Note that the fastInferiorHeap class's fork ctor will have already copied the
2376    // actual data; we need to fill in new meta-data (new houseKeeping entries).
2377
2378    allocatedIndex = src.allocatedIndex;
2379    allocatedLevel = src.allocatedLevel;
2380
2381    theSampleId = iCounterId;
2382    assert(theSampleId != src.theSampleId);
2383
2384    superTable &theTable = childProc->getTable();
2385
2386    // since the new shm seg is placed in exactly the same memory location as
2387    // the old one, nothing here should change.
2388    const superTable &theParentTable = parentProc->getTable();
2389    assert(theTable.index2InferiorAddr(1,childProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel)==theParentTable.index2InferiorAddr(1,parentProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel));
2390
2391    // Write new raw value in the inferior heap:
2392    // we set localTimerPtr as follows: protector1 and procetor2 should be copied from
2393    //    src. total should be reset to 0.  start should be set to now if active else 0.
2394    //    counter should be copied from the source.
2395    // NOTE: SINCE WE COPY FROM THE SOURCE, IT'S IMPORTANT THAT ON A FORK, BOTH THE
2396    //       PARENT AND CHILD ARE PAUSED UNTIL WE COPY THINGS OVER.  THAT THE CHILD IS
2397    //       PAUSED IS NOTHING NEW; THAT THE PARENT SHOULD BE PAUSED IS NEW NEWS!
2398
2399    for (unsigned i=0; i<childProc->threads.size(); i++) {
2400      tTimer *localTimerPtr = (tTimer *) theTable.index2LocalAddr(1,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2401      const tTimer *srcTimerPtr = (const tTimer *) childProc->getParent()->getTable().index2LocalAddr(1,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2402
2403      localTimerPtr->total = 0;
2404      localTimerPtr->counter = srcTimerPtr->counter;
2405      localTimerPtr->id.id   = theSampleId;
2406      localTimerPtr->protector1 = srcTimerPtr->protector1;
2407      localTimerPtr->protector2 = srcTimerPtr->protector2;
2408
2409      if (localTimerPtr->counter == 0)
2410         // inactive timer...this is the easy case to copy
2411         localTimerPtr->start = 0; // undefined, really
2412      else
2413         // active timer...don't copy the start time from the source...make it 'now'
2414         localTimerPtr->start = getCurrWallTime();
2415    }
2416
2417    // write new HK for this tTimer:
2418    // Note: we don't assert anything about mi->getMId(), because that id has no
2419    // relation to the ids we work with (theSampleId).  In fact, we (the sampling code)
2420    // just don't ever care what mi->getMId() is.
2421    assert(theSampleId >= 0);
2422    assert(midToMiMap.defines(theSampleId));
2423    assert(midToMiMap[theSampleId] == mi);
2424    wallTimerHK iHKValue(theSampleId, mi, 0); // is last param right?
2425       // the mi should differ from the mi of the parent; theSampleId differs too.
2426    theTable.initializeHKAfterForkWallTimer(allocatedIndex, allocatedLevel, iHKValue);
2427
2428    position_=0;
2429 }
2430
2431 dataReqNode *
2432 sampledShmWallTimerReqNode::dup(process *childProc,
2433                                 metricDefinitionNode *mi,
2434                                 int iCounterId,
2435                                 const dictionary_hash<instInstance*,instInstance*> &
2436                                 ) const {
2437    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2438
2439    sampledShmWallTimerReqNode *tmp;
2440    tmp = new sampledShmWallTimerReqNode(*this, childProc, mi, iCounterId, childProc->getParent());
2441       // fork constructor
2442
2443    return tmp;
2444 }
2445
2446 bool sampledShmWallTimerReqNode::insertInstrumentation(process *theProc,
2447                                                        metricDefinitionNode *iMi, bool) {
2448    // Remember inferiorTimerPtr is NULL until this routine gets called.
2449    // WARNING: there will be an assert failure if the applic hasn't yet attached to the
2450    //          shm segment!!!
2451
2452    // initialize the tTimer in the inferior heap
2453    tTimer iValue;
2454    P_memset(&iValue, '\0', sizeof(tTimer));
2455    iValue.id.id = this->theSampleId;
2456
2457    wallTimerHK iHKValue(this->theSampleId, iMi, 0);
2458
2459    superTable &theTable = theProc->getTable();
2460
2461    if (!theTable.allocWallTimer(iValue, iHKValue, this->allocatedIndex, this->allocatedLevel))
2462       return false; // failure
2463
2464    return true;
2465 }
2466
2467 void sampledShmWallTimerReqNode::disable(process *theProc,
2468                                          const vector<unsigVecType> &pointsToCheck) {
2469    // We used to remove the sample id from midToMiMap here but now the caller is
2470    // responsible for that.
2471
2472    superTable &theTable = theProc->getTable();
2473
2474    // Remove from inferior heap; make sure we won't be sampled any more:
2475    vector<unsigned> trampsMaybeUsing;
2476    for (unsigned pointlcv=0; pointlcv < pointsToCheck.size(); pointlcv++)
2477       for (unsigned tramplcv=0; tramplcv < pointsToCheck[pointlcv].size(); tramplcv++)
2478          trampsMaybeUsing += pointsToCheck[pointlcv][tramplcv];
2479
2480    theTable.makePendingFree(1,allocatedIndex,allocatedLevel,trampsMaybeUsing);
2481
2482 #if defined(MT_THREAD)
2483 //NOTE: Not yet implemented for shm sampling! naim 4/23/97
2484 //    pdThread *thr = theProc->threads[0];
2485 //    thr->CTvector->remove(this->theSampleId, this->position_);
2486 //    theProc->updateActiveCT(false,wallTimer);
2487 #endif
2488 }
2489
2490 /* ****************************************************************** */
2491
2492 sampledShmProcTimerReqNode::sampledShmProcTimerReqNode(int iCounterId,
2493                                                      metricDefinitionNode *iMi,
2494                                                      bool computingCost) :
2495                                                      dataReqNode() {
2496    theSampleId = iCounterId;
2497
2498    // The following fields are NULL until insertInstrumentatoin():
2499    allocatedIndex = UINT_MAX;
2500    allocatedLevel = UINT_MAX;
2501
2502    position_=0;
2503
2504    if (!computingCost) {
2505      bool isOk=false;
2506      isOk = insertInstrumentation(iMi->proc(), iMi);
2507      assert(isOk); 
2508    }
2509 }
2510
2511 sampledShmProcTimerReqNode::
2512 sampledShmProcTimerReqNode(const sampledShmProcTimerReqNode &src,
2513                            process *childProc,
2514                            metricDefinitionNode *mi,
2515                            int iCounterId, const process *parentProc) {
2516    // a dup()-like routine; call after a fork()
2517    // Assumes that the "childProc" has been duplicated already
2518
2519    // Note that the index w/in the inferior heap remains the same, so setting the new
2520    // inferiorTimerPtr isn't too hard.  Actually, it's trivial, since other code
2521    // ensures that the new shm segment is placed in exactly the same virtual mem loc
2522    // as the previous one.
2523    //
2524    // Note that the fastInferiorHeap class's fork ctor will have already copied the
2525    // actual data; we need to fill in new meta-data (new houseKeeping entries).
2526
2527    allocatedIndex = src.allocatedIndex;
2528    theSampleId = iCounterId;
2529    assert(theSampleId != src.theSampleId);
2530
2531    superTable &theTable = childProc->getTable();
2532
2533    // since the new shm seg is placed in exactly the same memory location as
2534    // the old one, nothing here should change.
2535    const superTable &theParentTable = parentProc->getTable();
2536    assert(theTable.index2InferiorAddr(2,childProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel)==theParentTable.index2InferiorAddr(2,parentProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel));
2537
2538    // Write new raw value:
2539    // we set localTimerPtr as follows: protector1 and procetor2 should be copied from
2540    //    src. total should be reset to 0.  start should be set to now if active else 0.
2541    //    counter should be copied from the source.
2542    // NOTE: SINCE WE COPY FROM THE SOURCE, IT'S IMPORTANT THAT ON A FORK, BOTH THE
2543    //       PARENT AND CHILD ARE PAUSED UNTIL WE COPY THINGS OVER.  THAT THE CHILD IS
2544    //       PAUSED IS NOTHING NEW; THAT THE PARENT SHOULD BE PAUSED IS NEW NEWS!
2545
2546    for (unsigned i=0; i<childProc->threads.size(); i++) {
2547      tTimer *localTimerPtr = (tTimer *) theTable.index2LocalAddr(2,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2548      const tTimer *srcTimerPtr = (const tTimer *) childProc->getParent()->getTable().index2LocalAddr(2,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2549
2550      localTimerPtr->total = 0;
2551      localTimerPtr->counter = srcTimerPtr->counter;
2552      localTimerPtr->id.id   = theSampleId;
2553      localTimerPtr->protector1 = srcTimerPtr->protector1;
2554      localTimerPtr->protector2 = srcTimerPtr->protector2;
2555
2556      if (localTimerPtr->counter == 0)
2557         // inactive timer...this is the easy case to copy
2558         localTimerPtr->start = 0; // undefined, really
2559      else
2560         // active timer...don't copy the start time from the source...make it 'now'
2561         localTimerPtr->start = childProc->getInferiorProcessCPUtime();
2562    }
2563
2564    // Write new HK for this tTimer:
2565    // Note: we don't assert anything about mi->getMId(), because that id has no
2566    // relation to the ids we work with (theSampleId).  In fact, we (the sampling code)
2567    // just don't ever care what mi->getMId() is.
2568    assert(theSampleId >= 0);
2569    assert(midToMiMap.defines(theSampleId));
2570    assert(midToMiMap[theSampleId] == mi);
2571    processTimerHK iHKValue(theSampleId, mi, 0); // is last param right?
2572       // the mi differs from the mi of the parent; theSampleId differs too.
2573    theTable.initializeHKAfterForkProcTimer(allocatedIndex, allocatedLevel, iHKValue);
2574
2575    position_=0;
2576 }
2577
2578 dataReqNode *
2579 sampledShmProcTimerReqNode::dup(process *childProc,
2580                                 metricDefinitionNode *mi,
2581                                 int iCounterId,
2582                                 const dictionary_hash<instInstance*,instInstance*> &
2583                                 ) const {
2584    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2585
2586    sampledShmProcTimerReqNode *tmp;
2587    tmp = new sampledShmProcTimerReqNode(*this, childProc, mi, iCounterId, childProc->getParent());
2588       // fork constructor
2589
2590    return tmp;
2591 }
2592
2593 bool sampledShmProcTimerReqNode::insertInstrumentation(process *theProc,
2594                                                        metricDefinitionNode *iMi, bool) {
2595    // Remember inferiorTimerPtr is NULL until this routine gets called.
2596    // WARNING: there will be an assert failure if the applic hasn't yet attached to the
2597    //          shm segment!!!
2598
2599    // initialize the tTimer in the inferior heap
2600    tTimer iValue;
2601    P_memset(&iValue, '\0', sizeof(tTimer));
2602    iValue.id.id = this->theSampleId;
2603
2604    processTimerHK iHKValue(this->theSampleId, iMi, 0);
2605
2606    superTable &theTable = theProc->getTable();
2607
2608    if (!theTable.allocProcTimer(iValue, iHKValue, this->allocatedIndex,this->allocatedLevel))
2609       return false; // failure
2610
2611    return true;
2612 }
2613
2614 void sampledShmProcTimerReqNode::disable(process *theProc,
2615                                          const vector<unsigVecType> &pointsToCheck) {
2616    // We used to remove the sample id from midToMiMap here but now the caller is
2617    // responsible for that.
2618
2619    superTable &theTable = theProc->getTable();
2620
2621    // Remove from inferior heap; make sure we won't be sampled any more:
2622    vector<unsigned> trampsMaybeUsing;
2623    for (unsigned pointlcv=0; pointlcv < pointsToCheck.size(); pointlcv++)
2624       for (unsigned tramplcv=0; tramplcv < pointsToCheck[pointlcv].size(); tramplcv++)
2625          trampsMaybeUsing += pointsToCheck[pointlcv][tramplcv];
2626
2627    theTable.makePendingFree(2,allocatedIndex,allocatedLevel,trampsMaybeUsing);
2628
2629 #if defined(MT_THREAD)
2630 //NOTE: Not yet implemented for shm sampling! naim 4/23/97
2631 //   pdThread *thr = theProc->threads[0];
2632 //   thr->CTvector->remove(this->theSampleId, this->position_);
2633 //   theProc->updateActiveCT(false,procTimer);
2634 #endif
2635 }
2636 #endif
2637
2638 /* **************************** */
2639
2640 void reportInternalMetrics(bool force) 
2641 {
2642     if (isApplicationPaused())
2643        return; // we don't sample when paused (is this right?)
2644
2645     static timeStamp end=0.0;
2646
2647     // see if we have a sample to establish time base.
2648     if (!firstRecordTime) {
2649        //cerr << "reportInternalMetrics: no because firstRecordTime==0" << endl;
2650        return;
2651     }
2652
2653     if (end==0.0)
2654         end = (timeStamp)firstRecordTime/MILLION;
2655
2656     const timeStamp now = getCurrentTime(false);
2657
2658     //  check if it is time for a sample
2659     if (!force && now < end + samplingRate)  {
2660 //        cerr << "reportInternalMetrics: no because now < end + samplingRate (end=" << end << "; samplingRate=" << samplingRate << "; now=" << now << ")" << endl;
2661 //      cerr << "difference is " << (end+samplingRate-now) << endl;
2662         return;
2663     }
2664
2665     timeStamp start = end;
2666     end = now;
2667
2668     // TODO -- clean me up, please
2669
2670     unsigned max1=0;
2671     unsigned max2=0;
2672     unsigned max3=0;
2673     for (unsigned u1 = 0; u1 < processVec.size(); u1++) {
2674       if (processVec[u1]->numOfActCounters_is > max1)
2675         max1=processVec[u1]->numOfActCounters_is;
2676       if (processVec[u1]->numOfActProcTimers_is > max2)
2677         max2=processVec[u1]->numOfActProcTimers_is;
2678       if (processVec[u1]->numOfActWallTimers_is > max3)
2679         max3=processVec[u1]->numOfActWallTimers_is;
2680     }
2681     numOfActCounters_all=max1;
2682     numOfActProcTimers_all=max2;
2683     numOfActWallTimers_all=max3;
2684
2685     unsigned ai_size = internalMetric::allInternalMetrics.size();
2686     for (unsigned u2=0; u2<ai_size; u2++) {
2687       internalMetric *theIMetric = internalMetric::allInternalMetrics[u2];
2688       // Loop thru all enabled instances of this internal metric...
2689
2690       for (unsigned v=0; v < theIMetric->num_enabled_instances(); v++) {
2691         internalMetric::eachInstance &theInstance = theIMetric->getEnabledInstance(v);
2692            // not "const" since bumpCumulativeValueBy() may be called
2693
2694         sampleValue value = (sampleValue) 0;
2695         if (theIMetric->name() == "active_processes") {
2696           //value = (end - start) * activeProcesses;
2697           value = (end - start) * theInstance.getValue();
2698         } else if (theIMetric->name() == "bucket_width") {
2699           //value = (end - start)* theInstance.getValue();
2700           // I would prefer to use (end-start) * theInstance.getValue(); however,
2701           // we've had some problems getting setValue() called in time, thus
2702           // leaving us with getValues() of 0 sometimes.  See longer comment in dynrpc.C --ari
2703           extern float currSamplingRate;
2704           value = (end - start) * currSamplingRate;
2705         } else if (theIMetric->name() == "number_of_cpus") {
2706           value = (end - start) * numberOfCPUs;
2707         } else if (theIMetric->name() == "total_CT") {
2708           value = (end - start) * internalMetricCounterId;
2709           assert(value>=0.0);
2710         } else if (theIMetric->name() == "numOfActCounters") {
2711           value = (end - start) * numOfActCounters_all;
2712           assert(value>=0.0);
2713         } else if (theIMetric->name() == "numOfActProcTimers") {
2714           value = (end - start) * numOfActProcTimers_all;
2715           assert(value>=0.0);
2716         } else if (theIMetric->name() == "numOfActWallTimers") {
2717           value = (end - start) * numOfActWallTimers_all;
2718           assert(value>=0.0);
2719         } else if (theIMetric->name() == "active_CT") {
2720           value = (end - start) * (numOfActCounters_all+numOfActProcTimers_all+numOfActWallTimers_all);
2721           assert(value>=0.0);
2722         } else if (theIMetric->name() == "infHeapMemAvailable") {
2723           value = (end - start) * inferiorMemAvailable;
2724           assert(value>=0.0);
2725         } else if (theIMetric->style() == EventCounter) {
2726           value = theInstance.getValue();
2727           // assert((value + 0.0001)  >= imp->cumulativeValue);
2728           value -= theInstance.getCumulativeValue();
2729           theInstance.bumpCumulativeValueBy(value);
2730         } else if (theIMetric->style() == SampledFunction) {
2731           value = theInstance.getValue();
2732         }
2733
2734         theInstance.report(start, end, value);
2735            // calls metricDefinitionNode->forwardSimpleValue()
2736       }
2737     }
2738 }
2739
2740 void disableAllInternalMetrics() {
2741     for (unsigned u=0; u < internalMetric::allInternalMetrics.size(); u++) {
2742       internalMetric *theIMetric = internalMetric::allInternalMetrics[u];
2743
2744       // Now loop thru all the enabled instances of this internal metric...
2745       while (theIMetric->num_enabled_instances() > 0) {
2746         internalMetric::eachInstance &theInstance = theIMetric->getEnabledInstance(0);
2747         tp->endOfDataCollection(theInstance.getMId());
2748         theIMetric->disableInstance(0);
2749       }
2750     }  
2751 }
2752
2753 #ifdef SHM_SAMPLING
2754
2755 unsigned sampledShmIntCounterReqNode::getInferiorPtr(process *proc) const {
2756     // counterPtr could be NULL if we are building AstNodes just to compute
2757     // the cost - naim 2/18/97
2758     // NOTE:
2759     // this routine will dissapear because we can't compute the address
2760     // of the counter/timer without knowing the thread id - naim 3/17/97
2761     //
2762     if (allocatedIndex == UINT_MAX || allocatedLevel == UINT_MAX) return(0);
2763     assert(proc != NULL);
2764     superTable &theTable = proc->getTable();
2765     // we assume there is only one thread
2766     return((unsigned) theTable.index2InferiorAddr(0,0,allocatedIndex,allocatedLevel));
2767 }
2768
2769 unsigned sampledShmWallTimerReqNode::getInferiorPtr(process *proc) const {
2770     // counterPtr could be NULL if we are building AstNodes just to compute
2771     // the cost - naim 2/18/97
2772     // NOTE:
2773     // this routine will dissapear because we can't compute the address
2774     // of the counter/timer without knowing the thread id - naim 3/17/97
2775     //
2776     if (allocatedIndex == UINT_MAX || allocatedLevel == UINT_MAX) return(0);
2777     assert(proc != NULL);
2778     superTable &theTable = proc->getTable();
2779     // we assume there is only one thread
2780     return((unsigned) theTable.index2InferiorAddr(1,0,allocatedIndex,allocatedLevel));
2781 }
2782
2783 unsigned sampledShmProcTimerReqNode::getInferiorPtr(process *proc) const {
2784     // counterPtr could be NULL if we are building AstNodes just to compute
2785     // the cost - naim 2/18/97
2786     // NOTE:
2787     // this routine will dissapear because we can't compute the address
2788     // of the counter/timer without knowing the thread id - naim 3/17/97
2789     //
2790     if (allocatedIndex == UINT_MAX || allocatedLevel == UINT_MAX) return(0);
2791     assert(proc != NULL);
2792     superTable &theTable = proc->getTable();
2793     // we assume there is only one thread
2794     return((unsigned) theTable.index2InferiorAddr(2,0,allocatedIndex,allocatedLevel));
2795 }
2796
2797 #endif