Fixed the problem of doing `delete this' with the following (original) line
[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),
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                                                int deleteComp = 1) {
651   unsigned size = components.size();
652   for (unsigned u = 0; u < size; u++) {
653     if (components[u] == comp) {
654       if (deleteComp) delete components[u];
655       components[u] = NULL;
656       components[u] = components[size-1];
657       components.resize(size-1);
658       if (size == 1) {
659         endOfDataCollection();
660       }
661       return;
662     }
663   }
664   // should always find the right component 
665   assert(0);
666 }
667
668 // remove this component mi from all aggregators it is a component of.
669 // if the aggregate mi no longer has any components then fry the mi aggregate mi.
670 // called by removeFromMetricInstances, below, when a process exits (or exec's)
671 void metricDefinitionNode::removeThisInstance() {
672   assert(!aggregate_);
673
674   // first, remove from allMIComponents (this is new --- is it right?)
675   assert(allMIComponents.defines(flat_name_));
676   allMIComponents.undef(flat_name_);
677
678   assert(aggregators.size() == samples.size());
679   unsigned aggr_size = aggregators.size();
680   assert(aggr_size > 0);
681
682   //for (unsigned u = 0; u < aggr_size; u++) {
683   for (unsigned u = 0; u < aggregators.size() && u < samples.size(); u++) {
684     aggregators[u]->aggSample.removeComponent(samples[u]);
685     aggregators[u]->removeFromAggregate(this, 0); 
686   }
687 }
688
689
690 // Called when a process exits, to remove the component associated to proc 
691 // from all metric instances.  (If, after an exec, we never want to carry over
692 // mi's from the pre-exec, then this routine will work there, too.  But we try to
693 // carry over mi's whenever appropriate.)
694 // Remove the aggregate metric instances that don't have any components left
695 void removeFromMetricInstances(process *proc) {
696     // Loop through all of the _component_ mi's; for each with component process
697     // of "proc", remove the component mi from its aggregate mi.
698     // Note: imho, there should be a *per-process* vector of mi-components.
699
700     vector<metricDefinitionNode *> MIs = allMIComponents.values();
701     for (unsigned j = 0; j < MIs.size(); j++) {
702       if (MIs[j]->proc() == proc)
703         MIs[j]->removeThisInstance();
704     }
705     costMetric::removeProcessFromAll(proc); // what about internal metrics?
706 }
707
708 /* *************************************************************************** */
709
710 // obligatory definition of static member vrble:
711 int metricDefinitionNode::counterId=0;
712
713 dataReqNode *metricDefinitionNode::addSampledIntCounter(int initialValue,
714                                                         bool computingCost,
715                                                         bool doNotSample) 
716 {
717    dataReqNode *result=NULL;
718
719 #ifdef SHM_SAMPLING
720    // shared memory sampling of a reported intCounter
721    result = new sampledShmIntCounterReqNode(initialValue,
722                                             metricDefinitionNode::counterId,
723                                             this, computingCost, doNotSample);
724       // implicit conversion to base class
725 #else
726    // non-shared-memory sampling of a reported intCounter
727    result = new sampledIntCounterReqNode(initialValue,
728                                          metricDefinitionNode::counterId,
729                                          this, computingCost);
730       // implicit conversion to base class
731 #endif
732
733    assert(result);
734    
735    metricDefinitionNode::counterId++;
736
737    internalMetricCounterId = metricDefinitionNode::counterId;
738
739    dataRequests += result;
740    return result;
741 }
742
743 dataReqNode *metricDefinitionNode::addUnSampledIntCounter(int initialValue,
744                                                           bool computingCost) {
745    // sampling of a non-reported intCounter (probably just a predicate)
746    // NOTE: In the future, we should probably put un-sampled intcounters
747    // into shared-memory when SHM_SAMPLING is defined.  After all, the shared
748    // memory heap is faster.
749    dataReqNode *result = new nonSampledIntCounterReqNode
750                          (initialValue, metricDefinitionNode::counterId, 
751                           this, computingCost);
752       // implicit conversion to base class
753    assert(result);
754
755    metricDefinitionNode::counterId++;
756
757    internalMetricCounterId = metricDefinitionNode::counterId;
758
759    dataRequests += result;
760    return result;
761 };
762
763 dataReqNode *metricDefinitionNode::addWallTimer(bool computingCost) {
764    dataReqNode *result = NULL;
765
766 #ifdef SHM_SAMPLING
767    result = new sampledShmWallTimerReqNode(metricDefinitionNode::counterId, this, computingCost);
768       // implicit conversion to base class
769 #else
770    result = new sampledTimerReqNode(wallTime, metricDefinitionNode::counterId, this, computingCost);
771       // implicit conversion to base class
772 #endif
773
774    assert(result);
775
776    metricDefinitionNode::counterId++;
777
778    internalMetricCounterId = metricDefinitionNode::counterId;
779
780    dataRequests += result;
781    return result;
782 }
783
784 dataReqNode *metricDefinitionNode::addProcessTimer(bool computingCost) {
785    dataReqNode *result = NULL;
786
787 #ifdef SHM_SAMPLING
788    result = new sampledShmProcTimerReqNode(metricDefinitionNode::counterId, this, computingCost);
789       // implicit conversion to base class
790 #else
791    result = new sampledTimerReqNode(processTime, metricDefinitionNode::counterId, this, computingCost);
792       // implicit conversion to base class
793 #endif
794
795    assert(result);
796
797    metricDefinitionNode::counterId++;
798
799    internalMetricCounterId = metricDefinitionNode::counterId;
800
801    dataRequests += result;
802    return result;
803 };
804
805 /* *************************************************************************** */
806
807 // called when a process forks (by handleFork(), below). "this" is a (component)
808 // mi in the parent process. Duplicate it for the child, with appropriate
809 // changes (i.e. the pid of the component focus name differs), and return the newly
810 // created child mi.  "map" maps all instInstance's of the parent to those copied into
811 // the child.
812 // 
813 // Note how beautifully everything falls into place.  Consider the case of alarm
814 // sampling with cpu/whole program.  Then comes the fork.  The parent process has
815 // (0) a tTimer structure allocated in a specific location in the inferior heap,
816 // (1) instrumentation @ main to call startTimer on that ptr, (2) instrumentation in
817 // DYNINSTsampleValues() to call DYNINSTreportTimer on that ptr.
818 // The child process of fork will have ALL of these things in the exact same locations,
819 // which is correct.  We want the timer to be located in the same spot; we want
820 // DYNINSTreportTimer to be called on the same pointer; and main() hasn't moved.
821 //
822 // So there's not much to do here.  We create a new component mi (with same flat name
823 // as in the parent, except for a different pid), and call "forkProcess" for all
824 // dataReqNodes and instReqNodes, none of which have to do anything titanic.
825
826 metricDefinitionNode *metricDefinitionNode::forkProcess(process *child,
827                         const dictionary_hash<instInstance*,instInstance*> &map) const {
828     // The "focus_" member vrble stays the same, because it was always for the
829     // metric as a whole, and not for some component.
830     //
831     // But two things must change, because they were component-specific (and the
832     // component has changed processes):
833     // (1) the flat name
834     // (2) the component focus (not to be confused with plain focus_)
835     //
836     // For example, instead of
837     // "/Code/foo.c/myfunc, /Process/100, ...", we should have
838     // "/Code/foo.c/myfunc, /Process/101, ...", because the pid of the child
839     // differs from that of the parent.
840
841     // The resource structure of a given process is found in the "rid"
842     // field of class process.
843     const resource *parentResource = child->getParent()->rid;
844     const string &parentPartName = parentResource->part_name();
845
846     const resource *childResource = child->rid;
847     const string &childPartName = childResource->part_name();
848
849     vector< vector<string> > newComponentFocus = this->component_focus;
850        // we'll change the process, but not the machine name.
851     bool foundProcess = false;
852
853     for (unsigned hier=0; hier < component_focus.size(); hier++) {
854        if (component_focus[hier][0] == "Process") {
855           foundProcess = true;
856           assert(component_focus[hier].size() == 2);
857              // since a component focus is by definition specific to some process
858
859           assert(component_focus[hier][1] == parentPartName);
860
861           // change the process:
862           newComponentFocus[hier][1] = childPartName;
863           break;
864        }
865     }
866     assert(foundProcess);
867     
868     string newComponentFlatName = metricAndCanonFocus2FlatName(met_, newComponentFocus);
869
870     metricDefinitionNode *mi =
871         new metricDefinitionNode(child,
872                          met_, // metric name doesn't change
873                          focus_, // focus doesn't change (tho component focus will)
874                          newComponentFocus, // this is a change
875                          newComponentFlatName, // this is a change
876                          aggOp // no change
877                          );
878     assert(mi);
879
880     metricDefinitionNode::counterId++;
881
882     forkexec_cerr << "metricDefinitionNode::forkProcess -- component flat name for parent is " << flat_name_ << "; for child is " << mi->flat_name_ << endl;
883
884     internalMetricCounterId = metricDefinitionNode::counterId;
885
886     assert(!allMIComponents.defines(newComponentFlatName));
887     allMIComponents[newComponentFlatName] = mi;
888
889     // Duplicate the dataReqNodes:
890     for (unsigned u1 = 0; u1 < dataRequests.size(); u1++) {
891        // must add to midToMiMap[] before dup() to avoid some assert fails
892        const int newCounterId = metricDefinitionNode::counterId++;
893           // no relation to mi->getMId();
894        forkexec_cerr << "forked dataReqNode going into midToMiMap with id " << newCounterId << endl;
895        assert(!midToMiMap.defines(newCounterId));
896        midToMiMap[newCounterId] = mi;
897        
898        dataReqNode *newNode = dataRequests[u1]->dup(child, mi, newCounterId, map);
899          // remember, dup() is a virtual fn, so the right dup() and hence the
900          // right fork-ctor is called.
901        assert(newNode);
902
903        mi->dataRequests += newNode;
904     }
905
906     // Duplicate the instReqNodes:
907     for (unsigned u2 = 0; u2 < instRequests.size(); u2++) {
908       mi->instRequests += instReqNode::forkProcess(instRequests[u2], map);
909     }
910
911     mi->inserted_ = true;
912
913     return mi;
914 }
915
916 bool metricDefinitionNode::unFork(dictionary_hash<instInstance*, instInstance*> &map,
917                                   bool unForkInstRequests,
918                                   bool unForkDataRequests) {
919    // see below handleFork() for explanation of why this routine is needed.
920    // "this" is a component mi for the parent process; we need to remove copied
921    // instrumentation from the _child_ process.
922    // Returns true iff the instrumentation was removed in the child (would be false
923    // if it's not safe to remove the instrumentation in the child because it was
924    // active.)
925
926    // "map" maps instInstances from the parent process to instInstances in the child
927    // process.
928
929    // We loop thru the instReqNodes of the parent process, unforking each.
930    // In addition, we need to unfork the dataReqNodes, because the alarm-sampled
931    // ones instrument DYNINSTsampleValues.
932
933    bool result = true;
934
935    if (unForkInstRequests)
936       for (unsigned lcv=0; lcv < instRequests.size(); lcv++)
937          if (!instRequests[lcv].unFork(map))
938             result = false; // failure
939
940    if (unForkDataRequests)
941       for (unsigned lcv=0; lcv < dataRequests.size(); lcv++)
942          if (!dataRequests[lcv]->unFork(map))
943             result = false; // failure
944
945    return result;
946 }
947
948
949 // called by forkProcess of context.C, just after the fork-constructor was
950 // called for the child process.
951 void metricDefinitionNode::handleFork(const process *parent, process *child,
952                               dictionary_hash<instInstance*,instInstance*> &map) {
953    // "map" defines a mapping from all instInstance's of the parent process to
954    // the copied one in the child process.  Some of the child process's ones may
955    // get fried by this routine, as it detects that instrumentation has been copied
956    // (by the fork syscall, which we have no control over) which doesn't belong in
957    // the child process and therefore gets deleted manually.
958   
959    // Remember that a given component can be shared by multiple aggregator-mi's,
960    // so be careful about duplicating a component twice.  Since we loop through
961    // component mi's instead of aggregate mi's, it's no problem.  Note that it's
962    // possible that only a subset of a component-mi's aggregators should get the newly
963    // created child component mi.
964
965    vector<metricDefinitionNode *> allComponents = allMIComponents.values();
966    for (unsigned complcv=0; complcv < allComponents.size(); complcv++) {
967       metricDefinitionNode *comp = allComponents[complcv];
968
969       // duplicate the component (create a new one) if it belongs in the
970       // child process.  It belongs if any of its aggregate mi's should be
971       // propagated to the child process.  An aggregate mi should be propagated
972       // if it wasn't refined to some process.
973
974       bool shouldBePropagated = false; // so far
975       bool shouldBeUnforkedIfNotPropagated = false; // so far
976       assert(comp->aggregators.size() > 0);
977       for (unsigned agglcv1=0; agglcv1 < comp->aggregators.size(); agglcv1++) {
978          metricDefinitionNode *aggMI = comp->aggregators[agglcv1];
979
980          if (aggMI->focus_[resource::process].size() == 1) {
981             // wasn't specific to any process
982             shouldBeUnforkedIfNotPropagated = false; // we'll definitely be using it
983             shouldBePropagated = true;
984             break;
985          }
986          else if (comp->proc() == parent)
987             // was specific to parent process, so fork() copied it into the child,
988             // unless it was an internal or cost metric, in which case there was nothing
989             // for fork to copy.
990             if (!internalMetric::isInternalMetric(aggMI->getMetName()) &&
991                 !costMetric::isCostMetric(aggMI->getMetName()))
992                shouldBeUnforkedIfNotPropagated = true;
993          else
994             // was specific to other process, so nothing is in the child for it yet
995             ;
996       }
997
998       if (!shouldBePropagated && shouldBeUnforkedIfNotPropagated) {
999          // this component mi isn't gonna be propagated to the child process, but
1000          // the fork syscall left some residue in the child.  Delete that residue now.
1001          assert(comp->proc() == parent);
1002          comp->unFork(map, true, true); // also modifies 'map' to remove items
1003       }
1004
1005       if (!shouldBePropagated)
1006          continue;
1007
1008       // Okay, it's time to propagate this component mi to the subset of its aggregate
1009       // mi's which weren't refined to a specific process.  If we've gotten to this
1010       // point, then there _is_ at least one such aggregate.
1011       assert(shouldBePropagated);
1012       metricDefinitionNode *newComp = comp->forkProcess(child, map);
1013          // copies instr (well, fork() does this for us), allocs ctr/timer space,
1014          // initializes.  Basically, copies dataReqNode's and instReqNode's.
1015
1016       bool foundAgg = false;
1017       for (unsigned agglcv2=0; agglcv2 < comp->aggregators.size(); agglcv2++) {
1018          metricDefinitionNode *aggMI = comp->aggregators[agglcv2];
1019          if (aggMI->focus_[resource::process].size() == 1) {
1020             // this aggregate mi wasn't specific to any process, so it gets the new
1021             // child component.
1022             aggMI->components += newComp;
1023             newComp->aggregators += aggMI;
1024             newComp->samples     += aggMI->aggSample.newComponent();
1025             foundAgg = true;
1026          }
1027       }
1028       assert(foundAgg);
1029    }
1030 }
1031
1032 bool metricDefinitionNode::anythingToManuallyTrigger() const {
1033    if (aggregate_) {
1034       for (unsigned i=0; i < components.size(); i++)
1035          if (components[i]->anythingToManuallyTrigger())
1036             return true;
1037       return false;
1038    }
1039    else {
1040       for (unsigned i=0; i < instRequests.size(); i++)
1041          if (instRequests[i].anythingToManuallyTrigger())
1042             return true;
1043       return false;
1044    }
1045
1046    assert(false);
1047 }
1048
1049 void metricDefinitionNode::manuallyTrigger() {
1050    assert(anythingToManuallyTrigger());
1051
1052    if (aggregate_) {
1053       for (unsigned i=0; i < components.size(); i++)
1054          components[i]->manuallyTrigger();
1055    }
1056    else {
1057       for (unsigned i=0; i < instRequests.size(); i++)
1058          if (instRequests[i].anythingToManuallyTrigger())
1059             if (!instRequests[i].triggerNow(proc())) {
1060                cerr << "manual trigger failed for an inst request" << endl;
1061             }
1062    }
1063 }
1064
1065
1066 // startCollecting is called by dynRPC::enableDataCollection (or enableDataCollection2)
1067 // in dynrpc.C
1068 // startCollecting is a friend of metricDefinitionNode; can it be
1069 // made a member function of metricDefinitionNode instead?
1070 // Especially since it clearly is an integral part of the class;
1071 // in particular, it sets the crucial vrble "id_"
1072 int startCollecting(string& metric_name, vector<u_int>& focus, int id,
1073                     vector<process *> &procsToCont)
1074 {
1075     bool internal = false;
1076
1077     // Make the unique ID for this metric/focus visible in MDL.
1078     string vname = "$globalId";
1079     mdl_env::add(vname, false, MDL_T_INT);
1080     mdl_env::set(id, vname);
1081
1082     metricDefinitionNode *mi = createMetricInstance(metric_name, focus,
1083                                                     true, internal);
1084        // calls mdl_do()
1085     if (!mi) {
1086        //cerr << "startCollecting for " << metric_name << " failed because createMetricInstance failed" << endl;
1087        return(-1);
1088     }
1089
1090     mi->id_ = id;
1091
1092     assert(!allMIs.defines(mi->id_));
1093     allMIs[mi->id_] = mi;
1094
1095     const float cost = mi->cost();
1096     mi->originalCost_ = cost;
1097
1098     currentPredictedCost += cost;
1099
1100 #ifdef ndef
1101     // enable timing stuff: also code in insertInstrumentation()
1102     u_int start_size = test_heapsize;
1103     printf("ENABLE: %d %s %s\n",start_size,
1104         (mi->getMetName()).string_of(),
1105         (mi->getFullName()).string_of());
1106     static timer inTimer;
1107     inTimer.start();
1108 #endif
1109
1110
1111     if (!internal) {
1112
1113         // pause processes that are running and add them to procsToCont.
1114         // We don't rerun the processes after we insert instrumentation,
1115         // this will be done by our caller, after all instrumentation
1116         // has been inserted.
1117         for (unsigned u = 0; u < mi->components.size(); u++) {
1118           process *p = mi->components[u]->proc();
1119           if (p->status() == running && p->pause()) {
1120             procsToCont += p;
1121           }
1122         }
1123
1124
1125         mi->insertInstrumentation(); // calls pause and unpause (this could be a bug, since the next line should be allowed to execute before the unpause!!!)
1126         mi->checkAndInstallInstrumentation();
1127
1128         // Now that the timers and counters have been allocated on the heap, and
1129         // the instrumentation added, we can manually execute instrumentation
1130         // we may have missed at $start.entry.  But has the process been paused
1131         // all this time?  Hopefully so; otherwise things can get screwy.
1132
1133         if (mi->anythingToManuallyTrigger()) {
1134            process *theProc = mi->components[0]->proc();
1135            assert(theProc);
1136
1137            bool alreadyRunning = (theProc->status_ == running);
1138
1139            if (alreadyRunning)
1140               theProc->pause();
1141
1142            mi->manuallyTrigger();
1143
1144            if (alreadyRunning)
1145               theProc->continueProc(); // the continue will trigger our code
1146            else
1147               ; // the next time the process continues, we'll trigger our code
1148         }
1149     }
1150
1151 #ifdef ndef
1152     inTimer.stop();
1153     if(!start_size) start_size = test_heapsize;
1154     printf("It took %f:user %f:system %f:wall seconds heap_left: %d used %d\n"
1155                 , inTimer.usecs(), inTimer.ssecs(), inTimer.wsecs(),
1156                 test_heapsize,start_size-test_heapsize);
1157 #endif
1158
1159     metResPairsEnabled++;
1160     return(mi->id_);
1161 }
1162
1163 float guessCost(string& metric_name, vector<u_int>& focus) {
1164    // called by dynrpc.C (getPredictedDataCost())
1165     bool internal;
1166     metricDefinitionNode *mi = createMetricInstance(metric_name, focus, false, internal);
1167     if (!mi) {
1168        //metric_cerr << "guessCost returning 0.0 since createMetricInstance failed" << endl;
1169        return(0.0);
1170     }
1171
1172     float cost = mi->cost();
1173     // delete the metric instance, if it is not being used 
1174     if (!allMIs.defines(mi->getMId()))
1175       delete mi;
1176
1177     return(cost);
1178 }
1179
1180 bool metricDefinitionNode::insertInstrumentation()
1181 {
1182     // returns true iff successful
1183     if (inserted_)
1184        return true;
1185
1186     inserted_ = true;
1187
1188     if (aggregate_) {
1189         unsigned c_size = components.size();
1190         for (unsigned u=0; u<c_size; u++)
1191           if (!components[u]->insertInstrumentation())
1192              return false; // shouldn't we try to undo what's already put in?
1193     } else {
1194       bool needToCont = proc_->status() == running;
1195       bool res = proc_->pause();
1196       if (!res)
1197         return false;
1198
1199       // Loop thru "dataRequests", an array of (ptrs to) dataReqNode:
1200       // Here we allocate ctrs/timers in the inferior heap but don't
1201       // stick in any code, except (if appropriate) that we'll instrument the
1202       // application's alarm-handler when not shm sampling.
1203       unsigned size = dataRequests.size();
1204       for (unsigned u=0; u<size; u++) {
1205         // the following allocs an object in inferior heap and arranges for
1206         // it to be alarm sampled, if appropriate.
1207         // Note: this is not necessary anymore because we are allocating the
1208         // space when the constructor for dataReqNode is called. This was
1209         // done for the dyninstAPI - naim 2/18/97
1210         //if (!dataRequests[u]->insertInstrumentation(proc_, this))
1211         //  return false; // shouldn't we try to undo what's already put in?
1212
1213         unsigned mid = dataRequests[u]->getSampleId();
1214         assert(!midToMiMap.defines(mid));
1215         midToMiMap[mid] = this;
1216       }
1217
1218       // Loop thru "instRequests", an array of instReqNode:
1219       // (Here we insert code instrumentation, tramps, etc. via addInstFunc())
1220       for (unsigned u1=0; u1<instRequests.size(); u1++) {
1221           // NEW: the following may also manually trigger the instrumentation
1222           // via inferiorRPC.
1223           returnInstance *retInst=NULL;
1224           if (!instRequests[u1].insertInstrumentation(proc_, retInst))
1225              return false; // shouldn't we try to undo what's already put in?
1226
1227           if (retInst)
1228             returnInsts += retInst;
1229       }
1230
1231       if (needToCont)
1232          proc_->continueProc();
1233     }
1234
1235     return(true);
1236 }
1237
1238 bool metricDefinitionNode::checkAndInstallInstrumentation() {
1239    // Patch up the application to make it jump to the base trampoline(s) of this
1240    // metric.  (The base trampoline and mini-tramps have already been installed
1241    // in the inferior heap).  We must first check to see if it's safe to install by
1242    // doing a stack walk, and determining if anything on it overlaps with any of our
1243    // desired jumps to base tramps.
1244    // The key variable is "returnsInsts", which was created for us when the base
1245    // tramp(s) were created.  Essentially, it contains the details of how we'll jump
1246    // to the base tramp (where in the code to patch, how many instructions, the
1247    // instructions themselves).
1248    // Note that it seems this routine is misnamed: it's not instrumentation that needs
1249    // to be installed (the base & mini tramps are already in place); it's just the
1250    // last step that is still needed: the jump to the base tramp.
1251    // If one or more can't be added, then a TRAP insn is inserted in the closest
1252    // common safe return point along the stack walk, and some structures are appended
1253    // to the process' "wait list", which is then checked when a TRAP signal arrives.
1254    // At that time, the jump to the base tramp is finally done.  WARNING: It seems to
1255    // me that such code isn't thread-safe...just because one thread hits the TRAP,
1256    // there may still be other threads that are unsafe.  It seems to me that we should
1257    // be doing this check again when a TRAP arrives...but for each thread (right now,
1258    // there's no stack walk for other threads).  --ari
1259  
1260    bool needToCont = false;
1261
1262     if (installed_) return(true);
1263
1264     installed_ = true;
1265
1266     if (aggregate_) {
1267         unsigned c_size = components.size();
1268         for (unsigned u=0; u<c_size; u++)
1269             components[u]->checkAndInstallInstrumentation();
1270             // why no checking of the return value?
1271     } else {
1272         needToCont = proc_->status() == running;
1273         if (!proc_->pause()) {
1274             cerr << "checkAnd... pause failed" << endl; cerr.flush();
1275             return false;
1276         }
1277
1278         vector<Address> pc = proc_->walkStack();
1279            // ndx 0 is where the pc is now; ndx 1 is the call site;
1280            // ndx 2 is the call site's call site, etc...
1281
1282         // for(u_int i=0; i < pc.size(); i++){
1283         //     printf("frame %d: pc = 0x%x\n",i,pc[i]);
1284         // }
1285
1286         unsigned rsize = returnInsts.size();
1287         u_int max_index = 0;  // first frame where it is safe to install instr
1288         bool delay_install = false; // true if some instr. needs to be delayed 
1289         vector<bool> delay_elm(rsize); // wch instr. to delay
1290         // for each inst point walk the stack to determine if it can be
1291         // inserted now (it can if it is not currently on the stack)
1292         // If some can not be inserted, then find the first safe point on
1293         // the stack where all can be inserted, and set a break point  
1294         for (unsigned u=0; u<rsize; u++) {
1295             u_int index = 0;
1296             bool installSafe = returnInsts[u] -> checkReturnInstance(pc,index);
1297                // if unsafe, index will be set to the first unsafe stack walk ndx
1298                // (0 being top of stack; i.e. the current pc)
1299
1300             if (!installSafe && index > max_index)
1301                max_index = index;
1302             
1303             if (installSafe) {
1304                 returnInsts[u] -> installReturnInstance(proc_);
1305                 delay_elm[u] = false;
1306             } else {
1307                 delay_install = true;
1308                 delay_elm[u] = true;
1309             }
1310         }
1311
1312         if (delay_install) {
1313             // get rid of pathological cases...caused by threaded applications 
1314             // TODO: this should be fixed to do something smarter
1315             if(max_index > 0 && max_index+1 >= pc.size()){
1316                max_index--;
1317                //printf("max_index changed: %d\n",max_index);
1318             }
1319             if(max_index > 0 && pc[max_index+1] == 0){
1320                max_index--;
1321                //printf("max_index changed: %d\n",max_index);
1322             }
1323             Address pc2 = pc[max_index+1];
1324             for (u_int i=0; i < rsize; i++)
1325                 if (delay_elm[i])
1326                     returnInsts[i]->addToReturnWaitingList(pc2, proc_);
1327         }
1328
1329         if (needToCont) proc_->continueProc();
1330     }
1331     return(true);
1332 }
1333
1334 float metricDefinitionNode::cost() const
1335 {
1336     float ret = 0.0;
1337     if (aggregate_) {
1338         unsigned c_size = components.size();
1339         for (unsigned u=0; u<c_size; u++) {
1340           float nc = components[u]->cost();
1341           if (nc > ret) ret = nc;
1342         }
1343     } else {
1344       for (unsigned u=0; u<instRequests.size(); u++)
1345         ret += instRequests[u].cost(proc_);
1346     }
1347     return(ret);
1348 }
1349
1350 void metricDefinitionNode::disable()
1351 {
1352     // check for internal metrics
1353
1354     unsigned ai_size = internalMetric::allInternalMetrics.size();
1355     for (unsigned u=0; u<ai_size; u++) {
1356       internalMetric *theIMetric = internalMetric::allInternalMetrics[u];
1357       if (theIMetric->disableByMetricDefinitionNode(this)) {
1358         //logLine("disabled internal metric\n");
1359         return;
1360       }
1361     }
1362
1363     // check for cost metrics
1364     for (unsigned i=0; i<costMetric::allCostMetrics.size(); i++){
1365       if (costMetric::allCostMetrics[i]->node == this) {
1366         costMetric::allCostMetrics[i]->disable();
1367         //logLine("disabled cost metric\n");
1368         return;
1369     }}
1370
1371     if (!inserted_) return;
1372
1373     inserted_ = false;
1374     if (aggregate_) {
1375         /* disable components of aggregate metrics */
1376         // unsigned c_size = components.size();
1377         //for (unsigned u=0; u<c_size; u++) {
1378         for (unsigned u=0; u<components.size(); u++) {
1379           //components[u]->disable();
1380           metricDefinitionNode *m = components[u];
1381           unsigned aggr_size = m->aggregators.size();
1382           assert(aggr_size == m->samples.size());
1383           for (unsigned u1=0; u1 < aggr_size; u1++) {
1384             if (m->aggregators[u1] == this) {
1385               m->aggregators[u1] = m->aggregators[aggr_size-1];
1386               m->aggregators.resize(aggr_size-1);
1387               m->samples[u1] = m->samples[aggr_size-1];
1388               m->samples.resize(aggr_size-1);
1389               break;
1390             }
1391           }
1392           if (aggr_size!=0) {
1393             assert(m->aggregators.size() == aggr_size-1);
1394           }
1395           // disable component only if it is not being shared
1396           if (aggr_size == 1) {
1397             m->disable();
1398           }
1399         }
1400
1401     } else {
1402       vector<unsigVecType> pointsToCheck;
1403       for (unsigned u1=0; u1<instRequests.size(); u1++) {
1404         unsigVecType pointsForThisRequest = 
1405             getAllTrampsAtPoint(instRequests[u1].getInstance());
1406         pointsToCheck += pointsForThisRequest;
1407
1408         instRequests[u1].disable(pointsForThisRequest); // calls deleteInst()
1409       }
1410
1411       for (unsigned u=0; u<dataRequests.size(); u++) {
1412         unsigned mid = dataRequests[u]->getSampleId();
1413         dataRequests[u]->disable(proc_, pointsToCheck); // deinstrument
1414         assert(midToMiMap.defines(mid));
1415         midToMiMap.undef(mid);
1416       }
1417     }
1418 }
1419
1420 void metricDefinitionNode::removeComponent(metricDefinitionNode *comp) {
1421     assert(!comp->aggregate_);
1422     unsigned aggr_size = comp->aggregators.size();
1423     unsigned found = aggr_size;
1424
1425     if (aggr_size == 0) {
1426       delete comp;
1427       return;
1428     }
1429
1430     // component has more than one aggregator. Remove this from list of aggregators
1431     for (unsigned u = 0; u < aggr_size; u++) {
1432       if (comp->aggregators[u] == this) {
1433         found = u;
1434         break;
1435       }
1436     }
1437     if (found == aggr_size)
1438      return;
1439     assert(found < aggr_size);
1440     assert(aggr_size == comp->samples.size());
1441     comp->aggregators[found] = comp->aggregators[aggr_size-1];
1442     comp->aggregators.resize(aggr_size-1);
1443     comp->samples[found] = comp->samples[aggr_size-1];
1444     comp->samples.resize(aggr_size-1);
1445
1446     if (aggr_size == 1) {
1447       delete comp;
1448       return;
1449     }
1450
1451 }
1452
1453 metricDefinitionNode::~metricDefinitionNode()
1454 {
1455     if (aggregate_) {
1456         /* delete components of aggregate metrics */
1457         unsigned c_size = components.size();
1458         for (unsigned u=0; u<c_size; u++)
1459           removeComponent(components[u]);
1460           //delete components[u];
1461         components.resize(0);
1462     } else {
1463       allMIComponents.undef(flat_name_);
1464       for (unsigned u=0; u<dataRequests.size(); u++) {
1465         delete dataRequests[u];
1466       }
1467       dataRequests.resize(0);
1468     }
1469 }
1470
1471 void metricDefinitionNode::cleanup_drn()
1472 {
1473       // we assume that it is safe to delete a dataReqNode at this point, 
1474       // otherwise, we would need to do something similar as in the disable
1475       // method for metricDefinitionNode - naim
1476       vector<unsigVecType> pointsToCheck;
1477       for (unsigned u=0; u<dataRequests.size(); u++) {
1478         dataRequests[u]->disable(proc_, pointsToCheck); // deinstrument
1479       }
1480 }
1481
1482 // NOTE: This stuff (flush_batch_buffer() and batchSampleData()) belongs
1483 //       in perfStream.C; this is an inappropriate file.
1484
1485 //////////////////////////////////////////////////////////////////////////////
1486 // Buffer the samples before we actually send it                            //
1487 //      Send it when the buffers are full                                   //
1488 //      or, send it when the last sample in the interval has arrived.       //
1489 //////////////////////////////////////////////////////////////////////////////
1490
1491 const unsigned SAMPLE_BUFFER_SIZE = (1*1024)/sizeof(T_dyninstRPC::batch_buffer_entry);
1492 bool BURST_HAS_COMPLETED = false;
1493    // set to true after a burst (after a processTraceStream(), or sampleNodes for
1494    // the CM5), which will force the buffer to be flushed before it fills up
1495    // (if not, we'd have bad response time)
1496
1497 vector<T_dyninstRPC::batch_buffer_entry> theBatchBuffer (SAMPLE_BUFFER_SIZE);
1498 unsigned int batch_buffer_next=0;
1499
1500 // The following routines (flush_batch_buffer() and batchSampleData() are
1501 // in an inappropriate src file...move somewhere more appropriate)
1502 void flush_batch_buffer() {
1503    // don't need to flush if the batch had no data (this does happen; see
1504    // perfStream.C)
1505    if (batch_buffer_next == 0)
1506       return;
1507
1508    // alloc buffer of the exact size to make communication
1509    // more efficient.  Why don't we send theBatchBuffer with a count?
1510    // This would work but would always (in the igen call) copy the entire
1511    // vector.  This solution has the downside of calling new but is not too bad
1512    // and is clean.
1513    vector<T_dyninstRPC::batch_buffer_entry> copyBatchBuffer(batch_buffer_next);
1514    assert(copyBatchBuffer.size() <= theBatchBuffer.size());
1515    for (unsigned i=0; i< batch_buffer_next; i++) {
1516       copyBatchBuffer[i] = theBatchBuffer[i];
1517    }
1518
1519 #ifdef FREEDEBUG
1520 timeStamp t1,t2;
1521 t1=getCurrentTime(false);
1522 #endif
1523
1524    // Now let's do the actual igen call!
1525    tp->batchSampleDataCallbackFunc(0, copyBatchBuffer);
1526
1527 #ifdef FREEDEBUG
1528 t2=getCurrentTime(false);
1529 if ((float)(t2-t1) > 15.0) {
1530 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));
1531 logLine(errorLine);
1532 }
1533 #endif
1534
1535    BURST_HAS_COMPLETED = false;
1536    batch_buffer_next = 0;
1537 }
1538
1539 void batchSampleData(int mid, double startTimeStamp,
1540                      double endTimeStamp, double value, unsigned val_weight,
1541                      bool internal_metric) 
1542 {
1543    // This routine is called where we used to call tp->sampleDataCallbackFunc.
1544    // We buffer things up and eventually call tp->batchSampleDataCallbackFunc
1545
1546 #ifdef notdef
1547    char myLogBuffer[120] ;
1548    sprintf(myLogBuffer, "mid %d, value %g\n", mid, value) ;
1549    logLine(myLogBuffer) ;
1550 #endif
1551
1552    // Flush the buffer if (1) it is full, or (2) for good response time, after
1553    // a burst of data:
1554    if (batch_buffer_next >= SAMPLE_BUFFER_SIZE || BURST_HAS_COMPLETED)
1555       flush_batch_buffer();
1556
1557    // Now let's batch this entry.
1558    T_dyninstRPC::batch_buffer_entry &theEntry = theBatchBuffer[batch_buffer_next];
1559    theEntry.mid = mid;
1560    theEntry.startTimeStamp = startTimeStamp;
1561    theEntry.endTimeStamp = endTimeStamp;
1562    theEntry.value = value;
1563    theEntry.weight = val_weight;
1564    theEntry.internal_met = internal_metric;
1565    batch_buffer_next++;
1566 }
1567
1568 //////////////////////////////////////////////////////////////////////////////
1569 // Buffer the traces before we actually send it                            //
1570 //      Send it when the buffers are full                                   //
1571 //      or, send it when the last sample in the interval has arrived.       //
1572 //////////////////////////////////////////////////////////////////////////////
1573
1574 const unsigned TRACE_BUFFER_SIZE = 10;
1575 bool TRACE_BURST_HAS_COMPLETED = false;
1576    // set to true after a burst (after a processTraceStream(), or sampleNodes for
1577    // the CM5), which will force the buffer to be flushed before it fills up
1578    // (if not, we'd have bad response time)
1579
1580 vector<T_dyninstRPC::trace_batch_buffer_entry> theTraceBatchBuffer (TRACE_BUFFER_SIZE);
1581 unsigned int trace_batch_buffer_next=0;
1582
1583 void flush_trace_batch_buffer(int program) {
1584    // don't need to flush if the batch had no data (this does happen; see
1585    // perfStream.C)
1586    if (trace_batch_buffer_next == 0)
1587       return;
1588
1589    vector<T_dyninstRPC::trace_batch_buffer_entry> copyTraceBatchBuffer(trace_batch_buffer_next);
1590    for (unsigned i=0; i< trace_batch_buffer_next; i++)
1591       copyTraceBatchBuffer[i] = theTraceBatchBuffer[i];
1592
1593
1594    // Now let's do the actual igen call!
1595
1596    tp->batchTraceDataCallbackFunc(program, copyTraceBatchBuffer);
1597
1598    TRACE_BURST_HAS_COMPLETED = false;
1599    trace_batch_buffer_next = 0;
1600 }
1601
1602 void batchTraceData(int program, int mid, int recordLength,
1603                      char *recordPtr)
1604 {
1605    // Now let's batch this entry.
1606    T_dyninstRPC::trace_batch_buffer_entry &theEntry = theTraceBatchBuffer[trace_batch_buffer_next];
1607    theEntry.mid = mid;
1608    theEntry.length = recordLength;
1609    theEntry.traceRecord = byteArray(recordPtr,recordLength);
1610    trace_batch_buffer_next++;
1611
1612    // We buffer things up and eventually call tp->batchTraceDataCallbackFunc
1613
1614    // Flush the buffer if (1) it is full, or (2) for good response time, after
1615    // a burst of data:
1616    if (trace_batch_buffer_next >= TRACE_BUFFER_SIZE || TRACE_BURST_HAS_COMPLETED) {
1617       flush_trace_batch_buffer(program);
1618    }
1619
1620 }
1621
1622 void metricDefinitionNode::forwardSimpleValue(timeStamp start, timeStamp end,
1623                                        sampleValue value, unsigned weight,
1624                                        bool internal_met)
1625 {
1626   // TODO mdc
1627     assert(start + 0.000001 >= (firstRecordTime/MILLION));
1628     assert(end >= (firstRecordTime/MILLION));
1629     assert(end > start);
1630
1631     batchSampleData(id_, start, end, value, weight, internal_met);
1632 }
1633
1634 void metricDefinitionNode::updateValue(time64 wallTime, 
1635                                        sampleValue value)
1636 {
1637     timeStamp sampleTime = wallTime / 1000000.0;
1638        // note: we can probably do integer division by million quicker
1639
1640     assert(value >= -0.01);
1641
1642     // TODO -- is this ok?
1643     // TODO -- do sampledFuncs work ?
1644     if (style_ == EventCounter) { 
1645
1646       // only use delta from last sample.
1647       if (value < cumulativeValue) {
1648         if ((value/cumulativeValue) < 0.99999) {
1649             assert((value + 0.0001)  >= cumulativeValue);
1650         } else {
1651           // floating point rounding error ignore
1652           cumulativeValue = value;
1653         }
1654       }
1655
1656       //        if (value + 0.0001 < cumulativeValue)
1657       //           printf ("WARNING:  sample went backwards!!!!!\n");
1658       value -= cumulativeValue;
1659       cumulativeValue += value;
1660     } 
1661
1662     //
1663     // If style==EventCounter then value is changed. Otherwise, it keeps the
1664     // the current "value" (e.g. SampledFunction case). That's why it is not
1665     // necessary to have an special case for SampledFunction.
1666     //
1667
1668     assert(samples.size() == aggregators.size());
1669     for (unsigned u = 0; u < samples.size(); u++) {
1670       if (samples[u]->firstValueReceived())
1671         samples[u]->newValue(sampleTime, value);
1672       else {
1673         samples[u]->startTime(sampleTime);
1674       }
1675       aggregators[u]->updateAggregateComponent();
1676     }
1677 }
1678
1679 void metricDefinitionNode::updateAggregateComponent()
1680 {
1681     // currently called (only) by the above routine
1682     sampleInterval ret = aggSample.aggregateValues();
1683     if (ret.valid) {
1684         assert(ret.end > ret.start);
1685         assert(ret.start + 0.000001 >= (firstRecordTime/MILLION));
1686         assert(ret.end >= (firstRecordTime/MILLION));
1687         batchSampleData(id_, ret.start, ret.end, ret.value,
1688                         aggSample.numComponents(),false);
1689     }
1690 //    else {
1691 //        metric_cerr << "sorry, ret.valid false so not batching sample data" << endl;
1692 //    }
1693 }
1694
1695 //
1696 // Costs are now reported to paradyn like other metrics (ie. we are not
1697 // calling reportInternalMetrics to deliver cost values, instead we wait
1698 // until we have received a new interval of cost data from each process)
1699 // note: this only works for the CM5 because all cost metrics are sumed
1700 // at the daemons and at paradyn, otherwise the CM5 needs its own version
1701 // of this routine that uses the same aggregate method as the one for paradyn 
1702 //
1703 #ifndef SHM_SAMPLING
1704 void processCost(process *proc, traceHeader *h, costUpdate *s)
1705 {
1706     // we can probably do integer division by million quicker.
1707     timeStamp newSampleTime = (h->wall / 1000000.0);
1708     timeStamp newProcessTime = (h->process / 1000000.0);
1709
1710     timeStamp lastProcessTime = 
1711                         totalPredictedCost->getLastSampleProcessTime(proc); 
1712
1713     // find the portion of uninstrumented time for this interval
1714     double unInstTime = ((newProcessTime - lastProcessTime) 
1715                          / (1+currentPredictedCost));
1716     // update predicted cost
1717     // note: currentPredictedCost is the same for all processes 
1718     //       this should be changed to be computed on a per process basis
1719     sampleValue newPredCost = totalPredictedCost->getCumulativeValue(proc);
1720     newPredCost += (float)(currentPredictedCost*unInstTime); 
1721     totalPredictedCost->updateValue(proc,newPredCost,
1722                                     newSampleTime,newProcessTime);
1723     // update observed cost 
1724     observed_cost->updateValue(proc,s->obsCostIdeal,
1725                                newSampleTime,newProcessTime);
1726
1727     // update smooth observed cost
1728     smooth_obs_cost->updateSmoothValue(proc,s->obsCostIdeal,
1729                                  newSampleTime,newProcessTime);
1730 }
1731 #endif
1732
1733 #ifndef SHM_SAMPLING
1734 void processSample(int /* pid */, traceHeader *h, traceSample *s)
1735 {
1736     // called from processTraceStream (perfStream.C) when a TR_SAMPLE record
1737     // has arrived from the appl.
1738
1739     unsigned mid = s->id.id; // low-level counterId (see primitives.C)
1740
1741     static time64 firstWall = 0;
1742
1743     static bool firstTime = true;
1744
1745     if (firstTime) {
1746        firstWall = h->wall;
1747     }
1748
1749     metricDefinitionNode *mi; // filled in by find() if found
1750     if (!midToMiMap.find(mid, mi)) { // low-level counterId to metricDefinitionNode
1751        metric_cerr << "TR_SAMPLE id " << s->id.id << " not for valid mi...discarding" << endl;
1752        return;
1753     }
1754
1755 //    metric_cerr << "FROM pid " << pid << " got value " << s->value << " for id " << s->id.id << endl;
1756
1757     //    sprintf(errorLine, "sample id %d at time %8.6f = %f\n", s->id.id, 
1758     //  ((double) *(int*) &h->wall) + (*(((int*) &h->wall)+1))/1000000.0, s->value);
1759     //    logLine(errorLine);
1760     mi->updateValue(h->wall, s->value);
1761     samplesDelivered++;
1762 }
1763 #endif
1764
1765 /*
1766  * functions to operate on inst request graph.
1767  *
1768  */
1769 instReqNode::instReqNode(instPoint *iPoint,
1770                          AstNode *iAst,
1771                          callWhen  iWhen,
1772                          callOrder o, bool iManuallyTrigger) {
1773     point = iPoint;
1774     when = iWhen;
1775     order = o;
1776     instance = NULL; // set when insertInstrumentation() calls addInstFunc()
1777     ast = assignAst(iAst);
1778     manuallyTrigger = iManuallyTrigger;
1779     assert(point);
1780 }
1781
1782 instReqNode instReqNode::forkProcess(const instReqNode &parentNode,
1783                              const dictionary_hash<instInstance*,instInstance*> &map) {
1784     instReqNode ret = instReqNode(parentNode.point, parentNode.ast, parentNode.when,
1785                                   parentNode.order,
1786                                   false // don't manually trigger
1787                                   );
1788
1789     if (!map.find(parentNode.instance, ret.instance)) // writes to ret.instance
1790        assert(false);
1791
1792     return ret;
1793 }
1794
1795 bool instReqNode::unFork(dictionary_hash<instInstance*,instInstance*> &map) const {
1796    // The fork syscall duplicates all trampolines from the parent into the child. For
1797    // those mi's which we don't want to propagate to the child, this creates a
1798    // problem.  We need to remove instrumentation code from the child.  This routine
1799    // does that.
1800    //
1801    // "this" represents an instReqNode in the PARENT process.
1802    // "map" maps all instInstance*'s of the parent process to instInstance*'s in the
1803    // child process.  We modify "map" by setting a value to NULL.
1804
1805    instInstance *parentInstance = getInstance();
1806    
1807    instInstance *childInstance;
1808    if (!map.find(parentInstance, childInstance)) // writes to childInstance
1809       assert(false);
1810
1811    vector<unsigned> pointsToCheck; // is it right leaving this empty on a fork()???
1812    deleteInst(childInstance, pointsToCheck);
1813
1814    map[parentInstance] = NULL; // since we've deleted...
1815
1816    return true; // success
1817 }
1818
1819 bool instReqNode::insertInstrumentation(process *theProc,
1820                                         returnInstance *&retInstance) 
1821 {
1822     // NEW: We may manually trigger the instrumentation, via a call to postRPCtoDo()
1823
1824     // addInstFunc() is one of the key routines in all paradynd.
1825     // It installs a base tramp at the point (if needed), generates code
1826     // for the tramp, calls inferiorMalloc() in the text heap to get space for it,
1827     // and actually inserts the instrumentation.
1828     instance = addInstFunc(theProc, point, ast, when, order,
1829                            false, // false --> don't exclude cost
1830                            retInstance);
1831
1832     return (instance != NULL);
1833 }
1834
1835 void instReqNode::disable(const vector<unsigned> &pointsToCheck)
1836 {
1837     deleteInst(instance, pointsToCheck);
1838     instance = NULL;
1839 }
1840
1841 instReqNode::~instReqNode()
1842 {
1843     instance = NULL;
1844     removeAst(ast);
1845 }
1846
1847 float instReqNode::cost(process *theProc) const
1848 {
1849     float value;
1850     float unitCost;
1851     float frequency;
1852     int unitCostInCycles;
1853
1854     unitCostInCycles = ast->cost() + getPointCost(theProc, point) +
1855                        getInsnCost(trampPreamble) + getInsnCost(trampTrailer);
1856     // printf("unit cost = %d cycles\n", unitCostInCycles);
1857     unitCost = unitCostInCycles/ cyclesPerSecond;
1858     frequency = getPointFrequency(point);
1859     value = unitCost * frequency;
1860     return(value);
1861 }
1862
1863 bool instReqNode::triggerNow(process *theProc) {
1864    assert(manuallyTrigger);
1865
1866    theProc->postRPCtoDo(ast, false, // don't skip cost
1867                         NULL, // no callback fn needed
1868                         NULL
1869                         );
1870       // the rpc will be launched with a call to launchRPCifAppropriate()
1871       // in the main loop (perfStream.C)
1872
1873    return true;
1874 }
1875
1876 /* ************************************************************************* */
1877
1878 #ifndef SHM_SAMPLING
1879 sampledIntCounterReqNode::sampledIntCounterReqNode(int iValue, int iCounterId,
1880                                                    metricDefinitionNode *iMi, 
1881                                                    bool computingCost) :
1882                                                    dataReqNode() {
1883    theSampleId = iCounterId;
1884    initialValue = iValue;
1885
1886    // The following fields are NULL until insertInstrumentation()
1887    counterPtr = NULL;
1888    sampler = NULL;
1889
1890    if (!computingCost) {
1891      bool isOk=false;
1892      isOk = insertInstrumentation(iMi->proc(), iMi);
1893      assert(isOk && counterPtr!=NULL); 
1894    }
1895 }
1896
1897 sampledIntCounterReqNode::sampledIntCounterReqNode(const sampledIntCounterReqNode &src,
1898                                                    process *childProc,
1899                                                    metricDefinitionNode *,
1900                                                    int iCounterId,
1901                                                    const dictionary_hash<instInstance*,instInstance*> &map) {
1902    // a dup() routine (call after a fork())
1903    counterPtr = src.counterPtr; // assumes addr spaces have been dup()d.
1904
1905    if (!map.find(src.sampler, this->sampler)) // writes to this->sampler
1906       assert(false);
1907
1908    theSampleId = iCounterId;
1909  
1910    intCounter temp;
1911    temp.id.id = this->theSampleId;
1912    temp.value = initialValue;
1913    writeToInferiorHeap(childProc, temp);
1914 }
1915
1916 dataReqNode *
1917 sampledIntCounterReqNode::dup(process *childProc,
1918                               metricDefinitionNode *mi,
1919                               int iCounterId,
1920                               const dictionary_hash<instInstance*,instInstance*> &map
1921                               ) const {
1922    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
1923
1924    sampledIntCounterReqNode *tmp;
1925    tmp = new sampledIntCounterReqNode(*this, childProc, mi, iCounterId, map);
1926       // fork ctor
1927   
1928    return tmp;
1929 }
1930
1931 bool sampledIntCounterReqNode::insertInstrumentation(process *theProc,
1932                                                      metricDefinitionNode *,
1933                                                      bool) {
1934    // Remember counterPtr and sampler are NULL until this routine
1935    // gets called.
1936    counterPtr = (intCounter*)inferiorMalloc(theProc, sizeof(intCounter), dataHeap);
1937    if (counterPtr == NULL)
1938       return false; // failure!
1939
1940    // initialize the intCounter in the inferior heap
1941    intCounter temp;
1942    temp.id.id = this->theSampleId;
1943    temp.value = this->initialValue;
1944
1945    writeToInferiorHeap(theProc, temp);
1946
1947    function_base *sampleFunction = 
1948         theProc->findOneFunction("DYNINSTsampleValues");
1949    assert(sampleFunction);
1950
1951    AstNode *ast, *tmp;
1952    tmp = new AstNode(AstNode::Constant, counterPtr);
1953    ast = new AstNode("DYNINSTreportCounter", tmp);
1954    removeAst(tmp);
1955
1956    instPoint *func_entry = (instPoint *)sampleFunction->funcEntry(theProc);
1957    sampler = addInstFunc(theProc, func_entry,
1958                          ast, callPreInsn, orderLastAtPoint, false);
1959    removeAst(ast);
1960
1961    return true; // success
1962 }
1963
1964 void sampledIntCounterReqNode::disable(process *theProc,
1965                                        const vector<unsigVecType> &pointsToCheck) {
1966    // We used to remove the sample id from midToMiMap here but now the caller is
1967    // responsible for that.
1968
1969    // Remove instrumentation added to DYNINSTsampleValues(), if necessary:
1970    if (sampler != NULL)
1971       ::deleteInst(sampler, getAllTrampsAtPoint(sampler));
1972
1973    // Deallocate space for intCounter in the inferior heap:
1974    assert(counterPtr != NULL);
1975    inferiorFree(theProc, (unsigned)counterPtr, dataHeap, pointsToCheck);
1976 }
1977
1978 void sampledIntCounterReqNode::writeToInferiorHeap(process *theProc,
1979                                                    const intCounter &dataSrc) const {
1980    // using the contents of "dataSrc", write to the inferior heap at loc
1981    // "counterPtr" via proc->writeDataSpace()
1982    assert(counterPtr);
1983    theProc->writeDataSpace(counterPtr, sizeof(intCounter), &dataSrc);
1984 }
1985
1986 bool sampledIntCounterReqNode::
1987 unFork(dictionary_hash<instInstance*,instInstance*> &map) {
1988    instInstance *parentSamplerInstance = this->sampler;
1989
1990    instInstance *childSamplerInstance;
1991    if (!map.find(parentSamplerInstance, childSamplerInstance))
1992       assert(false);
1993
1994    vector<unsigned> pointsToCheck; // empty on purpose
1995    deleteInst(childSamplerInstance, pointsToCheck);
1996
1997    map[parentSamplerInstance] = NULL;
1998
1999    return true;
2000 }
2001                                       
2002 #endif
2003
2004 /* ************************************************************************* */
2005
2006 #ifdef SHM_SAMPLING
2007
2008 sampledShmIntCounterReqNode::sampledShmIntCounterReqNode(int iValue, 
2009                                                      int iCounterId, 
2010                                                      metricDefinitionNode *iMi,
2011                                                      bool computingCost,
2012                                                      bool doNotSample) :
2013                                                      dataReqNode() {
2014    theSampleId = iCounterId;
2015    initialValue = iValue;
2016
2017    // The following fields are NULL until insertInstrumentation()
2018    allocatedIndex = UINT_MAX;
2019    allocatedLevel = UINT_MAX;
2020
2021    position_=0;
2022
2023    if (!computingCost) {
2024      bool isOk=false;
2025      isOk = insertInstrumentation(iMi->proc(), iMi, doNotSample);
2026      assert(isOk); 
2027    }
2028 }
2029
2030 sampledShmIntCounterReqNode::
2031 sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &src,
2032                             process *childProc, metricDefinitionNode *mi,
2033                             int iCounterId, const process *parentProc) {
2034    // a dup() routine (call after a fork())
2035    // Assumes that "childProc" has been copied already (e.g., the shm seg was copied).
2036
2037    // Note that the index w/in the inferior heap remains the same, so setting the
2038    // new inferiorCounterPtr isn't too hard.  Actually, it's trivial, since other code
2039    // ensures that the new shm segment is placed in exactly the same virtual mem loc
2040    // as the previous one.
2041    //
2042    // Note that the fastInferiorHeap class's fork ctor will have already copied the
2043    // actual data; we need to fill in new meta-data (new houseKeeping entries).
2044
2045    this->allocatedIndex = src.allocatedIndex;
2046    this->allocatedLevel = src.allocatedLevel;
2047
2048    this->theSampleId = iCounterId;  // this is different from the parent's value
2049    this->initialValue = src.initialValue;
2050
2051    superTable &theTable = childProc->getTable();
2052
2053    // since the new shm seg is placed in exactly the same memory location as
2054    // the old one, nothing here should change.
2055    const superTable &theParentTable = parentProc->getTable();
2056    assert(theTable.index2InferiorAddr(0,childProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel)==theParentTable.index2InferiorAddr(0,parentProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel));
2057
2058    for (unsigned i=0; i<childProc->threads.size(); i++) {
2059      // write to the raw item in the inferior heap:
2060      intCounter *localCounterPtr = (intCounter *) theTable.index2LocalAddr(0,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2061      const intCounter *localSrcCounterPtr = (const intCounter *) childProc->getParent()->getTable().index2LocalAddr(0,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2062      localCounterPtr->value = initialValue;
2063      localCounterPtr->id.id = theSampleId;
2064      localCounterPtr->theSpinner = localSrcCounterPtr->theSpinner;
2065         // in case we're in the middle of an operation
2066    }
2067
2068    // write HK for this intCounter:
2069    // Note: we don't assert anything about mi->getMId(), because that id has no
2070    // relation to the ids we work with (theSampleId).  In fact, we (the sampling code)
2071    // just don't ever care what mi->getMId() is.
2072    assert(theSampleId >= 0);
2073    assert(midToMiMap.defines(theSampleId));
2074    assert(midToMiMap[theSampleId] == mi);
2075    intCounterHK iHKValue(theSampleId, mi);
2076       // the mi differs from the mi of the parent; theSampleId differs too.
2077    theTable.initializeHKAfterForkIntCounter(allocatedIndex, allocatedLevel, iHKValue);
2078
2079    position_=0;
2080 }
2081
2082 dataReqNode *
2083 sampledShmIntCounterReqNode::dup(process *childProc,
2084                                  metricDefinitionNode *mi,
2085                                  int iCounterId,
2086                                  const dictionary_hash<instInstance*,instInstance*> &
2087                                  ) const {
2088    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2089
2090    sampledShmIntCounterReqNode *tmp;
2091    tmp = new sampledShmIntCounterReqNode(*this, childProc, mi, iCounterId, childProc->getParent());
2092       // fork ctor
2093
2094    return tmp;
2095 }
2096
2097 bool sampledShmIntCounterReqNode::insertInstrumentation(process *theProc,
2098                                                         metricDefinitionNode *iMi, bool doNotSample) {
2099    // Remember counterPtr is NULL until this routine gets called.
2100    // WARNING: there will be an assert failure if the applic hasn't yet attached to the
2101    //          shm segment!!!
2102
2103    // initialize the intCounter in the inferior heap
2104    intCounter iValue;
2105    iValue.id.id = this->theSampleId;
2106    iValue.value = this->initialValue; // what about initializing 'theSpinner'???
2107
2108    intCounterHK iHKValue(this->theSampleId, iMi);
2109
2110    superTable &theTable = theProc->getTable();
2111
2112    if (!theTable.allocIntCounter(iValue, iHKValue, this->allocatedIndex, this->allocatedLevel, doNotSample))
2113       return false; // failure
2114
2115    return true; // success
2116 }
2117
2118 void sampledShmIntCounterReqNode::disable(process *theProc,
2119                                           const vector<unsigVecType> &pointsToCheck) {
2120    // We used to remove the sample id from midToMiMap here but now the caller is
2121    // responsible for that.
2122
2123    superTable &theTable = theProc->getTable();
2124
2125    // Remove from inferior heap; make sure we won't be sampled any more:
2126    vector<unsigned> trampsMaybeUsing;
2127    for (unsigned pointlcv=0; pointlcv < pointsToCheck.size(); pointlcv++)
2128       for (unsigned tramplcv=0; tramplcv < pointsToCheck[pointlcv].size(); tramplcv++)
2129          trampsMaybeUsing += pointsToCheck[pointlcv][tramplcv];
2130
2131    theTable.makePendingFree(0,allocatedIndex,allocatedLevel,trampsMaybeUsing);
2132
2133 #if defined(MT_THREAD)
2134 //NOTE: Not yet implemented for shm sampling! naim 4/23/97
2135 //    pdThread *thr = theProc->threads[0];
2136 //    thr->CTvector->remove(this->theSampleId, this->position_);
2137 //    theProc->updateActiveCT(false,counter);
2138 #endif
2139 }
2140
2141 #endif
2142
2143 /* ************************************************************************* */
2144
2145 nonSampledIntCounterReqNode::nonSampledIntCounterReqNode(int iValue, 
2146                                                     int iCounterId,
2147                                                     metricDefinitionNode *iMi, 
2148                                                     bool computingCost) :
2149                                                     dataReqNode() {
2150    theSampleId = iCounterId;
2151    initialValue = iValue;
2152
2153    // The following fields are NULL until insertInstrumentation()
2154    counterPtr = NULL;
2155
2156    if (!computingCost) {
2157      bool isOk=false;
2158      isOk = insertInstrumentation(iMi->proc(), iMi);
2159      assert(isOk && counterPtr!=NULL); 
2160    }
2161 }
2162
2163 nonSampledIntCounterReqNode::
2164 nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &src,
2165                             process *childProc, metricDefinitionNode *,
2166                             int iCounterId) {
2167    // a dup() routine (call after a fork())
2168    counterPtr = src.counterPtr; // assumes addr spaces have been dup()d.
2169    initialValue = src.initialValue;
2170    theSampleId = iCounterId;
2171  
2172    intCounter temp;
2173    temp.id.id = this->theSampleId;
2174    temp.value = this->initialValue;
2175    writeToInferiorHeap(childProc, temp);
2176 }
2177
2178 dataReqNode *
2179 nonSampledIntCounterReqNode::dup(process *childProc,
2180                                  metricDefinitionNode *mi,
2181                                  int iCounterId,
2182                                  const dictionary_hash<instInstance*,instInstance*> &
2183                                  ) const {
2184    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2185
2186    nonSampledIntCounterReqNode *tmp;
2187    tmp = new nonSampledIntCounterReqNode(*this, childProc, mi, iCounterId);
2188       // fork ctor
2189
2190    return tmp;
2191 }
2192
2193 bool nonSampledIntCounterReqNode::insertInstrumentation(process *theProc,
2194                                                         metricDefinitionNode *,
2195                                                         bool) {
2196    // Remember counterPtr is NULL until this routine gets called.
2197    counterPtr = (intCounter*)inferiorMalloc(theProc, sizeof(intCounter), dataHeap);
2198    if (counterPtr == NULL)
2199       return false; // failure!
2200
2201    // initialize the intCounter in the inferior heap
2202    intCounter temp;
2203    temp.id.id = this->theSampleId;
2204    temp.value = this->initialValue;
2205
2206    writeToInferiorHeap(theProc, temp);
2207
2208    return true; // success
2209 }
2210
2211 void nonSampledIntCounterReqNode::disable(process *theProc,
2212                                           const vector<unsigVecType> &pointsToCheck) {
2213    // We used to remove the sample id from midToMiMap here but now the caller is
2214    // responsible for that.
2215
2216    // Deallocate space for intCounter in the inferior heap:
2217    assert(counterPtr != NULL);
2218    inferiorFree(theProc, (unsigned)counterPtr, dataHeap, pointsToCheck);
2219 }
2220
2221 void nonSampledIntCounterReqNode::writeToInferiorHeap(process *theProc,
2222                                                       const intCounter &dataSrc) const {
2223    // using the contents of "dataSrc", write to the inferior heap at loc
2224    // "counterPtr" via proc->writeDataSpace()
2225    assert(counterPtr);
2226    theProc->writeDataSpace(counterPtr, sizeof(intCounter), &dataSrc);
2227 }
2228
2229 /* ****************************************************************** */
2230
2231 #ifndef SHM_SAMPLING
2232 sampledTimerReqNode::sampledTimerReqNode(timerType iType, int iCounterId, 
2233                                          metricDefinitionNode *iMi,
2234                                          bool computingCost) :
2235                                          dataReqNode() {
2236    theSampleId = iCounterId;
2237    theTimerType = iType;
2238
2239    // The following fields are NULL until insertInstrumentatoin():
2240    timerPtr = NULL;
2241    sampler  = NULL;
2242
2243    if (!computingCost) {
2244      bool isOk=false;
2245      isOk = insertInstrumentation(iMi->proc(), iMi);
2246      assert(isOk && timerPtr!=NULL); 
2247    }
2248 }
2249
2250 sampledTimerReqNode::sampledTimerReqNode(const sampledTimerReqNode &src,
2251                                          process *childProc,
2252                                          metricDefinitionNode *,
2253                                          int iCounterId,
2254                                          const dictionary_hash<instInstance*,instInstance*> &map) {
2255    // a dup()-like routine; call after a fork()
2256    timerPtr = src.timerPtr; // assumes addr spaces have been dup()'d
2257
2258    if (!map.find(src.sampler, this->sampler)) // writes to this->sampler
2259       assert(false);
2260
2261    assert(sampler); // makes sense; timers are always sampled, whereas intCounters
2262                     // might be just non-sampled predicates.
2263    
2264    theSampleId = iCounterId;
2265    theTimerType = src.theTimerType;
2266
2267    tTimer temp;
2268    P_memset(&temp, '\0', sizeof(tTimer)); /* is this needed? */
2269    temp.id.id = this->theSampleId;
2270    temp.type = this->theTimerType;
2271    temp.normalize = 1000000;
2272    writeToInferiorHeap(childProc, temp);
2273
2274    // WARNING: shouldn't we be resetting the raw value to count=0, start=0,
2275    //          total = src.initialValue ???  On the other hand, it's not that
2276    //          simple -- if the timer is active in the parent, then it'll be active
2277    //          in the child.  So how about setting count to src.count, start=now,
2278    //          total=0 ???
2279 }
2280
2281 dataReqNode *
2282 sampledTimerReqNode::dup(process *childProc, metricDefinitionNode *mi,
2283                          int iCounterId,
2284                          const dictionary_hash<instInstance*,instInstance*> &map
2285                          ) const {
2286    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2287
2288    sampledTimerReqNode *result = new sampledTimerReqNode(*this, childProc, mi, iCounterId, map);
2289       // fork ctor
2290    if (!result)
2291       return NULL; // on failure, return w/o incrementing counterId
2292
2293    return result;
2294 }
2295
2296 bool sampledTimerReqNode::insertInstrumentation(process *theProc,
2297                                                 metricDefinitionNode *,
2298                                                 bool) {
2299    timerPtr = (tTimer *)inferiorMalloc(theProc, sizeof(tTimer), dataHeap);
2300    if (timerPtr == NULL)
2301       return false; // failure!
2302
2303    // Now let's initialize the newly allocated tTimer in the inferior heap:
2304    tTimer temp;
2305    P_memset(&temp, '\0', sizeof(tTimer));
2306    temp.id.id = this->theSampleId;
2307    temp.type = this->theTimerType;
2308    temp.normalize = 1000000;
2309    writeToInferiorHeap(theProc, temp);
2310
2311    // Now instrument DYNINSTreportTimer:
2312    function_base *sampleFunction = 
2313         theProc->findOneFunction("DYNINSTsampleValues");
2314    assert(sampleFunction);
2315
2316    AstNode *ast, *tmp;
2317    tmp = new AstNode(AstNode::Constant, timerPtr);
2318    ast = new AstNode("DYNINSTreportTimer", tmp);
2319    removeAst(tmp);
2320
2321    instPoint *func_entry = (instPoint *)sampleFunction->funcEntry(theProc);
2322    sampler = addInstFunc(theProc, func_entry, ast,
2323                          callPreInsn, orderLastAtPoint, false);
2324    removeAst(ast);
2325
2326    return true; // successful
2327 }
2328
2329 void sampledTimerReqNode::disable(process *theProc,
2330                                   const vector<unsigVecType> &pointsToCheck) {
2331    // We used to remove the sample id from midToMiMap here but now the caller is
2332    // responsible for that.
2333
2334    // Remove instrumentation added to DYNINSTsampleValues(), if necessary:
2335    if (sampler != NULL)
2336       ::deleteInst(sampler, getAllTrampsAtPoint(sampler));
2337
2338    // Deallocate space for tTimer in the inferior heap:
2339    assert(timerPtr);
2340    inferiorFree(theProc, (unsigned)timerPtr, dataHeap, pointsToCheck);
2341 }
2342
2343 void sampledTimerReqNode::writeToInferiorHeap(process *theProc,
2344                                               const tTimer &dataSrc) const {
2345    // using contents of "dataSrc", a local copy of the data,
2346    // write to inferior heap at loc "timerPtr" via proc->writeDataSpace()
2347    assert(timerPtr);
2348    theProc->writeDataSpace(timerPtr, sizeof(tTimer), &dataSrc);
2349 }
2350
2351 bool sampledTimerReqNode::
2352 unFork(dictionary_hash<instInstance*,instInstance*> &map) {
2353    instInstance *parentSamplerInstance = sampler;
2354
2355    instInstance *childSamplerInstance;
2356    if (!map.find(parentSamplerInstance, childSamplerInstance))
2357       assert(false);
2358
2359    vector<unsigned> pointsToCheck; // empty
2360    deleteInst(childSamplerInstance, pointsToCheck);
2361
2362    map[parentSamplerInstance] = NULL; // since we've deleted...
2363
2364    return true;
2365 }
2366                                  
2367 #endif
2368
2369 /* ****************************************************************** */
2370
2371 #ifdef SHM_SAMPLING
2372 sampledShmWallTimerReqNode::sampledShmWallTimerReqNode(int iCounterId,
2373                                                      metricDefinitionNode *iMi,
2374                                                      bool computingCost) :
2375                                                      dataReqNode() {
2376    theSampleId = iCounterId;
2377
2378    // The following fields are NULL until insertInstrumentation():
2379    allocatedIndex = UINT_MAX;
2380    allocatedLevel = UINT_MAX;
2381
2382    position_=0;
2383
2384    if (!computingCost) {
2385      bool isOk=false;
2386      isOk = insertInstrumentation(iMi->proc(), iMi);
2387      assert(isOk); 
2388    }
2389 }
2390
2391 sampledShmWallTimerReqNode::
2392 sampledShmWallTimerReqNode(const sampledShmWallTimerReqNode &src,
2393                            process *childProc,
2394                            metricDefinitionNode *mi,
2395                            int iCounterId, const process *parentProc) {
2396    // a dup()-like routine; call after a fork().
2397    // Assumes that the "childProc" has been duplicated already
2398
2399    // Note that the index w/in the inferior heap remains the same, so setting the new
2400    // inferiorTimerPtr isn't too hard.  Actually, it's trivial, since other code
2401    // ensures that the new shm segment is placed in exactly the same virtual mem loc
2402    // as the previous one.
2403    //
2404    // Note that the fastInferiorHeap class's fork ctor will have already copied the
2405    // actual data; we need to fill in new meta-data (new houseKeeping entries).
2406
2407    allocatedIndex = src.allocatedIndex;
2408    allocatedLevel = src.allocatedLevel;
2409
2410    theSampleId = iCounterId;
2411    assert(theSampleId != src.theSampleId);
2412
2413    superTable &theTable = childProc->getTable();
2414
2415    // since the new shm seg is placed in exactly the same memory location as
2416    // the old one, nothing here should change.
2417    const superTable &theParentTable = parentProc->getTable();
2418    assert(theTable.index2InferiorAddr(1,childProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel)==theParentTable.index2InferiorAddr(1,parentProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel));
2419
2420    // Write new raw value in the inferior heap:
2421    // we set localTimerPtr as follows: protector1 and procetor2 should be copied from
2422    //    src. total should be reset to 0.  start should be set to now if active else 0.
2423    //    counter should be copied from the source.
2424    // NOTE: SINCE WE COPY FROM THE SOURCE, IT'S IMPORTANT THAT ON A FORK, BOTH THE
2425    //       PARENT AND CHILD ARE PAUSED UNTIL WE COPY THINGS OVER.  THAT THE CHILD IS
2426    //       PAUSED IS NOTHING NEW; THAT THE PARENT SHOULD BE PAUSED IS NEW NEWS!
2427
2428    for (unsigned i=0; i<childProc->threads.size(); i++) {
2429      tTimer *localTimerPtr = (tTimer *) theTable.index2LocalAddr(1,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2430      const tTimer *srcTimerPtr = (const tTimer *) childProc->getParent()->getTable().index2LocalAddr(1,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2431
2432      localTimerPtr->total = 0;
2433      localTimerPtr->counter = srcTimerPtr->counter;
2434      localTimerPtr->id.id   = theSampleId;
2435      localTimerPtr->protector1 = srcTimerPtr->protector1;
2436      localTimerPtr->protector2 = srcTimerPtr->protector2;
2437
2438      if (localTimerPtr->counter == 0)
2439         // inactive timer...this is the easy case to copy
2440         localTimerPtr->start = 0; // undefined, really
2441      else
2442         // active timer...don't copy the start time from the source...make it 'now'
2443         localTimerPtr->start = getCurrWallTime();
2444    }
2445
2446    // write new HK for this tTimer:
2447    // Note: we don't assert anything about mi->getMId(), because that id has no
2448    // relation to the ids we work with (theSampleId).  In fact, we (the sampling code)
2449    // just don't ever care what mi->getMId() is.
2450    assert(theSampleId >= 0);
2451    assert(midToMiMap.defines(theSampleId));
2452    assert(midToMiMap[theSampleId] == mi);
2453    wallTimerHK iHKValue(theSampleId, mi, 0); // is last param right?
2454       // the mi should differ from the mi of the parent; theSampleId differs too.
2455    theTable.initializeHKAfterForkWallTimer(allocatedIndex, allocatedLevel, iHKValue);
2456
2457    position_=0;
2458 }
2459
2460 dataReqNode *
2461 sampledShmWallTimerReqNode::dup(process *childProc,
2462                                 metricDefinitionNode *mi,
2463                                 int iCounterId,
2464                                 const dictionary_hash<instInstance*,instInstance*> &
2465                                 ) const {
2466    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2467
2468    sampledShmWallTimerReqNode *tmp;
2469    tmp = new sampledShmWallTimerReqNode(*this, childProc, mi, iCounterId, childProc->getParent());
2470       // fork constructor
2471
2472    return tmp;
2473 }
2474
2475 bool sampledShmWallTimerReqNode::insertInstrumentation(process *theProc,
2476                                                        metricDefinitionNode *iMi, bool) {
2477    // Remember inferiorTimerPtr is NULL until this routine gets called.
2478    // WARNING: there will be an assert failure if the applic hasn't yet attached to the
2479    //          shm segment!!!
2480
2481    // initialize the tTimer in the inferior heap
2482    tTimer iValue;
2483    P_memset(&iValue, '\0', sizeof(tTimer));
2484    iValue.id.id = this->theSampleId;
2485
2486    wallTimerHK iHKValue(this->theSampleId, iMi, 0);
2487
2488    superTable &theTable = theProc->getTable();
2489
2490    if (!theTable.allocWallTimer(iValue, iHKValue, this->allocatedIndex, this->allocatedLevel))
2491       return false; // failure
2492
2493    return true;
2494 }
2495
2496 void sampledShmWallTimerReqNode::disable(process *theProc,
2497                                          const vector<unsigVecType> &pointsToCheck) {
2498    // We used to remove the sample id from midToMiMap here but now the caller is
2499    // responsible for that.
2500
2501    superTable &theTable = theProc->getTable();
2502
2503    // Remove from inferior heap; make sure we won't be sampled any more:
2504    vector<unsigned> trampsMaybeUsing;
2505    for (unsigned pointlcv=0; pointlcv < pointsToCheck.size(); pointlcv++)
2506       for (unsigned tramplcv=0; tramplcv < pointsToCheck[pointlcv].size(); tramplcv++)
2507          trampsMaybeUsing += pointsToCheck[pointlcv][tramplcv];
2508
2509    theTable.makePendingFree(1,allocatedIndex,allocatedLevel,trampsMaybeUsing);
2510
2511 #if defined(MT_THREAD)
2512 //NOTE: Not yet implemented for shm sampling! naim 4/23/97
2513 //    pdThread *thr = theProc->threads[0];
2514 //    thr->CTvector->remove(this->theSampleId, this->position_);
2515 //    theProc->updateActiveCT(false,wallTimer);
2516 #endif
2517 }
2518
2519 /* ****************************************************************** */
2520
2521 sampledShmProcTimerReqNode::sampledShmProcTimerReqNode(int iCounterId,
2522                                                      metricDefinitionNode *iMi,
2523                                                      bool computingCost) :
2524                                                      dataReqNode() {
2525    theSampleId = iCounterId;
2526
2527    // The following fields are NULL until insertInstrumentatoin():
2528    allocatedIndex = UINT_MAX;
2529    allocatedLevel = UINT_MAX;
2530
2531    position_=0;
2532
2533    if (!computingCost) {
2534      bool isOk=false;
2535      isOk = insertInstrumentation(iMi->proc(), iMi);
2536      assert(isOk); 
2537    }
2538 }
2539
2540 sampledShmProcTimerReqNode::
2541 sampledShmProcTimerReqNode(const sampledShmProcTimerReqNode &src,
2542                            process *childProc,
2543                            metricDefinitionNode *mi,
2544                            int iCounterId, const process *parentProc) {
2545    // a dup()-like routine; call after a fork()
2546    // Assumes that the "childProc" has been duplicated already
2547
2548    // Note that the index w/in the inferior heap remains the same, so setting the new
2549    // inferiorTimerPtr isn't too hard.  Actually, it's trivial, since other code
2550    // ensures that the new shm segment is placed in exactly the same virtual mem loc
2551    // as the previous one.
2552    //
2553    // Note that the fastInferiorHeap class's fork ctor will have already copied the
2554    // actual data; we need to fill in new meta-data (new houseKeeping entries).
2555
2556    allocatedIndex = src.allocatedIndex;
2557    theSampleId = iCounterId;
2558    assert(theSampleId != src.theSampleId);
2559
2560    superTable &theTable = childProc->getTable();
2561
2562    // since the new shm seg is placed in exactly the same memory location as
2563    // the old one, nothing here should change.
2564    const superTable &theParentTable = parentProc->getTable();
2565    assert(theTable.index2InferiorAddr(2,childProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel)==theParentTable.index2InferiorAddr(2,parentProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel));
2566
2567    // Write new raw value:
2568    // we set localTimerPtr as follows: protector1 and procetor2 should be copied from
2569    //    src. total should be reset to 0.  start should be set to now if active else 0.
2570    //    counter should be copied from the source.
2571    // NOTE: SINCE WE COPY FROM THE SOURCE, IT'S IMPORTANT THAT ON A FORK, BOTH THE
2572    //       PARENT AND CHILD ARE PAUSED UNTIL WE COPY THINGS OVER.  THAT THE CHILD IS
2573    //       PAUSED IS NOTHING NEW; THAT THE PARENT SHOULD BE PAUSED IS NEW NEWS!
2574
2575    for (unsigned i=0; i<childProc->threads.size(); i++) {
2576      tTimer *localTimerPtr = (tTimer *) theTable.index2LocalAddr(2,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2577      const tTimer *srcTimerPtr = (const tTimer *) childProc->getParent()->getTable().index2LocalAddr(2,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2578
2579      localTimerPtr->total = 0;
2580      localTimerPtr->counter = srcTimerPtr->counter;
2581      localTimerPtr->id.id   = theSampleId;
2582      localTimerPtr->protector1 = srcTimerPtr->protector1;
2583      localTimerPtr->protector2 = srcTimerPtr->protector2;
2584
2585      if (localTimerPtr->counter == 0)
2586         // inactive timer...this is the easy case to copy
2587         localTimerPtr->start = 0; // undefined, really
2588      else
2589         // active timer...don't copy the start time from the source...make it 'now'
2590         localTimerPtr->start = childProc->getInferiorProcessCPUtime();
2591    }
2592
2593    // Write new HK for this tTimer:
2594    // Note: we don't assert anything about mi->getMId(), because that id has no
2595    // relation to the ids we work with (theSampleId).  In fact, we (the sampling code)
2596    // just don't ever care what mi->getMId() is.
2597    assert(theSampleId >= 0);
2598    assert(midToMiMap.defines(theSampleId));
2599    assert(midToMiMap[theSampleId] == mi);
2600    processTimerHK iHKValue(theSampleId, mi, 0); // is last param right?
2601       // the mi differs from the mi of the parent; theSampleId differs too.
2602    theTable.initializeHKAfterForkProcTimer(allocatedIndex, allocatedLevel, iHKValue);
2603
2604    position_=0;
2605 }
2606
2607 dataReqNode *
2608 sampledShmProcTimerReqNode::dup(process *childProc,
2609                                 metricDefinitionNode *mi,
2610                                 int iCounterId,
2611                                 const dictionary_hash<instInstance*,instInstance*> &
2612                                 ) const {
2613    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2614
2615    sampledShmProcTimerReqNode *tmp;
2616    tmp = new sampledShmProcTimerReqNode(*this, childProc, mi, iCounterId, childProc->getParent());
2617       // fork constructor
2618
2619    return tmp;
2620 }
2621
2622 bool sampledShmProcTimerReqNode::insertInstrumentation(process *theProc,
2623                                                        metricDefinitionNode *iMi, bool) {
2624    // Remember inferiorTimerPtr is NULL until this routine gets called.
2625    // WARNING: there will be an assert failure if the applic hasn't yet attached to the
2626    //          shm segment!!!
2627
2628    // initialize the tTimer in the inferior heap
2629    tTimer iValue;
2630    P_memset(&iValue, '\0', sizeof(tTimer));
2631    iValue.id.id = this->theSampleId;
2632
2633    processTimerHK iHKValue(this->theSampleId, iMi, 0);
2634
2635    superTable &theTable = theProc->getTable();
2636
2637    if (!theTable.allocProcTimer(iValue, iHKValue, this->allocatedIndex,this->allocatedLevel))
2638       return false; // failure
2639
2640    return true;
2641 }
2642
2643 void sampledShmProcTimerReqNode::disable(process *theProc,
2644                                          const vector<unsigVecType> &pointsToCheck) {
2645    // We used to remove the sample id from midToMiMap here but now the caller is
2646    // responsible for that.
2647
2648    superTable &theTable = theProc->getTable();
2649
2650    // Remove from inferior heap; make sure we won't be sampled any more:
2651    vector<unsigned> trampsMaybeUsing;
2652    for (unsigned pointlcv=0; pointlcv < pointsToCheck.size(); pointlcv++)
2653       for (unsigned tramplcv=0; tramplcv < pointsToCheck[pointlcv].size(); tramplcv++)
2654          trampsMaybeUsing += pointsToCheck[pointlcv][tramplcv];
2655
2656    theTable.makePendingFree(2,allocatedIndex,allocatedLevel,trampsMaybeUsing);
2657
2658 #if defined(MT_THREAD)
2659 //NOTE: Not yet implemented for shm sampling! naim 4/23/97
2660 //   pdThread *thr = theProc->threads[0];
2661 //   thr->CTvector->remove(this->theSampleId, this->position_);
2662 //   theProc->updateActiveCT(false,procTimer);
2663 #endif
2664 }
2665 #endif
2666
2667 /* **************************** */
2668
2669 void reportInternalMetrics(bool force) 
2670 {
2671     if (isApplicationPaused())
2672        return; // we don't sample when paused (is this right?)
2673
2674     static timeStamp end=0.0;
2675
2676     // see if we have a sample to establish time base.
2677     if (!firstRecordTime) {
2678        //cerr << "reportInternalMetrics: no because firstRecordTime==0" << endl;
2679        return;
2680     }
2681
2682     if (end==0.0)
2683         end = (timeStamp)firstRecordTime/MILLION;
2684
2685     const timeStamp now = getCurrentTime(false);
2686
2687     //  check if it is time for a sample
2688     if (!force && now < end + samplingRate)  {
2689 //        cerr << "reportInternalMetrics: no because now < end + samplingRate (end=" << end << "; samplingRate=" << samplingRate << "; now=" << now << ")" << endl;
2690 //      cerr << "difference is " << (end+samplingRate-now) << endl;
2691         return;
2692     }
2693
2694     timeStamp start = end;
2695     end = now;
2696
2697     // TODO -- clean me up, please
2698
2699     unsigned max1=0;
2700     unsigned max2=0;
2701     unsigned max3=0;
2702     for (unsigned u1 = 0; u1 < processVec.size(); u1++) {
2703       if (processVec[u1]->numOfActCounters_is > max1)
2704         max1=processVec[u1]->numOfActCounters_is;
2705       if (processVec[u1]->numOfActProcTimers_is > max2)
2706         max2=processVec[u1]->numOfActProcTimers_is;
2707       if (processVec[u1]->numOfActWallTimers_is > max3)
2708         max3=processVec[u1]->numOfActWallTimers_is;
2709     }
2710     numOfActCounters_all=max1;
2711     numOfActProcTimers_all=max2;
2712     numOfActWallTimers_all=max3;
2713
2714     unsigned ai_size = internalMetric::allInternalMetrics.size();
2715     for (unsigned u2=0; u2<ai_size; u2++) {
2716       internalMetric *theIMetric = internalMetric::allInternalMetrics[u2];
2717       // Loop thru all enabled instances of this internal metric...
2718
2719       for (unsigned v=0; v < theIMetric->num_enabled_instances(); v++) {
2720         internalMetric::eachInstance &theInstance = theIMetric->getEnabledInstance(v);
2721            // not "const" since bumpCumulativeValueBy() may be called
2722
2723         sampleValue value = (sampleValue) 0;
2724         if (theIMetric->name() == "active_processes") {
2725           //value = (end - start) * activeProcesses;
2726           value = (end - start) * theInstance.getValue();
2727         } else if (theIMetric->name() == "bucket_width") {
2728           //value = (end - start)* theInstance.getValue();
2729           // I would prefer to use (end-start) * theInstance.getValue(); however,
2730           // we've had some problems getting setValue() called in time, thus
2731           // leaving us with getValues() of 0 sometimes.  See longer comment in dynrpc.C --ari
2732           extern float currSamplingRate;
2733           value = (end - start) * currSamplingRate;
2734         } else if (theIMetric->name() == "number_of_cpus") {
2735           value = (end - start) * numberOfCPUs;
2736         } else if (theIMetric->name() == "total_CT") {
2737           value = (end - start) * internalMetricCounterId;
2738           assert(value>=0.0);
2739         } else if (theIMetric->name() == "numOfActCounters") {
2740           value = (end - start) * numOfActCounters_all;
2741           assert(value>=0.0);
2742         } else if (theIMetric->name() == "numOfActProcTimers") {
2743           value = (end - start) * numOfActProcTimers_all;
2744           assert(value>=0.0);
2745         } else if (theIMetric->name() == "numOfActWallTimers") {
2746           value = (end - start) * numOfActWallTimers_all;
2747           assert(value>=0.0);
2748         } else if (theIMetric->name() == "active_CT") {
2749           value = (end - start) * (numOfActCounters_all+numOfActProcTimers_all+numOfActWallTimers_all);
2750           assert(value>=0.0);
2751         } else if (theIMetric->name() == "infHeapMemAvailable") {
2752           value = (end - start) * inferiorMemAvailable;
2753           assert(value>=0.0);
2754         } else if (theIMetric->style() == EventCounter) {
2755           value = theInstance.getValue();
2756           // assert((value + 0.0001)  >= imp->cumulativeValue);
2757           value -= theInstance.getCumulativeValue();
2758           theInstance.bumpCumulativeValueBy(value);
2759         } else if (theIMetric->style() == SampledFunction) {
2760           value = theInstance.getValue();
2761         }
2762
2763         theInstance.report(start, end, value);
2764            // calls metricDefinitionNode->forwardSimpleValue()
2765       }
2766     }
2767 }
2768
2769 void disableAllInternalMetrics() {
2770     for (unsigned u=0; u < internalMetric::allInternalMetrics.size(); u++) {
2771       internalMetric *theIMetric = internalMetric::allInternalMetrics[u];
2772
2773       // Now loop thru all the enabled instances of this internal metric...
2774       while (theIMetric->num_enabled_instances() > 0) {
2775         internalMetric::eachInstance &theInstance = theIMetric->getEnabledInstance(0);
2776         tp->endOfDataCollection(theInstance.getMId());
2777         theIMetric->disableInstance(0);
2778       }
2779     }  
2780 }
2781
2782 #ifdef SHM_SAMPLING
2783
2784 unsigned sampledShmIntCounterReqNode::getInferiorPtr(process *proc) const {
2785     // counterPtr could be NULL if we are building AstNodes just to compute
2786     // the cost - naim 2/18/97
2787     // NOTE:
2788     // this routine will dissapear because we can't compute the address
2789     // of the counter/timer without knowing the thread id - naim 3/17/97
2790     //
2791     if (allocatedIndex == UINT_MAX || allocatedLevel == UINT_MAX) return(0);
2792     assert(proc != NULL);
2793     superTable &theTable = proc->getTable();
2794     // we assume there is only one thread
2795     return((unsigned) theTable.index2InferiorAddr(0,0,allocatedIndex,allocatedLevel));
2796 }
2797
2798 unsigned sampledShmWallTimerReqNode::getInferiorPtr(process *proc) const {
2799     // counterPtr could be NULL if we are building AstNodes just to compute
2800     // the cost - naim 2/18/97
2801     // NOTE:
2802     // this routine will dissapear because we can't compute the address
2803     // of the counter/timer without knowing the thread id - naim 3/17/97
2804     //
2805     if (allocatedIndex == UINT_MAX || allocatedLevel == UINT_MAX) return(0);
2806     assert(proc != NULL);
2807     superTable &theTable = proc->getTable();
2808     // we assume there is only one thread
2809     return((unsigned) theTable.index2InferiorAddr(1,0,allocatedIndex,allocatedLevel));
2810 }
2811
2812 unsigned sampledShmProcTimerReqNode::getInferiorPtr(process *proc) const {
2813     // counterPtr could be NULL if we are building AstNodes just to compute
2814     // the cost - naim 2/18/97
2815     // NOTE:
2816     // this routine will dissapear because we can't compute the address
2817     // of the counter/timer without knowing the thread id - naim 3/17/97
2818     //
2819     if (allocatedIndex == UINT_MAX || allocatedLevel == UINT_MAX) return(0);
2820     assert(proc != NULL);
2821     superTable &theTable = proc->getTable();
2822     // we assume there is only one thread
2823     return((unsigned) theTable.index2InferiorAddr(2,0,allocatedIndex,allocatedLevel));
2824 }
2825
2826 #endif