Minor change to compile on nt - naim
[dyninst.git] / paradynd / src / metricFocusNode.C
1 /*
2  * Copyright (c) 1996 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 #include "util/h/headers.h"
43 #include <limits.h>
44 #include <assert.h>
45
46 #include "rtinst/h/rtinst.h"
47 #include "rtinst/h/trace.h"
48 #include "util/h/aggregateSample.h"
49 #include "dyninstAPI/src/symtab.h"
50 #include "dyninstAPI/src/pdThread.h"
51 #include "dyninstAPI/src/process.h"
52 #include "dyninstAPI/src/inst.h"
53 #include "dyninstAPI/src/instP.h"
54 #include "dyninstAPI/src/dyninstP.h"
55 #include "dyninstAPI/src/ast.h"
56 #include "dyninstAPI/src/util.h"
57 #include "paradynd/src/comm.h"
58 #include "paradynd/src/internalMetrics.h"
59 #include "paradynd/src/init.h"
60 #include "paradynd/src/perfStream.h"
61 #include "paradynd/src/main.h"
62 #include "dyninstAPI/src/stats.h"
63 #include "paradynd/src/dynrpc.h"
64 #include "paradynd/src/mdld.h"
65 #include "util/h/Timer.h"
66 #include "paradynd/src/showerror.h"
67 #include "paradynd/src/costmetrics.h"
68 #include "paradynd/src/metric.h"
69 #include "util/h/debugOstream.h"
70
71 // The following vrbles were defined in process.C:
72 extern debug_ostream attach_cerr;
73 extern debug_ostream inferiorrpc_cerr;
74 extern debug_ostream shmsample_cerr;
75 extern debug_ostream forkexec_cerr;
76 extern debug_ostream metric_cerr;
77
78 extern unsigned inferiorMemAvailable;
79 extern vector<unsigned> getAllTrampsAtPoint(instInstance *instance);
80 static unsigned internalMetricCounterId = 0;
81
82 static unsigned numOfActCounters_all=0;
83 static unsigned numOfActProcTimers_all=0;
84 static unsigned numOfActWallTimers_all=0;
85
86 void flush_batch_buffer();
87 void batchSampleData(int mid, double startTimeStamp, double endTimeStamp,
88                      double value, unsigned val_weight, bool internal_metric);
89
90 double currentPredictedCost = 0.0;
91
92 dictionary_hash <unsigned, metricDefinitionNode*> midToMiMap(uiHash);
93    // maps low-level counter-ids to metricDefinitionNodes
94
95 unsigned mdnHash(const metricDefinitionNode *&mdn) {
96   return ((unsigned)mdn) >> 2; // assume all addrs are 4-byte aligned
97 //  return ((unsigned) mdn);
98 }
99
100 unsigned componentMdnPtrHash(metricDefinitionNode * const &ptr) {
101    // maybe assert that "ptr" isn't for an aggregate mi
102    return string::hash(ptr->getFullName());
103 }
104
105
106 dictionary_hash<unsigned, metricDefinitionNode*> allMIs(uiHash);
107 dictionary_hash<string, metricDefinitionNode*> allMIComponents(string::hash);
108 vector<internalMetric*> internalMetric::allInternalMetrics;
109
110 // used to indicate the mi is no longer used.
111 #define DELETED_MI 1
112 #define MILLION 1000000.0
113
114 bool mdl_internal_metric_data(const string& metric_name, mdl_inst_data& result) {
115   unsigned size = internalMetric::allInternalMetrics.size();
116   for (unsigned u=0; u<size; u++) {
117     internalMetric *theIMetric = internalMetric::allInternalMetrics[u];
118     if (theIMetric->name() == metric_name) {
119       result.aggregate = theIMetric->aggregate();
120       result.style = theIMetric->style();
121       return true;
122     }
123   }
124
125   for (unsigned u2=0; u2< costMetric::allCostMetrics.size(); u2++) {
126     if (costMetric::allCostMetrics[u2]->name() == metric_name) {
127       result.aggregate = costMetric::allCostMetrics[u2]->aggregate();
128       result.style = costMetric::allCostMetrics[u2]->style();
129       return true;
130     }
131   }
132
133   return (mdl_metric_data(metric_name, result));
134 }
135
136 // for non-aggregate metrics
137 metricDefinitionNode::metricDefinitionNode(process *p, const string& met_name, 
138                                    const vector< vector<string> >& foc,
139                                    const vector< vector<string> >& component_foc,
140                                    const string& component_flat_name, int agg_style)
141 : aggregate_(false), 
142   aggOp(agg_style), // CM5 metrics need aggOp to be set
143   inserted_(false), installed_(false), met_(met_name),
144   focus_(foc), component_focus(component_foc),
145   flat_name_(component_flat_name),
146   aggSample(0),
147   cumulativeValue(0.0),
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) {
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   if (allMIComponents.defines(flat_name_)) {
676     allMIComponents.undef(flat_name_);
677   }
678
679   assert(aggregators.size() == samples.size());
680
681   for (unsigned u = 0; u < aggregators.size() && u < samples.size(); u++) {
682     aggregators[u]->aggSample.removeComponent(samples[u]);
683     aggregators[u]->removeFromAggregate(this, 0); 
684   }
685 }
686
687
688 // Called when a process exits, to remove the component associated to proc 
689 // from all metric instances.  (If, after an exec, we never want to carry over
690 // mi's from the pre-exec, then this routine will work there, too.  But we try to
691 // carry over mi's whenever appropriate.)
692 // Remove the aggregate metric instances that don't have any components left
693 void removeFromMetricInstances(process *proc) {
694     // Loop through all of the _component_ mi's; for each with component process
695     // of "proc", remove the component mi from its aggregate mi.
696     // Note: imho, there should be a *per-process* vector of mi-components.
697
698     vector<metricDefinitionNode *> MIs = allMIComponents.values();
699     for (unsigned j = 0; j < MIs.size(); j++) {
700       if (MIs[j]->proc() == proc)
701         MIs[j]->removeThisInstance();
702     }
703     costMetric::removeProcessFromAll(proc); // what about internal metrics?
704 }
705
706 /* *************************************************************************** */
707
708 // obligatory definition of static member vrble:
709 int metricDefinitionNode::counterId=0;
710
711 dataReqNode *metricDefinitionNode::addSampledIntCounter(int initialValue,
712                                                         bool computingCost,
713                                                         bool doNotSample) 
714 {
715    dataReqNode *result=NULL;
716
717 #ifdef SHM_SAMPLING
718    // shared memory sampling of a reported intCounter
719    result = new sampledShmIntCounterReqNode(initialValue,
720                                             metricDefinitionNode::counterId,
721                                             this, computingCost, doNotSample);
722       // implicit conversion to base class
723 #else
724    // non-shared-memory sampling of a reported intCounter
725    result = new sampledIntCounterReqNode(initialValue,
726                                          metricDefinitionNode::counterId,
727                                          this, computingCost);
728       // implicit conversion to base class
729 #endif
730
731    assert(result);
732    
733    metricDefinitionNode::counterId++;
734
735    internalMetricCounterId = metricDefinitionNode::counterId;
736
737    dataRequests += result;
738    return result;
739 }
740
741 dataReqNode *metricDefinitionNode::addUnSampledIntCounter(int initialValue,
742                                                           bool computingCost) {
743    // sampling of a non-reported intCounter (probably just a predicate)
744    // NOTE: In the future, we should probably put un-sampled intcounters
745    // into shared-memory when SHM_SAMPLING is defined.  After all, the shared
746    // memory heap is faster.
747    dataReqNode *result = new nonSampledIntCounterReqNode
748                          (initialValue, metricDefinitionNode::counterId, 
749                           this, computingCost);
750       // implicit conversion to base class
751    assert(result);
752
753    metricDefinitionNode::counterId++;
754
755    internalMetricCounterId = metricDefinitionNode::counterId;
756
757    dataRequests += result;
758    return result;
759 };
760
761 dataReqNode *metricDefinitionNode::addWallTimer(bool computingCost) {
762    dataReqNode *result = NULL;
763
764 #ifdef SHM_SAMPLING
765    result = new sampledShmWallTimerReqNode(metricDefinitionNode::counterId, this, computingCost);
766       // implicit conversion to base class
767 #else
768    result = new sampledTimerReqNode(wallTime, metricDefinitionNode::counterId, this, computingCost);
769       // implicit conversion to base class
770 #endif
771
772    assert(result);
773
774    metricDefinitionNode::counterId++;
775
776    internalMetricCounterId = metricDefinitionNode::counterId;
777
778    dataRequests += result;
779    return result;
780 }
781
782 dataReqNode *metricDefinitionNode::addProcessTimer(bool computingCost) {
783    dataReqNode *result = NULL;
784
785 #ifdef SHM_SAMPLING
786    result = new sampledShmProcTimerReqNode(metricDefinitionNode::counterId, this, computingCost);
787       // implicit conversion to base class
788 #else
789    result = new sampledTimerReqNode(processTime, metricDefinitionNode::counterId, this, computingCost);
790       // implicit conversion to base class
791 #endif
792
793    assert(result);
794
795    metricDefinitionNode::counterId++;
796
797    internalMetricCounterId = metricDefinitionNode::counterId;
798
799    dataRequests += result;
800    return result;
801 };
802
803 /* *************************************************************************** */
804
805 // called when a process forks (by handleFork(), below). "this" is a (component)
806 // mi in the parent process. Duplicate it for the child, with appropriate
807 // changes (i.e. the pid of the component focus name differs), and return the newly
808 // created child mi.  "map" maps all instInstance's of the parent to those copied into
809 // the child.
810 // 
811 // Note how beautifully everything falls into place.  Consider the case of alarm
812 // sampling with cpu/whole program.  Then comes the fork.  The parent process has
813 // (0) a tTimer structure allocated in a specific location in the inferior heap,
814 // (1) instrumentation @ main to call startTimer on that ptr, (2) instrumentation in
815 // DYNINSTsampleValues() to call DYNINSTreportTimer on that ptr.
816 // The child process of fork will have ALL of these things in the exact same locations,
817 // which is correct.  We want the timer to be located in the same spot; we want
818 // DYNINSTreportTimer to be called on the same pointer; and main() hasn't moved.
819 //
820 // So there's not much to do here.  We create a new component mi (with same flat name
821 // as in the parent, except for a different pid), and call "forkProcess" for all
822 // dataReqNodes and instReqNodes, none of which have to do anything titanic.
823
824 metricDefinitionNode *metricDefinitionNode::forkProcess(process *child,
825                         const dictionary_hash<instInstance*,instInstance*> &map) const {
826     // The "focus_" member vrble stays the same, because it was always for the
827     // metric as a whole, and not for some component.
828     //
829     // But two things must change, because they were component-specific (and the
830     // component has changed processes):
831     // (1) the flat name
832     // (2) the component focus (not to be confused with plain focus_)
833     //
834     // For example, instead of
835     // "/Code/foo.c/myfunc, /Process/100, ...", we should have
836     // "/Code/foo.c/myfunc, /Process/101, ...", because the pid of the child
837     // differs from that of the parent.
838
839     // The resource structure of a given process is found in the "rid"
840     // field of class process.
841     const resource *parentResource = child->getParent()->rid;
842     const string &parentPartName = parentResource->part_name();
843
844     const resource *childResource = child->rid;
845     const string &childPartName = childResource->part_name();
846
847     vector< vector<string> > newComponentFocus = this->component_focus;
848        // we'll change the process, but not the machine name.
849     bool foundProcess = false;
850
851     for (unsigned hier=0; hier < component_focus.size(); hier++) {
852        if (component_focus[hier][0] == "Process") {
853           foundProcess = true;
854           assert(component_focus[hier].size() == 2);
855              // since a component focus is by definition specific to some process
856
857           assert(component_focus[hier][1] == parentPartName);
858
859           // change the process:
860           newComponentFocus[hier][1] = childPartName;
861           break;
862        }
863     }
864     assert(foundProcess);
865     
866     string newComponentFlatName = metricAndCanonFocus2FlatName(met_, newComponentFocus);
867
868     metricDefinitionNode *mi =
869         new metricDefinitionNode(child,
870                          met_, // metric name doesn't change
871                          focus_, // focus doesn't change (tho component focus will)
872                          newComponentFocus, // this is a change
873                          newComponentFlatName, // this is a change
874                          aggOp // no change
875                          );
876     assert(mi);
877
878     metricDefinitionNode::counterId++;
879
880     forkexec_cerr << "metricDefinitionNode::forkProcess -- component flat name for parent is " << flat_name_ << "; for child is " << mi->flat_name_ << endl;
881
882     internalMetricCounterId = metricDefinitionNode::counterId;
883
884     assert(!allMIComponents.defines(newComponentFlatName));
885     allMIComponents[newComponentFlatName] = mi;
886
887     // Duplicate the dataReqNodes:
888     for (unsigned u1 = 0; u1 < dataRequests.size(); u1++) {
889        // must add to midToMiMap[] before dup() to avoid some assert fails
890        const int newCounterId = metricDefinitionNode::counterId++;
891           // no relation to mi->getMId();
892        forkexec_cerr << "forked dataReqNode going into midToMiMap with id " << newCounterId << endl;
893        assert(!midToMiMap.defines(newCounterId));
894        midToMiMap[newCounterId] = mi;
895        
896        dataReqNode *newNode = dataRequests[u1]->dup(child, mi, newCounterId, map);
897          // remember, dup() is a virtual fn, so the right dup() and hence the
898          // right fork-ctor is called.
899        assert(newNode);
900
901        mi->dataRequests += newNode;
902     }
903
904     // Duplicate the instReqNodes:
905     for (unsigned u2 = 0; u2 < instRequests.size(); u2++) {
906       mi->instRequests += instReqNode::forkProcess(instRequests[u2], map);
907     }
908
909     mi->inserted_ = true;
910
911     return mi;
912 }
913
914 bool metricDefinitionNode::unFork(dictionary_hash<instInstance*, instInstance*> &map,
915                                   bool unForkInstRequests,
916                                   bool unForkDataRequests) {
917    // see below handleFork() for explanation of why this routine is needed.
918    // "this" is a component mi for the parent process; we need to remove copied
919    // instrumentation from the _child_ process.
920    // Returns true iff the instrumentation was removed in the child (would be false
921    // if it's not safe to remove the instrumentation in the child because it was
922    // active.)
923
924    // "map" maps instInstances from the parent process to instInstances in the child
925    // process.
926
927    // We loop thru the instReqNodes of the parent process, unforking each.
928    // In addition, we need to unfork the dataReqNodes, because the alarm-sampled
929    // ones instrument DYNINSTsampleValues.
930
931    bool result = true;
932
933    if (unForkInstRequests)
934       for (unsigned lcv=0; lcv < instRequests.size(); lcv++)
935          if (!instRequests[lcv].unFork(map))
936             result = false; // failure
937
938    if (unForkDataRequests)
939       for (unsigned lcv=0; lcv < dataRequests.size(); lcv++)
940          if (!dataRequests[lcv]->unFork(map))
941             result = false; // failure
942
943    return result;
944 }
945
946
947 // called by forkProcess of context.C, just after the fork-constructor was
948 // called for the child process.
949 void metricDefinitionNode::handleFork(const process *parent, process *child,
950                               dictionary_hash<instInstance*,instInstance*> &map) {
951    // "map" defines a mapping from all instInstance's of the parent process to
952    // the copied one in the child process.  Some of the child process's ones may
953    // get fried by this routine, as it detects that instrumentation has been copied
954    // (by the fork syscall, which we have no control over) which doesn't belong in
955    // the child process and therefore gets deleted manually.
956   
957    // Remember that a given component can be shared by multiple aggregator-mi's,
958    // so be careful about duplicating a component twice.  Since we loop through
959    // component mi's instead of aggregate mi's, it's no problem.  Note that it's
960    // possible that only a subset of a component-mi's aggregators should get the newly
961    // created child component mi.
962
963    vector<metricDefinitionNode *> allComponents = allMIComponents.values();
964    for (unsigned complcv=0; complcv < allComponents.size(); complcv++) {
965       metricDefinitionNode *comp = allComponents[complcv];
966
967       // duplicate the component (create a new one) if it belongs in the
968       // child process.  It belongs if any of its aggregate mi's should be
969       // propagated to the child process.  An aggregate mi should be propagated
970       // if it wasn't refined to some process.
971
972       bool shouldBePropagated = false; // so far
973       bool shouldBeUnforkedIfNotPropagated = false; // so far
974       assert(comp->aggregators.size() > 0);
975       for (unsigned agglcv1=0; agglcv1 < comp->aggregators.size(); agglcv1++) {
976          metricDefinitionNode *aggMI = comp->aggregators[agglcv1];
977
978          if (aggMI->focus_[resource::process].size() == 1) {
979             // wasn't specific to any process
980             shouldBeUnforkedIfNotPropagated = false; // we'll definitely be using it
981             shouldBePropagated = true;
982             break;
983          }
984          else if (comp->proc() == parent)
985             // was specific to parent process, so fork() copied it into the child,
986             // unless it was an internal or cost metric, in which case there was nothing
987             // for fork to copy.
988             if (!internalMetric::isInternalMetric(aggMI->getMetName()) &&
989                 !costMetric::isCostMetric(aggMI->getMetName()))
990                shouldBeUnforkedIfNotPropagated = true;
991          else
992             // was specific to other process, so nothing is in the child for it yet
993             ;
994       }
995
996       if (!shouldBePropagated && shouldBeUnforkedIfNotPropagated) {
997          // this component mi isn't gonna be propagated to the child process, but
998          // the fork syscall left some residue in the child.  Delete that residue now.
999          assert(comp->proc() == parent);
1000          comp->unFork(map, true, true); // also modifies 'map' to remove items
1001       }
1002
1003       if (!shouldBePropagated)
1004          continue;
1005
1006       // Okay, it's time to propagate this component mi to the subset of its aggregate
1007       // mi's which weren't refined to a specific process.  If we've gotten to this
1008       // point, then there _is_ at least one such aggregate.
1009       assert(shouldBePropagated);
1010       metricDefinitionNode *newComp = comp->forkProcess(child, map);
1011          // copies instr (well, fork() does this for us), allocs ctr/timer space,
1012          // initializes.  Basically, copies dataReqNode's and instReqNode's.
1013
1014       bool foundAgg = false;
1015       for (unsigned agglcv2=0; agglcv2 < comp->aggregators.size(); agglcv2++) {
1016          metricDefinitionNode *aggMI = comp->aggregators[agglcv2];
1017          if (aggMI->focus_[resource::process].size() == 1) {
1018             // this aggregate mi wasn't specific to any process, so it gets the new
1019             // child component.
1020             aggMI->components += newComp;
1021             newComp->aggregators += aggMI;
1022             newComp->samples     += aggMI->aggSample.newComponent();
1023             foundAgg = true;
1024          }
1025       }
1026       assert(foundAgg);
1027    }
1028 }
1029
1030 bool metricDefinitionNode::anythingToManuallyTrigger() const {
1031    if (aggregate_) {
1032       for (unsigned i=0; i < components.size(); i++)
1033          if (components[i]->anythingToManuallyTrigger())
1034             return true;
1035       return false;
1036    }
1037    else {
1038       for (unsigned i=0; i < instRequests.size(); i++)
1039          if (instRequests[i].anythingToManuallyTrigger())
1040             return true;
1041       return false;
1042    }
1043
1044    assert(false);
1045 }
1046
1047 void metricDefinitionNode::manuallyTrigger(int parentMId) {
1048    assert(anythingToManuallyTrigger());
1049
1050    if (aggregate_) {
1051       for (unsigned i=0; i < components.size(); i++)
1052          if (components[i]->anythingToManuallyTrigger())
1053            components[i]->manuallyTrigger(parentMId);
1054    }
1055    else {
1056       for (unsigned i=0; i < instRequests.size(); i++)
1057         if (instRequests[i].anythingToManuallyTrigger()) {
1058             if (!instRequests[i].triggerNow(proc(),parentMId)) {
1059                cerr << "manual trigger failed for an inst request" << endl;
1060             }
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(id);
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         for (unsigned u=0; u<components.size(); u++) {
1377           metricDefinitionNode *m = components[u];
1378           unsigned aggr_size = m->aggregators.size();
1379           assert(aggr_size == m->samples.size());
1380           for (unsigned u1=0; u1 < aggr_size; u1++) {
1381             if (m->aggregators[u1] == this) {
1382               m->aggregators[u1] = m->aggregators[aggr_size-1];
1383               m->aggregators.resize(aggr_size-1);
1384               m->samples[u1] = m->samples[aggr_size-1];
1385               m->samples.resize(aggr_size-1);
1386               break;
1387             }
1388           }
1389           if (aggr_size!=0) {
1390             assert(m->aggregators.size() == aggr_size-1);
1391           }
1392           // disable component only if it is not being shared
1393           if (aggr_size == 1) {
1394             m->disable();
1395           }
1396         }
1397
1398     } else {
1399       vector<unsigVecType> pointsToCheck;
1400       for (unsigned u1=0; u1<instRequests.size(); u1++) {
1401         unsigVecType pointsForThisRequest = 
1402             getAllTrampsAtPoint(instRequests[u1].getInstance());
1403         pointsToCheck += pointsForThisRequest;
1404
1405         instRequests[u1].disable(pointsForThisRequest); // calls deleteInst()
1406       }
1407
1408       for (unsigned u=0; u<dataRequests.size(); u++) {
1409         unsigned mid = dataRequests[u]->getSampleId();
1410         dataRequests[u]->disable(proc_, pointsToCheck); // deinstrument
1411         assert(midToMiMap.defines(mid));
1412         midToMiMap.undef(mid);
1413       }
1414     }
1415 }
1416
1417 void metricDefinitionNode::removeComponent(metricDefinitionNode *comp) {
1418     assert(!comp->aggregate_);
1419     unsigned aggr_size = comp->aggregators.size();
1420     unsigned found = aggr_size;
1421
1422     if (aggr_size == 0) {
1423       delete comp;
1424       return;
1425     }
1426
1427     // component has more than one aggregator. Remove this from list of aggregators
1428     for (unsigned u = 0; u < aggr_size; u++) {
1429       if (comp->aggregators[u] == this) {
1430         found = u;
1431         break;
1432       }
1433     }
1434     if (found == aggr_size)
1435      return;
1436     assert(found < aggr_size);
1437     assert(aggr_size == comp->samples.size());
1438     comp->aggregators[found] = comp->aggregators[aggr_size-1];
1439     comp->aggregators.resize(aggr_size-1);
1440     comp->samples[found] = comp->samples[aggr_size-1];
1441     comp->samples.resize(aggr_size-1);
1442
1443     if (aggr_size == 1) {
1444       delete comp;
1445       return;
1446     }
1447
1448 }
1449
1450 metricDefinitionNode::~metricDefinitionNode()
1451 {
1452     if (aggregate_) {
1453         /* delete components of aggregate metrics */
1454         unsigned c_size = components.size();
1455         for (unsigned u=0; u<c_size; u++)
1456           removeComponent(components[u]);
1457           //delete components[u];
1458         components.resize(0);
1459     } else {
1460       allMIComponents.undef(flat_name_);
1461       for (unsigned u=0; u<dataRequests.size(); u++) {
1462         delete dataRequests[u];
1463       }
1464       dataRequests.resize(0);
1465     }
1466 }
1467
1468 void metricDefinitionNode::cleanup_drn()
1469 {
1470       // we assume that it is safe to delete a dataReqNode at this point, 
1471       // otherwise, we would need to do something similar as in the disable
1472       // method for metricDefinitionNode - naim
1473       vector<unsigVecType> pointsToCheck;
1474       for (unsigned u=0; u<dataRequests.size(); u++) {
1475         dataRequests[u]->disable(proc_, pointsToCheck); // deinstrument
1476       }
1477 }
1478
1479 // NOTE: This stuff (flush_batch_buffer() and batchSampleData()) belongs
1480 //       in perfStream.C; this is an inappropriate file.
1481
1482 //////////////////////////////////////////////////////////////////////////////
1483 // Buffer the samples before we actually send it                            //
1484 //      Send it when the buffers are full                                   //
1485 //      or, send it when the last sample in the interval has arrived.       //
1486 //////////////////////////////////////////////////////////////////////////////
1487
1488 const unsigned SAMPLE_BUFFER_SIZE = (1*1024)/sizeof(T_dyninstRPC::batch_buffer_entry);
1489 bool BURST_HAS_COMPLETED = false;
1490    // set to true after a burst (after a processTraceStream(), or sampleNodes for
1491    // the CM5), which will force the buffer to be flushed before it fills up
1492    // (if not, we'd have bad response time)
1493
1494 vector<T_dyninstRPC::batch_buffer_entry> theBatchBuffer (SAMPLE_BUFFER_SIZE);
1495 unsigned int batch_buffer_next=0;
1496
1497 // The following routines (flush_batch_buffer() and batchSampleData() are
1498 // in an inappropriate src file...move somewhere more appropriate)
1499 void flush_batch_buffer() {
1500    // don't need to flush if the batch had no data (this does happen; see
1501    // perfStream.C)
1502    if (batch_buffer_next == 0)
1503       return;
1504
1505    // alloc buffer of the exact size to make communication
1506    // more efficient.  Why don't we send theBatchBuffer with a count?
1507    // This would work but would always (in the igen call) copy the entire
1508    // vector.  This solution has the downside of calling new but is not too bad
1509    // and is clean.
1510    vector<T_dyninstRPC::batch_buffer_entry> copyBatchBuffer(batch_buffer_next);
1511    assert(copyBatchBuffer.size() <= theBatchBuffer.size());
1512    for (unsigned i=0; i< batch_buffer_next; i++) {
1513       copyBatchBuffer[i] = theBatchBuffer[i];
1514    }
1515
1516 #ifdef FREEDEBUG
1517 timeStamp t1,t2;
1518 t1=getCurrentTime(false);
1519 #endif
1520
1521    // Now let's do the actual igen call!
1522    tp->batchSampleDataCallbackFunc(0, copyBatchBuffer);
1523
1524 #ifdef FREEDEBUG
1525 t2=getCurrentTime(false);
1526 if ((float)(t2-t1) > 15.0) {
1527 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));
1528 logLine(errorLine);
1529 }
1530 #endif
1531
1532    BURST_HAS_COMPLETED = false;
1533    batch_buffer_next = 0;
1534 }
1535
1536 void batchSampleData(int mid, double startTimeStamp,
1537                      double endTimeStamp, double value, unsigned val_weight,
1538                      bool internal_metric) 
1539 {
1540    // This routine is called where we used to call tp->sampleDataCallbackFunc.
1541    // We buffer things up and eventually call tp->batchSampleDataCallbackFunc
1542
1543 #ifdef notdef
1544    char myLogBuffer[120] ;
1545    sprintf(myLogBuffer, "mid %d, value %g\n", mid, value) ;
1546    logLine(myLogBuffer) ;
1547 #endif
1548
1549    // Flush the buffer if (1) it is full, or (2) for good response time, after
1550    // a burst of data:
1551    if (batch_buffer_next >= SAMPLE_BUFFER_SIZE || BURST_HAS_COMPLETED)
1552       flush_batch_buffer();
1553
1554    // Now let's batch this entry.
1555    T_dyninstRPC::batch_buffer_entry &theEntry = theBatchBuffer[batch_buffer_next];
1556    theEntry.mid = mid;
1557    theEntry.startTimeStamp = startTimeStamp;
1558    theEntry.endTimeStamp = endTimeStamp;
1559    theEntry.value = value;
1560    theEntry.weight = val_weight;
1561    theEntry.internal_met = internal_metric;
1562    batch_buffer_next++;
1563 }
1564
1565 //////////////////////////////////////////////////////////////////////////////
1566 // Buffer the traces before we actually send it                            //
1567 //      Send it when the buffers are full                                   //
1568 //      or, send it when the last sample in the interval has arrived.       //
1569 //////////////////////////////////////////////////////////////////////////////
1570
1571 const unsigned TRACE_BUFFER_SIZE = 10;
1572 bool TRACE_BURST_HAS_COMPLETED = false;
1573    // set to true after a burst (after a processTraceStream(), or sampleNodes for
1574    // the CM5), which will force the buffer to be flushed before it fills up
1575    // (if not, we'd have bad response time)
1576
1577 vector<T_dyninstRPC::trace_batch_buffer_entry> theTraceBatchBuffer (TRACE_BUFFER_SIZE);
1578 unsigned int trace_batch_buffer_next=0;
1579
1580 void flush_trace_batch_buffer(int program) {
1581    // don't need to flush if the batch had no data (this does happen; see
1582    // perfStream.C)
1583    if (trace_batch_buffer_next == 0)
1584       return;
1585
1586    vector<T_dyninstRPC::trace_batch_buffer_entry> copyTraceBatchBuffer(trace_batch_buffer_next);
1587    for (unsigned i=0; i< trace_batch_buffer_next; i++)
1588       copyTraceBatchBuffer[i] = theTraceBatchBuffer[i];
1589
1590
1591    // Now let's do the actual igen call!
1592
1593    tp->batchTraceDataCallbackFunc(program, copyTraceBatchBuffer);
1594
1595    TRACE_BURST_HAS_COMPLETED = false;
1596    trace_batch_buffer_next = 0;
1597 }
1598
1599 void batchTraceData(int program, int mid, int recordLength,
1600                      char *recordPtr)
1601 {
1602    // Now let's batch this entry.
1603    T_dyninstRPC::trace_batch_buffer_entry &theEntry = theTraceBatchBuffer[trace_batch_buffer_next];
1604    theEntry.mid = mid;
1605    theEntry.length = recordLength;
1606    theEntry.traceRecord = byteArray(recordPtr,recordLength);
1607    trace_batch_buffer_next++;
1608
1609    // We buffer things up and eventually call tp->batchTraceDataCallbackFunc
1610
1611    // Flush the buffer if (1) it is full, or (2) for good response time, after
1612    // a burst of data:
1613    if (trace_batch_buffer_next >= TRACE_BUFFER_SIZE || TRACE_BURST_HAS_COMPLETED) {
1614       flush_trace_batch_buffer(program);
1615    }
1616
1617 }
1618
1619 void metricDefinitionNode::forwardSimpleValue(timeStamp start, timeStamp end,
1620                                        sampleValue value, unsigned weight,
1621                                        bool internal_met)
1622 {
1623   // TODO mdc
1624     assert(start + 0.000001 >= (firstRecordTime/MILLION));
1625     assert(end >= (firstRecordTime/MILLION));
1626     assert(end > start);
1627
1628     batchSampleData(id_, start, end, value, weight, internal_met);
1629 }
1630
1631 void metricDefinitionNode::updateValue(time64 wallTime, 
1632                                        sampleValue value)
1633 {
1634     timeStamp sampleTime = wallTime / 1000000.0;
1635        // note: we can probably do integer division by million quicker
1636
1637     assert(value >= -0.01);
1638
1639     // TODO -- is this ok?
1640     // TODO -- do sampledFuncs work ?
1641     if (style_ == EventCounter) { 
1642
1643       // only use delta from last sample.
1644       if (value < cumulativeValue) {
1645         if ((value/cumulativeValue) < 0.99999) {
1646             assert((value + 0.0001)  >= cumulativeValue);
1647         } else {
1648           // floating point rounding error ignore
1649           cumulativeValue = value;
1650         }
1651       }
1652
1653       //        if (value + 0.0001 < cumulativeValue)
1654       //           printf ("WARNING:  sample went backwards!!!!!\n");
1655       value -= cumulativeValue;
1656       cumulativeValue += value;
1657     } 
1658
1659     //
1660     // If style==EventCounter then value is changed. Otherwise, it keeps the
1661     // the current "value" (e.g. SampledFunction case). That's why it is not
1662     // necessary to have an special case for SampledFunction.
1663     //
1664
1665     assert(samples.size() == aggregators.size());
1666     for (unsigned u = 0; u < samples.size(); u++) {
1667       if (samples[u]->firstValueReceived())
1668         samples[u]->newValue(sampleTime, value);
1669       else {
1670         samples[u]->startTime(sampleTime);
1671       }
1672       aggregators[u]->updateAggregateComponent();
1673     }
1674 }
1675
1676 void metricDefinitionNode::updateAggregateComponent()
1677 {
1678     // currently called (only) by the above routine
1679     sampleInterval ret = aggSample.aggregateValues();
1680     if (ret.valid) {
1681         assert(ret.end > ret.start);
1682         assert(ret.start + 0.000001 >= (firstRecordTime/MILLION));
1683         assert(ret.end >= (firstRecordTime/MILLION));
1684         batchSampleData(id_, ret.start, ret.end, ret.value,
1685                         aggSample.numComponents(),false);
1686     }
1687 //    else {
1688 //        metric_cerr << "sorry, ret.valid false so not batching sample data" << endl;
1689 //    }
1690 }
1691
1692 //
1693 // Costs are now reported to paradyn like other metrics (ie. we are not
1694 // calling reportInternalMetrics to deliver cost values, instead we wait
1695 // until we have received a new interval of cost data from each process)
1696 // note: this only works for the CM5 because all cost metrics are sumed
1697 // at the daemons and at paradyn, otherwise the CM5 needs its own version
1698 // of this routine that uses the same aggregate method as the one for paradyn 
1699 //
1700 #ifndef SHM_SAMPLING
1701 void processCost(process *proc, traceHeader *h, costUpdate *s)
1702 {
1703     // we can probably do integer division by million quicker.
1704     timeStamp newSampleTime = (h->wall / 1000000.0);
1705     timeStamp newProcessTime = (h->process / 1000000.0);
1706
1707     timeStamp lastProcessTime = 
1708                         totalPredictedCost->getLastSampleProcessTime(proc); 
1709
1710     // find the portion of uninstrumented time for this interval
1711     double unInstTime = ((newProcessTime - lastProcessTime) 
1712                          / (1+currentPredictedCost));
1713     // update predicted cost
1714     // note: currentPredictedCost is the same for all processes 
1715     //       this should be changed to be computed on a per process basis
1716     sampleValue newPredCost = totalPredictedCost->getCumulativeValue(proc);
1717     newPredCost += (float)(currentPredictedCost*unInstTime); 
1718     totalPredictedCost->updateValue(proc,newPredCost,
1719                                     newSampleTime,newProcessTime);
1720     // update observed cost 
1721     observed_cost->updateValue(proc,s->obsCostIdeal,
1722                                newSampleTime,newProcessTime);
1723
1724     // update smooth observed cost
1725     smooth_obs_cost->updateSmoothValue(proc,s->obsCostIdeal,
1726                                  newSampleTime,newProcessTime);
1727 }
1728 #endif
1729
1730 #ifndef SHM_SAMPLING
1731 void processSample(int /* pid */, traceHeader *h, traceSample *s)
1732 {
1733     // called from processTraceStream (perfStream.C) when a TR_SAMPLE record
1734     // has arrived from the appl.
1735
1736     unsigned mid = s->id.id; // low-level counterId (see primitives.C)
1737
1738     static time64 firstWall = 0;
1739
1740     static bool firstTime = true;
1741
1742     if (firstTime) {
1743        firstWall = h->wall;
1744     }
1745
1746     metricDefinitionNode *mi; // filled in by find() if found
1747     if (!midToMiMap.find(mid, mi)) { // low-level counterId to metricDefinitionNode
1748        metric_cerr << "TR_SAMPLE id " << s->id.id << " not for valid mi...discarding" << endl;
1749        return;
1750     }
1751
1752 //    metric_cerr << "FROM pid " << pid << " got value " << s->value << " for id " << s->id.id << endl;
1753
1754     //    sprintf(errorLine, "sample id %d at time %8.6f = %f\n", s->id.id, 
1755     //  ((double) *(int*) &h->wall) + (*(((int*) &h->wall)+1))/1000000.0, s->value);
1756     //    logLine(errorLine);
1757     mi->updateValue(h->wall, s->value);
1758     samplesDelivered++;
1759 }
1760 #endif
1761
1762 /*
1763  * functions to operate on inst request graph.
1764  *
1765  */
1766 instReqNode::instReqNode(instPoint *iPoint,
1767                          AstNode *iAst,
1768                          callWhen  iWhen,
1769                          callOrder o, bool iManuallyTrigger) {
1770     point = iPoint;
1771     when = iWhen;
1772     order = o;
1773     instance = NULL; // set when insertInstrumentation() calls addInstFunc()
1774     ast = assignAst(iAst);
1775     manuallyTrigger = iManuallyTrigger;
1776     assert(point);
1777 }
1778
1779 instReqNode instReqNode::forkProcess(const instReqNode &parentNode,
1780                              const dictionary_hash<instInstance*,instInstance*> &map) {
1781     instReqNode ret = instReqNode(parentNode.point, parentNode.ast, parentNode.when,
1782                                   parentNode.order,
1783                                   false // don't manually trigger
1784                                   );
1785
1786     if (!map.find(parentNode.instance, ret.instance)) // writes to ret.instance
1787        assert(false);
1788
1789     return ret;
1790 }
1791
1792 bool instReqNode::unFork(dictionary_hash<instInstance*,instInstance*> &map) const {
1793    // The fork syscall duplicates all trampolines from the parent into the child. For
1794    // those mi's which we don't want to propagate to the child, this creates a
1795    // problem.  We need to remove instrumentation code from the child.  This routine
1796    // does that.
1797    //
1798    // "this" represents an instReqNode in the PARENT process.
1799    // "map" maps all instInstance*'s of the parent process to instInstance*'s in the
1800    // child process.  We modify "map" by setting a value to NULL.
1801
1802    instInstance *parentInstance = getInstance();
1803    
1804    instInstance *childInstance;
1805    if (!map.find(parentInstance, childInstance)) // writes to childInstance
1806       assert(false);
1807
1808    vector<unsigned> pointsToCheck; // is it right leaving this empty on a fork()???
1809    deleteInst(childInstance, pointsToCheck);
1810
1811    map[parentInstance] = NULL; // since we've deleted...
1812
1813    return true; // success
1814 }
1815
1816 bool instReqNode::insertInstrumentation(process *theProc,
1817                                         returnInstance *&retInstance) 
1818 {
1819     // NEW: We may manually trigger the instrumentation, via a call to postRPCtoDo()
1820
1821     // addInstFunc() is one of the key routines in all paradynd.
1822     // It installs a base tramp at the point (if needed), generates code
1823     // for the tramp, calls inferiorMalloc() in the text heap to get space for it,
1824     // and actually inserts the instrumentation.
1825     instance = addInstFunc(theProc, point, ast, when, order,
1826                            false, // false --> don't exclude cost
1827                            retInstance);
1828
1829     return (instance != NULL);
1830 }
1831
1832 void instReqNode::disable(const vector<unsigned> &pointsToCheck)
1833 {
1834     deleteInst(instance, pointsToCheck);
1835     instance = NULL;
1836 }
1837
1838 instReqNode::~instReqNode()
1839 {
1840     instance = NULL;
1841     removeAst(ast);
1842 }
1843
1844 float instReqNode::cost(process *theProc) const
1845 {
1846     float value;
1847     float unitCost;
1848     float frequency;
1849     int unitCostInCycles;
1850
1851     unitCostInCycles = ast->cost() + getPointCost(theProc, point) +
1852                        getInsnCost(trampPreamble) + getInsnCost(trampTrailer);
1853     // printf("unit cost = %d cycles\n", unitCostInCycles);
1854     unitCost = unitCostInCycles/ cyclesPerSecond;
1855     frequency = getPointFrequency(point);
1856     value = unitCost * frequency;
1857     return(value);
1858 }
1859
1860 bool instReqNode::triggerNow(process *theProc, int mid) {
1861    assert(manuallyTrigger);
1862
1863    theProc->postRPCtoDo(ast, false, // don't skip cost
1864                         NULL, // no callback fn needed
1865                         NULL,
1866                         mid);
1867       // the rpc will be launched with a call to launchRPCifAppropriate()
1868       // in the main loop (perfStream.C)
1869
1870    return true;
1871 }
1872
1873 /* ************************************************************************* */
1874
1875 #ifndef SHM_SAMPLING
1876 sampledIntCounterReqNode::sampledIntCounterReqNode(int iValue, int iCounterId,
1877                                                    metricDefinitionNode *iMi, 
1878                                                    bool computingCost) :
1879                                                    dataReqNode() {
1880    theSampleId = iCounterId;
1881    initialValue = iValue;
1882
1883    // The following fields are NULL until insertInstrumentation()
1884    counterPtr = NULL;
1885    sampler = NULL;
1886
1887    if (!computingCost) {
1888      bool isOk=false;
1889      isOk = insertInstrumentation(iMi->proc(), iMi);
1890      assert(isOk && counterPtr!=NULL); 
1891    }
1892 }
1893
1894 sampledIntCounterReqNode::sampledIntCounterReqNode(const sampledIntCounterReqNode &src,
1895                                                    process *childProc,
1896                                                    metricDefinitionNode *,
1897                                                    int iCounterId,
1898                                                    const dictionary_hash<instInstance*,instInstance*> &map) {
1899    // a dup() routine (call after a fork())
1900    counterPtr = src.counterPtr; // assumes addr spaces have been dup()d.
1901
1902    if (!map.find(src.sampler, this->sampler)) // writes to this->sampler
1903       assert(false);
1904
1905    theSampleId = iCounterId;
1906  
1907    intCounter temp;
1908    temp.id.id = this->theSampleId;
1909    temp.value = initialValue;
1910    writeToInferiorHeap(childProc, temp);
1911 }
1912
1913 dataReqNode *
1914 sampledIntCounterReqNode::dup(process *childProc,
1915                               metricDefinitionNode *mi,
1916                               int iCounterId,
1917                               const dictionary_hash<instInstance*,instInstance*> &map
1918                               ) const {
1919    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
1920
1921    sampledIntCounterReqNode *tmp;
1922    tmp = new sampledIntCounterReqNode(*this, childProc, mi, iCounterId, map);
1923       // fork ctor
1924   
1925    return tmp;
1926 }
1927
1928 bool sampledIntCounterReqNode::insertInstrumentation(process *theProc,
1929                                                      metricDefinitionNode *,
1930                                                      bool) {
1931    // Remember counterPtr and sampler are NULL until this routine
1932    // gets called.
1933    counterPtr = (intCounter*)inferiorMalloc(theProc, sizeof(intCounter), dataHeap);
1934    if (counterPtr == NULL)
1935       return false; // failure!
1936
1937    // initialize the intCounter in the inferior heap
1938    intCounter temp;
1939    temp.id.id = this->theSampleId;
1940    temp.value = this->initialValue;
1941
1942    writeToInferiorHeap(theProc, temp);
1943
1944    function_base *sampleFunction = 
1945         theProc->findOneFunction("DYNINSTsampleValues");
1946    assert(sampleFunction);
1947
1948    AstNode *ast, *tmp;
1949    tmp = new AstNode(AstNode::Constant, counterPtr);
1950    ast = new AstNode("DYNINSTreportCounter", tmp);
1951    removeAst(tmp);
1952
1953    instPoint *func_entry = (instPoint *)sampleFunction->funcEntry(theProc);
1954    sampler = addInstFunc(theProc, func_entry,
1955                          ast, callPreInsn, orderLastAtPoint, false);
1956    removeAst(ast);
1957
1958    return true; // success
1959 }
1960
1961 void sampledIntCounterReqNode::disable(process *theProc,
1962                                        const vector<unsigVecType> &pointsToCheck) {
1963    // We used to remove the sample id from midToMiMap here but now the caller is
1964    // responsible for that.
1965
1966    // Remove instrumentation added to DYNINSTsampleValues(), if necessary:
1967    if (sampler != NULL)
1968       ::deleteInst(sampler, getAllTrampsAtPoint(sampler));
1969
1970    // Deallocate space for intCounter in the inferior heap:
1971    assert(counterPtr != NULL);
1972    inferiorFree(theProc, (unsigned)counterPtr, dataHeap, pointsToCheck);
1973 }
1974
1975 void sampledIntCounterReqNode::writeToInferiorHeap(process *theProc,
1976                                                    const intCounter &dataSrc) const {
1977    // using the contents of "dataSrc", write to the inferior heap at loc
1978    // "counterPtr" via proc->writeDataSpace()
1979    assert(counterPtr);
1980    theProc->writeDataSpace(counterPtr, sizeof(intCounter), &dataSrc);
1981 }
1982
1983 bool sampledIntCounterReqNode::
1984 unFork(dictionary_hash<instInstance*,instInstance*> &map) {
1985    instInstance *parentSamplerInstance = this->sampler;
1986
1987    instInstance *childSamplerInstance;
1988    if (!map.find(parentSamplerInstance, childSamplerInstance))
1989       assert(false);
1990
1991    vector<unsigned> pointsToCheck; // empty on purpose
1992    deleteInst(childSamplerInstance, pointsToCheck);
1993
1994    map[parentSamplerInstance] = NULL;
1995
1996    return true;
1997 }
1998                                       
1999 #endif
2000
2001 /* ************************************************************************* */
2002
2003 #ifdef SHM_SAMPLING
2004
2005 sampledShmIntCounterReqNode::sampledShmIntCounterReqNode(int iValue, 
2006                                                      int iCounterId, 
2007                                                      metricDefinitionNode *iMi,
2008                                                      bool computingCost,
2009                                                      bool doNotSample) :
2010                                                      dataReqNode() {
2011    theSampleId = iCounterId;
2012    initialValue = iValue;
2013
2014    // The following fields are NULL until insertInstrumentation()
2015    allocatedIndex = UINT_MAX;
2016    allocatedLevel = UINT_MAX;
2017
2018    position_=0;
2019
2020    if (!computingCost) {
2021      bool isOk=false;
2022      isOk = insertInstrumentation(iMi->proc(), iMi, doNotSample);
2023      assert(isOk); 
2024    }
2025 }
2026
2027 sampledShmIntCounterReqNode::
2028 sampledShmIntCounterReqNode(const sampledShmIntCounterReqNode &src,
2029                             process *childProc, metricDefinitionNode *mi,
2030                             int iCounterId, const process *parentProc) {
2031    // a dup() routine (call after a fork())
2032    // Assumes that "childProc" has been copied already (e.g., the shm seg was copied).
2033
2034    // Note that the index w/in the inferior heap remains the same, so setting the
2035    // new inferiorCounterPtr isn't too hard.  Actually, it's trivial, since other code
2036    // ensures that the new shm segment is placed in exactly the same virtual mem loc
2037    // as the previous one.
2038    //
2039    // Note that the fastInferiorHeap class's fork ctor will have already copied the
2040    // actual data; we need to fill in new meta-data (new houseKeeping entries).
2041
2042    this->allocatedIndex = src.allocatedIndex;
2043    this->allocatedLevel = src.allocatedLevel;
2044
2045    this->theSampleId = iCounterId;  // this is different from the parent's value
2046    this->initialValue = src.initialValue;
2047
2048    superTable &theTable = childProc->getTable();
2049
2050    // since the new shm seg is placed in exactly the same memory location as
2051    // the old one, nothing here should change.
2052    const superTable &theParentTable = parentProc->getTable();
2053    assert(theTable.index2InferiorAddr(0,childProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel)==theParentTable.index2InferiorAddr(0,parentProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel));
2054
2055    for (unsigned i=0; i<childProc->threads.size(); i++) {
2056      // write to the raw item in the inferior heap:
2057      intCounter *localCounterPtr = (intCounter *) theTable.index2LocalAddr(0,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2058      const intCounter *localSrcCounterPtr = (const intCounter *) childProc->getParent()->getTable().index2LocalAddr(0,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2059      localCounterPtr->value = initialValue;
2060      localCounterPtr->id.id = theSampleId;
2061      localCounterPtr->theSpinner = localSrcCounterPtr->theSpinner;
2062         // in case we're in the middle of an operation
2063    }
2064
2065    // write HK for this intCounter:
2066    // Note: we don't assert anything about mi->getMId(), because that id has no
2067    // relation to the ids we work with (theSampleId).  In fact, we (the sampling code)
2068    // just don't ever care what mi->getMId() is.
2069    assert(theSampleId >= 0);
2070    assert(midToMiMap.defines(theSampleId));
2071    assert(midToMiMap[theSampleId] == mi);
2072    intCounterHK iHKValue(theSampleId, mi);
2073       // the mi differs from the mi of the parent; theSampleId differs too.
2074    theTable.initializeHKAfterForkIntCounter(allocatedIndex, allocatedLevel, iHKValue);
2075
2076    position_=0;
2077 }
2078
2079 dataReqNode *
2080 sampledShmIntCounterReqNode::dup(process *childProc,
2081                                  metricDefinitionNode *mi,
2082                                  int iCounterId,
2083                                  const dictionary_hash<instInstance*,instInstance*> &
2084                                  ) const {
2085    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2086
2087    sampledShmIntCounterReqNode *tmp;
2088    tmp = new sampledShmIntCounterReqNode(*this, childProc, mi, iCounterId, childProc->getParent());
2089       // fork ctor
2090
2091    return tmp;
2092 }
2093
2094 bool sampledShmIntCounterReqNode::insertInstrumentation(process *theProc,
2095                                                         metricDefinitionNode *iMi, bool doNotSample) {
2096    // Remember counterPtr is NULL until this routine gets called.
2097    // WARNING: there will be an assert failure if the applic hasn't yet attached to the
2098    //          shm segment!!!
2099
2100    // initialize the intCounter in the inferior heap
2101    intCounter iValue;
2102    iValue.id.id = this->theSampleId;
2103    iValue.value = this->initialValue; // what about initializing 'theSpinner'???
2104
2105    intCounterHK iHKValue(this->theSampleId, iMi);
2106
2107    superTable &theTable = theProc->getTable();
2108
2109    if (!theTable.allocIntCounter(iValue, iHKValue, this->allocatedIndex, this->allocatedLevel, doNotSample))
2110       return false; // failure
2111
2112    return true; // success
2113 }
2114
2115 void sampledShmIntCounterReqNode::disable(process *theProc,
2116                                           const vector<unsigVecType> &pointsToCheck) {
2117    // We used to remove the sample id from midToMiMap here but now the caller is
2118    // responsible for that.
2119
2120    superTable &theTable = theProc->getTable();
2121
2122    // Remove from inferior heap; make sure we won't be sampled any more:
2123    vector<unsigned> trampsMaybeUsing;
2124    for (unsigned pointlcv=0; pointlcv < pointsToCheck.size(); pointlcv++)
2125       for (unsigned tramplcv=0; tramplcv < pointsToCheck[pointlcv].size(); tramplcv++)
2126          trampsMaybeUsing += pointsToCheck[pointlcv][tramplcv];
2127
2128    theTable.makePendingFree(0,allocatedIndex,allocatedLevel,trampsMaybeUsing);
2129
2130 #if defined(MT_THREAD)
2131 //NOTE: Not yet implemented for shm sampling! naim 4/23/97
2132 //    pdThread *thr = theProc->threads[0];
2133 //    thr->CTvector->remove(this->theSampleId, this->position_);
2134 //    theProc->updateActiveCT(false,counter);
2135 #endif
2136 }
2137
2138 #endif
2139
2140 /* ************************************************************************* */
2141
2142 nonSampledIntCounterReqNode::nonSampledIntCounterReqNode(int iValue, 
2143                                                     int iCounterId,
2144                                                     metricDefinitionNode *iMi, 
2145                                                     bool computingCost) :
2146                                                     dataReqNode() {
2147    theSampleId = iCounterId;
2148    initialValue = iValue;
2149
2150    // The following fields are NULL until insertInstrumentation()
2151    counterPtr = NULL;
2152
2153    if (!computingCost) {
2154      bool isOk=false;
2155      isOk = insertInstrumentation(iMi->proc(), iMi);
2156      assert(isOk && counterPtr!=NULL); 
2157    }
2158 }
2159
2160 nonSampledIntCounterReqNode::
2161 nonSampledIntCounterReqNode(const nonSampledIntCounterReqNode &src,
2162                             process *childProc, metricDefinitionNode *,
2163                             int iCounterId) {
2164    // a dup() routine (call after a fork())
2165    counterPtr = src.counterPtr; // assumes addr spaces have been dup()d.
2166    initialValue = src.initialValue;
2167    theSampleId = iCounterId;
2168  
2169    intCounter temp;
2170    temp.id.id = this->theSampleId;
2171    temp.value = this->initialValue;
2172    writeToInferiorHeap(childProc, temp);
2173 }
2174
2175 dataReqNode *
2176 nonSampledIntCounterReqNode::dup(process *childProc,
2177                                  metricDefinitionNode *mi,
2178                                  int iCounterId,
2179                                  const dictionary_hash<instInstance*,instInstance*> &
2180                                  ) const {
2181    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2182
2183    nonSampledIntCounterReqNode *tmp;
2184    tmp = new nonSampledIntCounterReqNode(*this, childProc, mi, iCounterId);
2185       // fork ctor
2186
2187    return tmp;
2188 }
2189
2190 bool nonSampledIntCounterReqNode::insertInstrumentation(process *theProc,
2191                                                         metricDefinitionNode *,
2192                                                         bool) {
2193    // Remember counterPtr is NULL until this routine gets called.
2194    counterPtr = (intCounter*)inferiorMalloc(theProc, sizeof(intCounter), dataHeap);
2195    if (counterPtr == NULL)
2196       return false; // failure!
2197
2198    // initialize the intCounter in the inferior heap
2199    intCounter temp;
2200    temp.id.id = this->theSampleId;
2201    temp.value = this->initialValue;
2202
2203    writeToInferiorHeap(theProc, temp);
2204
2205    return true; // success
2206 }
2207
2208 void nonSampledIntCounterReqNode::disable(process *theProc,
2209                                           const vector<unsigVecType> &pointsToCheck) {
2210    // We used to remove the sample id from midToMiMap here but now the caller is
2211    // responsible for that.
2212
2213    // Deallocate space for intCounter in the inferior heap:
2214    assert(counterPtr != NULL);
2215    inferiorFree(theProc, (unsigned)counterPtr, dataHeap, pointsToCheck);
2216 }
2217
2218 void nonSampledIntCounterReqNode::writeToInferiorHeap(process *theProc,
2219                                                       const intCounter &dataSrc) const {
2220    // using the contents of "dataSrc", write to the inferior heap at loc
2221    // "counterPtr" via proc->writeDataSpace()
2222    assert(counterPtr);
2223    theProc->writeDataSpace(counterPtr, sizeof(intCounter), &dataSrc);
2224 }
2225
2226 /* ****************************************************************** */
2227
2228 #ifndef SHM_SAMPLING
2229 sampledTimerReqNode::sampledTimerReqNode(timerType iType, int iCounterId, 
2230                                          metricDefinitionNode *iMi,
2231                                          bool computingCost) :
2232                                          dataReqNode() {
2233    theSampleId = iCounterId;
2234    theTimerType = iType;
2235
2236    // The following fields are NULL until insertInstrumentatoin():
2237    timerPtr = NULL;
2238    sampler  = NULL;
2239
2240    if (!computingCost) {
2241      bool isOk=false;
2242      isOk = insertInstrumentation(iMi->proc(), iMi);
2243      assert(isOk && timerPtr!=NULL); 
2244    }
2245 }
2246
2247 sampledTimerReqNode::sampledTimerReqNode(const sampledTimerReqNode &src,
2248                                          process *childProc,
2249                                          metricDefinitionNode *,
2250                                          int iCounterId,
2251                                          const dictionary_hash<instInstance*,instInstance*> &map) {
2252    // a dup()-like routine; call after a fork()
2253    timerPtr = src.timerPtr; // assumes addr spaces have been dup()'d
2254
2255    if (!map.find(src.sampler, this->sampler)) // writes to this->sampler
2256       assert(false);
2257
2258    assert(sampler); // makes sense; timers are always sampled, whereas intCounters
2259                     // might be just non-sampled predicates.
2260    
2261    theSampleId = iCounterId;
2262    theTimerType = src.theTimerType;
2263
2264    tTimer temp;
2265    P_memset(&temp, '\0', sizeof(tTimer)); /* is this needed? */
2266    temp.id.id = this->theSampleId;
2267    temp.type = this->theTimerType;
2268    temp.normalize = 1000000;
2269    writeToInferiorHeap(childProc, temp);
2270
2271    // WARNING: shouldn't we be resetting the raw value to count=0, start=0,
2272    //          total = src.initialValue ???  On the other hand, it's not that
2273    //          simple -- if the timer is active in the parent, then it'll be active
2274    //          in the child.  So how about setting count to src.count, start=now,
2275    //          total=0 ???
2276 }
2277
2278 dataReqNode *
2279 sampledTimerReqNode::dup(process *childProc, metricDefinitionNode *mi,
2280                          int iCounterId,
2281                          const dictionary_hash<instInstance*,instInstance*> &map
2282                          ) const {
2283    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2284
2285    sampledTimerReqNode *result = new sampledTimerReqNode(*this, childProc, mi, iCounterId, map);
2286       // fork ctor
2287    if (!result)
2288       return NULL; // on failure, return w/o incrementing counterId
2289
2290    return result;
2291 }
2292
2293 bool sampledTimerReqNode::insertInstrumentation(process *theProc,
2294                                                 metricDefinitionNode *,
2295                                                 bool) {
2296    timerPtr = (tTimer *)inferiorMalloc(theProc, sizeof(tTimer), dataHeap);
2297    if (timerPtr == NULL)
2298       return false; // failure!
2299
2300    // Now let's initialize the newly allocated tTimer in the inferior heap:
2301    tTimer temp;
2302    P_memset(&temp, '\0', sizeof(tTimer));
2303    temp.id.id = this->theSampleId;
2304    temp.type = this->theTimerType;
2305    temp.normalize = 1000000;
2306    writeToInferiorHeap(theProc, temp);
2307
2308    // Now instrument DYNINSTreportTimer:
2309    function_base *sampleFunction = 
2310         theProc->findOneFunction("DYNINSTsampleValues");
2311    assert(sampleFunction);
2312
2313    AstNode *ast, *tmp;
2314    tmp = new AstNode(AstNode::Constant, timerPtr);
2315    ast = new AstNode("DYNINSTreportTimer", tmp);
2316    removeAst(tmp);
2317
2318    instPoint *func_entry = (instPoint *)sampleFunction->funcEntry(theProc);
2319    sampler = addInstFunc(theProc, func_entry, ast,
2320                          callPreInsn, orderLastAtPoint, false);
2321    removeAst(ast);
2322
2323    return true; // successful
2324 }
2325
2326 void sampledTimerReqNode::disable(process *theProc,
2327                                   const vector<unsigVecType> &pointsToCheck) {
2328    // We used to remove the sample id from midToMiMap here but now the caller is
2329    // responsible for that.
2330
2331    // Remove instrumentation added to DYNINSTsampleValues(), if necessary:
2332    if (sampler != NULL)
2333       ::deleteInst(sampler, getAllTrampsAtPoint(sampler));
2334
2335    // Deallocate space for tTimer in the inferior heap:
2336    assert(timerPtr);
2337    inferiorFree(theProc, (unsigned)timerPtr, dataHeap, pointsToCheck);
2338 }
2339
2340 void sampledTimerReqNode::writeToInferiorHeap(process *theProc,
2341                                               const tTimer &dataSrc) const {
2342    // using contents of "dataSrc", a local copy of the data,
2343    // write to inferior heap at loc "timerPtr" via proc->writeDataSpace()
2344    assert(timerPtr);
2345    theProc->writeDataSpace(timerPtr, sizeof(tTimer), &dataSrc);
2346 }
2347
2348 bool sampledTimerReqNode::
2349 unFork(dictionary_hash<instInstance*,instInstance*> &map) {
2350    instInstance *parentSamplerInstance = sampler;
2351
2352    instInstance *childSamplerInstance;
2353    if (!map.find(parentSamplerInstance, childSamplerInstance))
2354       assert(false);
2355
2356    vector<unsigned> pointsToCheck; // empty
2357    deleteInst(childSamplerInstance, pointsToCheck);
2358
2359    map[parentSamplerInstance] = NULL; // since we've deleted...
2360
2361    return true;
2362 }
2363                                  
2364 #endif
2365
2366 /* ****************************************************************** */
2367
2368 #ifdef SHM_SAMPLING
2369 sampledShmWallTimerReqNode::sampledShmWallTimerReqNode(int iCounterId,
2370                                                      metricDefinitionNode *iMi,
2371                                                      bool computingCost) :
2372                                                      dataReqNode() {
2373    theSampleId = iCounterId;
2374
2375    // The following fields are NULL until insertInstrumentation():
2376    allocatedIndex = UINT_MAX;
2377    allocatedLevel = UINT_MAX;
2378
2379    position_=0;
2380
2381    if (!computingCost) {
2382      bool isOk=false;
2383      isOk = insertInstrumentation(iMi->proc(), iMi);
2384      assert(isOk); 
2385    }
2386 }
2387
2388 sampledShmWallTimerReqNode::
2389 sampledShmWallTimerReqNode(const sampledShmWallTimerReqNode &src,
2390                            process *childProc,
2391                            metricDefinitionNode *mi,
2392                            int iCounterId, const process *parentProc) {
2393    // a dup()-like routine; call after a fork().
2394    // Assumes that the "childProc" has been duplicated already
2395
2396    // Note that the index w/in the inferior heap remains the same, so setting the new
2397    // inferiorTimerPtr isn't too hard.  Actually, it's trivial, since other code
2398    // ensures that the new shm segment is placed in exactly the same virtual mem loc
2399    // as the previous one.
2400    //
2401    // Note that the fastInferiorHeap class's fork ctor will have already copied the
2402    // actual data; we need to fill in new meta-data (new houseKeeping entries).
2403
2404    allocatedIndex = src.allocatedIndex;
2405    allocatedLevel = src.allocatedLevel;
2406
2407    theSampleId = iCounterId;
2408    assert(theSampleId != src.theSampleId);
2409
2410    superTable &theTable = childProc->getTable();
2411
2412    // since the new shm seg is placed in exactly the same memory location as
2413    // the old one, nothing here should change.
2414    const superTable &theParentTable = parentProc->getTable();
2415    assert(theTable.index2InferiorAddr(1,childProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel)==theParentTable.index2InferiorAddr(1,parentProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel));
2416
2417    // Write new raw value in the inferior heap:
2418    // we set localTimerPtr as follows: protector1 and procetor2 should be copied from
2419    //    src. total should be reset to 0.  start should be set to now if active else 0.
2420    //    counter should be copied from the source.
2421    // NOTE: SINCE WE COPY FROM THE SOURCE, IT'S IMPORTANT THAT ON A FORK, BOTH THE
2422    //       PARENT AND CHILD ARE PAUSED UNTIL WE COPY THINGS OVER.  THAT THE CHILD IS
2423    //       PAUSED IS NOTHING NEW; THAT THE PARENT SHOULD BE PAUSED IS NEW NEWS!
2424
2425    for (unsigned i=0; i<childProc->threads.size(); i++) {
2426      tTimer *localTimerPtr = (tTimer *) theTable.index2LocalAddr(1,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2427      const tTimer *srcTimerPtr = (const tTimer *) childProc->getParent()->getTable().index2LocalAddr(1,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2428
2429      localTimerPtr->total = 0;
2430      localTimerPtr->counter = srcTimerPtr->counter;
2431      localTimerPtr->id.id   = theSampleId;
2432      localTimerPtr->protector1 = srcTimerPtr->protector1;
2433      localTimerPtr->protector2 = srcTimerPtr->protector2;
2434
2435      if (localTimerPtr->counter == 0)
2436         // inactive timer...this is the easy case to copy
2437         localTimerPtr->start = 0; // undefined, really
2438      else
2439         // active timer...don't copy the start time from the source...make it 'now'
2440         localTimerPtr->start = getCurrWallTime();
2441    }
2442
2443    // write new HK for this tTimer:
2444    // Note: we don't assert anything about mi->getMId(), because that id has no
2445    // relation to the ids we work with (theSampleId).  In fact, we (the sampling code)
2446    // just don't ever care what mi->getMId() is.
2447    assert(theSampleId >= 0);
2448    assert(midToMiMap.defines(theSampleId));
2449    assert(midToMiMap[theSampleId] == mi);
2450    wallTimerHK iHKValue(theSampleId, mi, 0); // is last param right?
2451       // the mi should differ from the mi of the parent; theSampleId differs too.
2452    theTable.initializeHKAfterForkWallTimer(allocatedIndex, allocatedLevel, iHKValue);
2453
2454    position_=0;
2455 }
2456
2457 dataReqNode *
2458 sampledShmWallTimerReqNode::dup(process *childProc,
2459                                 metricDefinitionNode *mi,
2460                                 int iCounterId,
2461                                 const dictionary_hash<instInstance*,instInstance*> &
2462                                 ) const {
2463    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2464
2465    sampledShmWallTimerReqNode *tmp;
2466    tmp = new sampledShmWallTimerReqNode(*this, childProc, mi, iCounterId, childProc->getParent());
2467       // fork constructor
2468
2469    return tmp;
2470 }
2471
2472 bool sampledShmWallTimerReqNode::insertInstrumentation(process *theProc,
2473                                                        metricDefinitionNode *iMi, bool) {
2474    // Remember inferiorTimerPtr is NULL until this routine gets called.
2475    // WARNING: there will be an assert failure if the applic hasn't yet attached to the
2476    //          shm segment!!!
2477
2478    // initialize the tTimer in the inferior heap
2479    tTimer iValue;
2480    P_memset(&iValue, '\0', sizeof(tTimer));
2481    iValue.id.id = this->theSampleId;
2482
2483    wallTimerHK iHKValue(this->theSampleId, iMi, 0);
2484
2485    superTable &theTable = theProc->getTable();
2486
2487    if (!theTable.allocWallTimer(iValue, iHKValue, this->allocatedIndex, this->allocatedLevel))
2488       return false; // failure
2489
2490    return true;
2491 }
2492
2493 void sampledShmWallTimerReqNode::disable(process *theProc,
2494                                          const vector<unsigVecType> &pointsToCheck) {
2495    // We used to remove the sample id from midToMiMap here but now the caller is
2496    // responsible for that.
2497
2498    superTable &theTable = theProc->getTable();
2499
2500    // Remove from inferior heap; make sure we won't be sampled any more:
2501    vector<unsigned> trampsMaybeUsing;
2502    for (unsigned pointlcv=0; pointlcv < pointsToCheck.size(); pointlcv++)
2503       for (unsigned tramplcv=0; tramplcv < pointsToCheck[pointlcv].size(); tramplcv++)
2504          trampsMaybeUsing += pointsToCheck[pointlcv][tramplcv];
2505
2506    theTable.makePendingFree(1,allocatedIndex,allocatedLevel,trampsMaybeUsing);
2507
2508 #if defined(MT_THREAD)
2509 //NOTE: Not yet implemented for shm sampling! naim 4/23/97
2510 //    pdThread *thr = theProc->threads[0];
2511 //    thr->CTvector->remove(this->theSampleId, this->position_);
2512 //    theProc->updateActiveCT(false,wallTimer);
2513 #endif
2514 }
2515
2516 /* ****************************************************************** */
2517
2518 sampledShmProcTimerReqNode::sampledShmProcTimerReqNode(int iCounterId,
2519                                                      metricDefinitionNode *iMi,
2520                                                      bool computingCost) :
2521                                                      dataReqNode() {
2522    theSampleId = iCounterId;
2523
2524    // The following fields are NULL until insertInstrumentatoin():
2525    allocatedIndex = UINT_MAX;
2526    allocatedLevel = UINT_MAX;
2527
2528    position_=0;
2529
2530    if (!computingCost) {
2531      bool isOk=false;
2532      isOk = insertInstrumentation(iMi->proc(), iMi);
2533      assert(isOk); 
2534    }
2535 }
2536
2537 sampledShmProcTimerReqNode::
2538 sampledShmProcTimerReqNode(const sampledShmProcTimerReqNode &src,
2539                            process *childProc,
2540                            metricDefinitionNode *mi,
2541                            int iCounterId, const process *parentProc) {
2542    // a dup()-like routine; call after a fork()
2543    // Assumes that the "childProc" has been duplicated already
2544
2545    // Note that the index w/in the inferior heap remains the same, so setting the new
2546    // inferiorTimerPtr isn't too hard.  Actually, it's trivial, since other code
2547    // ensures that the new shm segment is placed in exactly the same virtual mem loc
2548    // as the previous one.
2549    //
2550    // Note that the fastInferiorHeap class's fork ctor will have already copied the
2551    // actual data; we need to fill in new meta-data (new houseKeeping entries).
2552
2553    allocatedIndex = src.allocatedIndex;
2554    allocatedLevel = src.allocatedLevel;
2555    theSampleId = iCounterId;
2556    assert(theSampleId != src.theSampleId);
2557
2558    superTable &theTable = childProc->getTable();
2559
2560    // since the new shm seg is placed in exactly the same memory location as
2561    // the old one, nothing here should change.
2562    const superTable &theParentTable = parentProc->getTable();
2563    assert(theTable.index2InferiorAddr(2,childProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel)==theParentTable.index2InferiorAddr(2,parentProc->threads[0]->get_pd_pos(),allocatedIndex,allocatedLevel));
2564
2565    // Write new raw value:
2566    // we set localTimerPtr as follows: protector1 and procetor2 should be copied from
2567    //    src. total should be reset to 0.  start should be set to now if active else 0.
2568    //    counter should be copied from the source.
2569    // NOTE: SINCE WE COPY FROM THE SOURCE, IT'S IMPORTANT THAT ON A FORK, BOTH THE
2570    //       PARENT AND CHILD ARE PAUSED UNTIL WE COPY THINGS OVER.  THAT THE CHILD IS
2571    //       PAUSED IS NOTHING NEW; THAT THE PARENT SHOULD BE PAUSED IS NEW NEWS!
2572
2573    for (unsigned i=0; i<childProc->threads.size(); i++) {
2574      tTimer *localTimerPtr = (tTimer *) theTable.index2LocalAddr(2,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2575      const tTimer *srcTimerPtr = (const tTimer *) childProc->getParent()->getTable().index2LocalAddr(2,childProc->threads[i]->get_pd_pos(),allocatedIndex,allocatedLevel);
2576
2577      localTimerPtr->total = 0;
2578      localTimerPtr->counter = srcTimerPtr->counter;
2579      localTimerPtr->id.id   = theSampleId;
2580      localTimerPtr->protector1 = srcTimerPtr->protector1;
2581      localTimerPtr->protector2 = srcTimerPtr->protector2;
2582
2583      if (localTimerPtr->counter == 0)
2584         // inactive timer...this is the easy case to copy
2585         localTimerPtr->start = 0; // undefined, really
2586      else
2587         // active timer...don't copy the start time from the source...make it 'now'
2588         localTimerPtr->start = childProc->getInferiorProcessCPUtime();
2589    }
2590
2591    // Write new HK for this tTimer:
2592    // Note: we don't assert anything about mi->getMId(), because that id has no
2593    // relation to the ids we work with (theSampleId).  In fact, we (the sampling code)
2594    // just don't ever care what mi->getMId() is.
2595    assert(theSampleId >= 0);
2596    assert(midToMiMap.defines(theSampleId));
2597    assert(midToMiMap[theSampleId] == mi);
2598    processTimerHK iHKValue(theSampleId, mi, 0); // is last param right?
2599       // the mi differs from the mi of the parent; theSampleId differs too.
2600    theTable.initializeHKAfterForkProcTimer(allocatedIndex, allocatedLevel, iHKValue);
2601
2602    position_=0;
2603 }
2604
2605 dataReqNode *
2606 sampledShmProcTimerReqNode::dup(process *childProc,
2607                                 metricDefinitionNode *mi,
2608                                 int iCounterId,
2609                                 const dictionary_hash<instInstance*,instInstance*> &
2610                                 ) const {
2611    // duplicate 'this' (allocate w/ new) and return.  Call after a fork().
2612
2613    sampledShmProcTimerReqNode *tmp;
2614    tmp = new sampledShmProcTimerReqNode(*this, childProc, mi, iCounterId, childProc->getParent());
2615       // fork constructor
2616
2617    return tmp;
2618 }
2619
2620 bool sampledShmProcTimerReqNode::insertInstrumentation(process *theProc,
2621                                                        metricDefinitionNode *iMi, bool) {
2622    // Remember inferiorTimerPtr is NULL until this routine gets called.
2623    // WARNING: there will be an assert failure if the applic hasn't yet attached to the
2624    //          shm segment!!!
2625
2626    // initialize the tTimer in the inferior heap
2627    tTimer iValue;
2628    P_memset(&iValue, '\0', sizeof(tTimer));
2629    iValue.id.id = this->theSampleId;
2630
2631    processTimerHK iHKValue(this->theSampleId, iMi, 0);
2632
2633    superTable &theTable = theProc->getTable();
2634
2635    if (!theTable.allocProcTimer(iValue, iHKValue, this->allocatedIndex,this->allocatedLevel))
2636       return false; // failure
2637
2638    return true;
2639 }
2640
2641 void sampledShmProcTimerReqNode::disable(process *theProc,
2642                                          const vector<unsigVecType> &pointsToCheck) {
2643    // We used to remove the sample id from midToMiMap here but now the caller is
2644    // responsible for that.
2645
2646    superTable &theTable = theProc->getTable();
2647
2648    // Remove from inferior heap; make sure we won't be sampled any more:
2649    vector<unsigned> trampsMaybeUsing;
2650    for (unsigned pointlcv=0; pointlcv < pointsToCheck.size(); pointlcv++)
2651       for (unsigned tramplcv=0; tramplcv < pointsToCheck[pointlcv].size(); tramplcv++)
2652          trampsMaybeUsing += pointsToCheck[pointlcv][tramplcv];
2653
2654    theTable.makePendingFree(2,allocatedIndex,allocatedLevel,trampsMaybeUsing);
2655
2656 #if defined(MT_THREAD)
2657 //NOTE: Not yet implemented for shm sampling! naim 4/23/97
2658 //   pdThread *thr = theProc->threads[0];
2659 //   thr->CTvector->remove(this->theSampleId, this->position_);
2660 //   theProc->updateActiveCT(false,procTimer);
2661 #endif
2662 }
2663 #endif
2664
2665 /* **************************** */
2666
2667 void reportInternalMetrics(bool force) 
2668 {
2669     if (isApplicationPaused())
2670        return; // we don't sample when paused (is this right?)
2671
2672     static timeStamp end=0.0;
2673
2674     // see if we have a sample to establish time base.
2675     if (!firstRecordTime) {
2676        //cerr << "reportInternalMetrics: no because firstRecordTime==0" << endl;
2677        return;
2678     }
2679
2680     if (end==0.0)
2681         end = (timeStamp)firstRecordTime/MILLION;
2682
2683     const timeStamp now = getCurrentTime(false);
2684
2685     //  check if it is time for a sample
2686     if (!force && now < end + samplingRate)  {
2687 //        cerr << "reportInternalMetrics: no because now < end + samplingRate (end=" << end << "; samplingRate=" << samplingRate << "; now=" << now << ")" << endl;
2688 //      cerr << "difference is " << (end+samplingRate-now) << endl;
2689         return;
2690     }
2691
2692     timeStamp start = end;
2693     end = now;
2694
2695     // TODO -- clean me up, please
2696
2697     unsigned max1=0;
2698     unsigned max2=0;
2699     unsigned max3=0;
2700     for (unsigned u1 = 0; u1 < processVec.size(); u1++) {
2701       if (processVec[u1]->numOfActCounters_is > max1)
2702         max1=processVec[u1]->numOfActCounters_is;
2703       if (processVec[u1]->numOfActProcTimers_is > max2)
2704         max2=processVec[u1]->numOfActProcTimers_is;
2705       if (processVec[u1]->numOfActWallTimers_is > max3)
2706         max3=processVec[u1]->numOfActWallTimers_is;
2707     }
2708     numOfActCounters_all=max1;
2709     numOfActProcTimers_all=max2;
2710     numOfActWallTimers_all=max3;
2711
2712     unsigned ai_size = internalMetric::allInternalMetrics.size();
2713     for (unsigned u2=0; u2<ai_size; u2++) {
2714       internalMetric *theIMetric = internalMetric::allInternalMetrics[u2];
2715       // Loop thru all enabled instances of this internal metric...
2716
2717       for (unsigned v=0; v < theIMetric->num_enabled_instances(); v++) {
2718         internalMetric::eachInstance &theInstance = theIMetric->getEnabledInstance(v);
2719            // not "const" since bumpCumulativeValueBy() may be called
2720
2721         sampleValue value = (sampleValue) 0;
2722         if (theIMetric->name() == "active_processes") {
2723           //value = (end - start) * activeProcesses;
2724           value = (end - start) * theInstance.getValue();
2725         } else if (theIMetric->name() == "bucket_width") {
2726           //value = (end - start)* theInstance.getValue();
2727           // I would prefer to use (end-start) * theInstance.getValue(); however,
2728           // we've had some problems getting setValue() called in time, thus
2729           // leaving us with getValues() of 0 sometimes.  See longer comment in dynrpc.C --ari
2730           extern float currSamplingRate;
2731           value = (end - start) * currSamplingRate;
2732         } else if (theIMetric->name() == "number_of_cpus") {
2733           value = (end - start) * numberOfCPUs;
2734         } else if (theIMetric->name() == "total_CT") {
2735           value = (end - start) * internalMetricCounterId;
2736           assert(value>=0.0);
2737         } else if (theIMetric->name() == "numOfActCounters") {
2738           value = (end - start) * numOfActCounters_all;
2739           assert(value>=0.0);
2740         } else if (theIMetric->name() == "numOfActProcTimers") {
2741           value = (end - start) * numOfActProcTimers_all;
2742           assert(value>=0.0);
2743         } else if (theIMetric->name() == "numOfActWallTimers") {
2744           value = (end - start) * numOfActWallTimers_all;
2745           assert(value>=0.0);
2746         } else if (theIMetric->name() == "active_CT") {
2747           value = (end - start) * (numOfActCounters_all+numOfActProcTimers_all+numOfActWallTimers_all);
2748           assert(value>=0.0);
2749         } else if (theIMetric->name() == "infHeapMemAvailable") {
2750           value = (end - start) * inferiorMemAvailable;
2751           assert(value>=0.0);
2752         } else if (theIMetric->style() == EventCounter) {
2753           value = theInstance.getValue();
2754           // assert((value + 0.0001)  >= imp->cumulativeValue);
2755           value -= theInstance.getCumulativeValue();
2756           theInstance.bumpCumulativeValueBy(value);
2757         } else if (theIMetric->style() == SampledFunction) {
2758           value = theInstance.getValue();
2759         }
2760
2761         theInstance.report(start, end, value);
2762            // calls metricDefinitionNode->forwardSimpleValue()
2763       }
2764     }
2765 }
2766
2767 void disableAllInternalMetrics() {
2768     for (unsigned u=0; u < internalMetric::allInternalMetrics.size(); u++) {
2769       internalMetric *theIMetric = internalMetric::allInternalMetrics[u];
2770
2771       // Now loop thru all the enabled instances of this internal metric...
2772       while (theIMetric->num_enabled_instances() > 0) {
2773         internalMetric::eachInstance &theInstance = theIMetric->getEnabledInstance(0);
2774         tp->endOfDataCollection(theInstance.getMId());
2775         theIMetric->disableInstance(0);
2776       }
2777     }  
2778 }
2779
2780 #ifdef SHM_SAMPLING
2781
2782 unsigned sampledShmIntCounterReqNode::getInferiorPtr(process *proc) const {
2783     // counterPtr could be NULL if we are building AstNodes just to compute
2784     // the cost - naim 2/18/97
2785     // NOTE:
2786     // this routine will dissapear because we can't compute the address
2787     // of the counter/timer without knowing the thread id - naim 3/17/97
2788     //
2789     if (allocatedIndex == UINT_MAX || allocatedLevel == UINT_MAX) return(0);
2790     assert(proc != NULL);
2791     superTable &theTable = proc->getTable();
2792     // we assume there is only one thread
2793     return((unsigned) theTable.index2InferiorAddr(0,0,allocatedIndex,allocatedLevel));
2794 }
2795
2796 unsigned sampledShmWallTimerReqNode::getInferiorPtr(process *proc) const {
2797     // counterPtr could be NULL if we are building AstNodes just to compute
2798     // the cost - naim 2/18/97
2799     // NOTE:
2800     // this routine will dissapear because we can't compute the address
2801     // of the counter/timer without knowing the thread id - naim 3/17/97
2802     //
2803     if (allocatedIndex == UINT_MAX || allocatedLevel == UINT_MAX) return(0);
2804     assert(proc != NULL);
2805     superTable &theTable = proc->getTable();
2806     // we assume there is only one thread
2807     return((unsigned) theTable.index2InferiorAddr(1,0,allocatedIndex,allocatedLevel));
2808 }
2809
2810 unsigned sampledShmProcTimerReqNode::getInferiorPtr(process *proc) const {
2811     // counterPtr could be NULL if we are building AstNodes just to compute
2812     // the cost - naim 2/18/97
2813     // NOTE:
2814     // this routine will dissapear because we can't compute the address
2815     // of the counter/timer without knowing the thread id - naim 3/17/97
2816     //
2817     if (allocatedIndex == UINT_MAX || allocatedLevel == UINT_MAX) return(0);
2818     assert(proc != NULL);
2819     superTable &theTable = proc->getTable();
2820     // we assume there is only one thread
2821     return((unsigned) theTable.index2InferiorAddr(2,0,allocatedIndex,allocatedLevel));
2822 }
2823
2824 #endif