This commit merges the AGG_LEV enumeration into the MDN_TYPE enumeration.
[dyninst.git] / paradynd / src / mdl.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 // $Id: mdl.C,v 1.95 2001/09/04 19:48:47 gurari Exp $
43
44 #include <iostream.h>
45 #include <stdio.h>
46 #include "dyninstRPC.xdr.SRVR.h"
47 #include "paradyn/src/met/mdl_data.h"
48 #include "paradynd/src/metric.h"
49 #include "dyninstAPI/src/inst.h"
50 #include "dyninstAPI/src/ast.h"
51 #include "paradynd/src/main.h"
52 #include "dyninstAPI/src/symtab.h"
53 #include "common/h/Timer.h"
54 #include "paradynd/src/mdld.h"
55 #include "dyninstAPI/src/showerror.h"
56 #include "dyninstAPI/src/process.h"
57 #include "dyninstAPI/src/pdThread.h"
58 #include "common/h/debugOstream.h"
59 #include "pdutil/h/pdDebugOstream.h"
60 #include "dyninstAPI/src/instPoint.h" // new...for class instPoint
61
62 // The following vrbles were defined in process.C:
63 extern debug_ostream attach_cerr;
64 extern debug_ostream inferiorrpc_cerr;
65 extern debug_ostream shmsample_cerr;
66 extern debug_ostream forkexec_cerr;
67 extern pdDebug_ostream metric_cerr;
68
69
70 // Some global variables
71 static string currentMetric;  // name of the metric that is being processed.
72 static string daemon_flavor;
73 static process *global_proc = NULL;
74 static bool mdl_met=false, mdl_cons=false, mdl_stmt=false, mdl_libs=false;
75
76 inline unsigned ui_hash(const unsigned &u) { return u; }
77
78 // static members of mdl_env
79 vector<unsigned> mdl_env::frames;
80 vector<mdl_var> mdl_env::all_vars;
81
82 // static members of mdl_data
83 dictionary_hash<unsigned, vector<mdl_type_desc> > mdl_data::fields(ui_hash);
84 vector<mdl_focus_element> mdl_data::foci;
85 vector<T_dyninstRPC::mdl_stmt*> mdl_data::stmts;
86 vector<T_dyninstRPC::mdl_constraint*> mdl_data::all_constraints;
87 vector<string> mdl_data::lib_constraints;
88 vector<T_dyninstRPC::mdl_metric*> mdl_data::all_metrics;
89
90
91 #if defined(MT_THREAD)
92 int index_in_data(unsigned lev, unsigned ind, vector<dataReqNode*>& data) {
93   int size = data.size();
94   
95   for (int i=0; i<size; i++) {
96     if ((lev == data[i]->getAllocatedLevel())
97         && (ind == data[i]->getAllocatedIndex()))
98       return i;
99   }
100   
101   // not matched: return < 0
102   return -1;
103 }
104 #else
105 int index_in_data(Address v, vector<dataReqNode*>& data) {
106   int size = data.size();
107   
108   for (int i=0; i<size; i++) {
109     if (v == data[i]->getInferiorPtr(global_proc))
110       return i;
111   }
112   
113   // not matched: return < 0
114   return -1;
115 }
116 #endif
117
118
119 //
120 // walk_deref() is used to process the fields of the MDL_EXPR_DOT
121 // expression.  the MDL_EXPR_DOT expression is used to be called
122 // MDL_EXPR_DEREF, which is inaccurate at best. --chun
123 //
124 static bool walk_deref(mdl_var& ret, vector<unsigned>& types);
125
126 //
127 // these two do_operation()'s are for processing MDL_EXPR_BINOP, 
128 // MDL_EXPR_POSTUP, MDL_EXPR_PREUOP expressions. --chun
129 //
130 static bool do_operation(mdl_var& ret, mdl_var& left, mdl_var& right, unsigned bin_op);
131 static bool do_operation(mdl_var& ret, mdl_var& lval, unsigned u_op, bool is_preop);
132
133
134 class list_closure 
135 {
136 public:
137   list_closure(string& i_name, mdl_var& list_v)
138     : index_name(i_name), element_type(0), index(0), int_list(NULL), 
139     float_list(NULL), string_list(NULL), bool_list(NULL), func_list(NULL), 
140     funcName_list(NULL), mod_list(NULL), point_list(NULL), max_index(0)
141   {
142     assert (list_v.is_list());
143
144     element_type = list_v.element_type();
145     switch(element_type) 
146     {
147       case MDL_T_INT:
148         assert (list_v.get(int_list));
149         max_index = int_list->size();
150         break;
151       case MDL_T_FLOAT:
152         assert (list_v.get(float_list));
153         max_index = float_list->size();
154         break;
155       case MDL_T_STRING:
156         assert (list_v.get(string_list));
157         max_index = string_list->size();
158         break;
159       case MDL_T_PROCEDURE_NAME:
160         assert (list_v.get(funcName_list));
161         max_index = funcName_list->size();
162         break;
163       case MDL_T_PROCEDURE:
164         assert (list_v.get(func_list));
165         max_index = func_list->size();
166         break;
167       case MDL_T_MODULE:
168         assert (list_v.get(mod_list));
169         max_index = mod_list->size();
170         break;
171       case MDL_T_POINT:
172         assert (list_v.get(point_list));
173         max_index = point_list->size();
174         break;
175       default:
176         assert(0);
177     }
178   }
179
180   ~list_closure() { }
181
182   bool next() 
183   {
184     string s;
185     function_base *pdf; module *m;
186     float f; int i;
187     instPoint *ip;
188
189     if (index >= max_index) return false;
190     switch(element_type) 
191     {
192       case MDL_T_INT:
193         i = (*int_list)[index++];
194         return (mdl_env::set(i, index_name));
195       case MDL_T_FLOAT:
196         f = (*float_list)[index++];
197         return (mdl_env::set(f, index_name));
198       case MDL_T_STRING:
199         s = (*string_list)[index++];
200         return (mdl_env::set(s, index_name));
201       case MDL_T_PROCEDURE_NAME:
202         // lookup-up the functions defined in resource lists
203         // the function may not exist in the image, in which case we get the
204         // next one
205         do 
206         {
207           functionName *fn = (*funcName_list)[index++];
208           pdf = global_proc->findOneFunction(fn->get());
209         }
210         while (pdf == NULL && index < max_index);
211         if (pdf == NULL)
212           return false;
213         return (mdl_env::set(pdf, index_name));
214       case MDL_T_PROCEDURE:
215         pdf = (*func_list)[index++];
216         assert(pdf);
217         return (mdl_env::set(pdf, index_name));
218       case MDL_T_MODULE: 
219         m = (*mod_list)[index++];
220         assert (m);
221         return (mdl_env::set(m, index_name));
222       case MDL_T_POINT:
223         ip = (*point_list)[index++];
224         assert (ip);
225         return (mdl_env::set(ip, index_name));
226       default:
227         assert(0);
228     }
229     return false;
230   }
231
232 private:
233   string index_name;
234   unsigned element_type;
235   unsigned index;
236   vector<int> *int_list;
237   vector<float> *float_list;
238   vector<string> *string_list;
239   vector<bool> *bool_list;
240   vector<function_base*> *func_list;
241   vector<functionName*> *funcName_list;
242   vector<module*> *mod_list;
243   vector<instPoint*> *point_list;
244   unsigned max_index;
245 };
246
247 //
248 // Since the metric, constraints, etc. are manufactured in paradyn and
249 // then shipped to daemons over the RPC, the non-noarg constructors of 
250 // mdl_metric, mdl_constraint, mdl_instr_stmt, etc. and their destructors
251 // shoudln't be called here, rather, the paradyn's version should be
252 // called.  But I could be wrong.  Put assert(0)'s to verify this; didn't
253 // encounter any problem.  Should any problem occur in the future, the
254 // assert's need to be removed.  --chun
255 //
256 T_dyninstRPC::mdl_metric::mdl_metric(string id, string name, string units, 
257                                     u_int agg, u_int sty, u_int type,
258                                     vector<T_dyninstRPC::mdl_stmt*> *mv, 
259                                     vector<string> *flav,
260                                     vector<T_dyninstRPC::mdl_constraint*> *cons,
261                                     vector<string> *temp_counters,
262                                     bool developerMode,
263                                     int unitstype)
264 : id_(id), name_(name), units_(units), agg_op_(agg), style_(sty),
265   type_(type), stmts_(mv), flavors_(flav), constraints_(cons),
266   temp_ctr_(temp_counters), developerMode_(developerMode),
267   unitstype_(unitstype) { assert(0); }
268
269 T_dyninstRPC::mdl_metric::mdl_metric()
270 : id_(""), name_(""), units_(""), agg_op_(0), style_(0), type_(0), 
271   stmts_(NULL), flavors_(NULL), constraints_(NULL), temp_ctr_(NULL),
272   developerMode_(false), unitstype_(0) { }
273
274 T_dyninstRPC::mdl_metric::~mdl_metric() {
275   assert (0);
276   if (stmts_) {
277     unsigned size = stmts_->size();
278     for (unsigned u=0; u<size; u++)
279       delete (*stmts_)[u];
280     delete stmts_;
281   }
282   delete flavors_;
283
284   if (constraints_) {
285     unsigned size = constraints_->size();
286     for (unsigned u=0; u<size; u++)
287       delete (*constraints_)[u];
288     delete constraints_;
289   }
290
291 }
292
293 bool mdl_data::new_metric(string id, string name, string units,
294                           u_int agg, u_int sty, u_int type,
295                           vector<T_dyninstRPC::mdl_stmt*> *mv,
296                           vector<string> *flav,
297                           vector<T_dyninstRPC::mdl_constraint*> *cons,
298                           vector<string> *temp_counters,
299                           bool developerMode,
300                           int unitstype) 
301 {
302   assert (0);
303   T_dyninstRPC::mdl_metric *m = new T_dyninstRPC::mdl_metric(id, name, 
304                                                              units, agg,
305                                                              sty, type, mv,
306                                                              flav, cons,
307                                                              temp_counters,
308                                                              developerMode,
309                                                              unitstype);
310   if (!m)
311     return false;
312   else {
313     all_metrics += m;
314     return true;
315   }
316 }
317
318 static bool other_machine_specified(vector< vector<string> > &focus,
319                                     string& machine) {
320   assert(focus[resource::machine][0] == "Machine");
321
322   switch (focus[resource::machine].size()) {
323   case 1: break;
324   case 2: //Machine/grilled
325   case 3: //Machine/grilled/process
326   case 4: //Machine/grilled/process/thread
327     if (machine != focus[resource::machine][1]) return true;
328     break;
329   default:
330     assert(0);
331   }
332   return false;
333 }
334
335 static void add_processes(vector< vector<string> > &focus,
336                                  vector<process*> procs,
337 #if defined(MT_THREAD)
338                           vector<process*> &ip,
339                           vector< vector<pdThread *> >& threadsVec,
340                           vector< vector<pdThread *> >& instThreadsVec) {
341 #else
342                                  vector<process*> &ip) {
343 #endif
344   assert(focus[resource::machine][0] == "Machine");
345   unsigned pi, ps;
346
347   switch(focus[resource::machine].size()) {
348   case 1:
349   case 2:
350     ip = procs;
351 #if defined(MT_THREAD)
352     instThreadsVec = threadsVec;
353 #endif
354     break;
355   case 3:
356     ps = procs.size();
357     for (pi=0; pi<ps; pi++)
358       if (procs[pi]->rid->part_name() == focus[resource::machine][2]) {
359         ip += procs[pi];
360         break;
361       }
362 #if defined(MT_THREAD)
363     for (pi=0; pi<ip.size(); pi++) {
364       instThreadsVec += ip[pi]->threads;
365     }
366 #endif
367     break;
368 #if defined(MT_THREAD)
369   case 4:
370     ps = threadsVec.size();
371     for (pi=0; pi<ps; pi++) {
372       vector<pdThread *> tmpThrVec; 
373       if (procs[pi]->rid->part_name() == focus[resource::machine][2]) {
374         ip += procs[pi];
375         for (unsigned ti=0; ti<threadsVec[pi].size(); ti++) {
376           pdThread *thr;
377           thr = (threadsVec[pi])[ti];
378           if (thr && thr->get_rid()) {
379             if (thr->get_rid()->part_name() == focus[resource::machine][3]) {
380               tmpThrVec += thr;
381               break;
382             }
383           }
384         }
385       }
386       if (tmpThrVec.size() > 0) instThreadsVec += tmpThrVec;
387     }
388     break;
389 #endif
390   default:
391     assert(0);
392   }
393 #if defined(TEST_DEL_DEBUG)
394   sprintf(errorLine,"--> instThreadsVec.size()=%d\n",instThreadsVec.size());
395   logLine(errorLine);
396   for (unsigned i=0;i<instThreadsVec.size();i++) {
397     sprintf(errorLine,"--> instThreadsVec[%d].size()=%d\n",i,(instThreadsVec[i]).size());
398     logLine(errorLine);
399     for (unsigned j=0;j<(instThreadsVec[i]).size();j++) {
400       pdThread *thr;
401       thr = (instThreadsVec[i])[j];
402       sprintf(errorLine,"--> thread %d has been selected\n",thr->get_tid());
403       logLine(errorLine);
404     }
405   }
406 #endif
407 }
408
409 static bool focus_matches(vector<string>& focus, vector<string> *match_path) {
410   unsigned mp_size = match_path->size();
411   unsigned f_size = focus.size();
412
413   if ((mp_size < 1) || (f_size < 2) || (mp_size != (f_size-1))) {
414     return false;
415   }
416
417   for (unsigned u = 0; u < mp_size; u++) {
418     if(((*match_path)[u] != "*") && (focus[u] != (*match_path)[u])) {
419       return false;
420     }
421   }
422
423   return true;
424 }
425
426
427 // Global constraints are specified by giving their name within a metric def
428 // Find the real constraint by searching the dictionary using this name
429 static T_dyninstRPC::mdl_constraint *flag_matches(vector<string>& focus, 
430                                                   T_dyninstRPC::mdl_constraint *match_me,
431                                                   bool& is_default) 
432 {
433   unsigned c_size = mdl_data::all_constraints.size();
434   for (unsigned cs=0; cs<c_size; cs++) 
435     if (mdl_data::all_constraints[cs]->id_ == match_me->id_) {
436       match_me = mdl_data::all_constraints[cs];
437       if (focus_matches(focus, mdl_data::all_constraints[cs]->match_path_)) {
438         if (mdl_data::all_constraints[cs]->data_type_ == MDL_T_NONE)
439           is_default = true;
440         else
441           is_default = false;
442         return match_me;
443       }
444     }
445
446   return NULL;
447 }
448
449 // Determine if the global and local constraints are applicable
450 // Global constraints that are applicable are put on flag_cons
451 // base_used returns the ONE replace constraint that matches
452
453 static bool check_constraints(vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
454                               vector<T_dyninstRPC::mdl_constraint*>& base_used,
455                               vector< vector<string> >& focus,
456                               vector<T_dyninstRPC::mdl_constraint*> *cons,
457                               vector<unsigned>& flag_dex,
458                               vector<unsigned>& base_dex) {
459   unsigned size = cons->size();
460
461   unsigned foc_size = focus.size();
462   for (unsigned fi=0; fi<foc_size; fi++) {
463     unsigned el_size = focus[fi].size();
464     if ((focus[fi][0] == "Machine") || (focus[fi][0] == "Process")) {
465       // do nothing, can't specify constraints for machine or process
466       ;
467     } else if (el_size) {
468       bool matched = false;
469       // Hack allow constraints such as "/SyncObject"
470       // However, these don't have to match
471       // Otherwise a failure to match means that the metric is invalid for the resource
472       unsigned ci=0;
473       while ((ci < size) && !matched) {
474         if (!(*cons)[ci]->match_path_) {
475           // this is an external constraint, apply if applicable
476           T_dyninstRPC::mdl_constraint *mc;
477           bool is_default;
478           if ((mc = flag_matches(focus[fi], (*cons)[ci], is_default))) {
479             matched = true;
480             if (!is_default) {
481               flag_cons += mc; flag_dex += fi;
482             }
483           }
484         } else {
485           // this could be the real constraint to use
486           // this guarantees that the first match is used
487           // TODO -- first matching replace constraint wins
488           // CHANGE: get all that match
489           if (focus_matches(focus[fi], (*cons)[ci]->match_path_)) {
490             matched = true;
491             base_used += (*cons)[ci]; base_dex += fi; 
492           }
493         }
494         ci++;
495       }
496       if (!matched && (el_size>1)) {
497         return false;
498       }
499     } else {
500       return false;
501     }
502   }
503   return true;
504 }
505
506 // update the interpreter environment for this processor
507 // Variable updated: $procedures, $modules, $exit, $start
508 static bool update_environment(process *proc) {
509
510   // for cases when libc is dynamically linked, the exit symbol is not
511   // correct
512   string vname = "$exit";
513   function_base *pdf = proc->findOneFunction(string(EXIT_NAME));
514    if (pdf) { 
515       mdl_env::add(vname, false, MDL_T_PROCEDURE);
516       mdl_env::set(pdf, vname);
517   }
518
519   vname = "$start";
520   pdf = proc->getMainFunction();
521   if (!pdf) return false;
522
523   vname = "$start";
524   mdl_env::add(vname, false, MDL_T_PROCEDURE);
525   mdl_env::set(pdf, vname);
526
527   vname = "$procedures";
528   mdl_env::add(vname, false, MDL_T_LIST_PROCEDURE);
529   // only get the functions that are not excluded by exclude_lib or 
530   // exclude_func
531   mdl_env::set(proc->getIncludedFunctions(), vname);
532
533   vname = "$modules";
534   mdl_env::add(vname, false, MDL_T_LIST_MODULE);
535   // only get functions that are not excluded by exclude_lib or exclude_func
536   mdl_env::set(proc->getIncludedModules(), vname);
537
538   return true;
539 }
540
541 dataReqNode *create_data_object(unsigned mdl_data_type,
542                                 metricDefinitionNode *mn,
543 #if defined(MT_THREAD)
544                                 bool computingCost,
545                                 pdThread *thr) {
546 #else
547                                 bool computingCost) {
548 #endif
549   switch (mdl_data_type) {
550   case MDL_T_COUNTER:
551 #if defined(MT_THREAD)
552     return (mn->addSampledIntCounter(thr, 0, computingCost));
553 #else
554     return (mn->addSampledIntCounter(0, computingCost));
555 #endif
556
557   case MDL_T_WALL_TIMER:
558 #if defined(MT_THREAD)
559     return (mn->addWallTimer(computingCost, thr));
560 #else
561     return (mn->addWallTimer(computingCost));
562 #endif
563
564   case MDL_T_PROC_TIMER:
565 #if defined(MT_THREAD)
566     return (mn->addProcessTimer(computingCost, thr));
567 #else
568     return (mn->addProcessTimer(computingCost));
569 #endif
570
571   case MDL_T_NONE:
572     // just to keep mdl apply allocate a dummy un-sampled counter.
573 #if defined(SHM_SAMPLING)
574     // "true" means that we are going to create a sampled int counter but
575     // we are *not* going to sample it, because it is just a temporary
576     // counter - naim 4/22/97
577     // By default, the last parameter is false - naim 4/23/97
578 #if defined(MT_THREAD)
579     return (mn->addSampledIntCounter(thr, 0, computingCost, true));
580 #else
581     return (mn->addSampledIntCounter(0, computingCost, true));
582 #endif //MT_THREAD
583 #else
584     return (mn->addUnSampledIntCounter(0, computingCost));
585 #endif //SHM_SAMPLING
586
587   default:
588     assert(0);
589     return NULL;
590   }
591 }
592
593 // used by both "non-threaded" version and "threaded" version
594 bool checkInMIPrimitives(string flat_name, metricDefinitionNode *&prim, bool replace_prim)
595 {
596   // this is DCG optimization that will be applied only if OPT_VERSION is on
597   // DCG for Dynamic Code Generation
598   if (!OPT_VERSION)
599     return false;
600   
601   metric_cerr << " -- in checkInMIPrimitives (by mdl apply_to_process) " << endl;
602   
603   metricDefinitionNode *temp = NULL;
604   const bool alreadyThere = allMIPrimitives.find(flat_name, temp);
605   
606   if (alreadyThere) {
607     if (replace_prim) {
608       // fry old entry in allMIPrimitives
609       metric_cerr << " checkInMIPrimitives: found primitive named " << flat_name 
610                   << " but continue anyway since replace_prim flag is set" << endl;
611       // note we don't call 'delete'
612       allMIPrimitives.undef(flat_name);
613       
614       return false;
615     }
616     else {
617       metric_cerr << " checkInMIPrimitives: found primitive for "
618                   << flat_name << " ... reusing it. " << endl;
619       metric_cerr << "   founded name = " << temp->getFullName() << endl;
620       
621       prim = temp;
622       return true;
623     }
624   }
625   else {
626     metric_cerr << " MDL: going to create new primitive since flatname "
627                 << flat_name << " doesn't exist" << endl;
628     
629     return false;
630   }
631 }
632
633 // same as "checkInMIPrimitives" except that this is checked in allMIComponents
634 // also used by both "non-threaded" version and "threaded" version
635 bool checkInMIComponents(string flat_name, metricDefinitionNode *&comp, bool replace_comp)
636 {
637   // this level of redundency check is applied no matter whether OPT_VERSION is on
638   // if (!OPT_VERSION)
639   // return false;
640   
641   metric_cerr << " -- in checkInMIComponents (by mdl apply_to_process) " << endl;
642   
643   metricDefinitionNode *temp = NULL;
644   const bool alreadyThere = allMIComponents.find(flat_name, temp);
645   
646   if (alreadyThere) {
647     if (replace_comp) {
648       // fry old entry in allMIComponents
649       metric_cerr << " checkInMIComponents: found component named " << flat_name 
650                   << " but continue anyway since replace_comp flag is set" << endl;
651       // note we don't call 'delete'
652       allMIComponents.undef(flat_name);
653       
654       return false;
655     }
656     else {
657       metric_cerr << " chekInMIComponents: found component for "
658                   << flat_name << " ... reusing it. " << endl;
659       metric_cerr << "   founded name = " << temp->getFullName() << endl;
660       
661       comp = temp;
662       return true;
663     }
664   }
665   else {
666     metric_cerr << " MDL: going to create new component since flatname "
667                 << flat_name << " doesn't exist" << endl;
668     
669     return false;
670   }
671 }
672
673 #if !defined(MT_THREAD)
674 // this prim should always be a new primitive mdn just constructed
675 // that is, not used by any component mdn yet, and not added to
676 // allMIPrimitives yet.
677 bool check2MIPrimitives(string flat_name, metricDefinitionNode *&prim,
678                         bool computingCost)
679 {
680   // this is DCG optimization that will be applied only if OPT_VERSION is on
681   // DCG for Dynamic Code Generation, basicly, a list of (where, definition) of a variable
682   // is checked, reuse an already instrumented variable if a match is found between the two
683   if (!OPT_VERSION)
684     return false;
685
686   metric_cerr << " -- in check2MIPrimitives " << endl;
687   assert(!allMIPrimitives.defines(flat_name));
688
689   metricDefinitionNode *match_prim = prim->matchInMIPrimitives();
690
691   if (match_prim != NULL) {  // matched!!
692     metric_cerr << "  matched in miprimitives! " << flat_name << endl;
693
694     if (!computingCost) {
695       if (toDeletePrimitiveMDN(prim))                                                   // cleanup_drn
696         delete prim;  // this is proper, should not be used anywhere else               // removeComponent
697       else                                                                              // then delete
698         metric_cerr << "  ERR: should be able to delete primitive! " << endl;
699     }
700
701     prim = match_prim;
702   }
703   else {
704     // the ONLY place to add into allMIPrimitives
705     allMIPrimitives[flat_name] = prim;
706   }
707
708   return (match_prim != NULL);
709 }
710
711 // create metric variable and temp varaibles for metric primitive
712 void initDataRequests(metricDefinitionNode *prim,
713                       string& id,
714                       unsigned& type,
715                       vector<string> *temp_ctr,
716                       bool computingCost)
717 {
718   // Create the timer, counter
719   dataReqNode *the_node = create_data_object(type, prim, computingCost);
720   assert(the_node);
721
722   // we've pushed it earlier
723   mdl_env::set(the_node, id);
724
725   // Create the temporary counters - are these useful
726   if (temp_ctr) {
727     unsigned tc_size = temp_ctr->size();
728     for (unsigned tc=0; tc<tc_size; tc++) {
729 #if defined(SHM_SAMPLING) 
730       // "true" means that we are going to create a sampled int counter but
731       // we are *not* going to sample it, because it is just a temporary
732       // counter - naim 4/22/97
733       // By default, the last parameter is false - naim 4/23/97
734       dataReqNode *temp_node=prim->addSampledIntCounter(0,computingCost,true);
735 #else
736       dataReqNode *temp_node=prim->addUnSampledIntCounter(0,computingCost);
737 #endif
738       // we've pushed them earlier too
739       mdl_env::set(temp_node, (*temp_ctr)[tc]);
740     }
741   }
742 }
743
744 metricDefinitionNode *
745 apply_to_process(process *proc, 
746                  string& id, string& name,
747                  vector< vector<string> >& focus,
748                  unsigned& agg_op, metricStyle /* metric_style */,
749                  unsigned& type,
750                  vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
751                  vector<T_dyninstRPC::mdl_constraint*>& base_use,
752                  vector<T_dyninstRPC::mdl_stmt*> *stmts,
753                  vector<unsigned>& flag_dex,
754                  vector<unsigned>& base_dex,
755                  vector<string> *temp_ctr,
756                  bool replace_component,
757                  bool computingCost) {
758
759     metric_cerr << "apply_to_process()" << endl;
760
761     if (!update_environment(proc)) return NULL;
762
763     // compute the flat_name for this component: the machine and process
764     // are always defined for the component, even if they are not defined
765     // for the aggregate metric.
766     vector< vector<string> > component_focus(focus); // they start off equal
767     string component_flat_name(name);
768
769     for (unsigned u1 = 0; u1 < focus.size(); u1++) {
770       for (unsigned u2 = 0; u2 < focus[u1].size(); u2++) {
771         component_flat_name += focus[u1][u2];
772       }
773
774       if (focus[u1][0] == "Machine") {
775         switch ( (focus[u1].size()) ) {
776           case 1: {
777             // there was no refinement to a specific machine...but the component focus
778             // must have such a refinement.
779             string tmp_part_name = machineResource->part_name();
780             component_flat_name += tmp_part_name;
781             component_focus[u1] += tmp_part_name;
782             // no break
783           }
784           case 2: {
785             // there was no refinement to a specific process...but the component
786             // focus must have such a refinement.
787             string tmp_part_name = proc->rid->part_name();
788             component_flat_name += tmp_part_name;
789             component_focus[u1] += tmp_part_name;
790             break;
791           }
792         } 
793       }
794     }//for u1
795
796     // now assert that focus2flatname(component_focus) equals component_flat_name
797     extern string metricAndCanonFocus2FlatName(const string &met,
798                                                const vector< vector<string> > &focus);
799     assert(component_flat_name == metricAndCanonFocus2FlatName(name, component_focus));
800
801     metricDefinitionNode *mn = NULL;
802     const bool matched = checkInMIComponents(component_flat_name, mn, replace_component);
803
804     if (matched)  return mn;
805
806
807     // TODO -- Using aggOp value for this metric -- what about folds
808     mn = new metricDefinitionNode(proc, name, focus, component_focus, 
809                                   component_flat_name, aggregateOp(agg_op), 
810                                   COMP_MDN);
811     assert(mn);
812
813     // If the component exists, then we've either already returned, or fried it.
814     assert(!allMIComponents.defines(component_flat_name));
815     allMIComponents[component_flat_name] = mn;
816
817
818     metricDefinitionNode *metric_prim = NULL;
819     string metric_flat_name(component_flat_name);
820     const bool alreadyThere = checkInMIPrimitives(metric_flat_name, metric_prim, replace_component);
821
822
823     // CASE 1:  there are "replaced constraints" that match, generate code accordingly
824     if (base_use.size() > 0) {
825
826       unsigned base_size = base_use.size();
827       metric_cerr << "  create base_use (size of " << base_size << ") primitive " << endl;
828
829       if (!alreadyThere) {
830         metric_cerr << "  base_use not already there " << endl;
831
832         // primitive metricDefinitionNode constructor
833         metric_prim = 
834           new metricDefinitionNode(proc, name, focus, component_focus,
835                                    metric_flat_name, aggregateOp(agg_op), 
836                                    PRIM_MDN);
837
838         initDataRequests(metric_prim, id, type, temp_ctr, computingCost); // to create the metric data sample
839
840         for (unsigned bs=0; bs<base_size; bs++) {
841           dataReqNode *flag = NULL;
842           // The following calls mdl_constraint::apply()
843           if (!base_use[bs]->apply(metric_prim,
844                                    flag, 
845                                    focus[base_dex[bs]], 
846                                    proc, 
847                                    (pdThread*) NULL, 
848                                    computingCost)) {
849             if (!computingCost) metric_prim->cleanup_drn();
850             delete metric_prim;
851             return NULL;
852           }
853         }
854       }
855       else {
856         metric_cerr << "  base_use already there, reuse it! " << endl;
857         assert(metric_prim);
858       }
859     } else {
860       // CASE 2: no "replace constraints" match, use normal constraints and metric def
861       //    First ------ normal constraints part, generate constraints code
862
863       if (!alreadyThere) {
864         unsigned flag_size = flag_cons.size(); // could be zero
865         vector<dataReqNode*> flags;
866         metric_cerr << "There are " << flag_size << " flags (constraints)" << endl;
867
868         for (unsigned fs=0; fs<flag_size; fs++) {
869           metricDefinitionNode *cons_prim = NULL;
870           string primitive_flat_name = metricAndCanonFocus2FlatName(flag_cons[fs]->id(), component_focus);
871
872           metric_cerr << "  create " << fs << "th constriant primitive" << endl
873                       << "    " << primitive_flat_name << endl;
874
875           const bool alThere = checkInMIPrimitives(primitive_flat_name, cons_prim, replace_component);
876
877           if (!alThere) {
878             metric_cerr << "  flag not already there " << endl;
879
880             // primitive metricDefinitionNode constructor
881             // the primitive_focus is same as the component_focus
882             cons_prim = 
883               new metricDefinitionNode(proc, flag_cons[fs]->id(), focus, 
884                                        component_focus, primitive_flat_name,
885                                        aggregateOp(agg_op), PRIM_MDN);
886
887             dataReqNode *flag = NULL;
888             // The following calls mdl_constraint::apply()
889             if (!flag_cons[fs]->apply(cons_prim,
890                                       flag, 
891                                       focus[flag_dex[fs]], 
892                                       proc, 
893                                       (pdThread*) NULL, 
894                                       computingCost)) {
895               if (!computingCost) cons_prim->cleanup_drn();
896               // delete cons_prim;
897               return NULL;
898             }
899
900             check2MIPrimitives(primitive_flat_name, cons_prim, computingCost);
901           }
902           else { // alThere (constraints)
903             metric_cerr << "  flag already there " << endl;
904             assert(cons_prim);
905           }
906
907           dataReqNode *flag = cons_prim->getFlagDRN();
908           assert(flag);
909           flags += flag;
910
911           mn->addPartDummySample(cons_prim);
912
913           // metric_cerr << "Applied constraint for " << flag_cons[fs]->id_ << endl;
914         }
915
916         // Second ------ met def part, generate metric code
917         metric_cerr << "  metric not already there, create:   " << endl;
918
919         // primitive metricDefinitionNode constructor
920         metric_prim = 
921           new metricDefinitionNode(proc, name, focus, component_focus, 
922                                    metric_flat_name, aggregateOp(agg_op),
923                                    PRIM_MDN);
924
925         // do data requests for metric primitive
926         initDataRequests(metric_prim, id, type, temp_ctr, computingCost);
927
928         unsigned size = stmts->size();
929         for (unsigned u=0; u<size; u++) {
930           if (!(*stmts)[u]->apply(metric_prim, flags)) { // virtual fn call depending on stmt type
931             if (!computingCost) metric_prim->cleanup_drn();
932             delete metric_prim;
933             return NULL;
934           }
935         }
936       }
937       else {
938         metric_cerr << "  metric already there, reuse it! " << endl;
939         assert(metric_prim);
940       }
941     } // !(base_use)
942
943     if (!metric_prim->nonNull()) {
944       metric_cerr << "metric_prim->nonNull()" << endl;
945       if (!computingCost) metric_prim->cleanup_drn();
946       delete metric_prim;
947       return NULL;
948     }
949
950     if (!alreadyThere)  check2MIPrimitives(metric_flat_name, metric_prim, computingCost);
951
952     mn->addPart(metric_prim);
953
954     return mn;
955 }
956
957 #else // following defined(MT_THREAD)
958
959 // this prim should always be a new primitive mdn just constructed
960 // that is, not used by any component mdn yet, and not added to
961 // allMIPrimitives yet.
962 bool checkFlagMIPrimitives(string flat_name, metricDefinitionNode *& prim,
963                            bool computingCost)
964 {
965   // this is DCG optimization that will be applied only if OPT_VERSION is on
966   // DCG for Dynamic Code Generation, basicly, a list of (where, definition) of a variable
967   // is checked, reuse an already instrumented variable if a match is found between the two
968   if (!OPT_VERSION)
969     return false;
970   
971   metric_cerr << " -- in checkFlagMIPrimitives " << endl;
972   assert(!allMIPrimitives.defines(flat_name));
973   
974   metricDefinitionNode *match_prim = prim->matchInMIPrimitives();
975   
976   if (match_prim != NULL) {  // matched!!
977     metric_cerr << "  flag matched in miprimitives! " << flat_name << endl;
978     
979     // if (toDeletePrimitiveMDN(prim))
980     // delete prim;  // this is proper, should not be used anywhere else
981     // else
982     // metric_cerr << "  ERR: should be able to delete primitive! " << endl;
983     if (!computingCost) {
984       prim->cleanup_drn();
985
986       for (unsigned u=0; u<(prim->getComponents()).size(); u++)
987         prim->removeComponent((prim->getComponents())[u]);
988       (prim->getComponents()).resize(0);
989       delete prim;
990     }
991     
992     prim = match_prim;
993   }
994   else {
995     // the ONLY 1 of 2 places to add into allMIPrimitives --- should be allMIPrimitiveFLAGS though
996     allMIPrimitives[flat_name] = prim;  // always has only one name
997   }
998   
999   return (match_prim != NULL);
1000 }
1001
1002 // same as "checkFlagMIPrimitives", except that this is for metric, --- not necessary
1003 // need to reuse proc_mn if a match is found
1004 bool checkMetricMIPrimitives(string metric_flat_name, metricDefinitionNode *& metric_prim,
1005                              bool computingCost)
1006 {
1007   // this is DCG optimization that will be applied only if OPT_VERSION is on
1008   // DCG for Dynamic Code Generation, basicly, a list of (where, definition) of a variable
1009   // is checked, reuse an already instrumented variable if a match is found between the two
1010   if (!OPT_VERSION)
1011     return false;
1012
1013   metric_cerr << " -- in checkMetricMIPrimitives " << endl;
1014   assert(!allMIPrimitives.defines(metric_flat_name));
1015   
1016   metricDefinitionNode *match_prim = metric_prim->matchInMIPrimitives();
1017   
1018   if (match_prim != NULL) {  // matched!!
1019     metric_cerr << "  metric matched in miprimitives! " << metric_flat_name << endl;
1020     
1021     // if (toDeletePrimitiveMDN(metric_prim))
1022     // delete metric_prim;  // this is proper, should not be used anywhere else
1023     // else
1024     // metric_cerr << "  ERR: should be able to delete primitive! " << endl;
1025     if (!computingCost) {
1026       metric_prim->cleanup_drn();
1027
1028       for (unsigned u=0; u<(metric_prim->getComponents()).size(); u++)
1029         metric_prim->removeComponent((metric_prim->getComponents())[u]);
1030       (metric_prim->getComponents()).resize(0);
1031       delete metric_prim;
1032     }
1033     
1034     metric_prim = match_prim;
1035   }
1036   else {
1037     // the ONLY 1 of 2 places to add into allMIPrimitives --- this is allMIPrimitives
1038     allMIPrimitives[metric_flat_name] = metric_prim;  // always has only one name
1039   }
1040
1041   return (match_prim != NULL);
1042 }
1043
1044 extern dictionary_hash <unsigned, metricDefinitionNode*> midToMiMap;//metric.C
1045 extern string metricAndCanonFocus2FlatName(const string &met, const vector< vector<string> > &focus);
1046
1047 // no "replace constraint" considered yet
1048 metricDefinitionNode *allocateConstraintData(
1049                  metricDefinitionNode* mn,
1050                  pdThread* thr,
1051                  process */*proc*/,
1052                  string& /*id*/,
1053                  vector< vector<string> >& /*focus*/,
1054                  unsigned& /*type*/,
1055                  T_dyninstRPC::mdl_constraint *flag_con,  // change from a vector to only one flag_con
1056                  vector<T_dyninstRPC::mdl_constraint*>& /*base_use*/,
1057                  vector<T_dyninstRPC::mdl_stmt*> */*stmts*/,
1058                  unsigned& /*flag_dex*/,
1059                  vector<unsigned>& /*base_dex*/,
1060                  vector<string> */*temp_ctr*/,
1061                  bool computingCost) {
1062
1063   assert(mn);
1064
1065   // from constraint::apply()
1066   switch (flag_con->data_type_) {
1067   case MDL_T_COUNTER:
1068   case MDL_T_WALL_TIMER:
1069   case MDL_T_PROC_TIMER:
1070     break;
1071   default:
1072     assert(0);
1073   }
1074   
1075   dataReqNode *drn = mn->addSampledIntCounter(thr,0,computingCost,true);
1076   
1077   // this flag will construct a predicate for the metric -- have to return it
1078   // flag = drn;
1079   assert(drn);
1080   
1081   if (!mn->nonNull()) {
1082     if (!computingCost) mn->cleanup_drn();
1083     delete mn;
1084     return NULL;
1085   }
1086   return mn;
1087 }
1088
1089 metricDefinitionNode *allocateMetricData(
1090                  metricDefinitionNode* mn,
1091                  pdThread* thr,
1092                  process */*proc*/,
1093                  string& /*id*/,
1094                  vector< vector<string> >& /*focus*/,
1095                  unsigned& type,
1096                  T_dyninstRPC::mdl_constraint */*flag_con*/,
1097                  vector<T_dyninstRPC::mdl_constraint*>& /*base_use*/,
1098                  vector<T_dyninstRPC::mdl_stmt*> */*stmts*/,
1099                  unsigned& /*flag_dex*/,
1100                  vector<unsigned>& /*base_dex*/,
1101                  vector<string> *temp_ctr,
1102                  bool computingCost) {
1103
1104   // very similar to initDataRequests
1105   // but did Not set var in mdl_env
1106   // because we are not going to generate any code for this thread
1107   
1108   dataReqNode *the_node = create_data_object(type, mn, computingCost, thr);
1109   assert(the_node);
1110   
1111   // Create the temporary counters 
1112   if (temp_ctr) {
1113     unsigned tc_size = temp_ctr->size();
1114     for (unsigned tc=0; tc<tc_size; tc++) {
1115       dataReqNode *temp_node = mn->addSampledIntCounter(thr,0,computingCost,true);
1116       assert(temp_node);
1117     }
1118   }
1119   
1120   if (!mn->nonNull()) {
1121     if (!computingCost) mn->cleanup_drn();
1122     delete mn;
1123     return NULL;
1124   }
1125   return mn;
1126 }
1127
1128 metricDefinitionNode *allocateConstraintData_and_generateCode(
1129                  metricDefinitionNode* mn,
1130                  pdThread* thr,
1131                  process *proc,
1132                  string& /*id*/,
1133                  vector< vector<string> >& focus,
1134                  unsigned& /*type*/,
1135                  T_dyninstRPC::mdl_constraint *flag_con,  // change from a vector to only one flag_con
1136                  vector<T_dyninstRPC::mdl_constraint*>& /*base_use*/,
1137                  vector<T_dyninstRPC::mdl_stmt*> */*stmts*/,
1138                  unsigned& flag_dex,
1139                  vector<unsigned>& /*base_dex*/,
1140                  vector<string> */*temp_ctr*/,
1141                  bool computingCost) {
1142
1143   dataReqNode *flag = NULL;
1144   // The following calls mdl_constraint::apply():
1145   if (!flag_con->apply(mn, flag, focus[flag_dex], proc, thr, computingCost)) {
1146     // flag not needed, already set in mn
1147     if (!computingCost) mn->cleanup_drn();
1148     delete mn;
1149     return NULL;
1150   }
1151   assert(flag);
1152   
1153   if (!mn->nonNull()) {
1154     if (!computingCost) mn->cleanup_drn();
1155     delete mn;
1156     return NULL;
1157   }
1158   return mn;
1159 }
1160
1161 metricDefinitionNode *allocateMetricData_and_generateCode(
1162                  vector<dataReqNode*> flags,
1163
1164                  metricDefinitionNode* mn,
1165                  pdThread* thr,
1166                  process *proc,
1167                  string& id,
1168                  vector< vector<string> >& focus,
1169                  unsigned& type,
1170                  T_dyninstRPC::mdl_constraint */*flag_con*/,
1171                  vector<T_dyninstRPC::mdl_constraint*>& base_use,
1172                  vector<T_dyninstRPC::mdl_stmt*> *stmts,
1173                  unsigned& /*flag_dex*/,
1174                  vector<unsigned>& base_dex,
1175                  vector<string> *temp_ctr,
1176                  bool computingCost) { // "flags" are passed in as an argument
1177   
1178   dataReqNode *the_node = create_data_object(type, mn, computingCost, thr);
1179   assert(the_node);
1180
1181   mdl_env::set(the_node, id);
1182   
1183   // Create the temporary counters 
1184   if (temp_ctr) {
1185     unsigned tc_size = temp_ctr->size();
1186     for (unsigned tc=0; tc<tc_size; tc++) {
1187       dataReqNode *temp_node=mn->addSampledIntCounter(thr,0,computingCost,true);
1188       assert(temp_node);
1189       mdl_env::set(temp_node, (*temp_ctr)[tc]);
1190     }
1191   }
1192   
1193   // so far, the same as in initDataRequests
1194   // "flags" are passed in
1195   
1196   if (base_use.size() > 0) {
1197     //mdl_constraint::apply()
1198     // metric_cerr << "base_use" <<endl ;
1199     for (unsigned bs=0; bs<base_use.size(); bs++) {
1200       dataReqNode *flag = NULL;
1201       if (!base_use[bs]->apply(mn, flag, focus[base_dex[bs]], proc, thr, computingCost)) {
1202         if (!computingCost) mn->cleanup_drn();
1203         delete mn;
1204         return NULL;
1205       }
1206     }
1207   } else {
1208     // metric_cerr << "!base_use" << endl ;
1209     unsigned size = stmts->size();
1210     for (unsigned u=0; u<size; u++) {
1211       if (!(*stmts)[u]->apply(mn, flags)) { // virtual fn call depending on stmt type
1212         if (!computingCost) mn->cleanup_drn();
1213         delete mn;
1214         return NULL;
1215       }
1216     }
1217   }
1218
1219   if (!mn->nonNull()) {
1220     if (!computingCost) mn->cleanup_drn();
1221     delete mn;
1222     return NULL;
1223   }
1224   return mn;
1225 }
1226
1227 // allocate data and generate code for all threads
1228 bool allDataGenCode_for_threads(
1229                  string& name,
1230                  vector< vector<string> > component_focus,
1231                  int processIdx,
1232                  unsigned agg_op,
1233                  metricStyle metric_style,
1234                  metricDefinitionNode* mn,
1235                  process *proc,
1236                  string& id,
1237                  vector< vector<string> > focus,
1238                  unsigned& type,
1239                  T_dyninstRPC::mdl_constraint *flag_con,
1240                  vector<T_dyninstRPC::mdl_constraint*>& base_use,
1241                  vector<T_dyninstRPC::mdl_stmt*> *stmts,
1242                  unsigned& flag_dex,
1243                  vector<unsigned>& base_dex,
1244                  vector<string> *temp_ctr,
1245                  vector<dataReqNode*> flags,
1246                  bool computingCost) // flag: "for constraint", or "for metric"
1247 {
1248     vector <metricDefinitionNode *> parts;
1249
1250     // STEP 3: create or retrieve the mns for all the threads
1251     string thr_component_flat_name(name);
1252     metricDefinitionNode* thr_mn;
1253     vector <pdThread *>& allThr = proc->threads ;
1254     unsigned i;
1255
1256     for (i=0;i<allThr.size();i++) {
1257       if (allThr[i] != NULL) {
1258         string thrName;
1259         thrName = string("thr_") + allThr[i]->get_tid()
1260           + string("{") + string(allThr[i]->get_start_func()->prettyName().string_of())+string("}"); 
1261         if (i==0) {
1262           component_focus[processIdx] += thrName;
1263           focus[processIdx] += thrName;
1264         } else {
1265           unsigned pSize ;
1266           pSize = component_focus[processIdx].size()-1;
1267           component_focus[processIdx][pSize] = thrName;
1268           pSize = focus[processIdx].size()-1;
1269           focus[processIdx][pSize] = thrName;
1270         }
1271         
1272         thr_component_flat_name = metricAndCanonFocus2FlatName(name,component_focus);
1273         
1274         if (base_use.size() == 0) {
1275           if (!stmts) {
1276             thr_component_flat_name += flag_con->id();      // append flag name at the end
1277           }
1278         }
1279
1280         // if (!allMIComponents.find(thr_component_flat_name,thr_mn)) 
1281         // thread level mn no longer added to allMIComponents
1282         thr_mn = 
1283           new metricDefinitionNode(proc, name, focus, component_focus,
1284                                    thr_component_flat_name, 
1285                                    aggregateOp(agg_op), THR_LEV);
1286         assert(thr_mn);
1287
1288         metric_cerr << "+++++++ construct thr_mn <" 
1289                     << thr_component_flat_name
1290                     << ">, " << (computingCost?"compute cost only!":"") << endl;
1291         
1292         // record thr_name and part(component) for (prim)mn
1293         mn->addThrName(thrName);  // make a method to thr_names in metricDefinitionNode
1294         parts += thr_mn;
1295       }
1296     }
1297     
1298     if (parts.size() == 0)
1299       return false;
1300     // Add thr_mns to proc_mn->components
1301     mn->addParts(parts);
1302
1303     //STEP 4 : allocate data and generate code
1304     // generate code for one thread since all threads share code
1305     // but data need to be allocated for all threads
1306     assert(allThr.size()==parts.size());
1307     for (i=0; i<allThr.size(); i++) {
1308        pdThread *thr = allThr[i];
1309        thr_mn = parts[i];
1310
1311        if (thr_mn->needData()||computingCost) {
1312          if (!computingCost)  
1313            thr_mn->needData() = false ;
1314
1315          if (base_use.size() == 0) {
1316            if (i == 0) {
1317              if (stmts == NULL) {  // non-base, fst thr, for constraint
1318                if (! (allocateConstraintData_and_generateCode(thr_mn, thr, proc, id, focus, type, flag_con,
1319                       base_use /* size == 0 */, NULL, flag_dex, base_dex, temp_ctr, computingCost)) ) 
1320                  return false ;
1321              }
1322              else {  // non-base, fst thr, for metric
1323                if (! (allocateMetricData_and_generateCode(flags, thr_mn, thr, proc, id, focus, type, NULL,
1324                       base_use /* size == 0 */, stmts, flag_dex, base_dex, temp_ctr, computingCost)) ) 
1325                  return false ;
1326              }
1327            }
1328            else {
1329              if (stmts == NULL) {  // non-base, non-fst thr, for constraint
1330                if (! (allocateConstraintData(thr_mn, thr, proc, id, focus, type, flag_con,
1331                       base_use /* size == 0 */, NULL, flag_dex, base_dex, temp_ctr, computingCost)) ) 
1332                  return false ;
1333              }
1334              else {  // non-base, non-fst thr, for metric
1335                if (! (allocateMetricData(thr_mn, thr, proc, id, focus, type, NULL,
1336                       base_use /* size == 0 */, stmts, flag_dex, base_dex, temp_ctr, computingCost)) ) 
1337                  return false ;
1338              }
1339            }
1340          }
1341          else {
1342            if (i == 0) {
1343              // base, fst thr, for metric;  no constraints needed
1344              if (! (allocateMetricData_and_generateCode(flags, thr_mn, thr, proc, id, focus, type, NULL,
1345                     base_use, NULL, flag_dex, base_dex, temp_ctr, computingCost)) ) 
1346                return false ;
1347            }
1348            else {
1349              // base, non-fst thr, for metric;  no constraints needed
1350              if (! (allocateMetricData(thr_mn, thr, proc, id, focus, type, NULL,
1351                     base_use, NULL, flag_dex, base_dex, temp_ctr, computingCost)) ) 
1352                return false ;
1353            }
1354          }
1355
1356          // cleanup the instRequests in thr_mn, and copy it to proc_mn
1357          // check in "duplicateInst" that code is generated only once
1358          if (i == 0) { // instrumentation code is generated when i == 0
1359            mn->duplicateInst(thr_mn);  // proc_mn
1360            metric_cerr << "  --- " << mn->getSizeOfInstRequests() << " instRequests are generated " << endl;
1361          }
1362        }
1363     }
1364
1365     return true;
1366 }
1367
1368 metricDefinitionNode *
1369 apply_to_process(process *proc,
1370                  string& id, string& name,
1371                  vector< vector<string> >& focus,
1372                  unsigned& agg_op, metricStyle metric_style,
1373                  unsigned& type,
1374                  vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
1375                  vector<T_dyninstRPC::mdl_constraint*>& base_use,
1376                  vector<T_dyninstRPC::mdl_stmt*> *stmts,
1377                  vector<unsigned>& flag_dex,
1378                  vector<unsigned>& base_dex,
1379                  vector<string> *temp_ctr,
1380                  bool replace_component,
1381                  bool computingCost) {
1382
1383     metric_cerr << "apply_to_process()" << endl;
1384     
1385     if (!update_environment(proc)) return NULL;
1386     
1387     // compute the flat_name for this component: the machine and process
1388     // are always defined for the component, even if they are not defined
1389     // for the aggregate metric.
1390     vector< vector<string> > component_focus(focus); // they start off equal
1391     string component_flat_name(name);
1392     
1393     int thrSelected = -1;  string thrName("-1");
1394     int processIdx = -1;
1395     
1396     for (unsigned u1 = 0; u1 < focus.size(); u1++) {
1397       for (unsigned u2 = 0; u2 < focus[u1].size(); u2++) {
1398         component_flat_name += focus[u1][u2];
1399       }
1400       
1401       if (focus[u1][0] == "Machine") {
1402         processIdx = u1;
1403         switch ( (focus[u1].size()) ) {
1404           case 1: {
1405             // there was no refinement to a specific machine...but the component focus
1406             // must have such a refinement.
1407             string tmp_part_name = machineResource->part_name();
1408             component_flat_name += tmp_part_name;
1409             component_focus[u1] += tmp_part_name;
1410             // no break
1411           }
1412           case 2: {
1413             // there was no refinement to a specific process...but the component
1414             // focus must have such a refinement.
1415             string tmp_part_name = proc->rid->part_name();
1416             component_flat_name += tmp_part_name;
1417             component_focus[u1] += tmp_part_name;
1418             break;
1419           }
1420           case 4: {
1421             thrSelected = u1;
1422             thrName = string(component_focus[u1][3]);
1423
1424             break;
1425           }
1426         }
1427       } // Machine 
1428     }//for u1
1429     
1430     // now assert that focus2flatname(component_focus) equals component_flat_name
1431     assert(component_flat_name == metricAndCanonFocus2FlatName(name, component_focus));
1432     
1433     
1434     // STEP 0: create or retrieve the mn for the selection: selected_mn;
1435     // STEP 1: create or retrieve the mn for the proc     : proc_mn;
1436     //         if selected_mn is not proc_mn, make proc_mn to be a component of selected_mn
1437     
1438     // STEP 2: create or retrieve the mns for each thread : thr_mn;
1439     // STEP 3: create or retrieve the mns for all the threads
1440     // STEP 4: allocate data and generate code
1441     
1442     
1443     // STEP 0 create or retrieve the proc_mn -- then create or retrieve seleted_mn out of it
1444     
1445     if (-1 != thrSelected) {
1446       // part of STEP 1:
1447       // restore original values for focus, component focus and flat name
1448       unsigned pSize ;
1449       pSize = component_focus[processIdx].size()-1;
1450       component_focus[processIdx].resize(pSize);
1451       pSize = focus[processIdx].size()-1;
1452       focus[processIdx].resize(pSize);
1453       // here component_flat_name is flat_name for thread, after removing thread
1454       // related focuses, proc_component_flat_name is flat_name for process
1455     }
1456     
1457     string proc_component_flat_name = metricAndCanonFocus2FlatName(name,component_focus);
1458     
1459     
1460     metricDefinitionNode * proc_mn = NULL;
1461     metricDefinitionNode * selected_mn = NULL;
1462     
1463     
1464     // component_flat_name could be flat_name for process, or for thread
1465     // allMIComponents record all proc_comp mdn's generated, try to get a match
1466     const bool matched = checkInMIComponents(proc_component_flat_name, proc_mn, replace_component);
1467
1468     // What is done in STEP 0:
1469     // if process mdn is found
1470     //   if thread is selected
1471     //     if thread is first time selected
1472     //       record name
1473     //   if process is selected
1474     //     record name
1475     if (matched) {
1476       bool recordName = false;
1477
1478       if (-1 != thrSelected) {
1479         metric_cerr << " a thread focus is selected. " << endl;
1480         
1481         metricDefinitionNode * metric_prim = proc_mn->getMetricPrim();
1482         selected_mn = metric_prim->getThrComp(thrName);  // thrSelected
1483         
1484         if (!selected_mn) {
1485           metric_cerr << " the thread not found, might have exited. " << endl;
1486           return NULL;
1487         }
1488         
1489         if (0 == selected_mn->getComponents().size()) {
1490           metric_cerr << " add proc_mn to selected_mn's comp " << endl;
1491           // for THR_LEV: aggregators[0] is a PRIM_MDN, components[0] is PROC_PROC
1492           //              could have aggregators[1+], are AGG_LEV's
1493           selected_mn->addPart(proc_mn);
1494           recordName = true;
1495         }
1496       }
1497       else {
1498         metric_cerr << " a process focus is selected. " << endl;
1499
1500         selected_mn = proc_mn;
1501         recordName = true;
1502       }
1503       
1504       if (recordName) {
1505         // @@ record the name of the next aggregator for this proc_mn:
1506         // next aggregator could be this thr_mn(selected_mn), or the agg_mn to-be-built
1507         // do this name record before return selected_mn
1508         proc_mn->addCompFlatName(proc_component_flat_name);
1509       }
1510       
1511       // either THR_LEV or COMP_MDN
1512       return selected_mn;
1513     }
1514     else
1515       metric_cerr // << "MDL: creating new component mi since flatname "
1516                   // << component_flat_name << " doesn't exist. "
1517                   << (computingCost? "compute cost only!" : "") << endl;
1518
1519     
1520     // STEP 1: create the proc_mn
1521     
1522     // again, if a thread is selected, component_flat_name is flat_name for thread,
1523     // after removing thread related focuses, proc_component_flat_name is flat_name for process
1524     // otherwise if a process is selected, component_flat_name is flat_name for thread,
1525     // and proc_component_flat_name will generate the same name for process
1526     
1527     proc_mn = new metricDefinitionNode(proc, name, focus, component_focus,
1528                                        proc_component_flat_name, 
1529                                        aggregateOp(agg_op), COMP_MDN);
1530     assert(proc_mn);
1531     
1532     // memorizing stuff
1533     proc_mn->setMetricRelated(type, computingCost, temp_ctr, flag_cons, base_use);
1534     
1535     
1536     // BEGIN_OF_MT_THREAD
1537     // can still use "checkInMIPrimitives", "checkFlagMIPrimitives"
1538     // for each primitive, create mdn and allocate data for all threads, 
1539     // and create one instrumentation for this primitive  
1540     
1541     metricDefinitionNode *metric_prim = NULL;
1542     string metric_flat_name(proc_component_flat_name);  // the same as proc_component_flat_name
1543     bool alreadyThere = false;
1544     
1545     // CASE 1:  there are "replaced constraints" that match, generate code accordingly
1546     if (base_use.size() > 0) {
1547       metric_cerr << "  create base_use (size of " << base_use.size() << ") primitive " << endl;
1548       
1549       alreadyThere = checkInMIPrimitives(metric_flat_name, metric_prim, replace_component);
1550       
1551       if (!alreadyThere) {
1552         metric_cerr << "  base_use not already there " << endl;
1553         
1554         // primitive metricDefinitionNode constructor
1555         metric_prim =
1556           new metricDefinitionNode(proc, name, // base_use[0]->id()
1557                                    focus, component_focus, metric_flat_name,
1558                                    aggregateOp(agg_op), PRIM_MDN);
1559         
1560         vector<dataReqNode*> empty_flags;
1561         unsigned int empty;
1562
1563         if (!allDataGenCode_for_threads(name, component_focus, processIdx, agg_op, metric_style, 
1564                                         metric_prim, proc, id, focus, type, NULL/*flag_con*/, base_use,
1565                                         NULL/*stmts*/, empty, base_dex, temp_ctr, empty_flags, computingCost)) {
1566           if (!computingCost) metric_prim->cleanup_drn();
1567           //delete metric_prim;
1568           return NULL;
1569         }
1570       }
1571       else {
1572         metric_cerr << "  base_use already there, reuse it! " << endl;
1573
1574         assert(metric_prim);
1575       } // endof alreadyThere (base_use)
1576     } // else of base_use
1577
1578     else {
1579       // CASE 2: no "replace constraints" match, use normal constraints and metric def
1580       //    First ------ normal constraints part, generate constraints and metric respectively 
1581       //                 as primitive and form component
1582       
1583       // metric_cerr << "  create metric primitive:  " << metric_flat_name << endl;
1584       alreadyThere = checkInMIPrimitives(metric_flat_name, metric_prim, replace_component);
1585       
1586       if (!alreadyThere) {
1587         unsigned flag_size = flag_cons.size(); // could be zero
1588         vector<dataReqNode*> flags;
1589         metric_cerr << " there are " << flag_size << " flags (constraints)" << endl;
1590         
1591         for (unsigned fs=0; fs<flag_size; fs++) {
1592           metricDefinitionNode *cons_prim = NULL;
1593           string primitive_flat_name = metricAndCanonFocus2FlatName(flag_cons[fs]->id(),component_focus);
1594
1595           metric_cerr << "  create " << fs << "th constraint primitive: " << endl
1596                       << "    " << primitive_flat_name << endl;
1597
1598           const bool alThere = checkInMIPrimitives(primitive_flat_name, cons_prim, replace_component);
1599           
1600           if (!alThere) {
1601             metric_cerr << "  flag not already there " << endl;
1602             
1603             string cons_name(flag_cons[fs]->id());
1604             // primitive metricDefinitionNode constructor
1605             // the primitive_focus is same as the component_focus
1606             cons_prim = 
1607               new metricDefinitionNode(proc, cons_name, focus, component_focus,
1608                                        primitive_flat_name, 
1609                                        aggregateOp(agg_op), PRIM_MDN);
1610             
1611             // add allocate data for each thread (into thr prims), 
1612             // generate instrument code (into proc prim)
1613             // then check if proc prim's code already exist
1614             // de-allocate data (level and index) for thread if already exist
1615             // (just reuse proc prim with its thr prims)
1616             
1617             vector<dataReqNode*> empty_flags;
1618             
1619             if (!allDataGenCode_for_threads(cons_name, component_focus, processIdx, agg_op, metric_style, 
1620                                             cons_prim, proc, id, focus, type, flag_cons[fs], base_use,
1621                                             NULL/*stmt*/, flag_dex[fs], base_dex, NULL/*temp_ctr*/, empty_flags, 
1622                                             computingCost)) {
1623               if (!computingCost) cons_prim->cleanup_drn();
1624               // delete cons_prim;
1625               return NULL;
1626             }
1627             
1628             // needed here and safe here, if flag is different, metric will be different,
1629             // unless metric is null, but in that case, metric will be cleaned up
1630             // allMIPrimitiveFLAGS should be used here!!
1631             checkFlagMIPrimitives(primitive_flat_name, cons_prim, computingCost);
1632           }
1633           else { // alThere (constraints)
1634             metric_cerr << "  flag already there " << endl;
1635             
1636             assert(cons_prim);
1637           }
1638           
1639           // cache created flags
1640           dataReqNode *flag = cons_prim->getFlagDRN();
1641           assert(flag);
1642           flags += flag;
1643           
1644           // TEMP: see create_data_object
1645           proc_mn->addPartDummySample(cons_prim);
1646           
1647           // metric_cerr << "Applied constraint for " << flag_cons[fs]->id() << endl;
1648         }
1649         
1650
1651         // Second ------ met def part, generate metric code
1652         metric_cerr << "  metric not already there " << endl;
1653         
1654         // primitive metricDefinitionNode constructor
1655         metric_prim = 
1656           new metricDefinitionNode(proc, name, focus, component_focus, 
1657                                    metric_flat_name,
1658                                   // should be NO metric_style and NO agg_style
1659                                    aggregateOp(agg_op), PRIM_MDN);
1660         
1661         // add allocate data for each thread (into thr prims), 
1662         // generate instrument code (into proc prim)
1663         // then check if proc prim's code already exist
1664         // de-allocate data (level and index) for thread if already exist
1665         // (just reuse proc prim with its thr prims)
1666         
1667         unsigned int empty;
1668         if (!allDataGenCode_for_threads(name, component_focus, processIdx, agg_op, metric_style, 
1669                                         metric_prim, proc, id, focus, type, NULL/*flag_con*/, base_use,
1670                                         stmts, empty, base_dex, temp_ctr, flags, computingCost)) {
1671           if (!computingCost) metric_prim->cleanup_drn();
1672           // delete metric_prim;
1673           return NULL;
1674         }
1675       }
1676       else {
1677         metric_cerr << "  metric already there, reuse it! " << endl;
1678         
1679         assert(metric_prim);
1680       } // endof alreadyThere (metric stmt)
1681     } // end of !base_use
1682     // END_OF_MT_THREAD
1683
1684     // now, metric_prim could be base_use or not
1685     
1686     // Difference: if found the same, reuse metric_prim AND PROC_MN!!
1687     // register MIComponents for threads in checkMetricMIPrimitives
1688     const bool alreadyExist = (alreadyThere? false : checkMetricMIPrimitives(metric_flat_name, metric_prim, computingCost));
1689     
1690     if (!metric_prim->nonNull()) {
1691       metric_cerr << "metric_prim->nonNull()" << endl;
1692       if (!computingCost) metric_prim->cleanup_drn();
1693
1694       // Extra cleanup
1695       allMIPrimitives.undef(metric_flat_name);
1696       allMIComponents.undef(metric_flat_name);
1697       (metric_prim->getComponents()).resize(0);
1698
1699       delete metric_prim;
1700       return NULL;
1701     }
1702     
1703     if (alreadyThere || alreadyExist) {
1704       // proc_mn: do not do cleanup_drn --- have already been cleaned in prims
1705       // delete proc_mn;  // metric_prim already deleted in checkMetricMIPrimitives
1706
1707       for (unsigned u=0; u<(proc_mn->getComponents()).size(); u++)
1708         proc_mn->removeComponent((proc_mn->getComponents())[u]);  // --- TEST: might remove
1709       (proc_mn->getComponents()).resize(0);
1710       delete proc_mn;
1711
1712       proc_mn = metric_prim->getProcComp();
1713     }
1714     else {
1715       proc_mn->addPart(metric_prim);
1716       
1717       if (!computingCost)
1718         proc->allMIComponentsWithThreads += proc_mn;
1719     }
1720     
1721     
1722     // move STEP 3 and STEP 4 into "allDataGenCode_for_threads"
1723     
1724     // start from recordName, same as before
1725     bool recordName = false;
1726     if (-1 != thrSelected) {
1727       metric_cerr << " a thread focus is selected. " << endl;
1728
1729       selected_mn = metric_prim->getThrComp(thrName);  // thrSelected
1730
1731       if (!selected_mn) {
1732         metric_cerr << " the thread not found, might have exited. " << endl;
1733         return NULL;
1734       }
1735       
1736       if (0 == selected_mn->getComponents().size()) {
1737         metric_cerr << " add proc_mn to selected_mn's comp " << endl;
1738         selected_mn->addPart(proc_mn);
1739         recordName = true;
1740       }
1741     }
1742     else {
1743       metric_cerr << " a process focus is selected. " << endl;
1744
1745       selected_mn = proc_mn;
1746       recordName = true;
1747     }
1748
1749     if (recordName) {
1750       // @@ record the name of the next aggregator for this proc_mn:
1751       // next aggregator could be this thr_mn(selected_mn), or the agg_mn to-be-built
1752       // do this name record before return selected_mn
1753       proc_mn->addCompFlatName(proc_component_flat_name);
1754
1755       // MOVE HERE: after checkMetric is done for its replace prim or metric prim:
1756       // the ONLY place to add into allMIComponents in mdl.C, this add COMP_MDN
1757       allMIComponents[proc_component_flat_name] = proc_mn;  // only if name is recorded
1758     }
1759
1760     //now we assert
1761     assert(-1 == thrSelected || selected_mn->getComponents().size()==1);
1762
1763     return selected_mn;
1764 }
1765 #endif // !defined(MT_THREAD)
1766
1767 static bool apply_to_process_list(vector<process*>& instProcess,
1768 #if defined(MT_THREAD)
1769                                   vector< vector<pdThread *> >& threadsVec,
1770 #endif
1771                                   vector<metricDefinitionNode*>& parts,
1772                                   string& id, string& name,
1773                                   vector< vector<string> >& focus,
1774                                   unsigned& agg_op, metricStyle metric_style,
1775                                   unsigned& type,
1776                                   vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
1777                                   vector<T_dyninstRPC::mdl_constraint*>& base_use,
1778                                   vector<T_dyninstRPC::mdl_stmt*> *stmts,
1779                                   vector<unsigned>& flag_dex,
1780                                   vector<unsigned>& base_dex,
1781                                   vector<string> *temp_ctr,
1782                                   bool replace_components_if_present,
1783                                   bool computingCost) {
1784   metric_cerr << "apply_to_process_list()" << endl;
1785 #ifdef DEBUG_MDL
1786   timer loadTimer, totalTimer;
1787   static ofstream *of=NULL;
1788   if (!of) {
1789     char buffer[100];
1790     ostrstream osb(buffer, 100, ios::out);
1791     osb << "mdl_" << "__" << getpid() << ends;
1792     of = new ofstream(buffer, ios::app);
1793   }
1794
1795   (*of) << "Instrumenting for " << name << " " << instProcess.size() << " processes\n";
1796 #endif
1797
1798   unsigned psize = instProcess.size();
1799 #ifdef DEBUG_MDL
1800   totalTimer.clear(); totalTimer.start();
1801 #endif
1802   for (unsigned p=0; p<psize; p++) {
1803 #ifdef DEBUG_MDL
1804     loadTimer.clear(); loadTimer.start();  // TIMER
1805 #endif
1806     process *proc = instProcess[p]; assert(proc);
1807     global_proc = proc;     // TODO -- global
1808
1809 #if defined(MT_THREAD)
1810     //check that this vector of threads corresponds to this process
1811     assert(p<threadsVec.size());
1812     vector<pdThread *> thrForThisProc = threadsVec[p];
1813     for (unsigned i=0;i<thrForThisProc.size();i++) 
1814       assert(thrForThisProc[i]->get_proc() == proc);
1815 #endif
1816     // skip neonatal and exited processes.
1817     if (proc->status() == exited || proc->status() == neonatal) continue;
1818
1819     metricDefinitionNode *comp = apply_to_process(proc, id, name, focus, 
1820                                                  agg_op, metric_style, type,
1821                                                  flag_cons, base_use, stmts, 
1822                                                  flag_dex,
1823                                                  base_dex, temp_ctr,
1824                                                  replace_components_if_present,
1825                                                  computingCost);
1826     if (comp) {
1827       // we have another component (i.e. process-specific) mi
1828       parts += comp;
1829     }
1830       
1831
1832 #ifdef DEBUG_MDL
1833     loadTimer.stop();
1834     char timeMsg[500];
1835     sprintf(timeMsg, "%f::%f  ", (float) loadTimer.usecs(), (float) loadTimer.wsecs());
1836     /*should be removed for output redirection
1837     tp->applicationIO(10, strlen(timeMsg), timeMsg);
1838     */
1839     (*of) << name << ":" << timeMsg << endl;
1840 #endif
1841
1842   }
1843 #ifdef DEBUG_MDL
1844   totalTimer.stop();
1845   char timeMsg[500];
1846   sprintf(timeMsg, "\nTotal:  %f:user\t%f:wall\n", (float) totalTimer.usecs(),
1847           (float) totalTimer.wsecs());
1848   /*should be removed for output redirection
1849   tp->applicationIO(10, strlen(timeMsg), timeMsg);
1850   */
1851   (*of) << name << ":" << timeMsg << endl;
1852 #endif
1853
1854   if (parts.size() == 0)
1855     // no components!
1856     return false;
1857
1858   return true;
1859 }
1860
1861 ///////////////////////////
1862 vector<string>global_excluded_funcs;
1863
1864
1865 metricDefinitionNode *T_dyninstRPC::mdl_metric::apply(vector< vector<string> > &focus,
1866                                                       string& flat_name,
1867                                                       vector<process *> procs,
1868                                                       vector< vector<pdThread *> >& 
1869 #if defined(MT_THREAD)
1870                                                       threadsVec
1871 #endif
1872                                                       ,
1873                                                       bool replace_components_if_present,
1874                                                       bool computingCost) {
1875   // TODO -- check to see if this is active ?
1876   // TODO -- create counter or timer
1877   // TODO -- put it into the environment ?
1878   // TODO -- this can be passed directly -- faster - later
1879   // TODO -- internal metrics
1880   // TODO -- assume no constraints, all processes instrumented
1881   // TODO -- support two-level aggregation: one at the daemon, one at paradyn
1882   // TODO -- how is folding specified ?
1883   // TODO -- are lists updated here ?
1884
1885   mdl_env::push();
1886   mdl_env::add(id_, false, MDL_T_DRN);
1887   assert(stmts_);
1888
1889   const unsigned tc_size = temp_ctr_->size();
1890   for (unsigned tc=0; tc<tc_size; tc++) {
1891     mdl_env::add((*temp_ctr_)[tc], false, MDL_T_DRN);
1892   }
1893
1894   static string machine;
1895   static bool machine_init= false;
1896   if (!machine_init) {
1897     machine_init = true;
1898     machine = getNetworkName();
1899   }
1900
1901   if (other_machine_specified(focus, machine)) return NULL;
1902   vector<process*> instProcess;
1903 #if defined(MT_THREAD)
1904   vector< vector<pdThread *> > instThreadsVec;
1905   add_processes(focus, procs, instProcess, threadsVec, instThreadsVec);
1906
1907   if (!instProcess.size() || !instThreadsVec.size()) return NULL;
1908 #else
1909   add_processes(focus, procs, instProcess);
1910
1911   if (!instProcess.size()) return NULL;
1912 #endif
1913
1914   // build the list of constraints to use
1915   vector<T_dyninstRPC::mdl_constraint*> flag_cons;
1916
1917   // CHANGE: to get all that match
1918   // the first replace constraint that matches, if any
1919   vector<T_dyninstRPC::mdl_constraint*> base_used;
1920
1921   // build list of global constraints that match and choose local replace constraint
1922   vector<unsigned> base_dex; vector<unsigned> flag_dex;
1923   if (!check_constraints(flag_cons, base_used, focus, constraints_, flag_dex, base_dex))
1924     return NULL;
1925
1926   //////////
1927   /* 
1928      Compute the list of excluded functions here. This is the list of functions
1929      that should be excluded from the calls sites.
1930      We set the global variable global_excluded_functions to the list of
1931      excluded functions.
1932
1933      At this point, the $constraint variable is not in the environment yet,
1934      so anything that uses $constraint will not be added to the list,
1935      which is what we want.
1936    */
1937   if (base_used.size() > 0) {
1938     for (unsigned i=0; i < base_used.size(); i++)
1939       base_used[i]->mk_list(global_excluded_funcs);
1940   } else {
1941     for (unsigned u1 = 0; u1 < flag_cons.size(); u1++)
1942       flag_cons[u1]->mk_list(global_excluded_funcs);
1943     for (unsigned u2 = 0; u2 < stmts_->size(); u2++)
1944       (*stmts_)[u2]->mk_list(global_excluded_funcs);
1945   }
1946   /*
1947   metric_cerr << "Metric: " << name_ << endl;
1948   for (unsigned x1 = 0; x1 < global_excluded_funcs.size(); x1++)
1949     metric_cerr << "  " << global_excluded_funcs[x1] << endl;
1950   */
1951   //////////
1952
1953
1954   // build the instrumentation request
1955   vector<metricDefinitionNode*> parts; // one per process
1956   metricStyle styleV = static_cast<metricStyle>(style_);
1957   if (!apply_to_process_list(instProcess, 
1958 #if defined(MT_THREAD)
1959                              instThreadsVec, 
1960 #endif
1961                              parts, id_, name_, focus,
1962                              agg_op_, styleV, type_, flag_cons, base_used,
1963                              stmts_, flag_dex, base_dex, temp_ctr_,
1964                              replace_components_if_present,
1965                              computingCost))
1966     return NULL;
1967
1968   // construct aggregate for the metric instance parts
1969   metricDefinitionNode *ret = NULL;
1970
1971   if (parts.size()) {
1972     // create aggregate mi, containing the process components "parts"
1973     ret = new metricDefinitionNode(name_, focus, flat_name, parts,  
1974                                    /* instProcess */ aggregateOp(agg_op_));
1975   }
1976
1977   metric_cerr << " apply of " << name_ << " ok" << endl;
1978   mdl_env::pop();
1979
1980   ////////////////////
1981   global_excluded_funcs.resize(0);
1982
1983   return ret;
1984 }
1985
1986 T_dyninstRPC::mdl_constraint::mdl_constraint()
1987 : id_(""), match_path_(NULL), stmts_(NULL), replace_(false),
1988   data_type_(0), hierarchy_(0), type_(0) { }
1989
1990 T_dyninstRPC::mdl_constraint::mdl_constraint(string id, 
1991                                         vector<string> *match_path,
1992                                         vector<T_dyninstRPC::mdl_stmt*> *stmts,
1993                                         bool replace, u_int d_type, bool& err)
1994 : id_(id), match_path_(match_path), stmts_(stmts), replace_(replace),
1995   data_type_(d_type), hierarchy_(0), type_(0) 
1996 { assert(0); err = false; }
1997
1998 T_dyninstRPC::mdl_constraint::~mdl_constraint() {
1999   assert (0);
2000   delete match_path_;
2001   if (stmts_) {
2002     for (unsigned u=0; u<stmts_->size(); u++)
2003       delete (*stmts_)[u];
2004     delete stmts_;
2005   }
2006 }
2007
2008
2009 static bool do_trailing_resources(vector<string>& resource_,
2010                                   process *proc)
2011 {
2012   vector<string>  resPath;
2013
2014   for(unsigned pLen = 0; pLen < resource_.size(); pLen++) {
2015     string   caStr = string("$constraint") + 
2016                      string(resource_.size()-pLen-1);
2017     string   trailingRes = resource_[pLen];
2018
2019     resPath += resource_[pLen];
2020     assert(resPath.size() == (pLen+1));
2021
2022     resource *r = resource::findResource(resPath);
2023     if (!r) assert(0);
2024
2025     switch (r->type()) {
2026     case MDL_T_INT: {
2027       const char* p = trailingRes.string_of();
2028       char*       q;
2029       int         val = (int) strtol(p, &q, 0);
2030       if (p == q) {
2031         string msg = string("unable to convert resource '") + trailingRes + 
2032                      string("' to integer.");
2033         showErrorCallback(92,msg.string_of());
2034         return(false);
2035       }
2036       mdl_env::add(caStr, false, MDL_T_INT);
2037       mdl_env::set(val, caStr);
2038       break;
2039     }
2040     case MDL_T_STRING:
2041       mdl_env::add(caStr, false, MDL_T_STRING);
2042       mdl_env::set(trailingRes, caStr);
2043       break;
2044     case MDL_T_PROCEDURE: {
2045       // find the resource corresponding to this function's module 
2046       vector<string> m_vec;
2047       for(u_int i=0; i < resPath.size()-1; i++){
2048         m_vec += resPath[i];
2049       }
2050       assert(m_vec.size());
2051       assert(m_vec.size() == (resPath.size()-1));
2052       resource *m_resource = resource::findResource(m_vec);
2053       if(!m_resource) return(false);
2054       
2055       function_base *pdf = proc->findOneFunction(r,m_resource);
2056       if (!pdf) return(false);
2057       mdl_env::add(caStr, false, MDL_T_PROCEDURE);
2058       mdl_env::set(pdf, caStr);
2059       break;
2060     }
2061     case MDL_T_MODULE: {
2062       module *mod = proc->findModule(trailingRes,true);
2063       if (!mod) return(false);
2064       mdl_env::add(caStr, false, MDL_T_MODULE);
2065       mdl_env::set(mod, caStr);
2066       break;
2067     }
2068     case MDL_T_MEMORY:
2069       break ;
2070     default:
2071       assert(0);
2072       break;
2073     }
2074   }
2075   return(true);
2076 }
2077
2078
2079 // Flag constraints need to return a handle to a data request node -- the flag
2080 bool T_dyninstRPC::mdl_constraint::apply(metricDefinitionNode *mn,
2081                                          dataReqNode *&flag,
2082                                          vector<string>& resource,
2083                                          process *proc, pdThread* 
2084 #if defined(MT_THREAD)
2085                                          thr
2086 #endif
2087                                          , bool computingCost) {
2088   assert(mn);
2089   switch (data_type_) {
2090   case MDL_T_COUNTER:
2091   case MDL_T_WALL_TIMER:
2092   case MDL_T_PROC_TIMER:
2093     break;
2094   default:
2095     assert(0);
2096   }
2097   mdl_env::push();
2098
2099   if (!replace_) {
2100     // create the counter used as a flag
2101     mdl_env::add(id_, false, MDL_T_DRN);
2102 #if defined(SHM_SAMPLING) 
2103     // "true" means that we are going to create a sampled int counter but
2104     // we are *not* going to sample it, because it is just a temporary
2105     // counter - naim 4/22/97
2106     // By default, the last parameter is false - naim 4/23/97
2107 #if defined(MT_THREAD)
2108     dataReqNode *drn = mn->addSampledIntCounter(thr,0,computingCost,true);
2109 #else
2110     dataReqNode *drn = mn->addSampledIntCounter(0,computingCost,true);
2111 #endif
2112 #else
2113     dataReqNode *drn = mn->addUnSampledIntCounter(0,computingCost);
2114 #endif
2115     // this flag will construct a predicate for the metric -- have to return it
2116     flag = drn;
2117     assert(drn);
2118 #if defined(MT_THREAD)
2119     if (mn->installed()) midToMiMap[drn->getSampleId()] = mn ; 
2120 #endif
2121     mdl_env::set(drn, id_);
2122   }
2123
2124   // put $constraint[X] in the environment
2125   if(!do_trailing_resources(resource, proc)) {
2126     mdl_env::pop();
2127     return(false);
2128   }
2129
2130   // Now evaluate the constraint statements
2131   unsigned size = stmts_->size();
2132   vector<dataReqNode*> flags;
2133   bool wasRunning = global_proc->status()==running;
2134 #ifdef DETACH_ON_THE_FLY
2135   global_proc->reattachAndPause();
2136 #else
2137   global_proc->pause();
2138 #endif
2139   for (unsigned u=0; u<size; u++) {
2140     if (!(*stmts_)[u]->apply(mn, flags)) { // virtual fn call; several possibilities
2141       metric_cerr << "apply of constraint " << id_ << " failed\n";
2142       if (wasRunning) {
2143 #ifdef DETACH_ON_THE_FLY
2144            global_proc->detachAndContinue();
2145 #else
2146            global_proc->continueProc();
2147 #endif
2148       }
2149       return(false);
2150     }
2151   }
2152   mdl_env::pop();
2153   if (wasRunning) {
2154 #ifdef DETACH_ON_THE_FLY
2155        global_proc->detachAndContinue();
2156 #else
2157        global_proc->continueProc();
2158 #endif
2159   }
2160   return(true);
2161 }
2162
2163 bool T_dyninstRPC::mdl_constraint::replace() {
2164   return replace_ ;
2165 }
2166
2167 string T_dyninstRPC::mdl_constraint::id() {
2168   return id_ ;
2169 }
2170
2171 T_dyninstRPC::mdl_constraint *mdl_data::new_constraint(string id, 
2172                                         vector<string> *path,
2173                                         vector<T_dyninstRPC::mdl_stmt*> *Cstmts,
2174                                         bool replace, u_int d_type) {
2175   assert (0);
2176   bool error;
2177   return (new T_dyninstRPC::mdl_constraint(id, path, Cstmts, replace, d_type, error));
2178 }
2179
2180 T_dyninstRPC::mdl_stmt::mdl_stmt() { }
2181
2182 T_dyninstRPC::mdl_for_stmt::mdl_for_stmt(string index_name, 
2183         T_dyninstRPC::mdl_expr *list_exp, T_dyninstRPC::mdl_stmt *body) 
2184 : for_body_(body), index_name_(index_name), list_expr_(list_exp) 
2185 {assert(0);}
2186
2187 T_dyninstRPC::mdl_for_stmt::mdl_for_stmt()
2188 : for_body_(NULL), index_name_(""), list_expr_(NULL) { }
2189
2190 T_dyninstRPC::mdl_for_stmt::~mdl_for_stmt() 
2191 {
2192   assert (0);
2193   delete for_body_;
2194   delete list_expr_;
2195 }
2196
2197 bool T_dyninstRPC::mdl_for_stmt::apply(metricDefinitionNode *mn,
2198                                        vector<dataReqNode*>& flags) {
2199   mdl_env::push();
2200   mdl_env::add(index_name_, false);
2201   mdl_var list_var(false);
2202
2203   // TODO -- build iterator closure here -- list may be vector or dictionary
2204   if (!list_expr_->apply(list_var))
2205     return false;
2206   if (!list_var.is_list())
2207     return false;
2208
2209   // TODO
2210   //  vector<function_base*> *vp;
2211   //  list_var.get(vp);
2212   list_closure closure(index_name_, list_var);
2213
2214   // mdl_env::set_type(list_var.element_type(), index_name_);
2215   while (closure.next()) {
2216     if (!for_body_->apply(mn, flags)) return false;
2217   }
2218
2219   mdl_env::pop();
2220   return true;
2221 }
2222
2223 T_dyninstRPC::mdl_icode::mdl_icode()
2224   : if_expr_(NULL), expr_(NULL) { }
2225
2226 T_dyninstRPC::mdl_icode::mdl_icode(
2227   T_dyninstRPC::mdl_expr* expr1, T_dyninstRPC::mdl_expr* expr2)
2228   : if_expr_(expr1), expr_(expr2)
2229 { assert (0); }
2230
2231 T_dyninstRPC::mdl_icode::~mdl_icode() 
2232 { assert(0); delete if_expr_; delete expr_; }
2233
2234 bool T_dyninstRPC::mdl_icode::apply(AstNode *&mn, bool mn_initialized) 
2235 {
2236   // a return value of true implies that "mn" has been written to
2237
2238   if (!expr_)
2239      return false;
2240
2241   AstNode* pred = NULL;
2242   AstNode* ast = NULL;
2243
2244   if (if_expr_) 
2245   {
2246     if (!if_expr_->apply(pred))
2247        return false;
2248   }
2249   if (!expr_->apply(ast))
2250     return false;
2251
2252   AstNode* code = NULL;
2253   if (pred) 
2254   {
2255     // Note: we don't use assignAst on purpose here
2256     code = createIf(pred, ast);
2257     removeAst(pred);
2258     removeAst(ast);
2259   }
2260   else
2261     code = ast;
2262
2263   if (mn_initialized) 
2264   {
2265     // Note: we don't use assignAst on purpose here
2266     AstNode *tmp=mn;
2267     mn = new AstNode(tmp, code);
2268     removeAst(tmp);
2269   }
2270   else 
2271     mn = assignAst(code);
2272
2273   removeAst(code);
2274   return true;
2275 }
2276
2277 T_dyninstRPC::mdl_expr::mdl_expr() { }
2278 T_dyninstRPC::mdl_expr::~mdl_expr() { }
2279
2280 T_dyninstRPC::mdl_v_expr::mdl_v_expr() 
2281 : type_(MDL_T_NONE), int_literal_(0), bin_op_(0), u_op_(0), left_(NULL), 
2282   right_(NULL), args_(NULL), do_type_walk_(false), ok_(false)
2283 { }
2284
2285 T_dyninstRPC::mdl_v_expr::mdl_v_expr(int int_lit) 
2286 : type_(MDL_EXPR_INT), int_literal_(int_lit), bin_op_(0), u_op_(0),
2287   left_(NULL), right_(NULL), args_(NULL), do_type_walk_(false), ok_(false)
2288 { assert(0); }
2289
2290 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string a_str, bool is_literal) 
2291 : int_literal_(0), bin_op_(0), u_op_(0), left_(NULL),
2292   right_(NULL), args_(NULL), do_type_walk_(false), ok_(false)
2293 {
2294   assert (0);
2295   if (is_literal)
2296   {
2297     type_ = MDL_EXPR_STRING;
2298     str_literal_ = a_str;
2299   }
2300   else
2301   {
2302     type_ = MDL_EXPR_VAR;
2303     var_ = a_str;
2304   }
2305 }
2306
2307 T_dyninstRPC::mdl_v_expr::mdl_v_expr(mdl_expr* expr, vector<string> fields) 
2308 : type_(MDL_EXPR_DOT), int_literal_(0), bin_op_(0),
2309   u_op_(0), left_(expr), right_(NULL), args_(NULL),
2310   fields_(fields), do_type_walk_(false), ok_(false)
2311 { assert(0); }
2312
2313 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string func_name,
2314                                      vector<T_dyninstRPC::mdl_expr *> *a) 
2315 : type_(MDL_EXPR_FUNC), int_literal_(0), var_(func_name), bin_op_(100000),
2316   u_op_(0), left_(NULL), right_(NULL), args_(a), do_type_walk_(false), 
2317   ok_(false)
2318 { assert(0); }
2319
2320 T_dyninstRPC::mdl_v_expr::mdl_v_expr(u_int bin_op, T_dyninstRPC::mdl_expr *left,
2321                                  T_dyninstRPC::mdl_expr *right) 
2322 : type_(MDL_EXPR_BINOP), int_literal_(0), bin_op_(bin_op), u_op_(0),
2323   left_(left), right_(right), args_(NULL), do_type_walk_(false), ok_(false)
2324 { assert(0); }
2325
2326 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string var, u_int assign_op,
2327     T_dyninstRPC::mdl_expr *expr)
2328 : type_(MDL_EXPR_ASSIGN), int_literal_(0), var_(var), bin_op_(assign_op),
2329   u_op_(0), left_(expr), right_(NULL), args_(NULL), do_type_walk_(false), 
2330   ok_(false)
2331 { assert(0); }
2332
2333 T_dyninstRPC::mdl_v_expr::mdl_v_expr(u_int u_op, T_dyninstRPC::mdl_expr *expr,
2334                  bool is_preop)
2335 : int_literal_(0), bin_op_(0), u_op_(u_op), left_(expr), right_(NULL),
2336   args_(NULL), do_type_walk_(false), ok_(false)
2337 {
2338   assert(0);
2339   if (is_preop)
2340     type_ = MDL_EXPR_PREUOP;
2341   else
2342     type_ = MDL_EXPR_POSTUOP;
2343 }
2344
2345 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string var, mdl_expr* index_expr) 
2346 : type_(MDL_EXPR_INDEX), int_literal_(0), var_(var), bin_op_(0),
2347   u_op_(0), left_(index_expr), right_(NULL), args_(NULL),
2348   do_type_walk_(false), ok_(false)
2349 { assert(0); }
2350
2351 T_dyninstRPC::mdl_v_expr::~mdl_v_expr() 
2352 {
2353   assert (0);
2354   if (args_) 
2355   {
2356     unsigned size = args_->size();
2357     for (unsigned u=0; u<size; u++)
2358       delete (*args_)[u];
2359     delete args_;
2360   }
2361   delete left_; delete right_;
2362 }
2363
2364 bool T_dyninstRPC::mdl_v_expr::apply(AstNode*& ast)
2365 {
2366   switch (type_) 
2367   {
2368     case MDL_EXPR_INT: 
2369     {
2370       ast = new AstNode(AstNode::Constant, (void*)int_literal_);
2371       return true;
2372     }
2373     case MDL_EXPR_STRING:
2374     {
2375       // create another string here and pass it to AstNode(), instead
2376       // of using str_literal_.string_of() directly, just to get rid
2377       // of the compiler warning of "cast discards const". --chun
2378       //
2379       char* tmp_str = new char[strlen(str_literal_.string_of())+1];
2380       strcpy (tmp_str, str_literal_.string_of());
2381       ast = new AstNode(AstNode::ConstantString, tmp_str);
2382       delete[] tmp_str;
2383       return true;
2384     }
2385     case MDL_EXPR_INDEX:
2386     {
2387       mdl_var index_var;
2388       if (!left_->apply (index_var))
2389         return false;
2390       int index_value;
2391       if (!index_var.get(index_value))
2392         return false;
2393
2394       if (var_ == string ("$arg"))
2395         ast = new AstNode (AstNode::Param, (void*)index_value);
2396       else if (var_ == string ("$constraint"))
2397       {
2398         string tmp = string("$constraint") + string(index_value);
2399         mdl_var int_var;
2400         assert (mdl_env::get(int_var, tmp));
2401         int value;
2402         if (!int_var.get(value))
2403         {
2404           fprintf (stderr, "Unable to get value for %s\n", tmp.string_of());
2405           fflush(stderr);
2406           return false;
2407         }
2408         ast = new AstNode(AstNode::Constant, (void*)value);
2409       }
2410       else
2411       {
2412         mdl_var array_var;
2413         if (!mdl_env::get(array_var, var_)) return false;
2414         if (!array_var.is_list()) return false;  
2415         mdl_var element;
2416         assert (array_var.get_ith_element(element, index_value));
2417         switch (element.get_type())
2418         {
2419           case MDL_T_INT:
2420           {
2421             int value;
2422             assert (element.get(value));
2423             ast = new AstNode(AstNode::Constant, (void*)value);
2424             break;
2425           }
2426           case MDL_T_STRING:
2427           {
2428             string value;
2429             assert (element.get(value));
2430             //
2431             // create another string here and pass it to AstNode(), instead
2432             // of using value.string_of() directly, just to get rid of the 
2433             // compiler warning of "cast discards const".  --chun
2434             //
2435             char* tmp_str = new char[strlen(value.string_of())+1];
2436             strcpy (tmp_str, value.string_of());
2437             ast = new AstNode(AstNode::ConstantString, tmp_str);
2438             delete[] tmp_str;
2439
2440             break;
2441           }
2442           default: return false;
2443         }
2444       }
2445       return true;
2446     }
2447     case MDL_EXPR_BINOP:
2448     {
2449       AstNode* lnode;
2450       AstNode* rnode;
2451       if (!left_->apply (lnode)) return false;
2452       if (!right_->apply (rnode)) return false;
2453       switch (bin_op_) 
2454       {
2455         case MDL_PLUS:
2456           ast = new AstNode(plusOp, lnode, rnode);
2457           break;
2458         case MDL_MINUS:
2459           ast = new AstNode(minusOp, lnode, rnode);
2460           break;
2461         case MDL_DIV:
2462           ast = new AstNode(divOp, lnode, rnode);
2463           break;
2464         case MDL_MULT:
2465           ast = new AstNode(timesOp, lnode, rnode);
2466           break;
2467         case MDL_LT:
2468           ast = new AstNode(lessOp, lnode, rnode);
2469           break;
2470         case MDL_GT:
2471           ast = new AstNode(greaterOp, lnode, rnode);
2472           break;
2473         case MDL_LE:
2474           ast = new AstNode(leOp, lnode, rnode);
2475           break;
2476         case MDL_GE:
2477           ast = new AstNode(geOp, lnode, rnode);
2478           break;
2479         case MDL_EQ:
2480           ast = new AstNode(eqOp, lnode, rnode);
2481           break;
2482         case MDL_NE:
2483           ast = new AstNode(neOp, lnode, rnode);
2484           break;
2485         case MDL_AND:
2486           ast = new AstNode(andOp, lnode, rnode);
2487           break;
2488         case MDL_OR:
2489           ast = new AstNode(orOp, lnode, rnode);
2490           break;
2491         default: return false;
2492       }
2493       return true;
2494     }
2495     case MDL_EXPR_FUNC:
2496     {
2497       if (var_ == "startWallTimer" || var_ == "stopWallTimer"
2498 #if defined(MT_THREAD)
2499       || var_ == "startProcessTimer" || var_ == "stopProcessTimer"
2500       || var_ == "startProcessTimer_lwp" || var_ == "destroyProcessTimer")
2501 #else
2502       || var_ == "startProcessTimer" || var_ == "stopProcessTimer")
2503 #endif
2504       {
2505         if (!args_) return false;
2506         unsigned size = args_->size();
2507         if (size != 1) return false;
2508
2509         mdl_var timer(false);
2510         dataReqNode* drn;
2511         if (!(*args_)[0]->apply(timer)) return false;
2512         if (!timer.get(drn)) return false;
2513
2514         string timer_func;
2515         if (var_ == "startWallTimer")
2516           timer_func = START_WALL_TIMER;
2517         else if (var_ == "stopWallTimer")
2518           timer_func = STOP_WALL_TIMER;
2519         else if (var_ == "startProcessTimer")
2520           timer_func = START_PROC_TIMER;
2521         else if (var_ == "stopProcessTimer")
2522           timer_func = STOP_PROC_TIMER;
2523 #if defined(MT_THREAD)
2524         else if (var_ == "startProcessTimer_lwp")
2525           timer_func = START_PROC_TIMER_LWP;
2526         else if (var_ == "destroyProcessTimer")
2527           timer_func = DESTROY_PROC_TIMER;
2528 #endif
2529
2530         vector<AstNode *> ast_args;
2531
2532 #if defined(SHM_SAMPLING)
2533   #if defined(MT_THREAD)
2534         ast = createTimer(timer_func, (void*)(drn->getAllocatedLevel()),
2535                           (void *)(drn->getAllocatedIndex()),
2536                           ast_args);
2537   #else
2538         ast = createTimer(timer_func, 
2539           (void*)(drn->getInferiorPtr(global_proc)), ast_args);
2540   #endif
2541 #else
2542         ast = createTimer(timer_func,(void*)(drn->getInferiorPtr()),ast_args);
2543 #endif
2544       }
2545       else if (var_ == "readSymbol")
2546       {
2547         mdl_var symbol_var;
2548         if (!(*args_)[0]->apply(symbol_var))
2549           return false;
2550         string symbol_name;
2551         if (!symbol_var.get(symbol_name))
2552         {
2553           fprintf (stderr, "Unable to get symbol name for readSymbol()\n");
2554           fflush(stderr);
2555           return false;
2556         }
2557
2558         // relying on global_proc to be set in mdl_metric::apply
2559         if (global_proc) 
2560         {
2561           Symbol info;
2562           Address baseAddr;
2563           if (global_proc->getSymbolInfo(symbol_name, info, baseAddr)) 
2564           {
2565             Address adr = info.addr();
2566             ast = new AstNode(AstNode::DataAddr, (void*)adr);
2567           } 
2568           else 
2569           {
2570             string msg = string("In metric '") + currentMetric + string("': ")
2571               + string("unable to find symbol '") + symbol_name + string("'");
2572             showErrorCallback(95, msg);
2573             return false;
2574           }
2575         }
2576       }
2577       else if (var_ == "readAddress")
2578       {
2579         mdl_var addr_var;
2580         if (!(*args_)[0]->apply (addr_var))
2581           return false;
2582         int addr;
2583         if (!addr_var.get(addr))
2584         {
2585           fprintf (stderr, "Unable to get address readAddress()\n");
2586           fflush(stderr);
2587           return false;
2588         }
2589         ast = new AstNode(AstNode::DataAddr, (void*)addr);
2590       }
2591       else
2592       {
2593         vector<AstNode *> astargs;
2594         for (unsigned u = 0; u < args_->size(); u++) 
2595         {
2596           AstNode *tmparg=NULL;
2597           if (!(*args_)[u]->apply(tmparg)) 
2598           {
2599             removeAst(tmparg);
2600             return false;
2601           }
2602           astargs += assignAst(tmparg);
2603           removeAst(tmparg);
2604         }
2605         function_base* pdf = global_proc->findOneFunction(var_);
2606         if (!pdf) 
2607         {
2608           string msg = string("In metric '") + currentMetric + string("': ")
2609             + string("unable to find procedure '") + var_ + string("'");
2610           showErrorCallback(95, msg);
2611           return false;
2612         }
2613         ast = new AstNode(var_, astargs); //Cannot use simple assignment here!
2614         for (unsigned i=0;i<astargs.size();i++)
2615           removeAst(astargs[i]);
2616         break;
2617       }
2618       return true;
2619     }
2620     case MDL_EXPR_DOT:
2621     {
2622       //??? only allow left hand of DOT to be "$constraint[i]"?
2623
2624       mdl_var dot_var;
2625       if (!left_->apply(dot_var))
2626       {
2627         fprintf (stderr, "Invalid expression on the left of DOT.\n");
2628         fflush(stderr);
2629         return false;
2630       }
2631       return true;
2632     }
2633     case MDL_EXPR_ASSIGN:
2634     {
2635       mdl_var get_drn;
2636       dataReqNode* drn;
2637       if (!mdl_env::get(get_drn, var_)) return false;
2638       if (!get_drn.get(drn)) return false;
2639       AstNode* ast_arg;
2640       if (!left_->apply(ast_arg)) return false;
2641
2642       string func_str;
2643       switch (bin_op_)
2644       {
2645         case MDL_ASSIGN: func_str = "setCounter"; break;
2646         case MDL_PLUSASSIGN: func_str = "addCounter"; break;
2647         case MDL_MINUSASSIGN: func_str = "subCounter"; break;
2648         default: return false;
2649       }
2650 #if defined(SHM_SAMPLING)
2651   #if defined(MT_THREAD)
2652       ast = createCounter(func_str, (void*)(drn->getAllocatedLevel()),
2653                           (void *)(drn->getAllocatedIndex()), 
2654                           ast_arg);
2655   #else
2656       ast = createCounter(func_str, 
2657         (void*)(drn->getInferiorPtr(global_proc)), ast_arg);
2658   #endif
2659 #else
2660       ast = createCounter(func_str, (void *)(drn->getInferiorPtr()), ast_arg);
2661 #endif
2662       removeAst (ast_arg);
2663       return true;
2664     }
2665     case MDL_EXPR_VAR:
2666     {
2667       if (var_ == "$return") {
2668         ast = new AstNode(AstNode::ReturnVal, (void*)0);
2669         return true;
2670       }
2671       mdl_var get_drn;
2672       assert (mdl_env::get(get_drn, var_));
2673       switch (get_drn.type())
2674       {
2675         case MDL_T_INT:
2676         {
2677           int value;
2678           if (!get_drn.get(value)) 
2679           {
2680             fprintf(stderr, "Unable to get value for %s\n", var_.string_of());
2681             fflush(stderr);
2682             return false;
2683           }
2684           else 
2685             ast = new AstNode(AstNode::Constant, (void*)value);
2686           return true;
2687         }
2688         //case MDL_T_COUNTER:
2689         case MDL_T_DRN:
2690         {
2691           dataReqNode* drn;
2692           if (!get_drn.get(drn))
2693           {
2694             fprintf(stderr, "Unable to get value for %s\n", var_.string_of());
2695             fflush(stderr);
2696             return false;
2697           }
2698 #if defined(SHM_SAMPLING)
2699   #if defined(MT_THREAD)
2700           AstNode *tmp_ast;
2701           tmp_ast = computeTheAddress((void*)(drn->getAllocatedLevel()),
2702                                       (void *)(drn->getAllocatedIndex()),
2703                                       0); // 0 is for intCounter
2704           // First we get the address, and now we get the value...
2705           ast = new AstNode(AstNode::DataIndir,tmp_ast);
2706           removeAst(tmp_ast);
2707   #else
2708           ast = new AstNode(AstNode::DataAddr,  // was AstNode::DataValue
2709           // ast = new AstNode(AstNode::DataValue,  // restore AstNode::DataValue
2710                     (void*)(drn->getInferiorPtr(global_proc)));
2711   #endif
2712 #else
2713           // Note: getInferiorPtr could return a NULL pointer here if
2714           // we are just computing cost - naim 2/18/97
2715           ast = new AstNode(AstNode::DataAddr,  // was AstNode::DataValue
2716           // ast = new AstNode(AstNode::DataValue,  // restore AstNode::DataValue
2717                     (void*)(drn->getInferiorPtr()));
2718 #endif
2719           return true;
2720         }
2721         default:
2722           fprintf(stderr, "type of variable %s is not known\n", 
2723             var_.string_of());
2724           fflush(stderr);
2725           return false;
2726       }
2727     }
2728     case MDL_EXPR_PREUOP:
2729     {
2730       switch (u_op_)
2731       {
2732         case MDL_ADDRESS:
2733         {
2734           mdl_var get_drn;
2735           if (!left_->apply(get_drn))
2736           {
2737             string msg = string("In metric '") + currentMetric 
2738               + string("' : ") + string("error in operand of address operator");
2739             showErrorCallback(92, msg);
2740             return false;
2741           }
2742           dataReqNode *drn;
2743           assert (get_drn.get(drn));
2744 #if defined(SHM_SAMPLING)
2745   #if defined(MT_THREAD)
2746           ast = computeTheAddress((void *)(drn->getAllocatedLevel()),
2747                                   (void *)(drn->getAllocatedIndex()),
2748                                   0); // 0 is for intCounter
2749   #else
2750           // ast = new AstNode(AstNode::Constant,  // was AstNode::DataPtr
2751           ast = new AstNode(AstNode::DataPtr,  // restore AstNode::DataPtr
2752             (void*)(drn->getInferiorPtr(global_proc)));
2753   #endif
2754 #else
2755           // ast = new AstNode(AstNode::Constant, (void*)(drn->getInferiorPtr()));  // was AstNode::DataPtr
2756           ast = new AstNode(AstNode::DataPtr, (void*)(drn->getInferiorPtr()));  // was AstNode::DataPtr
2757 #endif
2758           break;
2759         }
2760         case MDL_MINUS:
2761         {
2762           mdl_var tmp;
2763           if (!left_->apply (tmp)) return false;
2764           int value;
2765           if (!tmp.get(value)) return false;
2766           ast = new AstNode(AstNode::Constant, (void*)(-value));
2767           break;
2768         }
2769         default:
2770           return false;
2771       }
2772       return true;
2773     }
2774     case MDL_EXPR_POSTUOP:
2775     {
2776       switch (u_op_)
2777       {
2778         case MDL_PLUSPLUS:
2779         {
2780           dataReqNode* drn;
2781           mdl_var drn_var;
2782           if (!left_->apply(drn_var)) return false;
2783           if (!drn_var.get(drn)) return false;
2784
2785           int value = 1;
2786           AstNode* ast_arg = new AstNode(AstNode::Constant, (void*)value);
2787
2788 #if defined(SHM_SAMPLING)
2789   #if defined(MT_THREAD)
2790           ast = createCounter("addCounter", (void*)(drn->getAllocatedLevel()),
2791                               (void *)(drn->getAllocatedIndex()),
2792                               ast_arg);
2793   #else
2794           ast = createCounter("addCounter", 
2795             (void*)(drn->getInferiorPtr(global_proc)), ast_arg);
2796   #endif
2797 #else
2798           ast = createCounter("addCounter", (void *)(drn->getInferiorPtr()), 
2799             ast_arg);
2800 #endif
2801           removeAst(ast_arg);       
2802           break;
2803         }
2804         default: return false;
2805       }
2806       return true;
2807     }
2808     default:
2809       return false;
2810   }
2811   return true;
2812 }
2813
2814 bool T_dyninstRPC::mdl_v_expr::apply(mdl_var& ret) 
2815 {
2816   switch (type_) 
2817   {
2818     case MDL_EXPR_INT: 
2819       return (ret.set(int_literal_));
2820     case MDL_EXPR_STRING:
2821       return (ret.set(str_literal_));
2822     case MDL_EXPR_INDEX:
2823     {
2824       if (var_ == string ("$arg"))
2825       {
2826         // we only allow $arg to appear inside icode (is this right?),
2827         // and therefore, the other mdl_v_expr::apply() should be used for
2828         // $arg, and not this one. --chun
2829         assert (0);
2830       }
2831       if (var_ == string ("$constraint"))
2832       {
2833         mdl_var ndx(false);
2834         if (!left_->apply(ndx)) return false;
2835         int x;
2836         if (!ndx.get(x)) return false;
2837         return (mdl_env::get(ret, var_+string(x)));
2838       }
2839       mdl_var array(false);
2840       if (!mdl_env::get(array, var_)) return false;
2841       if (!array.is_list()) return false;  
2842       mdl_var index_var;
2843       if (!left_->apply(index_var)) return false;
2844       int index_value;
2845       if (!index_var.get(index_value)) return false;
2846       if (index_value >= (int)array.list_size()) return false;
2847       return (array.get_ith_element(ret, index_value));
2848     }
2849     case MDL_EXPR_BINOP:
2850     {
2851       mdl_var left_val(false), right_val(false);
2852       if (!left_ || !right_) return false;
2853       if (!left_->apply(left_val)) return false;
2854       if (!right_->apply(right_val)) return false;
2855       return (do_operation(ret, left_val, right_val, bin_op_));
2856     }
2857     case MDL_EXPR_FUNC:
2858     {
2859       if (var_ == "startWallTimer" || var_ == "stopWallTimer"
2860 #if defined(MT_THREAD)
2861       || var_ == "startProcessTimer" || var_ == "stopProcessTimer"
2862       || var_ == "startProcessTimer_lwp")
2863 #else
2864       || var_ == "startProcessTimer" || var_ == "stopProcessTimer")
2865 #endif
2866       {
2867         // this mdl_v_expr::apply() is for expressions outside
2868         // instrumentation blocks.  these timer functions are not
2869         // supposed to be used here
2870         return false;
2871       }
2872       else
2873       {
2874         mdl_var arg0(false);
2875         if (!(*args_)[0]->apply(arg0)) return false;
2876         string func_name;
2877         if (!arg0.get(func_name)) return false;
2878         if (global_proc)
2879         {
2880           // TODO -- what if the function is not found ?
2881           function_base *pdf = global_proc->findOneFunction(func_name);
2882           if (!pdf) { assert(0); return false; }
2883           return (ret.set(pdf));
2884         }
2885         else { assert(0); return false; }
2886       }
2887     }
2888     case MDL_EXPR_DOT:
2889     {
2890       if (!left_->apply(ret)) return false;
2891
2892       if (!do_type_walk_)
2893         return true;
2894       else
2895       { // do_type_walk and type_walk are set in paradyn's mdl.C
2896         return (walk_deref(ret, type_walk)); 
2897       }
2898     }
2899     case MDL_EXPR_ASSIGN:
2900     {
2901       mdl_var lval(false), rval(false);
2902       if (!mdl_env::get(lval, var_)) return false;
2903       if (!left_ || !left_->apply(rval))
2904         return false;
2905       if (rval.type() == MDL_T_NONE)
2906       {
2907         ok_ = true;
2908         return ok_;
2909       }
2910       switch (bin_op_)
2911       {
2912         case MDL_ASSIGN:
2913         {
2914           int x;
2915           if (!rval.get(x)) return false;
2916           ok_ = ret.set(x);
2917           return ok_;
2918         }
2919         case MDL_PLUSASSIGN:
2920         {
2921           //chun-- a hack for $arg[i]
2922           if (lval.type() != MDL_T_NONE && rval.type() != MDL_T_NONE)
2923             ok_ = do_operation(ret, lval, rval, MDL_MINUS);
2924           else
2925             ok_ = true;
2926           return ok_;
2927         }
2928         case MDL_MINUSASSIGN:
2929         {
2930           //chun-- a hack for $arg[i]
2931           if (lval.type() != MDL_T_NONE && rval.type() != MDL_T_NONE)
2932             ok_ = do_operation(ret, lval, rval, MDL_PLUS);
2933           else
2934             ok_ = true;
2935           return ok_;
2936         }
2937       }
2938     }
2939     case MDL_EXPR_VAR:
2940     {
2941       if (var_ == string("$cmin") || var_ == string("$cmax"))
2942         ok_ = true;
2943       else
2944         ok_ = mdl_env::get (ret, var_);
2945       return ok_;
2946     }
2947     case MDL_EXPR_PREUOP:
2948     {
2949       mdl_var lval(false);
2950       if (!left_ || !left_->apply (lval)) return false;
2951       ok_ = do_operation(ret, lval, u_op_, true);
2952       return ok_;
2953     }
2954     case MDL_EXPR_POSTUOP:
2955     {
2956       mdl_var lval(false);
2957       if (!left_ || !left_->apply (lval)) return false;
2958       ok_ = do_operation(ret, lval, u_op_, false);
2959       return ok_;
2960     }
2961     default:
2962       return false;
2963   }
2964   return true;
2965 }
2966
2967 T_dyninstRPC::mdl_if_stmt::mdl_if_stmt(T_dyninstRPC::mdl_expr *expr, T_dyninstRPC::mdl_stmt *body)
2968   : expr_(expr), body_(body) {assert(0);}
2969
2970 T_dyninstRPC::mdl_if_stmt::mdl_if_stmt()
2971   : expr_(NULL), body_(NULL) { }
2972
2973 T_dyninstRPC::mdl_if_stmt::~mdl_if_stmt() {
2974   assert (0);
2975   delete expr_; delete body_;
2976 }
2977
2978 bool T_dyninstRPC::mdl_if_stmt::apply(metricDefinitionNode *mn,
2979                                       vector<dataReqNode*>& flags) {
2980   // An if stmt is comprised of (1) the 'if' expr and (2) the body to
2981   // execute if true.
2982   mdl_var res(false);
2983   if (!expr_->apply(res))
2984     return false;
2985
2986   int iv;
2987   switch (res.type()) {
2988   case MDL_T_INT:
2989     if (!res.get(iv))
2990       return false;
2991     if (!iv)
2992       return true;
2993     break;
2994   default:
2995     return false;
2996   }
2997
2998   return body_->apply(mn, flags);
2999 }
3000
3001 T_dyninstRPC::mdl_seq_stmt::mdl_seq_stmt(vector<T_dyninstRPC::mdl_stmt*> *stmts)
3002  : stmts_(stmts) { assert (0); }
3003
3004 T_dyninstRPC::mdl_seq_stmt::mdl_seq_stmt() 
3005  : stmts_(NULL) { }
3006
3007 T_dyninstRPC::mdl_seq_stmt::~mdl_seq_stmt() {
3008   assert (0);
3009   if (stmts_) {
3010     unsigned size = stmts_->size();
3011     for (unsigned u=0; u<size; u++)
3012       delete (*stmts_)[u];
3013     delete stmts_;
3014   }
3015 }
3016
3017 bool T_dyninstRPC::mdl_seq_stmt::apply(metricDefinitionNode *mn,
3018                                        vector<dataReqNode*>& flags) {
3019   // a seq_stmt is simply a sequence of statements; apply them all.
3020   if (!stmts_)
3021     return true;
3022
3023   unsigned size = stmts_->size();
3024   for (unsigned index=0; index<size; index++)
3025     if (!(*stmts_)[index]->apply(mn, flags)) // virtual fn call
3026       return false;
3027
3028   return true;
3029 }
3030
3031 T_dyninstRPC::mdl_list_stmt::mdl_list_stmt(u_int type, string ident,
3032                                            vector<string> *elems,
3033                                            bool is_lib, vector<string>* flavor) 
3034   : type_(type), id_(ident), elements_(elems), is_lib_(is_lib), flavor_(flavor) 
3035   { assert (0); }
3036
3037 T_dyninstRPC::mdl_list_stmt::mdl_list_stmt()
3038   : type_(MDL_T_NONE), id_(""), elements_(NULL), is_lib_(false), flavor_(NULL)
3039   { }
3040
3041 T_dyninstRPC::mdl_list_stmt::~mdl_list_stmt() 
3042 { assert(0); delete elements_; }
3043
3044 bool T_dyninstRPC::mdl_list_stmt::apply(metricDefinitionNode * /*mn*/,
3045                                         vector<dataReqNode*>& /*flags*/) {
3046   bool found = false;
3047   for (unsigned u0 = 0; u0 < flavor_->size(); u0++) {
3048     if ((*flavor_)[u0] == daemon_flavor) {
3049       found = true;
3050       break;
3051     }
3052   }
3053   if (!found) return false;
3054   if (!elements_) return false;
3055   mdl_var list_var(id_, false);
3056   if (!list_var.make_list(type_)) return false;
3057
3058   unsigned size = elements_->size();
3059
3060   if (type_ == MDL_T_PROCEDURE_NAME) {
3061     vector<functionName*> *list_fn;
3062     bool aflag;
3063     aflag=list_var.get(list_fn);
3064     assert(aflag);
3065     for (unsigned u=0; u<size; u++) {
3066       functionName *fn = new functionName((*elements_)[u]);
3067       *list_fn += fn;
3068     }
3069   } else if (type_ == MDL_T_PROCEDURE) { 
3070     assert(0);
3071   } else if (type_ == MDL_T_MODULE) {
3072     assert(0);
3073   } else {
3074     for (unsigned u=0; u<size; u++) {
3075       int i; float f;
3076       mdl_var expr_var(false);
3077       switch (type_) {
3078       case MDL_T_INT:
3079         if (sscanf((*elements_)[u].string_of(), "%d", &i) != 1) return false;
3080         if (!expr_var.set(i)) return false; 
3081         break;
3082       case MDL_T_FLOAT:
3083         if (sscanf((*elements_)[u].string_of(), "%f", &f) != 1) return false;
3084         if (!expr_var.set(f)) return false; 
3085         break;
3086       case MDL_T_STRING: 
3087         if (!expr_var.set((*elements_)[u])) return false; 
3088         break;
3089       default:
3090         return false;
3091       }
3092       if (!list_var.add_to_list(expr_var)) return false;
3093     }
3094   }
3095   return (mdl_env::add(list_var));
3096 }
3097
3098 T_dyninstRPC::mdl_instr_stmt::mdl_instr_stmt(unsigned pos, 
3099                                       T_dyninstRPC::mdl_expr *expr,
3100                                       vector<T_dyninstRPC::mdl_icode*> *reqs,
3101                                       unsigned where, bool constrained) 
3102   : position_(pos), point_expr_(expr), icode_reqs_(reqs),
3103   where_instr_(where), constrained_(constrained) 
3104 { assert(0); }
3105
3106 T_dyninstRPC::mdl_instr_stmt::mdl_instr_stmt()
3107   : position_(0), point_expr_(NULL), icode_reqs_(NULL),
3108   where_instr_(0), constrained_(false) { }
3109
3110 T_dyninstRPC::mdl_instr_stmt::~mdl_instr_stmt() {
3111   assert (0);
3112   delete point_expr_;
3113   if (icode_reqs_) {
3114     unsigned size = icode_reqs_->size();
3115     for (unsigned u=0; u<size; u++)
3116       delete (*icode_reqs_)[u];
3117     delete icode_reqs_;
3118   }
3119 }
3120
3121 bool T_dyninstRPC::mdl_instr_stmt::apply(metricDefinitionNode *mn,
3122                                          vector<dataReqNode*>& inFlags) {
3123    // An instr statement is like:
3124    //    append preInsn $constraint[0].entry constrained
3125    //       (* setCounter(procedureConstraint, 1); *)
3126    // (note that there are other kinds of statements; i.e. there are other classes
3127    //  derived from the base class mdl_stmt; see dyninstRPC.I)
3128
3129   if (icode_reqs_ == NULL)
3130     return false; // no instrumentation code to put in!
3131
3132   mdl_var pointsVar(false);
3133   if (!point_expr_->apply(pointsVar)) // process the 'point(s)' e.g. "$start.entry"
3134     return false;
3135
3136   vector<instPoint *> points;
3137   if (pointsVar.type() == MDL_T_LIST_POINT) {
3138     vector<instPoint *> *pts;
3139     if (!pointsVar.get(pts)) return false;
3140     points = *pts;
3141   } else if (pointsVar.type() == MDL_T_POINT) {
3142     instPoint *p;
3143     if (!pointsVar.get(p)) return false; // where the point is located...
3144     points += p;
3145   } else {
3146     return false;
3147   }
3148
3149   // Let's generate the code now (we used to calculate it in the loop below,
3150   // which was a waste since the code is the same for all points).
3151   AstNode *code = NULL;
3152   unsigned size = icode_reqs_->size();
3153   for (unsigned u=0; u<size; u++) {
3154     if (!(*icode_reqs_)[u]->apply(code, u>0)) {
3155       // when u is 0, code is un-initialized
3156       removeAst(code);
3157       return false;
3158     }
3159   }
3160
3161   // Instantiate all constraints (flags) here (if any)
3162   // (if !constrained_ then don't do the following)
3163   if (constrained_) {
3164      unsigned fsize = inFlags.size();
3165      for (int fi=fsize-1; fi>=0; fi--) { // any reason why we go backwards?
3166 #if defined(SHM_SAMPLING)
3167   #if defined(MT_THREAD)
3168         AstNode *tmp_ast;
3169         tmp_ast = computeTheAddress((void *)((inFlags[fi])->getAllocatedLevel()),
3170                                     (void *)((inFlags[fi])->getAllocatedIndex()), 
3171                                     0); // 0 is for intCounter
3172         AstNode *temp1 = new AstNode(AstNode::DataIndir,tmp_ast);
3173         removeAst(tmp_ast);
3174   #else
3175         // Note: getInferiorPtr could return a NULL pointer here if we are
3176         // just computing cost - naim 2/18/97
3177         AstNode *temp1 = new AstNode(AstNode::DataAddr,  // was AstNode::DataValue
3178         // AstNode *temp1 = new AstNode(AstNode::DataValue,  // restore AstNode::DataValue
3179                                      (void*)((inFlags[fi])->getInferiorPtr(global_proc)));
3180   #endif
3181 #else
3182         // Note: getInferiorPtr could return a NULL pointer here if we are
3183         // just computing cost - naim 2/18/97
3184         AstNode *temp1 = new AstNode(AstNode::DataAddr,  // was AstNode::DataValue
3185         // AstNode *temp1 = new AstNode(AstNode::DataValue,  // restore AstNode::DataValue
3186                                      (void*)((inFlags[fi])->getInferiorPtr()));
3187 #endif
3188         // Note: we don't use assignAst on purpose here
3189         AstNode *temp2 = code;
3190         code = createIf(temp1, temp2);
3191         removeAst(temp1);
3192         removeAst(temp2);
3193      }
3194   }
3195
3196   if (!code) {
3197     // we are probably defining an empty metric
3198     code = new AstNode();
3199   }
3200
3201   callOrder corder;
3202   switch (position_) {
3203       case MDL_PREPEND: 
3204           corder = orderFirstAtPoint; 
3205           break;
3206       case MDL_APPEND: 
3207           corder = orderLastAtPoint; 
3208           break;
3209       default: assert(0);
3210   }
3211
3212   callWhen cwhen;
3213   switch (where_instr_) {
3214       case MDL_PRE_INSN: 
3215           cwhen = callPreInsn; 
3216           break;
3217       case MDL_POST_INSN: 
3218           cwhen = callPostInsn; 
3219           break;
3220       default: assert(0);
3221   }
3222
3223   // for all of the inst points, insert the predicates and the code itself.
3224   for (unsigned i = 0; i < points.size(); i++) {
3225       mn->addInst(points[i], code, cwhen, corder );
3226          // appends an instReqNode to mn's instRequests; actual 
3227          // instrumentation only
3228          // takes place when mn->insertInstrumentation() is later called.
3229   }
3230   removeAst(code); 
3231   return true;
3232 }
3233
3234 bool mdl_can_do(string& met_name) {
3235   // NOTE: We can do better if there's a dictionary of <metric-name> to <anything>
3236   unsigned size = mdl_data::all_metrics.size();
3237   for (unsigned u=0; u<size; u++)
3238     if (mdl_data::all_metrics[u]->name_ == met_name)
3239       return true;
3240
3241   /*
3242   metric_cerr << endl << " all metric names: " << endl;
3243   for (unsigned u=0; u<size; u++)
3244     metric_cerr << "  metric name [" << u << "] = [" 
3245                 << mdl_data::all_metrics[u]->name_ << "] " << endl;
3246   */
3247
3248   return false;
3249 }
3250
3251 metricDefinitionNode *mdl_do(vector< vector<string> >& canon_focus, 
3252                              string& met_name,
3253                              string& flat_name,
3254                              vector<process *> procs,
3255                              vector< vector<pdThread *> >& threadsVec,
3256                              bool replace_components_if_present,
3257                              bool computingCost) {
3258   currentMetric = met_name;
3259   unsigned size = mdl_data::all_metrics.size();
3260   // NOTE: We can do better if there's a dictionary of <metric-name> to <metric>!
3261   for (unsigned u=0; u<size; u++) {
3262     if (mdl_data::all_metrics[u]->name_ == met_name) {
3263       return (mdl_data::all_metrics[u]->apply(canon_focus, flat_name, procs,
3264                                               threadsVec,
3265                                               replace_components_if_present,
3266                                               computingCost));
3267       // calls mdl_metric::apply()
3268     }
3269   }
3270   return NULL;
3271 }
3272
3273 bool mdl_init(string& flavor) { 
3274
3275   daemon_flavor = flavor;
3276
3277 #ifdef notdef
3278   vector<mdl_type_desc> kids;
3279   mdl_type_desc self, kid;
3280   mdl_focus_element fe;
3281
3282   self.name = "SyncObject"; self.type = 0; self.end_allowed = false; 
3283   kid.name = "Message"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
3284   kid.name = "Barrier"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
3285   kid.name = "Semaphore"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
3286   kid.name = "SpinLock"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
3287   fe.self = self; fe.kids = kids;
3288   mdl_data::foci += fe;
3289   kids.resize(0);
3290
3291 //  self.name = "Procedure"; self.type = MDL_T_MODULE; self.end_allowed = true;
3292   self.name = "Code"; self.type = MDL_T_MODULE; self.end_allowed = true;
3293   kid.name = "Module"; kid.type = MDL_T_PROCEDURE; self.end_allowed = true; kids += kids;
3294   fe.self = self; fe.kids = kids;
3295   mdl_data::foci += fe;
3296   kids.resize(0);
3297
3298   self.name = "Machine"; self.type = MDL_T_STRING; self.end_allowed = true;
3299   kid.name = "Process"; kid.type = MDL_T_PROCESS; kid.end_allowed = true; kids += kid;
3300   fe.self = self; fe.kids = kids;
3301   mdl_data::foci += fe;
3302   kids.resize(0);
3303 #endif
3304
3305   mdl_env::push();
3306   // These are pushed on per-process
3307   // mdl_env::add("$procedures", false, MDL_T_LIST_PROCEDURE);
3308   // mdl_env::add("$modules", false, MDL_T_LIST_MODULE);
3309
3310   string vname = "$machine";
3311   mdl_env::add(vname, false, MDL_T_STRING);
3312   string nodename = getNetworkName();
3313   mdl_env::set(nodename, vname);
3314
3315   /* Are these entered by hand at the new scope ? */
3316   /* $arg, $return */
3317
3318   vector<mdl_type_desc> field_list;
3319   mdl_type_desc desc;
3320   desc.end_allowed = false;     // random initialization
3321
3322   desc.name = "name"; desc.type = MDL_T_STRING; field_list += desc;
3323   desc.name = "calls"; desc.type = MDL_T_LIST_POINT; field_list += desc;
3324   desc.name = "entry"; desc.type = MDL_T_POINT; field_list += desc;
3325   desc.name = "return"; desc.type = MDL_T_POINT; field_list += desc;
3326   mdl_data::fields[MDL_T_PROCEDURE] = field_list;
3327   field_list.resize(0);
3328
3329   desc.name = "name"; desc.type = MDL_T_STRING; field_list += desc;
3330   desc.name = "funcs"; desc.type = MDL_T_LIST_PROCEDURE; field_list += desc;
3331   mdl_data::fields[MDL_T_MODULE] = field_list;
3332   field_list.resize(0);
3333
3334   return true;
3335 }
3336
3337 void dynRPC::send_metrics(vector<T_dyninstRPC::mdl_metric*>* var_0) {
3338   mdl_met = true;
3339
3340   if (var_0) {
3341     unsigned var_size = var_0->size();
3342     for (unsigned v=0; v<var_size; v++) {
3343       // fprintf(stderr, "Got metric %s\n", (*var_0)[v]->name_.string_of());
3344       // fflush(stderr);
3345       bool found = false;
3346       unsigned f_size = (*var_0)[v]->flavors_->size();
3347
3348       bool flavor_found = false;
3349       for (unsigned f=0; f<f_size; f++) {
3350         if ((*(*var_0)[v]->flavors_)[f] == daemon_flavor) {
3351           flavor_found = true; break;
3352         }
3353       }
3354       if (flavor_found) {
3355         unsigned size=mdl_data::all_metrics.size();
3356         for (unsigned u=0; u<size; u++) 
3357           if (mdl_data::all_metrics[u]->id_ == (*var_0)[v]->id_) {
3358             delete mdl_data::all_metrics[u];
3359             mdl_data::all_metrics[u] = (*var_0)[v];
3360             found = true;
3361           }
3362         if (!found) {
3363           T_dyninstRPC::mdl_metric *m = (*var_0)[v];
3364           mdl_data::all_metrics += m;
3365         }
3366       }
3367     }
3368   } else {
3369      fprintf(stderr, "no metric defined\n");
3370      fflush(stderr);
3371   }
3372 }
3373
3374 void dynRPC::send_constraints(vector<T_dyninstRPC::mdl_constraint*> *cv) {
3375
3376   mdl_cons = true;
3377   if (cv) {
3378     unsigned var_size = cv->size();
3379     for (unsigned v=0; v<var_size; v++) {
3380       bool found = false;
3381       // cout << "Received " << (*cv)[v]->id_ << endl;
3382       for (unsigned u=0; u<mdl_data::all_constraints.size(); u++) 
3383         if (mdl_data::all_constraints[u]->id_ == (*cv)[v]->id_) {
3384           delete mdl_data::all_constraints[u];
3385           mdl_data::all_constraints[u] = (*cv)[v];
3386           found = true;
3387         }
3388       if (!found) {
3389         mdl_data::all_constraints += (*cv)[v];
3390         // cout << *(*cv)[v] << endl;
3391       }
3392     }
3393   }
3394 }
3395
3396
3397 // TODO -- are these executed immediately ?
3398 void dynRPC::send_stmts(vector<T_dyninstRPC::mdl_stmt*> *vs) {
3399   mdl_stmt = true;
3400   if (vs) {
3401     // ofstream of("other_out", (been_here ? ios::app : ios::out));
3402     // been_here = true;
3403     // of << "SEND_STMTS\n";
3404     // unsigned size = vs->size();
3405     // for (unsigned u=0; u<size; u++) 
3406     // (*vs)[u]->print(of);
3407     mdl_data::stmts += *vs;
3408
3409     // TODO -- handle errors here
3410     // TODO -- apply these statements without a metric definition node ?
3411     unsigned s_size = vs->size();
3412     vector<dataReqNode*> flags;
3413
3414     // Application may fail if the list flavor is different than the flavor
3415     // of this daemon
3416
3417     for (unsigned s=0; s<s_size; s++) {
3418       if (!(*vs)[s]->apply(NULL, flags)) 
3419         ;
3420       // (*vs)[s]->print(cout);
3421       // cout << endl;
3422     }
3423   }
3424 }
3425
3426 // recieves the list of shared libraries to exclude 
3427 void dynRPC::send_libs(vector<string> *libs) {
3428
3429     mdl_libs = true;
3430     //metric_cerr << "void dynRPC::send_libs(vector<string> *libs) called" << endl;
3431     for(u_int i=0; i < libs->size(); i++){
3432         mdl_data::lib_constraints += (*libs)[i]; 
3433         //metric_cerr << " send_libs : adding " << (*libs)[i] << " to paradynd set of mdl_data::lib_constraints" << endl;
3434     }
3435
3436 }
3437
3438 // recieves notification that there are no excluded libraries 
3439 void dynRPC::send_no_libs() {
3440     mdl_libs = true;
3441 }
3442
3443 static bool do_operation(mdl_var& ret, mdl_var& lval, unsigned u_op, bool/*is_preop*/) 
3444 {
3445   switch (u_op) 
3446   {
3447     case MDL_PLUSPLUS:
3448     {
3449       if (lval.type() == MDL_T_INT)
3450       {
3451         int x;
3452         if (!lval.get(x)) return false;
3453         return (ret.set(x++));
3454       }
3455       else
3456       {
3457         metric_cerr << "Invalid type for operator ++" << endl;
3458         return false;
3459       }
3460     }
3461     case MDL_MINUS:
3462     {
3463       if (lval.type() == MDL_T_INT)
3464       {
3465         int x;
3466         if (!lval.get(x)) return false;
3467         return ret.set(-x);
3468       }
3469       else
3470       {
3471         metric_cerr << "Invalid type for operator -" << endl;
3472         return false;
3473       }
3474     }
3475     case MDL_ADDRESS:
3476       return true;
3477     case MDL_NOT:
3478     default:
3479       return false;
3480   }
3481   return false;
3482 }
3483
3484 static bool do_operation(mdl_var& ret, mdl_var& left_val,
3485                          mdl_var& right_val, unsigned bin_op) 
3486 {
3487   switch (bin_op) 
3488   {
3489     case MDL_PLUS:
3490     case MDL_MINUS:
3491     case MDL_DIV:
3492     case MDL_MULT:
3493     {
3494       if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) 
3495       {
3496         int v1, v2;
3497         if (!left_val.get(v1)) return false;
3498         if (!right_val.get(v2)) return false;
3499         switch (bin_op) 
3500         {
3501           case MDL_PLUS: return (ret.set(v1+v2));
3502           case MDL_MINUS: return (ret.set(v1-v2));
3503           case MDL_DIV: return (ret.set(v1/v2));
3504           case MDL_MULT: return (ret.set(v1*v2));
3505         }
3506       }
3507       else if (((left_val.type()==MDL_T_INT)||(left_val.type()==MDL_T_FLOAT)) 
3508         && ((right_val.type()==MDL_T_INT)||(right_val.type()==MDL_T_FLOAT)))
3509       {
3510         float v1, v2;
3511         if (left_val.type() == MDL_T_INT) 
3512         {
3513           int i1;
3514           if (!left_val.get(i1)) return false; v1 = (float)i1;
3515         }
3516         else 
3517         {
3518           if (!left_val.get(v1)) return false;
3519         }
3520         if (right_val.type() == MDL_T_INT) 
3521         {
3522           int i1;
3523           if (!right_val.get(i1)) return false; v2 = (float)i1;
3524         } 
3525         else 
3526         {
3527           if (!right_val.get(v2)) return false;
3528         }
3529         switch (bin_op) 
3530         {
3531           case MDL_PLUS: return (ret.set(v1+v2));
3532           case MDL_MINUS: return (ret.set(v1-v2));
3533           case MDL_DIV: return (ret.set(v1/v2));
3534           case MDL_MULT: return (ret.set(v1*v2));
3535         }
3536       }
3537       else
3538         return false;
3539     }
3540     case MDL_LT:
3541     case MDL_GT:
3542     case MDL_LE:
3543     case MDL_GE:
3544     case MDL_EQ:
3545     case MDL_NE:
3546     {
3547       if ((left_val.type()==MDL_T_STRING)&&(right_val.type()==MDL_T_STRING)) 
3548       {
3549         string v1, v2;
3550         if (!left_val.get(v1)) return false;
3551         if (!right_val.get(v2)) return false;
3552         switch (bin_op) 
3553         {
3554           case MDL_LT: return (ret.set(v1 < v2));
3555           case MDL_GT: return (ret.set(v1 > v2));
3556           case MDL_LE: return (ret.set(v1 <= v2));
3557           case MDL_GE: return (ret.set(v1 >= v2));
3558           case MDL_EQ: return (ret.set(v1 == v2));
3559           case MDL_NE: return (ret.set(v1 != v2));
3560         }  
3561       }
3562       if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) 
3563       {
3564         int v1, v2;
3565         if (!left_val.get(v1)) return false;
3566         if (!right_val.get(v2)) return false;
3567         switch (bin_op) 
3568         {
3569           case MDL_LT: return (ret.set(v1 < v2));
3570           case MDL_GT: return (ret.set(v1 > v2));
3571           case MDL_LE: return (ret.set(v1 <= v2));
3572           case MDL_GE: return (ret.set(v1 >= v2));
3573           case MDL_EQ: return (ret.set(v1 == v2));
3574           case MDL_NE: return (ret.set(v1 != v2));
3575         }
3576       }
3577       else if (((left_val.type()==MDL_T_INT)||(left_val.type()==MDL_T_FLOAT))
3578         && ((right_val.type()==MDL_T_INT)||(right_val.type()==MDL_T_FLOAT))) 
3579       {
3580         float v1, v2;
3581         if (left_val.type() == MDL_T_INT) 
3582         {
3583           int i1;
3584           if (!left_val.get(i1)) return false; v1 = (float)i1;
3585         } 
3586         else 
3587         {
3588           if (!left_val.get(v1)) return false;
3589         }
3590         if (right_val.type() == MDL_T_INT) 
3591         {
3592           int i1;
3593           if (!right_val.get(i1)) return false; v2 = (float)i1;
3594         }
3595         else 
3596         {
3597           if (!right_val.get(v2)) return false;
3598         }
3599         switch (bin_op) 
3600         {
3601           case MDL_LT: return (ret.set(v1 < v2));
3602           case MDL_GT: return (ret.set(v1 > v2));
3603           case MDL_LE: return (ret.set(v1 <= v2));
3604           case MDL_GE: return (ret.set(v1 >= v2));
3605           case MDL_EQ: return (ret.set(v1 == v2));
3606           case MDL_NE: return (ret.set(v1 != v2));
3607         }
3608       }
3609       else
3610         return false;
3611     }
3612     case MDL_AND:
3613     case MDL_OR:
3614     {
3615       if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) 
3616       {
3617         int v1, v2;
3618         if (!left_val.get(v1)) return false;
3619         if (!right_val.get(v2)) return false;
3620         switch (bin_op) 
3621         {
3622           case MDL_AND: return (ret.set(v1 && v2));
3623           case MDL_OR: return (ret.set(v1 || v2));
3624         }
3625       }
3626       else
3627         return false;
3628     }
3629     default:
3630       return false;
3631   }
3632   return false;
3633 }
3634
3635 static bool walk_deref(mdl_var& ret, vector<unsigned>& types) 
3636 {
3637   unsigned index=0;
3638   unsigned max = types.size();
3639
3640   while (index < max) 
3641   {
3642     unsigned current_type = types[index++];
3643     unsigned next_field = types[index++];
3644
3645     switch (current_type) 
3646     {
3647       case MDL_T_PROCEDURE_NAME:
3648       case MDL_T_PROCEDURE:
3649       {
3650         function_base *pdf = 0;
3651         if (!ret.get(pdf)) return false;
3652         switch (next_field) 
3653         {
3654           case 0: 
3655           {
3656             string prettyName = pdf->prettyName();
3657             if (!ret.set(prettyName)) return false;
3658             break;
3659             // TODO: should these be passed a process?  yes, they definitely should!
3660           }
3661           case 1:
3662           {
3663             //
3664             /*****
3665              here we should check the calls and exclude the calls to fns in the
3666              global_excluded_funcs list.
3667              *****/
3668             // ARI -- This is probably the spot!
3669
3670             vector<instPoint*> calls = pdf->funcCalls(global_proc);
3671             // makes a copy of the return value (on purpose), since we 
3672             // may delete some items that shouldn't be a call site for