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