Cleaning up dataReqNodes for certain cases of deletion of metricDefinitionNodes
[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 #include <iostream.h>
43 #include <stdio.h>
44 #include "dyninstRPC.xdr.SRVR.h"
45 #include "paradyn/src/met/globals.h"
46 #include "paradynd/src/metric.h"
47 #include "dyninstAPI/src/inst.h"
48 #include "dyninstAPI/src/ast.h"
49 #include "paradynd/src/main.h"
50 #include "dyninstAPI/src/symtab.h"
51 #include "util/h/Timer.h"
52 #include "paradynd/src/mdld.h"
53 #include "showerror.h"
54 #include "dyninstAPI/src/process.h"
55 #include "util/h/debugOstream.h"
56 #include "paradynd/src/blizzard_memory.h"
57
58 // The following vrbles were defined in process.C:
59 extern debug_ostream attach_cerr;
60 extern debug_ostream inferiorrpc_cerr;
61 extern debug_ostream shmsample_cerr;
62 extern debug_ostream forkexec_cerr;
63 extern debug_ostream metric_cerr;
64
65
66 // Some global variables used to print error messages:
67 string currentMetric;  // name of the metric that is being processed.
68 string currentFocus;   // the focus
69
70
71 static string daemon_flavor;
72 static process *global_proc = NULL;
73 static bool mdl_met=false, mdl_cons=false, mdl_stmt=false, mdl_libs=false,mdl_funcs=false;
74
75 inline unsigned ui_hash(const unsigned &u) { return u; }
76
77 vector<unsigned> mdl_env::frames;
78 vector<mdl_var> mdl_env::all_vars;
79
80 vector<T_dyninstRPC::mdl_stmt*> mdl_data::stmts;
81 vector<T_dyninstRPC::mdl_metric*> mdl_data::all_metrics;
82 dictionary_hash<unsigned, vector<mdl_type_desc> > mdl_data::fields(ui_hash);
83 vector<mdl_focus_element> mdl_data::foci;
84 vector<T_dyninstRPC::mdl_constraint*> mdl_data::all_constraints;
85 vector<string> mdl_data::lib_constraints;
86 vector<string> mdl_data::func_constraints;
87
88 static bool walk_deref(mdl_var& ret, vector<unsigned>& types, string& var_name);
89 static bool do_operation(mdl_var& ret, mdl_var& left, mdl_var& right, unsigned bin_op);
90
91 class list_closure {
92 public:
93   list_closure(string& i_name, mdl_var& list_v)
94     : index_name(i_name), element_type(0), index(0), int_iter(NULL), float_iter(NULL),
95   string_iter(NULL), bool_iter(NULL), func_iter(NULL), mod_iter(NULL), max_index(0)
96   {
97     bool aflag;
98     aflag=list_v.is_list();
99     assert(aflag);
100
101     element_type = list_v.element_type();
102     switch(element_type) {
103     case MDL_T_INT:
104       aflag=list_v.get(int_iter); assert(aflag);
105       max_index = int_iter->size(); break;
106     case MDL_T_FLOAT:
107       aflag=list_v.get(float_iter); assert(aflag);
108       max_index = float_iter->size(); break;
109     case MDL_T_STRING:
110       aflag=list_v.get(string_iter); assert(aflag);
111       max_index = string_iter->size(); break;
112     case MDL_T_PROCEDURE_NAME:
113       aflag=list_v.get(funcName_iter); assert(aflag);
114       max_index = funcName_iter->size();
115       break;
116     case MDL_T_PROCEDURE:
117       aflag=list_v.get(func_iter); assert(aflag);
118       max_index = func_iter->size();
119       break;
120     case MDL_T_MODULE:
121       aflag=list_v.get(mod_iter); assert(aflag);
122       max_index = mod_iter->size();
123       break;
124     case MDL_T_POINT:
125       aflag=list_v.get(point_iter); assert(aflag);
126       max_index = point_iter->size();
127       break;
128     default:
129       assert(0);
130     }
131   }
132   ~list_closure() { }
133   bool next() {
134     string s;
135     function_base *pdf; module *m;
136     float f; int i;
137     instPoint *ip;
138
139     if (index >= max_index) return false;
140     switch(element_type) {
141     case MDL_T_INT:
142       i = (*int_iter)[index++];      return (mdl_env::set(i, index_name));
143     case MDL_T_FLOAT:
144       f = (*float_iter)[index++];    return (mdl_env::set(f, index_name));
145     case MDL_T_STRING:
146       s = (*string_iter)[index++];   return (mdl_env::set(s, index_name));
147     case MDL_T_PROCEDURE_NAME:
148       // lookup-up the functions defined in resource lists
149       // the function may not exist in the image, in which case we get the
150       // next one
151       do {
152         functionName *fn = (*funcName_iter)[index++];
153         pdf = global_proc->findOneFunction(fn->get());
154       } while (pdf == NULL && index < max_index);
155       if (pdf == NULL)
156         return false;
157       return (mdl_env::set(pdf, index_name));
158     case MDL_T_PROCEDURE:
159       pdf = (*func_iter)[index++];
160       assert(pdf);
161       return (mdl_env::set(pdf, index_name));
162     case MDL_T_MODULE: 
163       m = (*mod_iter)[index++];      return (mdl_env::set(m, index_name));
164     case MDL_T_POINT:
165       ip = (*point_iter)[index++];   return (mdl_env::set(ip, index_name));
166     default:
167       assert(0);
168     }
169     return false;
170   }
171
172 private:
173   string index_name;
174   unsigned element_type;
175   unsigned index;
176   vector<int> *int_iter;
177   vector<float> *float_iter;
178   vector<string> *string_iter;
179   vector<bool> *bool_iter;
180   vector<function_base*> *func_iter;
181   vector<functionName*> *funcName_iter;
182   vector<module*> *mod_iter;
183   vector<instPoint*> *point_iter;
184   unsigned max_index;
185 };
186
187 T_dyninstRPC::mdl_metric::mdl_metric(string id, string name, string units, 
188                                     u_int agg, u_int sty, u_int type,
189                                     vector<T_dyninstRPC::mdl_stmt*> *mv, 
190                                     vector<string> *flav,
191                                     vector<T_dyninstRPC::mdl_constraint*> *cons,
192                                     vector<string> *temp_counters,
193                                     bool developerMode,
194                                     int unitstype)
195 : id_(id), name_(name), units_(units), agg_op_(agg), style_(sty),
196   type_(type), stmts_(mv), flavors_(flav), constraints_(cons),
197   temp_ctr_(temp_counters), developerMode_(developerMode),
198   unitstype_(unitstype) { }
199
200 T_dyninstRPC::mdl_metric::mdl_metric() { }
201
202 T_dyninstRPC::mdl_metric::~mdl_metric() {
203   if (stmts_) {
204     unsigned size = stmts_->size();
205     for (unsigned u=0; u<size; u++)
206       delete (*stmts_)[u];
207     delete stmts_;
208   }
209   delete flavors_;
210
211   if (constraints_) {
212     unsigned size = constraints_->size();
213     for (unsigned u=0; u<size; u++)
214       delete (*constraints_)[u];
215     delete constraints_;
216   }
217
218 }
219
220 bool mdl_data::new_metric(string id, string name, string units,
221                           u_int agg, u_int sty, u_int type,
222                           vector<T_dyninstRPC::mdl_stmt*> *mv,
223                           vector<string> *flav,
224                           vector<T_dyninstRPC::mdl_constraint*> *cons,
225                           vector<string> *temp_counters,
226                           bool developerMode,
227                           int unitstype) {
228   T_dyninstRPC::mdl_metric *m = new T_dyninstRPC::mdl_metric(id, name, 
229                                                              units, agg,
230                                                              sty, type, mv,
231                                                              flav, cons,
232                                                              temp_counters,
233                                                              developerMode,
234                                                              unitstype);
235   if (!m)
236     return false;
237   else {
238     all_metrics += m;
239     return true;
240   }
241 }
242
243 static bool other_machine_specified(vector< vector<string> > &focus,
244                                     string& machine) {
245   assert(focus[resource::machine][0] == "Machine");
246
247   switch (focus[resource::machine].size()) {
248   case 1: break;
249   case 2:
250     if (machine != focus[resource::machine][1]) return true;
251     break;
252   default:
253     assert(0);
254   }
255   return false;
256 }
257
258 static void add_processes(vector< vector<string> > &focus,
259                                  vector<process*> procs,
260                                  vector<process*> &ip) {
261   assert(focus[resource::process][0] == "Process");
262   unsigned pi, ps;
263
264   switch(focus[resource::process].size()) {
265   case 1:
266     ip = procs;
267     break;
268   case 2:
269 #if defined(MT_THREAD)
270   case 3:
271 #endif
272     ps = procs.size();
273     for (pi=0; pi<ps; pi++)
274       if (procs[pi]->rid->part_name() == focus[resource::process][1]) {
275         ip += procs[pi];
276         break;
277       }
278     break;
279   default:
280     assert(0);
281   }
282 }
283
284 static bool focus_matches(vector<string>& focus, vector<string> *match_path) {
285   unsigned mp_size = match_path->size();
286   unsigned f_size = focus.size();
287
288   if ((mp_size < 1) || (f_size < 2) || (mp_size != (f_size-1))) {
289     return false;
290   }
291
292   for (unsigned u = 0; u < mp_size; u++) {
293     if(((*match_path)[u] != "*") && (focus[u] != (*match_path)[u])) {
294       return false;
295     }
296   }
297
298   return true;
299 }
300
301
302 // Global constraints are specified by giving their name within a metric def
303 // Find the real constraint by searching the dictionary using this name
304 static T_dyninstRPC::mdl_constraint *flag_matches(vector<string>& focus, 
305                                                   T_dyninstRPC::mdl_constraint *match_me,
306                                                   bool& is_default) {
307   unsigned c_size = mdl_data::all_constraints.size();
308   for (unsigned cs=0; cs<c_size; cs++) 
309     if (mdl_data::all_constraints[cs]->id_ == match_me->id_) {
310       match_me = mdl_data::all_constraints[cs];
311       if (focus_matches(focus, mdl_data::all_constraints[cs]->match_path_)) {
312         if (mdl_data::all_constraints[cs]->data_type_ == MDL_T_NONE)
313           is_default = true;
314         else
315           is_default = false;
316         return match_me;
317       }
318     }
319
320   return NULL;
321 }
322
323 // Determine if the global and local constraints are applicable
324 // Global constraints that are applicable are put on flag_cons
325 // base_used returns the ONE replace constraint that matches
326
327 static bool check_constraints(vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
328                               T_dyninstRPC::mdl_constraint *&base_used,
329                               vector< vector<string> >& focus,
330                               vector<T_dyninstRPC::mdl_constraint*> *cons,
331                               vector<unsigned>& flag_dex, unsigned& base_dex) {
332   unsigned size = cons->size();
333
334   unsigned foc_size = focus.size();
335   for (unsigned fi=0; fi<foc_size; fi++) {
336     unsigned el_size = focus[fi].size();
337     if ((focus[fi][0] == "Machine") || (focus[fi][0] == "Process")) {
338       // do nothing, can't specify constraints for machine or process
339       ;
340     } else if (el_size) {
341       bool matched = false;
342       // Hack allow constraints such as "/SyncObject"
343       // However, these don't have to match
344       // Otherwise a failure to match means that the metric is invalid for the resource
345       unsigned ci=0;
346       while ((ci < size) && !matched) {
347         if (!(*cons)[ci]->match_path_) {
348           // this is an external constraint, apply if applicable
349           T_dyninstRPC::mdl_constraint *mc;
350           bool is_default;
351           if ((mc = flag_matches(focus[fi], (*cons)[ci], is_default))) {
352             matched = true;
353             if (!is_default) {
354               flag_cons += mc; flag_dex += fi;
355             }
356           }
357         } else {
358           // this could be the real constraint to use
359           // this guarantees that the first match is used
360           // TODO -- first matching replace constraint wins
361           if (focus_matches(focus[fi], (*cons)[ci]->match_path_)) {
362             matched = true;
363             base_used = (*cons)[ci]; base_dex = fi; 
364           }
365         }
366         ci++;
367       }
368       if (!matched && (el_size>1)) {
369         return false;
370       }
371     } else {
372       return false;
373     }
374   }
375   return true;
376 }
377
378 // update the interpreter environment for this processor
379 // Variable updated: $procedures, $modules, $exit, $start
380 static bool update_environment(process *proc) {
381
382   // for cases when libc is dynamically linked, the exit symbol is not
383   // correct
384   string vname = "$exit";
385   function_base *pdf = proc->findOneFunction(string(EXIT_NAME));
386    if (pdf) { 
387       mdl_env::add(vname, false, MDL_T_PROCEDURE);
388       mdl_env::set(pdf, vname);
389   }
390
391   vname = "$start";
392   pdf = proc->getMainFunction();
393   if (!pdf) return false;
394
395   vname = "$start";
396   mdl_env::add(vname, false, MDL_T_PROCEDURE);
397   mdl_env::set(pdf, vname);
398
399   vname = "$procedures";
400   mdl_env::add(vname, false, MDL_T_LIST_PROCEDURE);
401   // only get the functions that are not excluded by exclude_lib or 
402   // exclude_func
403   mdl_env::set(proc->getIncludedFunctions(), vname);
404
405   vname = "$modules";
406   mdl_env::add(vname, false, MDL_T_LIST_MODULE);
407   // only get functions that are not excluded by exclude_lib or exclude_func
408   mdl_env::set(proc->getIncludedModules(), vname);
409
410   //Blizzard
411
412     vname = "$gmin";
413     mdl_env::add(vname, false, MDL_T_INT);
414     mdl_env::set(theMemory->getGlobalMin(), vname);
415
416     vname = "$gmax";
417     mdl_env::add(vname, false, MDL_T_INT);
418     mdl_env::set(theMemory->getGlobalMax(), vname);
419
420     vname = "$cmin";
421     mdl_env::add(vname, false, MDL_T_INT);
422     mdl_env::set(theMemory->getCurrentMin(), vname);
423
424     vname = "$cmax";
425     mdl_env::add(vname, false, MDL_T_INT);
426     mdl_env::set(theMemory->getCurrentMax(), vname);
427   //
428
429   return true;
430 }
431
432 dataReqNode *create_data_object(unsigned mdl_data_type,
433                                 metricDefinitionNode *mn,
434                                 bool computingCost) {
435   switch (mdl_data_type) {
436   case MDL_T_COUNTER:
437     return (mn->addSampledIntCounter(0, computingCost));
438
439   case MDL_T_WALL_TIMER:
440     return (mn->addWallTimer(computingCost));
441
442   case MDL_T_PROC_TIMER:
443     return (mn->addProcessTimer(computingCost));
444
445   case MDL_T_NONE:
446     // just to keep mdl apply allocate a dummy un-sampled counter.
447 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
448     // "true" means that we are going to create a sampled int counter but
449     // we are *not* going to sample it, because it is just a temporary
450     // counter - naim 4/22/97
451     // By default, the last parameter is false - naim 4/23/97
452     return (mn->addSampledIntCounter(0, computingCost, true));
453 #else
454     return (mn->addUnSampledIntCounter(0, computingCost));
455 #endif
456
457   default:
458     assert(0);
459     return NULL;
460   }
461 }
462
463
464 metricDefinitionNode *
465 apply_to_process(process *proc, 
466                  string& id, string& name,
467                  vector< vector<string> >& focus,
468                  unsigned& agg_op,
469                  unsigned& type,
470                  vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
471                  T_dyninstRPC::mdl_constraint *base_use,
472                  vector<T_dyninstRPC::mdl_stmt*> *stmts,
473                  vector<unsigned>& flag_dex,
474                  unsigned& base_dex,
475                  vector<string> *temp_ctr,
476                  bool replace_component,
477                  bool computingCost) {
478
479     if (!update_environment(proc)) return NULL;
480
481     // compute the flat_name for this component: the machine and process
482     // are always defined for the component, even if they are not defined
483     // for the aggregate metric.
484     vector< vector<string> > component_focus(focus); // they start off equal
485
486     string component_flat_name(name);
487     for (unsigned u1 = 0; u1 < focus.size(); u1++) {
488       if (focus[u1][0] == "Process") {
489         component_flat_name += focus[u1][0] + proc->rid->part_name();
490         if (focus[u1].size() == 1) {
491            // there was no refinement to a specific process...but the component
492            // focus must have such a refinement.
493            component_focus[u1] += proc->rid->part_name();
494         }
495       }
496       else if (focus[u1][0] == "Machine") {
497         component_flat_name += focus[u1][0] + machineResource->part_name();
498         if (focus[u1].size() == 1) {
499            // there was no refinement to a specific machine...but the component focus
500            // must have such a refinement.
501            component_focus[u1] += machineResource->part_name();
502         }
503       }
504       else
505         for (unsigned u2 = 0; u2 < focus[u1].size(); u2++)
506           component_flat_name += focus[u1][u2];
507     }
508
509     // now assert that focus2flatname(component_focus) equals component_flat_name
510     extern string metricAndCanonFocus2FlatName(const string &met,
511                                                const vector< vector<string> > &focus);
512     assert(component_flat_name == metricAndCanonFocus2FlatName(name, component_focus));
513
514     metricDefinitionNode *existingMI;
515     const bool alreadyThere = allMIComponents.find(component_flat_name, existingMI);
516     if (alreadyThere) {
517        if (replace_component) {
518           // fry old entry...
519           metric_cerr << "apply_to_process: found " << component_flat_name
520                       << " but continuing anyway since replace_component flag set"
521                       << endl;
522           // note that we don't call 'delete'.
523           allMIComponents.undef(component_flat_name);
524        }
525        else {
526          metric_cerr << "mdl apply_to_process: found component for "
527                      << component_flat_name << "...reusing it" << endl;
528
529          return existingMI;
530        }
531     }
532     else
533        metric_cerr << "MDL: creating new component mi since flatname "
534                    << component_flat_name << " doesn't exist" << endl;
535
536     // If the component exists, then we've either already returned, or fried it.
537     assert(!allMIComponents.defines(component_flat_name));
538
539     // TODO -- Using aggOp value for this metric -- what about folds
540     metricDefinitionNode *mn = new metricDefinitionNode(proc, name, focus,
541                                                         component_focus,
542                                                         component_flat_name, agg_op);
543     assert(mn);
544
545     assert(!allMIComponents.defines(component_flat_name));
546     allMIComponents[component_flat_name] = mn;
547
548     // Create the timer, counter
549     dataReqNode *the_node = create_data_object(type, mn, computingCost);
550     assert(the_node);
551     mdl_env::set(the_node, id);
552
553     // Create the temporary counters - are these useful
554     if (temp_ctr) {
555       unsigned tc_size = temp_ctr->size();
556       for (unsigned tc=0; tc<tc_size; tc++) {
557 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
558         // "true" means that we are going to create a sampled int counter but
559         // we are *not* going to sample it, because it is just a temporary
560         // counter - naim 4/22/97
561         // By default, the last parameter is false - naim 4/23/97
562         dataReqNode *temp_node=mn->addSampledIntCounter(0,computingCost,true);
563 #else
564         dataReqNode *temp_node=mn->addUnSampledIntCounter(0,computingCost);
565 #endif
566         mdl_env::set(temp_node, (*temp_ctr)[tc]);
567       }
568     }
569
570     unsigned flag_size = flag_cons.size();
571     vector<dataReqNode*> flags;
572     if (flag_size) {
573       for (unsigned fs=0; fs<flag_size; fs++) {
574         // TODO -- cache these created flags
575         dataReqNode *flag = NULL;
576         if (! (flag_cons[fs]->apply(mn, flag, focus[flag_dex[fs]], proc, computingCost))) {
577           mn->cleanup_drn();
578           delete mn;
579           return NULL;
580         }
581         assert(flag);
582         flags += flag;
583         // cout << "Applying constraint for " << flag_cons[fs]->id_ << endl;
584       }
585     }
586
587     if (base_use) {
588       dataReqNode *flag = NULL;
589       if (!base_use->apply(mn, flag, focus[base_dex], proc, computingCost)) {
590         // cout << "apply of " << name << " failed\n";
591         mn->cleanup_drn();  
592         delete mn;
593         return NULL;
594       }
595     } else {
596       unsigned size = stmts->size();
597       for (unsigned u=0; u<size; u++) {
598         if (!(*stmts)[u]->apply(mn, flags)) { // virtual fn call depending on the statement type
599           // cout << "apply of " << name << " failed\n";
600           mn->cleanup_drn();  
601           delete mn;
602           return NULL;
603         }
604       }
605     }
606
607     if (!mn->nonNull()) {
608       mn->cleanup_drn();
609       delete mn;
610       return NULL;
611     }
612
613     return mn;
614 }
615
616 static bool apply_to_process_list(vector<process*>& instProcess,
617                                   vector<metricDefinitionNode*>& parts,
618                                   string& id, string& name,
619                                   vector< vector<string> >& focus,
620                                   unsigned& agg_op,
621                                   unsigned& type,
622                                   vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
623                                   T_dyninstRPC::mdl_constraint *base_use,
624                                   vector<T_dyninstRPC::mdl_stmt*> *stmts,
625                                   vector<unsigned>& flag_dex,
626                                   unsigned& base_dex,
627                                   vector<string> *temp_ctr,
628                                   bool replace_components_if_present,
629                                   bool computingCost) {
630 #ifdef DEBUG_MDL
631   timer loadTimer, totalTimer;
632   static ofstream *of=NULL;
633   if (!of) {
634     char buffer[100];
635     ostrstream osb(buffer, 100, ios::out);
636     osb << "mdl_" << "__" << getpid() << ends;
637     of = new ofstream(buffer, ios::app);
638   }
639
640   (*of) << "Instrumenting for " << name << " " << instProcess.size() << " processes\n";
641 #endif
642
643   unsigned psize = instProcess.size();
644 #ifdef DEBUG_MDL
645   totalTimer.clear(); totalTimer.start();
646 #endif
647   for (unsigned p=0; p<psize; p++) {
648 #ifdef DEBUG_MDL
649     loadTimer.clear(); loadTimer.start();  // TIMER
650 #endif
651     process *proc = instProcess[p]; assert(proc);
652     global_proc = proc;     // TODO -- global
653
654     // skip neonatal and exited processes.
655     if (proc->status() == exited || proc->status() == neonatal) continue;
656
657     metricDefinitionNode *comp = apply_to_process(proc, id, name, focus, 
658                                                  agg_op, type,
659                                                  flag_cons, base_use, stmts, 
660                                                  flag_dex,
661                                                  base_dex, temp_ctr,
662                                                  replace_components_if_present,
663                                                  computingCost);
664     if (comp)
665       // we have another component (i.e. process-specific) mi
666       parts += comp;
667
668 #ifdef DEBUG_MDL
669     loadTimer.stop();
670     char timeMsg[500];
671     sprintf(timeMsg, "%f::%f  ", (float) loadTimer.usecs(), (float) loadTimer.wsecs());
672     // tp->applicationIO(10, strlen(timeMsg), timeMsg);
673     (*of) << name << ":" << timeMsg << endl;
674 #endif
675
676   }
677 #ifdef DEBUG_MDL
678   totalTimer.stop();
679   char timeMsg[500];
680   sprintf(timeMsg, "\nTotal:  %f:user\t%f:wall\n", (float) totalTimer.usecs(),
681           (float) totalTimer.wsecs());
682   // tp->applicationIO(10, strlen(timeMsg), timeMsg);
683   (*of) << name << ":" << timeMsg << endl;
684 #endif
685
686   if (parts.size() == 0)
687     // no components!
688     return false;
689
690   return true;
691 }
692
693 metricDefinitionNode *T_dyninstRPC::mdl_metric::apply(vector< vector<string> > &focus,
694                                                       string& flat_name,
695                                                       vector<process *> procs,
696                                                       bool replace_components_if_present,
697                                                       bool computingCost) {
698   // TODO -- check to see if this is active ?
699   // TODO -- create counter or timer
700   // TODO -- put it into the environment ?
701   // TODO -- this can be passed directly -- faster - later
702   // TODO -- internal metrics
703   // TODO -- assume no constraints, all processes instrumented
704   // TODO -- support two-level aggregation: one at the daemon, one at paradyn
705   // TODO -- how is folding specified ?
706   // TODO -- are lists updated here ?
707
708   mdl_env::push();
709   mdl_env::add(id_, false, MDL_T_DRN);
710   assert(stmts_);
711
712   const unsigned tc_size = temp_ctr_->size();
713   for (unsigned tc=0; tc<tc_size; tc++) {
714     mdl_env::add((*temp_ctr_)[tc], false, MDL_T_DRN);
715   }
716
717   static string machine;
718   static bool machine_init= false;
719   if (!machine_init) {
720     machine_init = true;
721     machine = getHostName();
722   }
723
724   // TODO -- I am assuming that a canonical resource list is
725   // machine, procedure, process, syncobject
726
727   if (other_machine_specified(focus, machine)) return NULL;
728   vector<process*> instProcess;
729   add_processes(focus, procs, instProcess);
730
731   if (!instProcess.size()) return NULL;
732
733   // build the list of constraints to use
734   vector<T_dyninstRPC::mdl_constraint*> flag_cons;
735
736   // the first replace constraint that matches, if any
737   T_dyninstRPC::mdl_constraint *base_used=NULL;
738
739   // build list of global constraints that match and choose local replace constraint
740   unsigned base_dex; vector<unsigned> flag_dex;
741   if (!check_constraints(flag_cons, base_used, focus, constraints_, flag_dex, base_dex))
742     return NULL;
743
744   // build the instrumentation request
745   vector<metricDefinitionNode*> parts; // one per process
746   if (!apply_to_process_list(instProcess, parts, id_, name_, focus,
747                              agg_op_, type_, flag_cons, base_used,
748                              stmts_, flag_dex, base_dex, temp_ctr_,
749                              replace_components_if_present,
750                              computingCost))
751     return NULL;
752
753   // construct aggregate for the metric instance parts
754   metricDefinitionNode *ret = NULL;
755
756   if (parts.size())
757     // create aggregate mi, containing the process components "parts"
758     ret = new metricDefinitionNode(name_, focus, flat_name, parts, agg_op_);
759
760   // cout << "apply of " << name_ << " ok\n";
761   mdl_env::pop();
762   return ret;
763 }
764
765 T_dyninstRPC::mdl_constraint::mdl_constraint() { }
766 T_dyninstRPC::mdl_constraint::mdl_constraint(string id, vector<string> *match_path,
767                                              vector<T_dyninstRPC::mdl_stmt*> *stmts,
768                                              bool replace, u_int d_type, bool& error)
769 : id_(id), match_path_(match_path), stmts_(stmts), replace_(replace),
770   data_type_(d_type), hierarchy_(0), type_(0) { error = false; }
771 T_dyninstRPC::mdl_constraint::~mdl_constraint() {
772   delete match_path_;
773   if (stmts_) {
774     for (unsigned u=0; u<stmts_->size(); u++)
775       delete (*stmts_)[u];
776     delete stmts_;
777   }
778 }
779
780
781 static bool do_trailing_resources(vector<string>& resource_,
782                                   process *proc)
783 {
784   vector<string>  resPath;
785
786   for(int pLen = 0; pLen < resource_.size(); pLen++) {
787     string   caStr = string("$constraint") + 
788                      string(resource_.size()-pLen-1);
789     string   trailingRes = resource_[pLen];
790
791     resPath += resource_[pLen];
792     assert(resPath.size() == (pLen+1));
793
794     resource *r = resource::findResource(resPath);
795     if (!r) assert(0);
796
797     switch (r->type()) {
798     case MDL_T_INT: {
799       const char* p = trailingRes.string_of();
800       char*       q;
801       int         val = (int) strtol(p, &q, 0);
802       if (p == q) {
803         string msg = string("unable to convert resource '") + trailingRes + 
804                      string("' to integer.");
805         showErrorCallback(92,msg.string_of());
806         return(false);
807       }
808       mdl_env::add(caStr, false, MDL_T_INT);
809       mdl_env::set(val, caStr);
810       break;
811     }
812     case MDL_T_STRING:
813       mdl_env::add(caStr, false, MDL_T_STRING);
814       mdl_env::set(trailingRes, caStr);
815       break;
816     case MDL_T_PROCEDURE: {
817       // find the resource corresponding to this function's module 
818       vector<string> m_vec;
819       for(u_int i=0; i < resPath.size()-1; i++){
820         m_vec += resPath[i];
821       }
822       assert(m_vec.size());
823       assert(m_vec.size() == (resPath.size()-1));
824       resource *m_resource = resource::findResource(m_vec);
825       if(!m_resource) return(false);
826       
827       function_base *pdf = proc->findOneFunction(r,m_resource);
828       if (!pdf) return(false);
829       mdl_env::add(caStr, false, MDL_T_PROCEDURE);
830       mdl_env::set(pdf, caStr);
831       break;
832     }
833     case MDL_T_MODULE: {
834       module *mod = proc->findModule(trailingRes,true);
835       if (!mod) return(false);
836       mdl_env::add(caStr, false, MDL_T_MODULE);
837       mdl_env::set(mod, caStr);
838       break;
839     }
840     case MDL_T_MEMORY:
841       break ;
842     case MDL_T_VARIABLE: {
843         //bounds is defined in metric.h
844         memory::bounds b = theMemory->getVariableBounds(trailingRes) ;
845         mdl_env::add(caStr, false, MDL_T_VARIABLE) ;
846         mdl_env::set(b, caStr) ;
847     }
848     break ;
849     default:
850       assert(0);
851       break;
852     }
853   }
854   return(true);
855 }
856
857
858 // Replace constraints not working yet
859 // Flag constraints need to return a handle to a data request node -- the flag
860 bool T_dyninstRPC::mdl_constraint::apply(metricDefinitionNode *mn,
861                                          dataReqNode *&flag,
862                                          vector<string>& resource,
863                                          process *proc, bool computingCost) {
864   assert(mn);
865   switch (data_type_) {
866   case MDL_T_COUNTER:
867   case MDL_T_WALL_TIMER:
868   case MDL_T_PROC_TIMER:
869     break;
870   default:
871     assert(0);
872   }
873   mdl_env::push();
874
875   if (!replace_) {
876     // create the counter used as a flag
877     mdl_env::add(id_, false, MDL_T_DRN);
878 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
879     // "true" means that we are going to create a sampled int counter but
880     // we are *not* going to sample it, because it is just a temporary
881     // counter - naim 4/22/97
882     // By default, the last parameter is false - naim 4/23/97
883     dataReqNode *drn = mn->addSampledIntCounter(0,computingCost,true);
884 #else
885     dataReqNode *drn = mn->addUnSampledIntCounter(0,computingCost);
886 #endif
887     // this flag will construct a predicate for the metric -- have to return it
888     flag = drn;
889     assert(drn);
890     mdl_env::set(drn, id_);
891   }
892
893   // put $constraint[X] in the environment
894   if(!do_trailing_resources(resource, proc)) {
895     mdl_env::pop();
896     return(false);
897   }
898
899   // Now evaluate the constraint statements
900   unsigned size = stmts_->size();
901   vector<dataReqNode*> flags;
902   for (unsigned u=0; u<size; u++) {
903     if (!(*stmts_)[u]->apply(mn, flags)) {
904       // cout << "apply of constraint " << id_ << " failed\n";
905       return(false);
906     }
907   }
908   mdl_env::pop();
909   return(true);
910 }
911
912 T_dyninstRPC::mdl_constraint *mdl_data::new_constraint(string id, vector<string> *path,
913                                                 vector<T_dyninstRPC::mdl_stmt*> *stmts,
914                                                 bool replace, u_int d_type) {
915   bool error;
916   return (new T_dyninstRPC::mdl_constraint(id, path, stmts, replace, d_type, error));
917 }
918
919
920 T_dyninstRPC::mdl_rand::mdl_rand() {}
921
922 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand() {}
923
924 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type): type_(type) {}
925
926 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type, u_int val)
927 : type_(type), val_(val) {}
928
929 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type, string name)
930 : type_(type), name_(name) {}
931
932 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type, string name, vector<mdl_instr_rand *>args)
933 : type_(type), name_(name) {
934   for (unsigned u = 0; u < args.size(); u++)
935     args_ += args[u];
936 }
937
938 T_dyninstRPC::mdl_instr_rand::~mdl_instr_rand() { } 
939
940 bool T_dyninstRPC::mdl_instr_rand::apply(AstNode *&ast) {
941   function_base *pdf;
942   mdl_var get_drn;
943
944   switch (type_) {
945   case MDL_T_RECORD://TO DO
946        {
947            int value ;
948            mdl_var get_record ;
949            mdl_env::get(get_record, string("$constraint0")) ;
950            unsigned type = mdl_env::get_type(string("$constraint0")) ;
951            switch(type)
952            {
953             case MDL_T_VARIABLE:
954                 memory::bounds b ;
955                 if (!get_record.get(b))
956                 {
957                     return false;
958                 }else
959                 {
960                     if(!strncmp(name_.string_of(), "upper", 5))
961                         value = (int)b.upper ;
962                     else
963                         value = (int)b.lower;
964                     ast = new AstNode(AstNode::Constant, (void*) value);
965                 }
966                 break ;
967            }// switch
968        }
969        break ;
970
971   
972   case MDL_T_INT:
973     if (name_.length()) {
974       // variable in the expression.
975       mdl_var get_int;
976       int value;
977       bool aflag;
978       aflag=mdl_env::get(get_int, name_);
979       assert(aflag);
980       if (!get_int.get(value)) {
981           fprintf(stderr, "Unable to get value for %s\n", name_.string_of());
982           fflush(stderr);
983           return false;
984       } else {
985           ast = new AstNode(AstNode::Constant, (void*) value);
986       }
987     } else {
988       ast = new AstNode(AstNode::Constant, (void*) val_);
989     }
990     break;
991   case MDL_ARG:
992     ast = new AstNode(AstNode::Param, (void*) val_);
993     break;
994   case MDL_RETURN:
995     ast = new AstNode(AstNode::ReturnVal, (void*)0);
996     break;
997   case MDL_READ_SYMBOL:
998     // TODO -- I am relying on global_proc to be set in mdl_metric::apply
999     if (global_proc) {
1000       Symbol info;
1001       Address baseAddr;
1002       if (global_proc->getSymbolInfo(name_, info, baseAddr)) {
1003         Address adr = info.addr();
1004         ast = new AstNode(AstNode::DataAddr, (void*) adr);
1005       } else {
1006         string msg = string("In metric '") + currentMetric + string("': ") +
1007           string("unable to find symbol '") + name_ + string("'");
1008         showErrorCallback(95, msg);
1009         return false;
1010       }
1011     }
1012     break;
1013   case MDL_READ_ADDRESS:
1014     // TODO -- check on the range of this address!
1015     ast = new AstNode(AstNode::DataAddr, (void*) val_);
1016     break;
1017   case MDL_CALL_FUNC: {
1018     // don't confuse 'args' with 'args_' here!
1019     vector<AstNode *> args;
1020     for (unsigned u = 0; u < args_.size(); u++) {
1021       AstNode *arg=NULL;
1022       if (!args_[u]->apply(arg)) { 
1023         // fills in 'arg'
1024         removeAst(arg);
1025         return false;
1026       }
1027       args += assignAst(arg);
1028       removeAst(arg);
1029     }
1030     string temp = string(name_);
1031     pdf = global_proc->findOneFunctionFromAll(temp);
1032     if (!pdf) {
1033         string msg = string("In metric '") + currentMetric + string("': ") +
1034           string("unable to find procedure '") + name_ + string("'");
1035         showErrorCallback(95, msg);
1036         return false;
1037     }
1038     ast = new AstNode(name_, args); //Cannot use simple assignment here!
1039     for (unsigned i=0;i<args.size();i++) removeAst(args[i]);
1040     break;
1041   }
1042   case MDL_T_COUNTER_PTR:
1043     { mdl_var get_drn;
1044       dataReqNode *drn;
1045       if (!mdl_env::get(get_drn, name_)) {
1046         string msg = string("In metric '") + currentMetric + string("' : ") +
1047           string("undefined variable '") + name_ + string("'");
1048         showErrorCallback(92, msg);
1049         return false;
1050       }
1051       bool aflag;
1052       aflag=get_drn.get(drn);
1053       assert(aflag);
1054 #if defined(SHM_SAMPLING)
1055   #if defined(MT_THREAD)
1056       ast = computeAddress((void *)(drn->getAllocatedLevel()),
1057                            (void *)(drn->getAllocatedIndex()),
1058                            0); // 0 is for intCounter
1059   #else
1060       ast = new AstNode(AstNode::DataPtr, (void *)(drn->getInferiorPtr(global_proc)));
1061   #endif
1062 #else
1063       ast = new AstNode(AstNode::DataPtr, (void *)(drn->getInferiorPtr()));
1064 #endif
1065     }
1066     break;
1067   case MDL_T_COUNTER:
1068     {
1069       mdl_var get_drn;
1070       dataReqNode *drn;
1071       bool aflag;
1072       aflag=mdl_env::get(get_drn, name_);
1073       assert(aflag);
1074       //
1075       // This code was added to support additional mdl evaluation time 
1076       //     variables.  To keep it simple, I left the parser alone and so
1077       //     any unknown identifier maps to MDL_T_COUNTER.  We lookup the
1078       //     variable's type here to generate the correct code.  MDL
1079       //     really should have a general type system and all functions
1080       //     signatures. - jkh 7/5/95
1081       //
1082       switch (get_drn.type()) {
1083           case MDL_T_INT:
1084               int value;
1085               if (!get_drn.get(value)) {
1086                   fprintf(stderr, "Unable to get value for %s\n", 
1087                       name_.string_of());
1088                   fflush(stderr);
1089                   return false;
1090               } else {
1091                   ast = new AstNode(AstNode::Constant, (void*) value);
1092               }
1093               break;
1094           case MDL_T_COUNTER:   // is MDL_T_COUNTER used here ??? jkh 7/31/95
1095           case MDL_T_DRN:
1096               if (!get_drn.get(drn)) {
1097                   fprintf(stderr, "Unable to find variable %s\n", 
1098                       name_.string_of());
1099                   fflush(stderr);
1100                   return false;
1101               } else {
1102 #if defined(SHM_SAMPLING)
1103   #if defined(MT_THREAD)
1104                   AstNode *tmp_ast;
1105                   tmp_ast = computeAddress((void *)(drn->getAllocatedLevel()),
1106                                            (void *)(drn->getAllocatedIndex()),
1107                                            0); // 0 is for intCounter
1108                   // First we get the address, and now we get the value...
1109                   ast = new AstNode(AstNode::DataIndir,tmp_ast); 
1110                   removeAst(tmp_ast);
1111   #else
1112                   ast = new AstNode(AstNode::DataValue, 
1113                                     (void*)(drn->getInferiorPtr(global_proc)));
1114   #endif
1115 #else
1116                   // Note: getInferiorPtr could return a NULL pointer here if
1117                   // we are just computing cost - naim 2/18/97
1118                   ast = new AstNode(AstNode::DataValue, 
1119                                     (void*)(drn->getInferiorPtr()));
1120 #endif
1121               }
1122               break;
1123           default:
1124               fprintf(stderr, "type of variable %s is not known\n",
1125                   name_.string_of());
1126               fflush(stderr);
1127               return false;
1128       }
1129     }
1130     break;
1131   default:
1132     break;
1133   }
1134   return true;
1135 }
1136
1137
1138
1139 T_dyninstRPC::mdl_instr_req::mdl_instr_req(T_dyninstRPC::mdl_instr_rand *rand,
1140                                            u_int type, string obj_name)
1141 : type_(type), rand_(rand), timer_counter_name_(obj_name) { }
1142
1143 T_dyninstRPC::mdl_instr_req::mdl_instr_req(u_int type, string obj_name)
1144 : type_(type), timer_counter_name_(obj_name) { }
1145
1146 T_dyninstRPC::mdl_instr_req::mdl_instr_req(u_int type,
1147                                            T_dyninstRPC::mdl_instr_rand *rand)
1148 : type_(type), rand_(rand) { }
1149
1150 T_dyninstRPC::mdl_instr_req::mdl_instr_req() : type_(0) { }
1151 T_dyninstRPC::mdl_instr_req::~mdl_instr_req() { }
1152
1153 bool T_dyninstRPC::mdl_instr_req::apply(AstNode *&mn, AstNode *pred,
1154                                         bool mn_initialized) {
1155   // a return value of true implies that "mn" was written to
1156   AstNode *ast_arg=NULL;
1157
1158   vector<AstNode *> ast_args;
1159   string timer_fun;
1160
1161   switch (type_) {
1162   case MDL_SET_COUNTER:
1163   case MDL_ADD_COUNTER:
1164   case MDL_SUB_COUNTER:
1165     if (! rand_->apply(ast_arg))
1166       return false;
1167     break;
1168   case MDL_START_WALL_TIMER:
1169     timer_fun = START_WALL_TIMER;
1170     break;
1171   case MDL_STOP_WALL_TIMER:
1172     timer_fun = STOP_WALL_TIMER;
1173     break;
1174   case MDL_START_PROC_TIMER:
1175     timer_fun = START_PROC_TIMER;
1176     break;
1177   case MDL_STOP_PROC_TIMER:
1178     timer_fun = STOP_PROC_TIMER;
1179     break;
1180   }
1181
1182   dataReqNode *drn;
1183   mdl_var get_drn;
1184   if (type_ != MDL_CALL_FUNC) {
1185       bool aflag;
1186       aflag=mdl_env::get(get_drn, timer_counter_name_);
1187       assert(aflag);
1188       aflag=get_drn.get(drn);
1189       assert(aflag);
1190   }
1191
1192   AstNode *code=NULL;
1193
1194   switch (type_) {
1195   case MDL_SET_COUNTER:
1196 #if defined(SHM_SAMPLING)
1197   #if defined(MT_THREAD)
1198     code = createCounter("setCounter", (void *)(drn->getAllocatedLevel()), 
1199                          (void *)(drn->getAllocatedIndex()),ast_arg);
1200   #else
1201     code = createCounter("setCounter", (void *)(drn->getInferiorPtr(global_proc)), ast_arg);
1202   #endif
1203 #else
1204     code = createCounter("setCounter", (void *)(drn->getInferiorPtr()), ast_arg);
1205 #endif
1206     break;
1207   case MDL_ADD_COUNTER:
1208 #if defined(SHM_SAMPLING)
1209   #if defined(MT_THREAD)
1210     code = createCounter("addCounter", (void *)(drn->getAllocatedLevel()), 
1211                          (void *)(drn->getAllocatedIndex()), ast_arg);
1212   #else
1213     code = createCounter("addCounter", (void *)(drn->getInferiorPtr(global_proc)), ast_arg);
1214   #endif
1215 #else
1216     code = createCounter("addCounter", (void *)(drn->getInferiorPtr()), ast_arg);
1217 #endif
1218     break;
1219   case MDL_SUB_COUNTER:
1220 #if defined(SHM_SAMPLING)
1221   #if defined(MT_THREAD)
1222     code = createCounter("subCounter", (void *)(drn->getAllocatedLevel()), 
1223                          (void *)(drn->getAllocatedIndex()), ast_arg);
1224   #else
1225     code = createCounter("subCounter", (void *)(drn->getInferiorPtr(global_proc)), ast_arg);
1226   #endif
1227 #else
1228     code = createCounter("subCounter", (void *)(drn->getInferiorPtr()), ast_arg);
1229 #endif
1230     break;
1231   case MDL_START_WALL_TIMER:
1232   case MDL_STOP_WALL_TIMER:
1233   case MDL_START_PROC_TIMER:
1234   case MDL_STOP_PROC_TIMER:
1235 #if defined(SHM_SAMPLING)
1236   #if defined(MT_THREAD)
1237     code = createTimer(timer_fun, (void *)(drn->getAllocatedLevel()), 
1238                        (void *)(drn->getAllocatedIndex()), ast_args);
1239   #else
1240     code = createTimer(timer_fun, (void *)(drn->getInferiorPtr(global_proc)), ast_args);
1241   #endif
1242 #else
1243     code = createTimer(timer_fun, (void *)(drn->getInferiorPtr()), ast_args);
1244 #endif
1245     break;
1246   case MDL_CALL_FUNC:
1247     if (! rand_->apply(code))
1248       return false;
1249     break;
1250   default:
1251     return false;
1252   }
1253   if (pred) {
1254     // Note: we don't use assignAst on purpose here
1255     AstNode *tmp=code;
1256     code = createIf(pred, tmp);
1257     removeAst(tmp);
1258   }
1259
1260   if (mn_initialized) {
1261     // Note: we don't use assignAst on purpose here
1262     AstNode *tmp=mn;
1263     mn = new AstNode(tmp, code);
1264     removeAst(tmp);
1265   } else {
1266     mn = assignAst(code);
1267   }
1268
1269   removeAst(ast_arg);
1270   removeAst(code);
1271   return true;
1272 }
1273
1274 T_dyninstRPC::mdl_stmt::mdl_stmt() { }
1275
1276 T_dyninstRPC::mdl_for_stmt::mdl_for_stmt(string index_name, T_dyninstRPC::mdl_expr *list_exp, T_dyninstRPC::mdl_stmt *body) 
1277 : for_body_(body), index_name_(index_name), list_expr_(list_exp) { }
1278 T_dyninstRPC::mdl_for_stmt::mdl_for_stmt() { }
1279 T_dyninstRPC::mdl_for_stmt::~mdl_for_stmt() {
1280   delete for_body_;
1281   delete list_expr_;
1282 }
1283
1284 bool T_dyninstRPC::mdl_for_stmt::apply(metricDefinitionNode *mn,
1285                                        vector<dataReqNode*>& flags) {
1286   mdl_env::push();
1287   mdl_env::add(index_name_, false);
1288   mdl_var list_var(false);
1289
1290   // TODO -- build iterator closure here -- list may be vector or dictionary
1291   if (!list_expr_->apply(list_var))
1292     return false;
1293   if (!list_var.is_list())
1294     return false;
1295
1296   // TODO
1297   //  vector<function_base*> *vp;
1298   //  list_var.get(vp);
1299   list_closure closure(index_name_, list_var);
1300
1301   // mdl_env::set_type(list_var.element_type(), index_name_);
1302   while (closure.next()) {
1303     if (!for_body_->apply(mn, flags)) return false;
1304   }
1305
1306   mdl_env::pop();
1307   return true;
1308 }
1309
1310 T_dyninstRPC::mdl_icode::mdl_icode() { }
1311 T_dyninstRPC::mdl_icode::mdl_icode(T_dyninstRPC::mdl_instr_rand *iop1,
1312                                    T_dyninstRPC::mdl_instr_rand *iop2,
1313                                    u_int bin_op, bool use_if,
1314                                    T_dyninstRPC::mdl_instr_req *ireq)
1315 : if_op1_(iop1), if_op2_(iop2),
1316   bin_op_(bin_op), use_if_(use_if), req_(ireq) { }
1317 T_dyninstRPC::mdl_icode::~mdl_icode() { delete req_; }
1318
1319 static AstNode *do_rel_op(opCode op, T_dyninstRPC::mdl_instr_rand *if_op2,
1320                           AstNode *ast_left) {
1321    // NOTE: ast_left _must_ be defined
1322    AstNode *ast_right=NULL;
1323    AstNode *tmp=NULL;
1324    if (!if_op2->apply(ast_right)) {
1325       removeAst(ast_right);
1326       return(new AstNode());
1327    }
1328    tmp = new AstNode(op, ast_left, ast_right);
1329    removeAst(ast_right);
1330    return(tmp);;
1331 }
1332
1333 bool T_dyninstRPC::mdl_icode::apply(AstNode *&mn, bool mn_initialized) {
1334   // a return value of true implies that "mn" has been written to
1335   // TODO -- handle the if case here
1336   // TODO -- call req_->apply() after building if
1337
1338   if (!req_)
1339      return false;
1340
1341   AstNode *pred=NULL;
1342   AstNode *pred_ptr=NULL;
1343
1344   if (use_if_) {
1345     AstNode *ast1=NULL;
1346     if (!if_op1_->apply(ast1))
1347        return false;
1348     switch (bin_op_) {
1349     case MDL_LT:
1350       pred = do_rel_op(lessOp, if_op2_, ast1);
1351       break;
1352     case MDL_GT:
1353       pred = do_rel_op(greaterOp, if_op2_, ast1);
1354       break;
1355     case MDL_LE:
1356       pred = do_rel_op(leOp, if_op2_, ast1);
1357       break;
1358     case MDL_GE:
1359       pred = do_rel_op(geOp, if_op2_, ast1);
1360       break;
1361     case MDL_EQ:
1362       pred = do_rel_op(eqOp, if_op2_, ast1);
1363       break;
1364     case MDL_NE:
1365       pred = do_rel_op(neOp, if_op2_, ast1);
1366       break;
1367     case MDL_T_NONE:
1368       pred = new AstNode(ast1);
1369       break;
1370     default: return false;
1371     }
1372     removeAst(ast1);
1373     pred_ptr = new AstNode(pred);
1374   } // if ()
1375   else
1376     pred_ptr = NULL;
1377
1378   bool result = req_->apply(mn, pred_ptr, mn_initialized);
1379      // note: a result of true implies that "mn" was written to
1380      // Hence, a result of true from this routine means the same.
1381
1382   removeAst(pred);
1383   removeAst(pred_ptr);
1384   return result;
1385 }
1386
1387 T_dyninstRPC::mdl_expr::mdl_expr() { }
1388 T_dyninstRPC::mdl_expr::~mdl_expr() { }
1389
1390 T_dyninstRPC::mdl_v_expr::mdl_v_expr() 
1391 : args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL), type_(MDL_T_NONE),
1392   do_type_walk_(false), ok_(false) { }
1393
1394 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string var, vector<string> fields) 
1395 : var_(var), fields_(fields),
1396   args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL),
1397   type_(MDL_RVAL_DEREF), do_type_walk_(false), ok_(false) { assert(0); }
1398
1399 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string func_name,
1400                                      vector<T_dyninstRPC::mdl_expr *> *a) 
1401 : var_(func_name), args_(a),
1402   literal_(0), arg_(100000), left_(NULL), right_(NULL),
1403   type_(MDL_RVAL_FUNC), do_type_walk_(false), ok_(false) { assert(0); }
1404
1405 T_dyninstRPC::mdl_v_expr::mdl_v_expr(int int_lit) 
1406 : args_(NULL), literal_(int_lit), arg_(0), left_(NULL), right_(NULL),
1407   type_(MDL_RVAL_INT), do_type_walk_(false), ok_(false) { assert(0); }
1408
1409 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string string_lit) 
1410 : var_(string_lit),
1411   args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL),
1412   type_(MDL_RVAL_STRING), do_type_walk_(false), ok_(false) { assert(0); }
1413
1414 T_dyninstRPC::mdl_v_expr::mdl_v_expr(u_int bin_op, T_dyninstRPC::mdl_expr *left,
1415                                  T_dyninstRPC::mdl_expr *right) 
1416 : args_(NULL), literal_(0),
1417   arg_(bin_op), left_(left), right_(right),
1418   type_(MDL_RVAL_EXPR), do_type_walk_(false), ok_(false) { assert(0); }
1419
1420 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string var, u_int array_index) 
1421 : var_(var), args_(NULL), literal_(0), arg_(array_index), left_(NULL), right_(NULL),
1422   type_(MDL_RVAL_ARRAY), do_type_walk_(false), ok_(false) { assert(0); }
1423
1424 T_dyninstRPC::mdl_v_expr::~mdl_v_expr() {
1425   delete args_; delete left_; delete right_;
1426   if (args_) {
1427     unsigned size = args_->size();
1428     for (unsigned u=0; u<size; u++)
1429       delete (*args_)[u];
1430     delete args_;
1431   }
1432 }
1433
1434 bool T_dyninstRPC::mdl_v_expr::apply(mdl_var& ret) {
1435   switch (type_) {
1436   case MDL_RVAL_INT: 
1437     return (ret.set(literal_));
1438   case MDL_RVAL_STRING:
1439     return (ret.set(var_));
1440   case MDL_RVAL_ARRAY:
1441     {
1442       mdl_var array(false);
1443       if (!mdl_env::get(array, var_)) return false;
1444       if (!array.is_list()) return false;  
1445       if (arg_ >= array.list_size()) return false;
1446       return (array.get_ith_element(ret, arg_));
1447     }
1448   case MDL_RVAL_EXPR:
1449     {
1450       mdl_var left_val(false), right_val(false);
1451       if (!left_ || !right_) return false;
1452       if (!left_->apply(left_val)) return false;
1453       if (!right_->apply(right_val)) return false;
1454       return (do_operation(ret, left_val, right_val, arg_));
1455     }
1456   case MDL_RVAL_FUNC:
1457     // TODO
1458     switch (arg_) {
1459     case 0:
1460       // lookupFunction
1461       {
1462         mdl_var arg0(false);
1463         if (!(*args_)[0]->apply(arg0)) return false;
1464         string func_name;
1465         if (!arg0.get(func_name)) return false;
1466         if (global_proc) {
1467           // TODO -- what if the function is not found ?
1468           function_base *pdf = global_proc->findOneFunction(func_name);
1469           return (ret.set(pdf));
1470         } else {
1471           assert(0); return false;
1472         }
1473       }
1474     case 1:
1475       // lookupModule
1476       {
1477         mdl_var arg0(false);
1478         if (!(*args_)[0]->apply(arg0)) return false;
1479         string mod_name;
1480         if (!arg0.get(mod_name)) return false;
1481         if (global_proc) {
1482           // TODO -- what if the function is not found ?
1483           module *mod = global_proc->findModule(mod_name,false);
1484           if (!mod) { assert(0); return false; }
1485           return (ret.set(mod));
1486         } else {
1487           assert(0); return false;
1488         }
1489       }
1490     case 2:
1491       // libraryTag
1492       {
1493         mdl_var arg0(false);
1494         if (!(*args_)[0]->apply(arg0)) return false;
1495         int tag;
1496         if (!arg0.get(tag)) return false;
1497         int res = tag & TAG_LIB_FUNC;
1498         return (ret.set(res));
1499       }
1500     default:
1501       return false;
1502     }
1503   case MDL_RVAL_DEREF:
1504     if (!do_type_walk_)
1505       return (mdl_env::get(ret, var_));
1506     else
1507       return (walk_deref(ret, type_walk, var_)); 
1508   default:
1509     return false;
1510   }
1511   return true;
1512 }
1513
1514 T_dyninstRPC::mdl_if_stmt::mdl_if_stmt(T_dyninstRPC::mdl_expr *expr, T_dyninstRPC::mdl_stmt *body) : expr_(expr), body_(body) { }
1515 T_dyninstRPC::mdl_if_stmt::mdl_if_stmt() { }
1516 T_dyninstRPC::mdl_if_stmt::~mdl_if_stmt() {
1517   delete expr_; delete body_;
1518 }
1519
1520 bool T_dyninstRPC::mdl_if_stmt::apply(metricDefinitionNode *mn,
1521                                       vector<dataReqNode*>& flags) {
1522   // An if stmt is comprised of (1) the 'if' expr and (2) the body to
1523   // execute if true.
1524   mdl_var res(false);
1525   if (!expr_->apply(res))
1526     return false;
1527
1528   int iv;
1529   switch (res.type()) {
1530   case MDL_T_INT:
1531     if (!res.get(iv))
1532       return false;
1533     if (!iv)
1534       return true;
1535     break;
1536   default:
1537     return false;
1538   }
1539
1540   return body_->apply(mn, flags);
1541 }
1542
1543 T_dyninstRPC::mdl_seq_stmt::mdl_seq_stmt(vector<T_dyninstRPC::mdl_stmt*> *stmts) : stmts_(stmts) { }
1544 T_dyninstRPC::mdl_seq_stmt::mdl_seq_stmt() { }
1545 T_dyninstRPC::mdl_seq_stmt::~mdl_seq_stmt() {
1546   if (stmts_) {
1547     unsigned size = stmts_->size();
1548     for (unsigned u=0; u<size; u++)
1549       delete (*stmts_)[u];
1550     delete stmts_;
1551   }
1552 }
1553
1554 bool T_dyninstRPC::mdl_seq_stmt::apply(metricDefinitionNode *mn,
1555                                        vector<dataReqNode*>& flags) {
1556   // a seq_stmt is simply a sequence of statements; apply them all.
1557   if (!stmts_)
1558     return true;
1559
1560   unsigned size = stmts_->size();
1561   for (unsigned index=0; index<size; index++)
1562     if (!(*stmts_)[index]->apply(mn, flags)) // virtual fn call
1563       return false;
1564
1565   return true;
1566 }
1567
1568 T_dyninstRPC::mdl_list_stmt::mdl_list_stmt(u_int type, string ident,
1569                                            vector<string> *elems,
1570                                            bool is_lib, vector<string>* flavor) 
1571 : type_(type), id_(ident), elements_(elems), is_lib_(is_lib), flavor_(flavor) { }
1572 T_dyninstRPC::mdl_list_stmt::mdl_list_stmt() { }
1573 T_dyninstRPC::mdl_list_stmt::~mdl_list_stmt() { delete elements_; }
1574
1575 bool T_dyninstRPC::mdl_list_stmt::apply(metricDefinitionNode * /*mn*/,
1576                                         vector<dataReqNode*>& /*flags*/) {
1577   bool found = false;
1578   for (unsigned u0 = 0; u0 < flavor_->size(); u0++) {
1579     if ((*flavor_)[u0] == daemon_flavor) {
1580       found = true;
1581       break;
1582     }
1583   }
1584   if (!found) return false;
1585   if (!elements_) return false;
1586   mdl_var expr_var;
1587   mdl_var list_var(id_, false);
1588   unsigned size = elements_->size();
1589   if (!list_var.make_list(type_)) return false;
1590
1591   if (type_ == MDL_T_PROCEDURE_NAME) {
1592     vector<functionName*> *list_fn;
1593     bool aflag;
1594     aflag=list_var.get(list_fn);
1595     assert(aflag);
1596     for (unsigned u=0; u<size; u++) {
1597       functionName *fn = new functionName((*elements_)[u]);
1598       *list_fn += fn;
1599     }
1600   } else if (type_ == MDL_T_PROCEDURE) { 
1601     assert(0);
1602   } else if (type_ == MDL_T_MODULE) {
1603     assert(0);
1604   } else {
1605     for (unsigned u=0; u<size; u++) {
1606       int i; float f; string s; mdl_var expr_var;
1607       switch (type_) {
1608       case MDL_T_INT:
1609         if (sscanf((*elements_)[u].string_of(), "%d", &i) != 1) return false;
1610         if (!expr_var.set(i)) return false; break;
1611       case MDL_T_FLOAT:
1612         if (sscanf((*elements_)[u].string_of(), "%f", &f) != 1) return false;
1613         if (!expr_var.set(f)) return false; break;
1614       case MDL_T_STRING: 
1615         if (!expr_var.set((*elements_)[u])) return false; break;
1616       default:
1617         return false;
1618       }
1619       if (!list_var.add_to_list(expr_var)) return false;
1620     }
1621   }
1622   return (mdl_env::add(list_var));
1623 }
1624
1625 T_dyninstRPC::mdl_instr_stmt::mdl_instr_stmt(unsigned pos, T_dyninstRPC::mdl_expr *expr,
1626                                       vector<T_dyninstRPC::mdl_icode*> *reqs,
1627                                       unsigned where, bool constrained) 
1628 : position_(pos), point_expr_(expr), icode_reqs_(reqs),
1629   where_instr_(where), constrained_(constrained) { }
1630 T_dyninstRPC::mdl_instr_stmt::mdl_instr_stmt() { }
1631 T_dyninstRPC::mdl_instr_stmt::~mdl_instr_stmt() {
1632   delete point_expr_;
1633   if (icode_reqs_) {
1634     unsigned size = icode_reqs_->size();
1635     for (unsigned u=0; u<size; u++)
1636       delete (*icode_reqs_)[u];
1637     delete icode_reqs_;
1638   }
1639 }
1640
1641 bool T_dyninstRPC::mdl_instr_stmt::apply(metricDefinitionNode *mn,
1642                                          vector<dataReqNode*>& inFlags) {
1643    // An instr statement is like:
1644    //    append preInsn $start.entry constrained (* startWallTimer(a_wallTime); *)
1645    // (note that there are other kinds of statements; i.e. there are other classes
1646    //  derived from the base class mdl_stmt; see dyninstRPC.I)
1647
1648   if (icode_reqs_ == NULL)
1649     return false; // no instrumentation code to put in!
1650
1651   mdl_var pointsVar(false);
1652   if (!point_expr_->apply(pointsVar)) // process the 'point(s)' e.g. "$start.entry"
1653     return false;
1654
1655   vector<instPoint *> points;
1656   if (pointsVar.type() == MDL_T_LIST_POINT) {
1657     vector<instPoint *> *pts;
1658     if (!pointsVar.get(pts)) return false;
1659     points = *pts;
1660   } else if (pointsVar.type() == MDL_T_POINT) {
1661     instPoint *p;
1662     if (!pointsVar.get(p)) return false; // where the point is located...
1663     points += p;
1664   } else {
1665     return false;
1666   }
1667
1668   // Let's generate the code now (we used to calculate it in the loop below,
1669   // which was a waste since the code is the same for all points).
1670   AstNode *code = NULL;
1671   unsigned size = icode_reqs_->size();
1672   for (unsigned u=0; u<size; u++) {
1673     if (!(*icode_reqs_)[u]->apply(code, u>0)) {
1674       // when u is 0, code is un-initialized
1675       removeAst(code);
1676       return false;
1677     }
1678   }
1679
1680   // Instantiate all constraints (flags) here (if any)
1681   // (if !constrained_ then don't do the following)
1682   if (constrained_) {
1683      unsigned fsize = inFlags.size();
1684      for (int fi=fsize-1; fi>=0; fi--) { // any reason why we go backwards?
1685 #if defined(SHM_SAMPLING)
1686   #if defined(MT_THREAD)
1687         AstNode *tmp_ast;
1688         tmp_ast = computeAddress((void *)((inFlags[fi])->getAllocatedLevel()),(void *)((inFlags[fi])->getAllocatedIndex()), 0); // 0 is for intCounter
1689         AstNode *temp1 = new AstNode(AstNode::DataIndir,tmp_ast);
1690         removeAst(tmp_ast);
1691   #else
1692         // Note: getInferiorPtr could return a NULL pointer here if we are
1693         // just computing cost - naim 2/18/97
1694         AstNode *temp1 = new AstNode(AstNode::DataValue, 
1695                                      (void*)((inFlags[fi])->getInferiorPtr(global_proc)));
1696   #endif
1697 #else
1698         // Note: getInferiorPtr could return a NULL pointer here if we are
1699         // just computing cost - naim 2/18/97
1700         AstNode *temp1 = new AstNode(AstNode::DataValue, 
1701                                      (void*)((inFlags[fi])->getInferiorPtr()));
1702 #endif
1703         // Note: we don't use assignAst on purpose here
1704         AstNode *temp2 = code;
1705         code = createIf(temp1, temp2);
1706         removeAst(temp1);
1707         removeAst(temp2);
1708      }
1709   }
1710
1711   if (!code) {
1712     // we are probably defining an empty metric
1713     code = new AstNode();
1714   }
1715
1716   callOrder corder;
1717   switch (position_) {
1718       case MDL_PREPEND: 
1719           corder = orderFirstAtPoint; 
1720           break;
1721       case MDL_APPEND: 
1722           corder = orderLastAtPoint; 
1723           break;
1724       default: assert(0);
1725   }
1726
1727   callWhen cwhen;
1728   switch (where_instr_) {
1729       case MDL_PRE_INSN: 
1730           cwhen = callPreInsn; 
1731           break;
1732       case MDL_POST_INSN: 
1733           cwhen = callPostInsn; 
1734           break;
1735       default: assert(0);
1736   }
1737
1738   // Here is where auto-activate should occur.
1739   // If there is 1 point and it is $start.entry then
1740   // do an inferiorRPC right now (of the ast 'code').
1741   // In this way, we can get metrics like cpu and exec-time for whole program
1742   // to work correctly even when the metrics are instantiated after
1743   // the entrypoint of main() is in execution.
1744
1745   bool manuallyTrigger = false; // for now
1746
1747   if (points.size() == 1) {
1748      // now look at the mdl variable to check for $start.entry.
1749      if (pointsVar.name() == "$start" && pointsVar.type()==MDL_T_POINT) {
1750         // having a type of MDL_T_POINT should mean $start.entry as opposed to
1751         // $start.exit, since $start.exit would yield a type of MDL_T_LIST_POINT,
1752         // since exit locations are always a list-of-points.  Sorry for the kludge.
1753
1754         instPoint *theVrbleInstPoint; // NOTE: instPoint is defined in arch-specific files!!!
1755         bool aflag = pointsVar.get(theVrbleInstPoint);
1756         // theVrbleInstPoint set to equiv of points[0]
1757         assert(aflag);
1758
1759         assert(theVrbleInstPoint == points[0]); // just a sanity check
1760
1761         mdl_var theVar;
1762         string varName = pointsVar.name();
1763         aflag=mdl_env::get(theVar, varName);
1764         assert(aflag);
1765
1766         function_base *theFunction;
1767         aflag=theVar.get(theFunction);
1768         assert(aflag);
1769
1770         // Make a note to do an inferiorRPC to manually execute this code.
1771 //      if (!manuallyTrigger)
1772 //         cerr << "mdl: found $start.entry; going to manually execute via inferior-RPC" << endl;
1773
1774         manuallyTrigger = true;
1775      }
1776   }
1777
1778   // for all of the inst points, insert the predicates and the code itself.
1779   for (unsigned i = 0; i < points.size(); i++) {
1780       mn->addInst(points[i], code, cwhen, corder,
1781                   manuallyTrigger && (i==0)); // manually trigger at most once
1782          // appends an instReqNode to mn's instRequests; actual 
1783          // instrumentation only
1784          // takes place when mn->insertInstrumentation() is later called.
1785   }
1786   removeAst(code); 
1787   return true;
1788 }
1789
1790 bool mdl_can_do(string& met_name) {
1791   // NOTE: We can do better if there's a dictionary of <metric-name> to <anything>
1792   unsigned size = mdl_data::all_metrics.size();
1793   for (unsigned u=0; u<size; u++) 
1794     if (mdl_data::all_metrics[u]->name_ == met_name)
1795       return true;
1796
1797   return false;
1798 }
1799
1800 metricDefinitionNode *mdl_do(vector< vector<string> >& canon_focus, 
1801                              string& met_name,
1802                              string& flat_name,
1803                              vector<process *> procs,
1804                              bool replace_components_if_present,
1805                              bool computingCost) {
1806   currentMetric = met_name;
1807   unsigned size = mdl_data::all_metrics.size();
1808   // NOTE: We can do better if there's a dictionary of <metric-name> to <metric>!
1809   for (unsigned u=0; u<size; u++) {
1810     if (mdl_data::all_metrics[u]->name_ == met_name) {
1811       return (mdl_data::all_metrics[u]->apply(canon_focus, flat_name, procs,
1812                                               replace_components_if_present,
1813                                               computingCost));
1814          // calls mdl_metric::apply()
1815     }
1816   }
1817   return NULL;
1818 }
1819
1820 bool mdl_init(string& flavor) { 
1821
1822   daemon_flavor = flavor;
1823
1824 #ifdef notdef
1825   vector<mdl_type_desc> kids;
1826   mdl_type_desc self, kid;
1827   mdl_focus_element fe;
1828
1829   self.name = "SyncObject"; self.type = 0; self.end_allowed = false; 
1830   kid.name = "Message"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1831   kid.name = "Barrier"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1832   kid.name = "Semaphore"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1833   kid.name = "SpinLock"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1834   fe.self = self; fe.kids = kids;
1835   mdl_data::foci += fe;
1836   kids.resize(0);
1837
1838 //  self.name = "Procedure"; self.type = MDL_T_MODULE; self.end_allowed = true;
1839   self.name = "Code"; self.type = MDL_T_MODULE; self.end_allowed = true;
1840   kid.name = "Module"; kid.type = MDL_T_PROCEDURE; self.end_allowed = true; kids += kids;
1841   fe.self = self; fe.kids = kids;
1842   mdl_data::foci += fe;
1843   kids.resize(0);
1844
1845   self.name = "Process"; self.type = MDL_T_PROCESS; self.end_allowed = true;
1846   fe.self = self; fe.kids.resize(0);
1847   mdl_data::foci += fe;
1848
1849   self.name = "Machine"; self.type = MDL_T_STRING; self.end_allowed = true;
1850   fe.self = self; fe.kids.resize(0);
1851   mdl_data::foci += fe;
1852 #endif
1853
1854   mdl_env::push();
1855   // These are pushed on per-process
1856   // mdl_env::add("$procedures", false, MDL_T_LIST_PROCEDURE);
1857   // mdl_env::add("$modules", false, MDL_T_LIST_MODULE);
1858
1859   string vname = "$machine";
1860   mdl_env::add(vname, false, MDL_T_STRING);
1861   string nodename = getHostName();
1862   mdl_env::set(nodename, vname);
1863
1864   /* Are these entered by hand at the new scope ? */
1865   /* $arg, $return */
1866
1867   vector<mdl_type_desc> field_list;
1868   mdl_type_desc desc;
1869   desc.name = "name"; desc.type = MDL_T_STRING; field_list += desc;
1870   desc.name = "calls"; desc.type = MDL_T_LIST_POINT; field_list += desc;
1871   desc.name = "entry"; desc.type = MDL_T_POINT; field_list += desc;
1872   desc.name = "return"; desc.type = MDL_T_POINT; field_list += desc;
1873   desc.name = "tag"; desc.type = MDL_T_INT; field_list += desc;
1874   mdl_data::fields[MDL_T_PROCEDURE] = field_list;
1875   field_list.resize(0);
1876
1877   desc.name = "name"; desc.type = MDL_T_STRING; field_list += desc;
1878   desc.name = "funcs"; desc.type = MDL_T_LIST_PROCEDURE; field_list += desc;
1879   mdl_data::fields[MDL_T_MODULE] = field_list;
1880   field_list.resize(0);
1881
1882   desc.name = "upper"; desc.type = MDL_T_INT; field_list += desc;
1883   desc.name = "lower"; desc.type = MDL_T_INT; field_list += desc;
1884   mdl_data::fields[MDL_T_VARIABLE] = field_list;
1885   field_list.resize(0);
1886
1887   return true;
1888 }
1889
1890 void dynRPC::send_metrics(vector<T_dyninstRPC::mdl_metric*>* var_0) {
1891   mdl_met = true;
1892
1893   if (var_0) {
1894     unsigned var_size = var_0->size();
1895     for (unsigned v=0; v<var_size; v++) {
1896       // fprintf(stderr, "Got metric %s\n", (*var_0)[v]->name_.string_of());
1897       // fflush(stderr);
1898       bool found = false;
1899       unsigned f_size = (*var_0)[v]->flavors_->size();
1900
1901       bool flavor_found = false;
1902       for (unsigned f=0; f<f_size; f++) {
1903         if ((*(*var_0)[v]->flavors_)[f] == daemon_flavor) {
1904           flavor_found = true; break;
1905         }
1906       }
1907       if (flavor_found) {
1908         unsigned size=mdl_data::all_metrics.size();
1909         for (unsigned u=0; u<size; u++) 
1910           if (mdl_data::all_metrics[u]->id_ == (*var_0)[v]->id_) {
1911             delete mdl_data::all_metrics[u];
1912             mdl_data::all_metrics[u] = (*var_0)[v];
1913             found = true;
1914           }
1915         if (!found) {
1916           T_dyninstRPC::mdl_metric *m = (*var_0)[v];
1917           mdl_data::all_metrics += m;
1918         }
1919       }
1920     }
1921   } else {
1922      fprintf(stderr, "no metric defined\n");
1923      fflush(stderr);
1924   }
1925 }
1926
1927 void dynRPC::send_constraints(vector<T_dyninstRPC::mdl_constraint*> *cv) {
1928
1929   mdl_cons = true;
1930   if (cv) {
1931     unsigned var_size = cv->size();
1932     for (unsigned v=0; v<var_size; v++) {
1933       bool found = false;
1934       // cout << "Received " << (*cv)[v]->id_ << endl;
1935       for (unsigned u=0; u<mdl_data::all_constraints.size(); u++) 
1936         if (mdl_data::all_constraints[u]->id_ == (*cv)[v]->id_) {
1937           delete mdl_data::all_constraints[u];
1938           mdl_data::all_constraints[u] = (*cv)[v];
1939           found = true;
1940         }
1941       if (!found) {
1942         mdl_data::all_constraints += (*cv)[v];
1943         // cout << *(*cv)[v] << endl;
1944       }
1945     }
1946   }
1947 }
1948
1949
1950 // TODO -- are these executed immediately ?
1951 void dynRPC::send_stmts(vector<T_dyninstRPC::mdl_stmt*> *vs) {
1952   mdl_stmt = true;
1953   if (vs) {
1954     // ofstream of("other_out", (been_here ? ios::app : ios::out));
1955     // been_here = true;
1956     // of << "SEND_STMTS\n";
1957     // unsigned size = vs->size();
1958     // for (unsigned u=0; u<size; u++) 
1959     // (*vs)[u]->print(of);
1960     mdl_data::stmts += *vs;
1961
1962     // TODO -- handle errors here
1963     // TODO -- apply these statements without a metric definition node ?
1964     unsigned s_size = vs->size();
1965     vector<dataReqNode*> flags;
1966
1967     // Application may fail if the list flavor is different than the flavor
1968     // of this daemon
1969
1970     for (unsigned s=0; s<s_size; s++) {
1971       if (!(*vs)[s]->apply(NULL, flags)) 
1972         ;
1973       // (*vs)[s]->print(cout);
1974       // cout << endl;
1975     }
1976   }
1977 }
1978
1979 // recieves the list of shared libraries to exclude 
1980 void dynRPC::send_libs(vector<string> *libs) {
1981
1982     mdl_libs = true;
1983     for(u_int i=0; i < libs->size(); i++){
1984         mdl_data::lib_constraints += (*libs)[i]; 
1985     }
1986
1987 }
1988
1989 // recieves the list of functions from  shared libraries to exclude 
1990 void dynRPC::send_funcs(vector<string> *funcs) {
1991
1992     mdl_funcs = true;
1993     for(u_int i=0; i < funcs->size(); i++){
1994         mdl_data::func_constraints += (*funcs)[i]; 
1995     }
1996 }
1997
1998 // recieves notification that there are no excluded libraries 
1999 void dynRPC::send_no_libs() {
2000
2001     mdl_libs = true;
2002
2003 }
2004
2005 // recieves notification that there are no excluded functions 
2006 void dynRPC::send_no_funcs() {
2007
2008     mdl_funcs = true;
2009 }
2010
2011 static bool do_operation(mdl_var& ret, mdl_var& left_val,
2012                          mdl_var& right_val, unsigned bin_op) {
2013   switch (bin_op) {
2014   case MDL_PLUS:
2015   case MDL_MINUS:
2016   case MDL_DIV:
2017   case MDL_MULT:
2018     if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
2019       int v1, v2;
2020       if (!left_val.get(v1)) return false;
2021       if (!right_val.get(v2)) return false;
2022       switch (bin_op) {
2023       case MDL_PLUS: return (ret.set(v1+v2));
2024       case MDL_MINUS: return (ret.set(v1-v2));
2025       case MDL_DIV: return (ret.set(v1/v2));
2026       case MDL_MULT: return (ret.set(v1*v2));
2027       }
2028     } else if (((left_val.type() == MDL_T_INT) || (left_val.type() == MDL_T_FLOAT)) &&
2029                ((right_val.type() == MDL_T_INT) || (right_val.type() == MDL_T_FLOAT))) {
2030       float v1, v2;
2031       if (left_val.type() == MDL_T_INT) {
2032         int i1; if (!left_val.get(i1)) return false; v1 = (float)i1;
2033       } else {
2034         if (!left_val.get(v1)) return false;
2035       }
2036       if (right_val.type() == MDL_T_INT) {
2037         int i1; if (!right_val.get(i1)) return false; v2 = (float)i1;
2038       } else {
2039         if (!right_val.get(v2)) return false;
2040       }
2041       switch (bin_op) {
2042       case MDL_PLUS: return (ret.set(v1+v2));
2043       case MDL_MINUS: return (ret.set(v1-v2));
2044       case MDL_DIV: return (ret.set(v1/v2));
2045       case MDL_MULT: return (ret.set(v1*v2));
2046       }
2047     } else
2048       return false;
2049   case MDL_LT:
2050   case MDL_GT:
2051   case MDL_LE:
2052   case MDL_GE:
2053   case MDL_EQ:
2054   case MDL_NE:
2055     if ((left_val.type() == MDL_T_STRING) && (right_val.type() == MDL_T_STRING)) {
2056       string v1, v2;
2057       if (!left_val.get(v1)) return false;
2058       if (!right_val.get(v2)) return false;
2059       switch (bin_op) {
2060       case MDL_LT: return (ret.set(v1 < v2));
2061       case MDL_GT: return (ret.set(v1 > v2));
2062       case MDL_LE: return (ret.set(v1 <= v2));
2063       case MDL_GE: return (ret.set(v1 >= v2));
2064       case MDL_EQ: return (ret.set(v1 == v2));
2065       case MDL_NE: return (ret.set(v1 != v2));
2066       }  
2067     }
2068     if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
2069       int v1, v2;
2070       if (!left_val.get(v1)) return false;
2071       if (!right_val.get(v2)) return false;
2072       switch (bin_op) {
2073       case MDL_LT: return (ret.set(v1 < v2));
2074       case MDL_GT: return (ret.set(v1 > v2));
2075       case MDL_LE: return (ret.set(v1 <= v2));
2076       case MDL_GE: return (ret.set(v1 >= v2));
2077       case MDL_EQ: return (ret.set(v1 == v2));
2078       case MDL_NE: return (ret.set(v1 != v2));
2079       }
2080     } else if (((left_val.type() == MDL_T_INT) ||
2081                 (left_val.type() == MDL_T_FLOAT)) &&
2082                ((right_val.type() == MDL_T_INT) ||
2083                 (right_val.type() == MDL_T_FLOAT))) {
2084       float v1, v2;
2085       if (left_val.type() == MDL_T_INT) {
2086         int i1; if (!left_val.get(i1)) return false; v1 = (float)i1;
2087       } else {
2088         if (!left_val.get(v1)) return false;
2089       }
2090       if (right_val.type() == MDL_T_INT) {
2091         int i1; if (!right_val.get(i1)) return false; v2 = (float)i1;
2092       } else {
2093         if (!right_val.get(v2)) return false;
2094       }
2095       switch (bin_op) {
2096       case MDL_LT: return (ret.set(v1 < v2));
2097       case MDL_GT: return (ret.set(v1 > v2));
2098       case MDL_LE: return (ret.set(v1 <= v2));
2099       case MDL_GE: return (ret.set(v1 >= v2));
2100       case MDL_EQ: return (ret.set(v1 == v2));
2101       case MDL_NE: return (ret.set(v1 != v2));
2102       }
2103     } else
2104       return false;
2105   case MDL_AND:
2106   case MDL_OR:
2107     if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
2108       int v1, v2;
2109       if (!left_val.get(v1)) return false;
2110       if (!right_val.get(v2)) return false;
2111       switch (bin_op) {
2112       case MDL_AND: return (ret.set(v1 && v2));
2113       case MDL_OR: return (ret.set(v1 || v2));
2114       }
2115     } else
2116       return false;
2117   default:
2118       return false;
2119   }
2120   return false;
2121 }
2122
2123 static bool walk_deref(mdl_var& ret, vector<unsigned>& types, string& var_name) {
2124
2125   function_base *pdf = 0;
2126   if (!mdl_env::get(ret, var_name)) return false;
2127   
2128   unsigned index=0;
2129   unsigned max = types.size();
2130
2131   while (index < max) {
2132     unsigned current_type = types[index++];
2133     unsigned next_field = types[index++];
2134
2135     switch (current_type) {
2136     case MDL_T_PROCEDURE:
2137       // function_base *pdf = 0;
2138       if (!ret.get(pdf)) return false;
2139       switch (next_field) {
2140       case 0: {
2141         string prettyName = pdf->prettyName();
2142         if (!ret.set(prettyName)) return false;
2143         break;
2144       }
2145       // TODO: should these be passed a process?
2146       case 1:
2147         if (!ret.set((vector<instPoint *>*)&pdf->funcCalls(global_proc)))
2148           return false;
2149         break;
2150       case 2: 
2151         if (!ret.set((instPoint *)pdf->funcEntry(global_proc)))
2152         return false; 
2153         break;
2154       case 3:
2155         if (!ret.set((vector<instPoint *>*)&pdf->funcExits(global_proc)))
2156           return false;
2157         break;
2158       case 4:
2159         if (!ret.set((int)pdf->tag()))
2160           return false;
2161         break;
2162       default:
2163         assert(0);
2164         break;
2165       }
2166       break;
2167     case MDL_T_MODULE:
2168       module *mod;
2169       if (!ret.get(mod)) return false;
2170       switch (next_field) {
2171       case 0: { string fileName = mod->fileName();
2172                 if (!ret.set(fileName)) return false; 
2173               } break;
2174       case 1: {
2175         if (global_proc) {
2176             if (!ret.set(global_proc->getIncludedFunctions(mod))) return false; 
2177         }
2178         else {
2179             if (!ret.set(mod->getFunctions())) return false; 
2180         }
2181         break;
2182       }
2183       default: assert(0); break;               
2184       }
2185       break;
2186     default:
2187       assert(0); return false;
2188     }
2189   }
2190   return true;
2191 }
2192
2193
2194 bool mdl_get_initial(string flavor, pdRPC *connection) {
2195   mdl_init(flavor);
2196   while (!(mdl_met && mdl_cons && mdl_stmt && mdl_libs && mdl_funcs)) {
2197     switch (connection->waitLoop()) {
2198     case T_dyninstRPC::error:
2199       return false;
2200     default:
2201       break;
2202     }
2203     while (connection->buffered_requests()) {
2204       switch (connection->process_buffered()) {
2205       case T_dyninstRPC::error:
2206         return false;
2207       default:
2208         break;
2209       }
2210     }
2211   }
2212   return true;
2213 }
2214
2215 bool mdl_get_lib_constraints(vector<string> &lc){
2216     for(u_int i=0; i < mdl_data::lib_constraints.size(); i++){
2217         lc += mdl_data::lib_constraints[i];
2218     }
2219     return (lc.size()>0);
2220 }
2221
2222 bool mdl_get_func_constraints(vector<string> &lc){
2223     for(u_int i=0; i < mdl_data::func_constraints.size(); i++){
2224         lc += mdl_data::func_constraints[i];
2225     }
2226     return (lc.size()>0);
2227 }
2228
2229 void mdl_get_info(vector<T_dyninstRPC::metricInfo>& metInfo) {
2230   unsigned size = mdl_data::all_metrics.size();
2231   T_dyninstRPC::metricInfo element;
2232   for (unsigned u=0; u<size; u++) {
2233     element.name = mdl_data::all_metrics[u]->name_;
2234     element.style = mdl_data::all_metrics[u]->style_;
2235     element.aggregate = mdl_data::all_metrics[u]->agg_op_;
2236     element.units = mdl_data::all_metrics[u]->units_;
2237     element.developerMode = mdl_data::all_metrics[u]->developerMode_;
2238     element.unitstype = mdl_data::all_metrics[u]->unitstype_;
2239     metInfo += element;
2240   }
2241 }
2242
2243 bool mdl_metric_data(const string& met_name, mdl_inst_data& md) {
2244   unsigned size = mdl_data::all_metrics.size();
2245   for (unsigned u=0; u<size; u++)
2246     if (mdl_data::all_metrics[u]->name_ == met_name) {
2247       md.aggregate = mdl_data::all_metrics[u]->agg_op_;
2248       md.style = (metricStyle) mdl_data::all_metrics[u]->style_;
2249       return true;
2250     }
2251   return false;
2252 }