Extra debugging information in main.C
[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 #include "dyninstAPI/src/instPoint.h" // new...for class instPoint
58
59 // The following vrbles were defined in process.C:
60 extern debug_ostream attach_cerr;
61 extern debug_ostream inferiorrpc_cerr;
62 extern debug_ostream shmsample_cerr;
63 extern debug_ostream forkexec_cerr;
64 extern debug_ostream metric_cerr;
65
66
67 // Some global variables used to print error messages:
68 string currentMetric;  // name of the metric that is being processed.
69 string currentFocus;   // the focus
70
71
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 vector<unsigned> mdl_env::frames;
79 vector<mdl_var> mdl_env::all_vars;
80
81 vector<T_dyninstRPC::mdl_stmt*> mdl_data::stmts;
82 vector<T_dyninstRPC::mdl_metric*> mdl_data::all_metrics;
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_constraint*> mdl_data::all_constraints;
86 vector<string> mdl_data::lib_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(); // could be zero
571     vector<dataReqNode*> flags;
572     metric_cerr << "There are " << flag_size << " flags (constraints)" << endl;
573
574     for (unsigned fs=0; fs<flag_size; fs++) {
575         // TODO -- cache these created flags
576         dataReqNode *flag = NULL;
577         // The following calls mdl_constraint::apply():
578         if (!flag_cons[fs]->apply(mn, flag, focus[flag_dex[fs]], proc, computingCost)) {
579           if (!computingCost) mn->cleanup_drn();
580           delete mn;
581           return NULL;
582         }
583         assert(flag);
584         flags += flag;
585
586         metric_cerr << "Applied constraint for " << flag_cons[fs]->id_ << endl;
587     }
588
589     if (base_use) {
590       dataReqNode *flag = NULL;
591       if (!base_use->apply(mn, flag, focus[base_dex], proc, computingCost)) {
592         if (!computingCost) mn->cleanup_drn();  
593         delete mn;
594         return NULL;
595       }
596     } else {
597       unsigned size = stmts->size();
598       for (unsigned u=0; u<size; u++) {
599         if (!(*stmts)[u]->apply(mn, flags)) { // virtual fn call depending on stmt type
600           if (!computingCost) mn->cleanup_drn();  
601           delete mn;
602           return NULL;
603         }
604       }
605     }
606
607     if (!mn->nonNull()) {
608       if (!computingCost) 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 ///////////////////////////
694 vector<string>global_excluded_funcs;
695
696
697 metricDefinitionNode *T_dyninstRPC::mdl_metric::apply(vector< vector<string> > &focus,
698                                                       string& flat_name,
699                                                       vector<process *> procs,
700                                                       bool replace_components_if_present,
701                                                       bool computingCost) {
702   // TODO -- check to see if this is active ?
703   // TODO -- create counter or timer
704   // TODO -- put it into the environment ?
705   // TODO -- this can be passed directly -- faster - later
706   // TODO -- internal metrics
707   // TODO -- assume no constraints, all processes instrumented
708   // TODO -- support two-level aggregation: one at the daemon, one at paradyn
709   // TODO -- how is folding specified ?
710   // TODO -- are lists updated here ?
711
712   mdl_env::push();
713   mdl_env::add(id_, false, MDL_T_DRN);
714   assert(stmts_);
715
716   const unsigned tc_size = temp_ctr_->size();
717   for (unsigned tc=0; tc<tc_size; tc++) {
718     mdl_env::add((*temp_ctr_)[tc], false, MDL_T_DRN);
719   }
720
721   static string machine;
722   static bool machine_init= false;
723   if (!machine_init) {
724     machine_init = true;
725     machine = getHostName();
726   }
727
728   // TODO -- I am assuming that a canonical resource list is
729   // machine, procedure, process, syncobject
730
731   if (other_machine_specified(focus, machine)) return NULL;
732   vector<process*> instProcess;
733   add_processes(focus, procs, instProcess);
734
735   if (!instProcess.size()) return NULL;
736
737   // build the list of constraints to use
738   vector<T_dyninstRPC::mdl_constraint*> flag_cons;
739
740   // the first replace constraint that matches, if any
741   T_dyninstRPC::mdl_constraint *base_used=NULL;
742
743   // build list of global constraints that match and choose local replace constraint
744   unsigned base_dex; vector<unsigned> flag_dex;
745   if (!check_constraints(flag_cons, base_used, focus, constraints_, flag_dex, base_dex))
746     return NULL;
747
748   //////////
749   /* 
750      Compute the list of excluded functions here. This is the list of functions
751      that should be excluded from the calls sites.
752      We set the global variable global_excluded_functions to the list of excluded
753      functions.
754
755      At this point, the $constraint variable is not in the environment yet,
756      so anything that uses $constraint will not be added to the list,
757      which is what we want.
758    */
759   if (base_used) {
760     base_used->mk_list(global_excluded_funcs);
761   } else {
762     for (unsigned u1 = 0; u1 < flag_cons.size(); u1++)
763       flag_cons[u1]->mk_list(global_excluded_funcs);
764     for (unsigned u2 = 0; u2 < stmts_->size(); u2++)
765       (*stmts_)[u2]->mk_list(global_excluded_funcs);
766   }
767   metric_cerr << "Metric: " << name_ << endl;
768   for (unsigned x1 = 0; x1 < global_excluded_funcs.size(); x1++)
769     metric_cerr << "  " << global_excluded_funcs[x1] << endl;
770   //////////
771
772
773   // build the instrumentation request
774   vector<metricDefinitionNode*> parts; // one per process
775   if (!apply_to_process_list(instProcess, parts, id_, name_, focus,
776                              agg_op_, type_, flag_cons, base_used,
777                              stmts_, flag_dex, base_dex, temp_ctr_,
778                              replace_components_if_present,
779                              computingCost))
780     return NULL;
781
782   // construct aggregate for the metric instance parts
783   metricDefinitionNode *ret = NULL;
784
785   if (parts.size())
786     // create aggregate mi, containing the process components "parts"
787     ret = new metricDefinitionNode(name_, focus, flat_name, parts, agg_op_);
788
789   // cout << "apply of " << name_ << " ok\n";
790   mdl_env::pop();
791
792   ////////////////////
793   global_excluded_funcs.resize(0);
794
795   return ret;
796 }
797
798 T_dyninstRPC::mdl_constraint::mdl_constraint() { }
799 T_dyninstRPC::mdl_constraint::mdl_constraint(string id, vector<string> *match_path,
800                                              vector<T_dyninstRPC::mdl_stmt*> *stmts,
801                                              bool replace, u_int d_type, bool& error)
802 : id_(id), match_path_(match_path), stmts_(stmts), replace_(replace),
803   data_type_(d_type), hierarchy_(0), type_(0) { error = false; }
804 T_dyninstRPC::mdl_constraint::~mdl_constraint() {
805   delete match_path_;
806   if (stmts_) {
807     for (unsigned u=0; u<stmts_->size(); u++)
808       delete (*stmts_)[u];
809     delete stmts_;
810   }
811 }
812
813
814 static bool do_trailing_resources(vector<string>& resource_,
815                                   process *proc)
816 {
817   vector<string>  resPath;
818
819   for(int pLen = 0; pLen < resource_.size(); pLen++) {
820     string   caStr = string("$constraint") + 
821                      string(resource_.size()-pLen-1);
822     string   trailingRes = resource_[pLen];
823
824     resPath += resource_[pLen];
825     assert(resPath.size() == (pLen+1));
826
827     resource *r = resource::findResource(resPath);
828     if (!r) assert(0);
829
830     switch (r->type()) {
831     case MDL_T_INT: {
832       const char* p = trailingRes.string_of();
833       char*       q;
834       int         val = (int) strtol(p, &q, 0);
835       if (p == q) {
836         string msg = string("unable to convert resource '") + trailingRes + 
837                      string("' to integer.");
838         showErrorCallback(92,msg.string_of());
839         return(false);
840       }
841       mdl_env::add(caStr, false, MDL_T_INT);
842       mdl_env::set(val, caStr);
843       break;
844     }
845     case MDL_T_STRING:
846       mdl_env::add(caStr, false, MDL_T_STRING);
847       mdl_env::set(trailingRes, caStr);
848       break;
849     case MDL_T_PROCEDURE: {
850       // find the resource corresponding to this function's module 
851       vector<string> m_vec;
852       for(u_int i=0; i < resPath.size()-1; i++){
853         m_vec += resPath[i];
854       }
855       assert(m_vec.size());
856       assert(m_vec.size() == (resPath.size()-1));
857       resource *m_resource = resource::findResource(m_vec);
858       if(!m_resource) return(false);
859       
860       function_base *pdf = proc->findOneFunction(r,m_resource);
861       if (!pdf) return(false);
862       mdl_env::add(caStr, false, MDL_T_PROCEDURE);
863       mdl_env::set(pdf, caStr);
864       break;
865     }
866     case MDL_T_MODULE: {
867       module *mod = proc->findModule(trailingRes,true);
868       if (!mod) return(false);
869       mdl_env::add(caStr, false, MDL_T_MODULE);
870       mdl_env::set(mod, caStr);
871       break;
872     }
873     case MDL_T_MEMORY:
874       break ;
875     case MDL_T_VARIABLE: {
876         //bounds is defined in metric.h
877         memory::bounds b = theMemory->getVariableBounds(trailingRes) ;
878         mdl_env::add(caStr, false, MDL_T_VARIABLE) ;
879         mdl_env::set(b, caStr) ;
880     }
881     break ;
882     default:
883       assert(0);
884       break;
885     }
886   }
887   return(true);
888 }
889
890
891 // Replace constraints not working yet
892 // Flag constraints need to return a handle to a data request node -- the flag
893 bool T_dyninstRPC::mdl_constraint::apply(metricDefinitionNode *mn,
894                                          dataReqNode *&flag,
895                                          vector<string>& resource,
896                                          process *proc, bool computingCost) {
897   assert(mn);
898   switch (data_type_) {
899   case MDL_T_COUNTER:
900   case MDL_T_WALL_TIMER:
901   case MDL_T_PROC_TIMER:
902     break;
903   default:
904     assert(0);
905   }
906   mdl_env::push();
907
908   if (!replace_) {
909     // create the counter used as a flag
910     mdl_env::add(id_, false, MDL_T_DRN);
911 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
912     // "true" means that we are going to create a sampled int counter but
913     // we are *not* going to sample it, because it is just a temporary
914     // counter - naim 4/22/97
915     // By default, the last parameter is false - naim 4/23/97
916     dataReqNode *drn = mn->addSampledIntCounter(0,computingCost,true);
917 #else
918     dataReqNode *drn = mn->addUnSampledIntCounter(0,computingCost);
919 #endif
920     // this flag will construct a predicate for the metric -- have to return it
921     flag = drn;
922     assert(drn);
923     mdl_env::set(drn, id_);
924   }
925
926   // put $constraint[X] in the environment
927   if(!do_trailing_resources(resource, proc)) {
928     mdl_env::pop();
929     return(false);
930   }
931
932   // Now evaluate the constraint statements
933   unsigned size = stmts_->size();
934   vector<dataReqNode*> flags;
935   for (unsigned u=0; u<size; u++) {
936     if (!(*stmts_)[u]->apply(mn, flags)) { // virtual fn call; several possibilities
937       // cout << "apply of constraint " << id_ << " failed\n";
938       return(false);
939     }
940   }
941   mdl_env::pop();
942   return(true);
943 }
944
945 T_dyninstRPC::mdl_constraint *mdl_data::new_constraint(string id, vector<string> *path,
946                                                 vector<T_dyninstRPC::mdl_stmt*> *stmts,
947                                                 bool replace, u_int d_type) {
948   bool error;
949   return (new T_dyninstRPC::mdl_constraint(id, path, stmts, replace, d_type, error));
950 }
951
952
953 T_dyninstRPC::mdl_rand::mdl_rand() {}
954
955 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand() {}
956
957 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type): type_(type) {}
958
959 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type, u_int val)
960 : type_(type), val_(val) {}
961
962 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type, string name)
963 : type_(type), name_(name) {}
964
965 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type, string name, vector<mdl_instr_rand *>args)
966 : type_(type), name_(name) {
967   for (unsigned u = 0; u < args.size(); u++)
968     args_ += args[u];
969 }
970
971 T_dyninstRPC::mdl_instr_rand::~mdl_instr_rand() { } 
972
973 bool T_dyninstRPC::mdl_instr_rand::apply(AstNode *&ast) {
974   function_base *pdf;
975   mdl_var get_drn;
976
977   switch (type_) {
978   case MDL_T_RECORD://TO DO
979        {
980            int value ;
981            mdl_var get_record ;
982            mdl_env::get(get_record, string("$constraint0")) ;
983            unsigned type = mdl_env::get_type(string("$constraint0")) ;
984            switch(type)
985            {
986             case MDL_T_VARIABLE:
987                 memory::bounds b ;
988                 if (!get_record.get(b))
989                 {
990                     return false;
991                 }else
992                 {
993                     if(!strncmp(name_.string_of(), "upper", 5))
994                         value = (int)b.upper ;
995                     else
996                         value = (int)b.lower;
997                     ast = new AstNode(AstNode::Constant, (void*) value);
998                 }
999                 break ;
1000            }// switch
1001        }
1002        break ;
1003
1004   
1005   case MDL_T_INT:
1006     if (name_.length()) {
1007       // variable in the expression.
1008       mdl_var get_int;
1009       int value;
1010       bool aflag;
1011       aflag=mdl_env::get(get_int, name_);
1012       assert(aflag);
1013       if (!get_int.get(value)) {
1014           fprintf(stderr, "Unable to get value for %s\n", name_.string_of());
1015           fflush(stderr);
1016           return false;
1017       } else {
1018           ast = new AstNode(AstNode::Constant, (void*) value);
1019       }
1020     } else {
1021       ast = new AstNode(AstNode::Constant, (void*) val_);
1022     }
1023     break;
1024   case MDL_ARG:
1025     ast = new AstNode(AstNode::Param, (void*) val_);
1026     break;
1027   case MDL_RETURN:
1028     ast = new AstNode(AstNode::ReturnVal, (void*)0);
1029     break;
1030   case MDL_READ_SYMBOL:
1031     // TODO -- I am relying on global_proc to be set in mdl_metric::apply
1032     if (global_proc) {
1033       Symbol info;
1034       Address baseAddr;
1035       if (global_proc->getSymbolInfo(name_, info, baseAddr)) {
1036         Address adr = info.addr();
1037         ast = new AstNode(AstNode::DataAddr, (void*) adr);
1038       } else {
1039         string msg = string("In metric '") + currentMetric + string("': ") +
1040           string("unable to find symbol '") + name_ + string("'");
1041         showErrorCallback(95, msg);
1042         return false;
1043       }
1044     }
1045     break;
1046   case MDL_READ_ADDRESS:
1047     // TODO -- check on the range of this address!
1048     ast = new AstNode(AstNode::DataAddr, (void*) val_);
1049     break;
1050   case MDL_CALL_FUNC: {
1051     // don't confuse 'args' with 'args_' here!
1052
1053     vector<AstNode *> args;
1054     for (unsigned u = 0; u < args_.size(); u++) {
1055       AstNode *arg=NULL;
1056       if (!args_[u]->apply(arg)) { 
1057         // fills in 'arg'
1058         removeAst(arg);
1059         return false;
1060       }
1061       args += assignAst(arg);
1062       removeAst(arg);
1063     }
1064     string temp = string(name_);
1065     pdf = global_proc->findOneFunctionFromAll(temp);
1066     if (!pdf) {
1067         string msg = string("In metric '") + currentMetric + string("': ") +
1068           string("unable to find procedure '") + name_ + string("'");
1069         showErrorCallback(95, msg);
1070         return false;
1071     }
1072     ast = new AstNode(name_, args); //Cannot use simple assignment here!
1073     for (unsigned i=0;i<args.size();i++) removeAst(args[i]);
1074     break;
1075   }
1076   case MDL_T_COUNTER_PTR:
1077     { mdl_var get_drn;
1078       dataReqNode *drn;
1079       if (!mdl_env::get(get_drn, name_)) {
1080         string msg = string("In metric '") + currentMetric + string("' : ") +
1081           string("undefined variable '") + name_ + string("'");
1082         showErrorCallback(92, msg);
1083         return false;
1084       }
1085       bool aflag;
1086       aflag=get_drn.get(drn);
1087       assert(aflag);
1088 #if defined(SHM_SAMPLING)
1089   #if defined(MT_THREAD)
1090       ast = computeAddress((void *)(drn->getAllocatedLevel()),
1091                            (void *)(drn->getAllocatedIndex()),
1092                            0); // 0 is for intCounter
1093   #else
1094       ast = new AstNode(AstNode::DataPtr, (void *)(drn->getInferiorPtr(global_proc)));
1095   #endif
1096 #else
1097       ast = new AstNode(AstNode::DataPtr, (void *)(drn->getInferiorPtr()));
1098 #endif
1099     }
1100     break;
1101   case MDL_T_COUNTER:
1102     {
1103       mdl_var get_drn;
1104       dataReqNode *drn;
1105       bool aflag;
1106       aflag=mdl_env::get(get_drn, name_);
1107       assert(aflag);
1108       //
1109       // This code was added to support additional mdl evaluation time 
1110       //     variables.  To keep it simple, I left the parser alone and so
1111       //     any unknown identifier maps to MDL_T_COUNTER.  We lookup the
1112       //     variable's type here to generate the correct code.  MDL
1113       //     really should have a general type system and all functions
1114       //     signatures. - jkh 7/5/95
1115       //
1116       switch (get_drn.type()) {
1117           case MDL_T_INT:
1118               int value;
1119               if (!get_drn.get(value)) {
1120                   fprintf(stderr, "Unable to get value for %s\n", 
1121                       name_.string_of());
1122                   fflush(stderr);
1123                   return false;
1124               } else {
1125                   ast = new AstNode(AstNode::Constant, (void*) value);
1126               }
1127               break;
1128           case MDL_T_COUNTER:   // is MDL_T_COUNTER used here ??? jkh 7/31/95
1129           case MDL_T_DRN:
1130               if (!get_drn.get(drn)) {
1131                   fprintf(stderr, "Unable to find variable %s\n", 
1132                       name_.string_of());
1133                   fflush(stderr);
1134                   return false;
1135               } else {
1136 #if defined(SHM_SAMPLING)
1137   #if defined(MT_THREAD)
1138                   AstNode *tmp_ast;
1139                   tmp_ast = computeAddress((void *)(drn->getAllocatedLevel()),
1140                                            (void *)(drn->getAllocatedIndex()),
1141                                            0); // 0 is for intCounter
1142                   // First we get the address, and now we get the value...
1143                   ast = new AstNode(AstNode::DataIndir,tmp_ast); 
1144                   removeAst(tmp_ast);
1145   #else
1146                   ast = new AstNode(AstNode::DataValue, 
1147                                     (void*)(drn->getInferiorPtr(global_proc)));
1148   #endif
1149 #else
1150                   // Note: getInferiorPtr could return a NULL pointer here if
1151                   // we are just computing cost - naim 2/18/97
1152                   ast = new AstNode(AstNode::DataValue, 
1153                                     (void*)(drn->getInferiorPtr()));
1154 #endif
1155               }
1156               break;
1157           default:
1158               fprintf(stderr, "type of variable %s is not known\n",
1159                   name_.string_of());
1160               fflush(stderr);
1161               return false;
1162       }
1163     }
1164     break;
1165   default:
1166     break;
1167   }
1168   return true;
1169 }
1170
1171
1172
1173 T_dyninstRPC::mdl_instr_req::mdl_instr_req(T_dyninstRPC::mdl_instr_rand *rand,
1174                                            u_int type, string obj_name)
1175 : type_(type), rand_(rand), timer_counter_name_(obj_name) { }
1176
1177 T_dyninstRPC::mdl_instr_req::mdl_instr_req(u_int type, string obj_name)
1178 : type_(type), timer_counter_name_(obj_name) { }
1179
1180 T_dyninstRPC::mdl_instr_req::mdl_instr_req(u_int type,
1181                                            T_dyninstRPC::mdl_instr_rand *rand)
1182 : type_(type), rand_(rand) { }
1183
1184 T_dyninstRPC::mdl_instr_req::mdl_instr_req() : type_(0) { }
1185 T_dyninstRPC::mdl_instr_req::~mdl_instr_req() { }
1186
1187 bool T_dyninstRPC::mdl_instr_req::apply(AstNode *&mn, AstNode *pred,
1188                                         bool mn_initialized) {
1189   // a return value of true implies that "mn" was written to
1190   AstNode *ast_arg=NULL;
1191
1192   vector<AstNode *> ast_args;
1193   string timer_fun;
1194
1195   switch (type_) {
1196   case MDL_SET_COUNTER:
1197   case MDL_ADD_COUNTER:
1198   case MDL_SUB_COUNTER:
1199     if (! rand_->apply(ast_arg))
1200       return false;
1201     break;
1202   case MDL_START_WALL_TIMER:
1203     timer_fun = START_WALL_TIMER;
1204     break;
1205   case MDL_STOP_WALL_TIMER:
1206     timer_fun = STOP_WALL_TIMER;
1207     break;
1208   case MDL_START_PROC_TIMER:
1209     timer_fun = START_PROC_TIMER;
1210     break;
1211   case MDL_STOP_PROC_TIMER:
1212     timer_fun = STOP_PROC_TIMER;
1213     break;
1214   }
1215
1216   dataReqNode *drn;
1217   mdl_var get_drn;
1218   if (type_ != MDL_CALL_FUNC) {
1219       bool aflag=mdl_env::get(get_drn, timer_counter_name_);
1220       assert(aflag);
1221
1222       aflag=get_drn.get(drn);
1223       assert(aflag);
1224   }
1225
1226   AstNode *code=NULL;
1227
1228   switch (type_) {
1229   case MDL_SET_COUNTER:
1230 #if defined(SHM_SAMPLING)
1231   #if defined(MT_THREAD)
1232     code = createCounter("setCounter", (void *)(drn->getAllocatedLevel()), 
1233                          (void *)(drn->getAllocatedIndex()),ast_arg);
1234   #else
1235     code = createCounter("setCounter", (void *)(drn->getInferiorPtr(global_proc)), ast_arg);
1236   #endif
1237 #else
1238     code = createCounter("setCounter", (void *)(drn->getInferiorPtr()), ast_arg);
1239 #endif
1240     break;
1241   case MDL_ADD_COUNTER:
1242 #if defined(SHM_SAMPLING)
1243   #if defined(MT_THREAD)
1244     code = createCounter("addCounter", (void *)(drn->getAllocatedLevel()), 
1245                          (void *)(drn->getAllocatedIndex()), ast_arg);
1246   #else
1247     code = createCounter("addCounter", (void *)(drn->getInferiorPtr(global_proc)), ast_arg);
1248   #endif
1249 #else
1250     code = createCounter("addCounter", (void *)(drn->getInferiorPtr()), ast_arg);
1251 #endif
1252     break;
1253   case MDL_SUB_COUNTER:
1254 #if defined(SHM_SAMPLING)
1255   #if defined(MT_THREAD)
1256     code = createCounter("subCounter", (void *)(drn->getAllocatedLevel()), 
1257                          (void *)(drn->getAllocatedIndex()), ast_arg);
1258   #else
1259     code = createCounter("subCounter", (void *)(drn->getInferiorPtr(global_proc)), ast_arg);
1260   #endif
1261 #else
1262     code = createCounter("subCounter", (void *)(drn->getInferiorPtr()), ast_arg);
1263 #endif
1264     break;
1265   case MDL_START_WALL_TIMER:
1266   case MDL_STOP_WALL_TIMER:
1267   case MDL_START_PROC_TIMER:
1268   case MDL_STOP_PROC_TIMER:
1269 #if defined(SHM_SAMPLING)
1270   #if defined(MT_THREAD)
1271     code = createTimer(timer_fun, (void *)(drn->getAllocatedLevel()), 
1272                        (void *)(drn->getAllocatedIndex()), ast_args);
1273   #else
1274     code = createTimer(timer_fun, (void *)(drn->getInferiorPtr(global_proc)), ast_args);
1275   #endif
1276 #else
1277     code = createTimer(timer_fun, (void *)(drn->getInferiorPtr()), ast_args);
1278 #endif
1279     break;
1280   case MDL_CALL_FUNC:
1281     if (! rand_->apply(code))
1282       return false;
1283     break;
1284   default:
1285     return false;
1286   }
1287   if (pred) {
1288     // Note: we don't use assignAst on purpose here
1289     AstNode *tmp=code;
1290     code = createIf(pred, tmp);
1291     removeAst(tmp);
1292   }
1293
1294   if (mn_initialized) {
1295     // Note: we don't use assignAst on purpose here
1296     AstNode *tmp=mn;
1297     mn = new AstNode(tmp, code);
1298     removeAst(tmp);
1299   } else {
1300     mn = assignAst(code);
1301   }
1302
1303   removeAst(ast_arg);
1304   removeAst(code);
1305   return true;
1306 }
1307
1308 T_dyninstRPC::mdl_stmt::mdl_stmt() { }
1309
1310 T_dyninstRPC::mdl_for_stmt::mdl_for_stmt(string index_name, T_dyninstRPC::mdl_expr *list_exp, T_dyninstRPC::mdl_stmt *body) 
1311 : for_body_(body), index_name_(index_name), list_expr_(list_exp) { }
1312 T_dyninstRPC::mdl_for_stmt::mdl_for_stmt() { }
1313 T_dyninstRPC::mdl_for_stmt::~mdl_for_stmt() {
1314   delete for_body_;
1315   delete list_expr_;
1316 }
1317
1318 bool T_dyninstRPC::mdl_for_stmt::apply(metricDefinitionNode *mn,
1319                                        vector<dataReqNode*>& flags) {
1320   mdl_env::push();
1321   mdl_env::add(index_name_, false);
1322   mdl_var list_var(false);
1323
1324   // TODO -- build iterator closure here -- list may be vector or dictionary
1325   if (!list_expr_->apply(list_var))
1326     return false;
1327   if (!list_var.is_list())
1328     return false;
1329
1330   // TODO
1331   //  vector<function_base*> *vp;
1332   //  list_var.get(vp);
1333   list_closure closure(index_name_, list_var);
1334
1335   // mdl_env::set_type(list_var.element_type(), index_name_);
1336   while (closure.next()) {
1337     if (!for_body_->apply(mn, flags)) return false;
1338   }
1339
1340   mdl_env::pop();
1341   return true;
1342 }
1343
1344 T_dyninstRPC::mdl_icode::mdl_icode() { }
1345 T_dyninstRPC::mdl_icode::mdl_icode(T_dyninstRPC::mdl_instr_rand *iop1,
1346                                    T_dyninstRPC::mdl_instr_rand *iop2,
1347                                    u_int bin_op, bool use_if,
1348                                    T_dyninstRPC::mdl_instr_req *ireq)
1349 : if_op1_(iop1), if_op2_(iop2),
1350   bin_op_(bin_op), use_if_(use_if), req_(ireq) { }
1351 T_dyninstRPC::mdl_icode::~mdl_icode() { delete req_; }
1352
1353 static AstNode *do_rel_op(opCode op, T_dyninstRPC::mdl_instr_rand *if_op2,
1354                           AstNode *ast_left) {
1355    // NOTE: ast_left _must_ be defined
1356    AstNode *ast_right=NULL;
1357    AstNode *tmp=NULL;
1358    if (!if_op2->apply(ast_right)) {
1359       removeAst(ast_right);
1360       return(new AstNode());
1361    }
1362    tmp = new AstNode(op, ast_left, ast_right);
1363    removeAst(ast_right);
1364    return(tmp);;
1365 }
1366
1367 bool T_dyninstRPC::mdl_icode::apply(AstNode *&mn, bool mn_initialized) {
1368   // a return value of true implies that "mn" has been written to
1369   // TODO -- handle the if case here
1370   // TODO -- call req_->apply() after building if
1371
1372   if (!req_)
1373      return false;
1374
1375   AstNode *pred=NULL;
1376   AstNode *pred_ptr=NULL;
1377
1378   if (use_if_) {
1379     AstNode *ast1=NULL;
1380     if (!if_op1_->apply(ast1))
1381        return false;
1382     switch (bin_op_) {
1383     case MDL_LT:
1384       pred = do_rel_op(lessOp, if_op2_, ast1);
1385       break;
1386     case MDL_GT:
1387       pred = do_rel_op(greaterOp, if_op2_, ast1);
1388       break;
1389     case MDL_LE:
1390       pred = do_rel_op(leOp, if_op2_, ast1);
1391       break;
1392     case MDL_GE:
1393       pred = do_rel_op(geOp, if_op2_, ast1);
1394       break;
1395     case MDL_EQ:
1396       pred = do_rel_op(eqOp, if_op2_, ast1);
1397       break;
1398     case MDL_NE:
1399       pred = do_rel_op(neOp, if_op2_, ast1);
1400       break;
1401     case MDL_T_NONE:
1402       pred = new AstNode(ast1);
1403       break;
1404     default: return false;
1405     }
1406     removeAst(ast1);
1407     pred_ptr = new AstNode(pred);
1408   } // if ()
1409   else
1410     pred_ptr = NULL;
1411
1412   bool result = req_->apply(mn, pred_ptr, mn_initialized);
1413      // note: a result of true implies that "mn" was written to
1414      // Hence, a result of true from this routine means the same.
1415
1416   removeAst(pred);
1417   removeAst(pred_ptr);
1418   return result;
1419 }
1420
1421 T_dyninstRPC::mdl_expr::mdl_expr() { }
1422 T_dyninstRPC::mdl_expr::~mdl_expr() { }
1423
1424 T_dyninstRPC::mdl_v_expr::mdl_v_expr() 
1425 : args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL), type_(MDL_T_NONE),
1426   do_type_walk_(false), ok_(false) { }
1427
1428 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string var, vector<string> fields) 
1429 : var_(var), fields_(fields),
1430   args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL),
1431   type_(MDL_RVAL_DEREF), do_type_walk_(false), ok_(false) { assert(0); }
1432
1433 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string func_name,
1434                                      vector<T_dyninstRPC::mdl_expr *> *a) 
1435 : var_(func_name), args_(a),
1436   literal_(0), arg_(100000), left_(NULL), right_(NULL),
1437   type_(MDL_RVAL_FUNC), do_type_walk_(false), ok_(false) { assert(0); }
1438
1439 T_dyninstRPC::mdl_v_expr::mdl_v_expr(int int_lit) 
1440 : args_(NULL), literal_(int_lit), arg_(0), left_(NULL), right_(NULL),
1441   type_(MDL_RVAL_INT), do_type_walk_(false), ok_(false) { assert(0); }
1442
1443 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string string_lit) 
1444 : var_(string_lit),
1445   args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL),
1446   type_(MDL_RVAL_STRING), do_type_walk_(false), ok_(false) { assert(0); }
1447
1448 T_dyninstRPC::mdl_v_expr::mdl_v_expr(u_int bin_op, T_dyninstRPC::mdl_expr *left,
1449                                  T_dyninstRPC::mdl_expr *right) 
1450 : args_(NULL), literal_(0),
1451   arg_(bin_op), left_(left), right_(right),
1452   type_(MDL_RVAL_EXPR), do_type_walk_(false), ok_(false) { assert(0); }
1453
1454 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string var, u_int array_index) 
1455 : var_(var), args_(NULL), literal_(0), arg_(array_index), left_(NULL), right_(NULL),
1456   type_(MDL_RVAL_ARRAY), do_type_walk_(false), ok_(false) { assert(0); }
1457
1458 T_dyninstRPC::mdl_v_expr::~mdl_v_expr() {
1459   delete args_; delete left_; delete right_;
1460   if (args_) {
1461     unsigned size = args_->size();
1462     for (unsigned u=0; u<size; u++)
1463       delete (*args_)[u];
1464     delete args_;
1465   }
1466 }
1467
1468 bool T_dyninstRPC::mdl_v_expr::apply(mdl_var& ret) {
1469   switch (type_) {
1470   case MDL_RVAL_INT: 
1471     return (ret.set(literal_));
1472   case MDL_RVAL_STRING:
1473     return (ret.set(var_));
1474   case MDL_RVAL_ARRAY:
1475     {
1476       mdl_var array(false);
1477       if (!mdl_env::get(array, var_)) return false;
1478       if (!array.is_list()) return false;  
1479       if (arg_ >= array.list_size()) return false;
1480       return (array.get_ith_element(ret, arg_));
1481     }
1482   case MDL_RVAL_EXPR:
1483     {
1484       mdl_var left_val(false), right_val(false);
1485       if (!left_ || !right_) return false;
1486       if (!left_->apply(left_val)) return false;
1487       if (!right_->apply(right_val)) return false;
1488       return (do_operation(ret, left_val, right_val, arg_));
1489     }
1490   case MDL_RVAL_FUNC:
1491     // TODO
1492     switch (arg_) {
1493     case 0:
1494       // lookupFunction
1495       {
1496         mdl_var arg0(false);
1497         if (!(*args_)[0]->apply(arg0)) return false;
1498         string func_name;
1499         if (!arg0.get(func_name)) return false;
1500         if (global_proc) {
1501           // TODO -- what if the function is not found ?
1502           function_base *pdf = global_proc->findOneFunction(func_name);
1503           return (ret.set(pdf));
1504         } else {
1505           assert(0); return false;
1506         }
1507       }
1508     case 1:
1509       // lookupModule
1510       {
1511         mdl_var arg0(false);
1512         if (!(*args_)[0]->apply(arg0)) return false;
1513         string mod_name;
1514         if (!arg0.get(mod_name)) return false;
1515         if (global_proc) {
1516           // TODO -- what if the function is not found ?
1517           module *mod = global_proc->findModule(mod_name,false);
1518           if (!mod) { assert(0); return false; }
1519           return (ret.set(mod));
1520         } else {
1521           assert(0); return false;
1522         }
1523       }
1524     case 2:
1525       // libraryTag
1526       {
1527         mdl_var arg0(false);
1528         if (!(*args_)[0]->apply(arg0)) return false;
1529         int tag;
1530         if (!arg0.get(tag)) return false;
1531         int res = tag & TAG_LIB_FUNC;
1532         return (ret.set(res));
1533       }
1534     default:
1535       return false;
1536     }
1537   case MDL_RVAL_DEREF:
1538     if (!do_type_walk_)
1539       return (mdl_env::get(ret, var_));
1540     else
1541       return (walk_deref(ret, type_walk, var_)); 
1542   default:
1543     return false;
1544   }
1545   return true;
1546 }
1547
1548 T_dyninstRPC::mdl_if_stmt::mdl_if_stmt(T_dyninstRPC::mdl_expr *expr, T_dyninstRPC::mdl_stmt *body) : expr_(expr), body_(body) { }
1549 T_dyninstRPC::mdl_if_stmt::mdl_if_stmt() { }
1550 T_dyninstRPC::mdl_if_stmt::~mdl_if_stmt() {
1551   delete expr_; delete body_;
1552 }
1553
1554 bool T_dyninstRPC::mdl_if_stmt::apply(metricDefinitionNode *mn,
1555                                       vector<dataReqNode*>& flags) {
1556   // An if stmt is comprised of (1) the 'if' expr and (2) the body to
1557   // execute if true.
1558   mdl_var res(false);
1559   if (!expr_->apply(res))
1560     return false;
1561
1562   int iv;
1563   switch (res.type()) {
1564   case MDL_T_INT:
1565     if (!res.get(iv))
1566       return false;
1567     if (!iv)
1568       return true;
1569     break;
1570   default:
1571     return false;
1572   }
1573
1574   return body_->apply(mn, flags);
1575 }
1576
1577 T_dyninstRPC::mdl_seq_stmt::mdl_seq_stmt(vector<T_dyninstRPC::mdl_stmt*> *stmts) : stmts_(stmts) { }
1578 T_dyninstRPC::mdl_seq_stmt::mdl_seq_stmt() { }
1579 T_dyninstRPC::mdl_seq_stmt::~mdl_seq_stmt() {
1580   if (stmts_) {
1581     unsigned size = stmts_->size();
1582     for (unsigned u=0; u<size; u++)
1583       delete (*stmts_)[u];
1584     delete stmts_;
1585   }
1586 }
1587
1588 bool T_dyninstRPC::mdl_seq_stmt::apply(metricDefinitionNode *mn,
1589                                        vector<dataReqNode*>& flags) {
1590   // a seq_stmt is simply a sequence of statements; apply them all.
1591   if (!stmts_)
1592     return true;
1593
1594   unsigned size = stmts_->size();
1595   for (unsigned index=0; index<size; index++)
1596     if (!(*stmts_)[index]->apply(mn, flags)) // virtual fn call
1597       return false;
1598
1599   return true;
1600 }
1601
1602 T_dyninstRPC::mdl_list_stmt::mdl_list_stmt(u_int type, string ident,
1603                                            vector<string> *elems,
1604                                            bool is_lib, vector<string>* flavor) 
1605 : type_(type), id_(ident), elements_(elems), is_lib_(is_lib), flavor_(flavor) { }
1606 T_dyninstRPC::mdl_list_stmt::mdl_list_stmt() { }
1607 T_dyninstRPC::mdl_list_stmt::~mdl_list_stmt() { delete elements_; }
1608
1609 bool T_dyninstRPC::mdl_list_stmt::apply(metricDefinitionNode * /*mn*/,
1610                                         vector<dataReqNode*>& /*flags*/) {
1611   bool found = false;
1612   for (unsigned u0 = 0; u0 < flavor_->size(); u0++) {
1613     if ((*flavor_)[u0] == daemon_flavor) {
1614       found = true;
1615       break;
1616     }
1617   }
1618   if (!found) return false;
1619   if (!elements_) return false;
1620   mdl_var expr_var;
1621   mdl_var list_var(id_, false);
1622   unsigned size = elements_->size();
1623   if (!list_var.make_list(type_)) return false;
1624
1625   if (type_ == MDL_T_PROCEDURE_NAME) {
1626     vector<functionName*> *list_fn;
1627     bool aflag;
1628     aflag=list_var.get(list_fn);
1629     assert(aflag);
1630     for (unsigned u=0; u<size; u++) {
1631       functionName *fn = new functionName((*elements_)[u]);
1632       *list_fn += fn;
1633     }
1634   } else if (type_ == MDL_T_PROCEDURE) { 
1635     assert(0);
1636   } else if (type_ == MDL_T_MODULE) {
1637     assert(0);
1638   } else {
1639     for (unsigned u=0; u<size; u++) {
1640       int i; float f; string s; mdl_var expr_var;
1641       switch (type_) {
1642       case MDL_T_INT:
1643         if (sscanf((*elements_)[u].string_of(), "%d", &i) != 1) return false;
1644         if (!expr_var.set(i)) return false; break;
1645       case MDL_T_FLOAT:
1646         if (sscanf((*elements_)[u].string_of(), "%f", &f) != 1) return false;
1647         if (!expr_var.set(f)) return false; break;
1648       case MDL_T_STRING: 
1649         if (!expr_var.set((*elements_)[u])) return false; break;
1650       default:
1651         return false;
1652       }
1653       if (!list_var.add_to_list(expr_var)) return false;
1654     }
1655   }
1656   return (mdl_env::add(list_var));
1657 }
1658
1659 T_dyninstRPC::mdl_instr_stmt::mdl_instr_stmt(unsigned pos, T_dyninstRPC::mdl_expr *expr,
1660                                       vector<T_dyninstRPC::mdl_icode*> *reqs,
1661                                       unsigned where, bool constrained) 
1662 : position_(pos), point_expr_(expr), icode_reqs_(reqs),
1663   where_instr_(where), constrained_(constrained) { }
1664 T_dyninstRPC::mdl_instr_stmt::mdl_instr_stmt() { }
1665 T_dyninstRPC::mdl_instr_stmt::~mdl_instr_stmt() {
1666   delete point_expr_;
1667   if (icode_reqs_) {
1668     unsigned size = icode_reqs_->size();
1669     for (unsigned u=0; u<size; u++)
1670       delete (*icode_reqs_)[u];
1671     delete icode_reqs_;
1672   }
1673 }
1674
1675 bool T_dyninstRPC::mdl_instr_stmt::apply(metricDefinitionNode *mn,
1676                                          vector<dataReqNode*>& inFlags) {
1677    // An instr statement is like:
1678    //    append preInsn $constraint[0].entry constrained
1679    //       (* setCounter(procedureConstraint, 1); *)
1680    // (note that there are other kinds of statements; i.e. there are other classes
1681    //  derived from the base class mdl_stmt; see dyninstRPC.I)
1682
1683   if (icode_reqs_ == NULL)
1684     return false; // no instrumentation code to put in!
1685
1686   mdl_var pointsVar(false);
1687   if (!point_expr_->apply(pointsVar)) // process the 'point(s)' e.g. "$start.entry"
1688     return false;
1689
1690   vector<instPoint *> points;
1691   if (pointsVar.type() == MDL_T_LIST_POINT) {
1692     vector<instPoint *> *pts;
1693     if (!pointsVar.get(pts)) return false;
1694     points = *pts;
1695   } else if (pointsVar.type() == MDL_T_POINT) {
1696     instPoint *p;
1697     if (!pointsVar.get(p)) return false; // where the point is located...
1698     points += p;
1699   } else {
1700     return false;
1701   }
1702
1703   // Let's generate the code now (we used to calculate it in the loop below,
1704   // which was a waste since the code is the same for all points).
1705   AstNode *code = NULL;
1706   unsigned size = icode_reqs_->size();
1707   for (unsigned u=0; u<size; u++) {
1708     if (!(*icode_reqs_)[u]->apply(code, u>0)) {
1709       // when u is 0, code is un-initialized
1710       removeAst(code);
1711       return false;
1712     }
1713   }
1714
1715   // Instantiate all constraints (flags) here (if any)
1716   // (if !constrained_ then don't do the following)
1717   if (constrained_) {
1718      unsigned fsize = inFlags.size();
1719      for (int fi=fsize-1; fi>=0; fi--) { // any reason why we go backwards?
1720 #if defined(SHM_SAMPLING)
1721   #if defined(MT_THREAD)
1722         AstNode *tmp_ast;
1723         tmp_ast = computeAddress((void *)((inFlags[fi])->getAllocatedLevel()),(void *)((inFlags[fi])->getAllocatedIndex()), 0); // 0 is for intCounter
1724         AstNode *temp1 = new AstNode(AstNode::DataIndir,tmp_ast);
1725         removeAst(tmp_ast);
1726   #else
1727         // Note: getInferiorPtr could return a NULL pointer here if we are
1728         // just computing cost - naim 2/18/97
1729         AstNode *temp1 = new AstNode(AstNode::DataValue, 
1730                                      (void*)((inFlags[fi])->getInferiorPtr(global_proc)));
1731   #endif
1732 #else
1733         // Note: getInferiorPtr could return a NULL pointer here if we are
1734         // just computing cost - naim 2/18/97
1735         AstNode *temp1 = new AstNode(AstNode::DataValue, 
1736                                      (void*)((inFlags[fi])->getInferiorPtr()));
1737 #endif
1738         // Note: we don't use assignAst on purpose here
1739         AstNode *temp2 = code;
1740         code = createIf(temp1, temp2);
1741         removeAst(temp1);
1742         removeAst(temp2);
1743      }
1744   }
1745
1746   if (!code) {
1747     // we are probably defining an empty metric
1748     code = new AstNode();
1749   }
1750
1751   callOrder corder;
1752   switch (position_) {
1753       case MDL_PREPEND: 
1754           corder = orderFirstAtPoint; 
1755           break;
1756       case MDL_APPEND: 
1757           corder = orderLastAtPoint; 
1758           break;
1759       default: assert(0);
1760   }
1761
1762   callWhen cwhen;
1763   switch (where_instr_) {
1764       case MDL_PRE_INSN: 
1765           cwhen = callPreInsn; 
1766           break;
1767       case MDL_POST_INSN: 
1768           cwhen = callPostInsn; 
1769           break;
1770       default: assert(0);
1771   }
1772
1773   // Here is where auto-activate should occur.
1774   // If there is 1 point and it is $start.entry then
1775   // do an inferiorRPC right now (of the ast 'code').
1776   // In this way, we can get metrics like cpu and exec-time for whole program
1777   // to work correctly even when the metrics are instantiated after
1778   // the entrypoint of main() is in execution.
1779
1780   bool manuallyTrigger = false; // for now
1781
1782   if (points.size() == 1) {
1783      // now look at the mdl variable to check for $start.entry.
1784      if (pointsVar.name() == "$start" && pointsVar.type()==MDL_T_POINT) {
1785         // having a type of MDL_T_POINT should mean $start.entry as opposed to
1786         // $start.exit, since $start.exit would yield a type of MDL_T_LIST_POINT,
1787         // since exit locations are always a list-of-points.  Sorry for the kludge.
1788
1789         instPoint *theVrbleInstPoint; // NOTE: instPoint is defined in arch-specific files!!!
1790         bool aflag = pointsVar.get(theVrbleInstPoint);
1791         // theVrbleInstPoint set to equiv of points[0]
1792         assert(aflag);
1793
1794         assert(theVrbleInstPoint == points[0]); // just a sanity check
1795
1796         mdl_var theVar;
1797         string varName = pointsVar.name();
1798         aflag=mdl_env::get(theVar, varName);
1799         assert(aflag);
1800
1801         function_base *theFunction;
1802         aflag=theVar.get(theFunction);
1803         assert(aflag);
1804
1805         // Make a note to do an inferiorRPC to manually execute this code.
1806 //      if (!manuallyTrigger)
1807 //         cerr << "mdl: found $start.entry; going to manually execute via inferior-RPC" << endl;
1808
1809         manuallyTrigger = true;
1810      }
1811   }
1812
1813   // for all of the inst points, insert the predicates and the code itself.
1814   for (unsigned i = 0; i < points.size(); i++) {
1815       mn->addInst(points[i], code, cwhen, corder,
1816                   manuallyTrigger && (i==0)); // manually trigger at most once
1817          // appends an instReqNode to mn's instRequests; actual 
1818          // instrumentation only
1819          // takes place when mn->insertInstrumentation() is later called.
1820   }
1821   removeAst(code); 
1822   return true;
1823 }
1824
1825 bool mdl_can_do(string& met_name) {
1826   // NOTE: We can do better if there's a dictionary of <metric-name> to <anything>
1827   unsigned size = mdl_data::all_metrics.size();
1828   for (unsigned u=0; u<size; u++) 
1829     if (mdl_data::all_metrics[u]->name_ == met_name)
1830       return true;
1831
1832   return false;
1833 }
1834
1835 metricDefinitionNode *mdl_do(vector< vector<string> >& canon_focus, 
1836                              string& met_name,
1837                              string& flat_name,
1838                              vector<process *> procs,
1839                              bool replace_components_if_present,
1840                              bool computingCost) {
1841   currentMetric = met_name;
1842   unsigned size = mdl_data::all_metrics.size();
1843   // NOTE: We can do better if there's a dictionary of <metric-name> to <metric>!
1844   for (unsigned u=0; u<size; u++) {
1845     if (mdl_data::all_metrics[u]->name_ == met_name) {
1846       return (mdl_data::all_metrics[u]->apply(canon_focus, flat_name, procs,
1847                                               replace_components_if_present,
1848                                               computingCost));
1849          // calls mdl_metric::apply()
1850     }
1851   }
1852   return NULL;
1853 }
1854
1855 bool mdl_init(string& flavor) { 
1856
1857   daemon_flavor = flavor;
1858
1859 #ifdef notdef
1860   vector<mdl_type_desc> kids;
1861   mdl_type_desc self, kid;
1862   mdl_focus_element fe;
1863
1864   self.name = "SyncObject"; self.type = 0; self.end_allowed = false; 
1865   kid.name = "Message"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1866   kid.name = "Barrier"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1867   kid.name = "Semaphore"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1868   kid.name = "SpinLock"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1869   fe.self = self; fe.kids = kids;
1870   mdl_data::foci += fe;
1871   kids.resize(0);
1872
1873 //  self.name = "Procedure"; self.type = MDL_T_MODULE; self.end_allowed = true;
1874   self.name = "Code"; self.type = MDL_T_MODULE; self.end_allowed = true;
1875   kid.name = "Module"; kid.type = MDL_T_PROCEDURE; self.end_allowed = true; kids += kids;
1876   fe.self = self; fe.kids = kids;
1877   mdl_data::foci += fe;
1878   kids.resize(0);
1879
1880   self.name = "Process"; self.type = MDL_T_PROCESS; self.end_allowed = true;
1881   fe.self = self; fe.kids.resize(0);
1882   mdl_data::foci += fe;
1883
1884   self.name = "Machine"; self.type = MDL_T_STRING; self.end_allowed = true;
1885   fe.self = self; fe.kids.resize(0);
1886   mdl_data::foci += fe;
1887 #endif
1888
1889   mdl_env::push();
1890   // These are pushed on per-process
1891   // mdl_env::add("$procedures", false, MDL_T_LIST_PROCEDURE);
1892   // mdl_env::add("$modules", false, MDL_T_LIST_MODULE);
1893
1894   string vname = "$machine";
1895   mdl_env::add(vname, false, MDL_T_STRING);
1896   string nodename = getHostName();
1897   mdl_env::set(nodename, vname);
1898
1899   /* Are these entered by hand at the new scope ? */
1900   /* $arg, $return */
1901
1902   vector<mdl_type_desc> field_list;
1903   mdl_type_desc desc;
1904   desc.name = "name"; desc.type = MDL_T_STRING; field_list += desc;
1905   desc.name = "calls"; desc.type = MDL_T_LIST_POINT; field_list += desc;
1906   desc.name = "entry"; desc.type = MDL_T_POINT; field_list += desc;
1907   desc.name = "return"; desc.type = MDL_T_POINT; field_list += desc;
1908   desc.name = "tag"; desc.type = MDL_T_INT; field_list += desc;
1909   mdl_data::fields[MDL_T_PROCEDURE] = field_list;
1910   field_list.resize(0);
1911
1912   desc.name = "name"; desc.type = MDL_T_STRING; field_list += desc;
1913   desc.name = "funcs"; desc.type = MDL_T_LIST_PROCEDURE; field_list += desc;
1914   mdl_data::fields[MDL_T_MODULE] = field_list;
1915   field_list.resize(0);
1916
1917   desc.name = "upper"; desc.type = MDL_T_INT; field_list += desc;
1918   desc.name = "lower"; desc.type = MDL_T_INT; field_list += desc;
1919   mdl_data::fields[MDL_T_VARIABLE] = field_list;
1920   field_list.resize(0);
1921
1922   return true;
1923 }
1924
1925 void dynRPC::send_metrics(vector<T_dyninstRPC::mdl_metric*>* var_0) {
1926   mdl_met = true;
1927
1928   if (var_0) {
1929     unsigned var_size = var_0->size();
1930     for (unsigned v=0; v<var_size; v++) {
1931       // fprintf(stderr, "Got metric %s\n", (*var_0)[v]->name_.string_of());
1932       // fflush(stderr);
1933       bool found = false;
1934       unsigned f_size = (*var_0)[v]->flavors_->size();
1935
1936       bool flavor_found = false;
1937       for (unsigned f=0; f<f_size; f++) {
1938         if ((*(*var_0)[v]->flavors_)[f] == daemon_flavor) {
1939           flavor_found = true; break;
1940         }
1941       }
1942       if (flavor_found) {
1943         unsigned size=mdl_data::all_metrics.size();
1944         for (unsigned u=0; u<size; u++) 
1945           if (mdl_data::all_metrics[u]->id_ == (*var_0)[v]->id_) {
1946             delete mdl_data::all_metrics[u];
1947             mdl_data::all_metrics[u] = (*var_0)[v];
1948             found = true;
1949           }
1950         if (!found) {
1951           T_dyninstRPC::mdl_metric *m = (*var_0)[v];
1952           mdl_data::all_metrics += m;
1953         }
1954       }
1955     }
1956   } else {
1957      fprintf(stderr, "no metric defined\n");
1958      fflush(stderr);
1959   }
1960 }
1961
1962 void dynRPC::send_constraints(vector<T_dyninstRPC::mdl_constraint*> *cv) {
1963
1964   mdl_cons = true;
1965   if (cv) {
1966     unsigned var_size = cv->size();
1967     for (unsigned v=0; v<var_size; v++) {
1968       bool found = false;
1969       // cout << "Received " << (*cv)[v]->id_ << endl;
1970       for (unsigned u=0; u<mdl_data::all_constraints.size(); u++) 
1971         if (mdl_data::all_constraints[u]->id_ == (*cv)[v]->id_) {
1972           delete mdl_data::all_constraints[u];
1973           mdl_data::all_constraints[u] = (*cv)[v];
1974           found = true;
1975         }
1976       if (!found) {
1977         mdl_data::all_constraints += (*cv)[v];
1978         // cout << *(*cv)[v] << endl;
1979       }
1980     }
1981   }
1982 }
1983
1984
1985 // TODO -- are these executed immediately ?
1986 void dynRPC::send_stmts(vector<T_dyninstRPC::mdl_stmt*> *vs) {
1987   mdl_stmt = true;
1988   if (vs) {
1989     // ofstream of("other_out", (been_here ? ios::app : ios::out));
1990     // been_here = true;
1991     // of << "SEND_STMTS\n";
1992     // unsigned size = vs->size();
1993     // for (unsigned u=0; u<size; u++) 
1994     // (*vs)[u]->print(of);
1995     mdl_data::stmts += *vs;
1996
1997     // TODO -- handle errors here
1998     // TODO -- apply these statements without a metric definition node ?
1999     unsigned s_size = vs->size();
2000     vector<dataReqNode*> flags;
2001
2002     // Application may fail if the list flavor is different than the flavor
2003     // of this daemon
2004
2005     for (unsigned s=0; s<s_size; s++) {
2006       if (!(*vs)[s]->apply(NULL, flags)) 
2007         ;
2008       // (*vs)[s]->print(cout);
2009       // cout << endl;
2010     }
2011   }
2012 }
2013
2014 // recieves the list of shared libraries to exclude 
2015 void dynRPC::send_libs(vector<string> *libs) {
2016
2017     mdl_libs = true;
2018     cerr << "void dynRPC::send_libs(vector<string> *libs) called" << endl;
2019     for(u_int i=0; i < libs->size(); i++){
2020         mdl_data::lib_constraints += (*libs)[i]; 
2021         cerr << " send_libs : adding " << (*libs)[i] << " to paradynd set of mdl_data::lib_constraints" << endl;
2022     }
2023
2024 }
2025
2026 // recieves notification that there are no excluded libraries 
2027 void dynRPC::send_no_libs() {
2028     mdl_libs = true;
2029 }
2030
2031 static bool do_operation(mdl_var& ret, mdl_var& left_val,
2032                          mdl_var& right_val, unsigned bin_op) {
2033   switch (bin_op) {
2034   case MDL_PLUS:
2035   case MDL_MINUS:
2036   case MDL_DIV:
2037   case MDL_MULT:
2038     if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
2039       int v1, v2;
2040       if (!left_val.get(v1)) return false;
2041       if (!right_val.get(v2)) return false;
2042       switch (bin_op) {
2043       case MDL_PLUS: return (ret.set(v1+v2));
2044       case MDL_MINUS: return (ret.set(v1-v2));
2045       case MDL_DIV: return (ret.set(v1/v2));
2046       case MDL_MULT: return (ret.set(v1*v2));
2047       }
2048     } else if (((left_val.type() == MDL_T_INT) || (left_val.type() == MDL_T_FLOAT)) &&
2049                ((right_val.type() == MDL_T_INT) || (right_val.type() == MDL_T_FLOAT))) {
2050       float v1, v2;
2051       if (left_val.type() == MDL_T_INT) {
2052         int i1; if (!left_val.get(i1)) return false; v1 = (float)i1;
2053       } else {
2054         if (!left_val.get(v1)) return false;
2055       }
2056       if (right_val.type() == MDL_T_INT) {
2057         int i1; if (!right_val.get(i1)) return false; v2 = (float)i1;
2058       } else {
2059         if (!right_val.get(v2)) return false;
2060       }
2061       switch (bin_op) {
2062       case MDL_PLUS: return (ret.set(v1+v2));
2063       case MDL_MINUS: return (ret.set(v1-v2));
2064       case MDL_DIV: return (ret.set(v1/v2));
2065       case MDL_MULT: return (ret.set(v1*v2));
2066       }
2067     } else
2068       return false;
2069   case MDL_LT:
2070   case MDL_GT:
2071   case MDL_LE:
2072   case MDL_GE:
2073   case MDL_EQ:
2074   case MDL_NE:
2075     if ((left_val.type() == MDL_T_STRING) && (right_val.type() == MDL_T_STRING)) {
2076       string v1, v2;
2077       if (!left_val.get(v1)) return false;
2078       if (!right_val.get(v2)) return false;
2079       switch (bin_op) {
2080       case MDL_LT: return (ret.set(v1 < v2));
2081       case MDL_GT: return (ret.set(v1 > v2));
2082       case MDL_LE: return (ret.set(v1 <= v2));
2083       case MDL_GE: return (ret.set(v1 >= v2));
2084       case MDL_EQ: return (ret.set(v1 == v2));
2085       case MDL_NE: return (ret.set(v1 != v2));
2086       }  
2087     }
2088     if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
2089       int v1, v2;
2090       if (!left_val.get(v1)) return false;
2091       if (!right_val.get(v2)) return false;
2092       switch (bin_op) {
2093       case MDL_LT: return (ret.set(v1 < v2));
2094       case MDL_GT: return (ret.set(v1 > v2));
2095       case MDL_LE: return (ret.set(v1 <= v2));
2096       case MDL_GE: return (ret.set(v1 >= v2));
2097       case MDL_EQ: return (ret.set(v1 == v2));
2098       case MDL_NE: return (ret.set(v1 != v2));
2099       }
2100     } else if (((left_val.type() == MDL_T_INT) ||
2101                 (left_val.type() == MDL_T_FLOAT)) &&
2102                ((right_val.type() == MDL_T_INT) ||
2103                 (right_val.type() == MDL_T_FLOAT))) {
2104       float v1, v2;
2105       if (left_val.type() == MDL_T_INT) {
2106         int i1; if (!left_val.get(i1)) return false; v1 = (float)i1;
2107       } else {
2108         if (!left_val.get(v1)) return false;
2109       }
2110       if (right_val.type() == MDL_T_INT) {
2111         int i1; if (!right_val.get(i1)) return false; v2 = (float)i1;
2112       } else {
2113         if (!right_val.get(v2)) return false;
2114       }
2115       switch (bin_op) {
2116       case MDL_LT: return (ret.set(v1 < v2));
2117       case MDL_GT: return (ret.set(v1 > v2));
2118       case MDL_LE: return (ret.set(v1 <= v2));
2119       case MDL_GE: return (ret.set(v1 >= v2));
2120       case MDL_EQ: return (ret.set(v1 == v2));
2121       case MDL_NE: return (ret.set(v1 != v2));
2122       }
2123     } else
2124       return false;
2125   case MDL_AND:
2126   case MDL_OR:
2127     if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
2128       int v1, v2;
2129       if (!left_val.get(v1)) return false;
2130       if (!right_val.get(v2)) return false;
2131       switch (bin_op) {
2132       case MDL_AND: return (ret.set(v1 && v2));
2133       case MDL_OR: return (ret.set(v1 || v2));
2134       }
2135     } else
2136       return false;
2137   default:
2138       return false;
2139   }
2140   return false;
2141 }
2142
2143 static bool walk_deref(mdl_var& ret, vector<unsigned>& types, string& var_name) {
2144
2145   function_base *pdf = 0;
2146   if (!mdl_env::get(ret, var_name)) return false;
2147   
2148   unsigned index=0;
2149   unsigned max = types.size();
2150
2151   while (index < max) {
2152     unsigned current_type = types[index++];
2153     unsigned next_field = types[index++];
2154
2155     switch (current_type) {
2156     case MDL_T_PROCEDURE:
2157       // function_base *pdf = 0;
2158       if (!ret.get(pdf)) return false;
2159       switch (next_field) {
2160       case 0: {
2161         string prettyName = pdf->prettyName();
2162         if (!ret.set(prettyName)) return false;
2163         break;
2164       }
2165       // TODO: should these be passed a process?  yes, they definitely should!
2166       case 1:
2167         {
2168           //
2169           /*****
2170             here we should check the calls and exclude the calls to fns in the
2171             global_excluded_funcs list.
2172             *****/
2173           // ARI -- This is probably the spot!
2174
2175           vector<instPoint*> calls = pdf->funcCalls(global_proc);
2176           // makes a copy of the return value (on purpose), since we may delete some
2177           // items that shouldn't be a call site for this metric.
2178           bool anythingRemoved = false; // so far
2179
2180           metric_cerr << "global_excluded_funcs size is: "
2181                       << global_excluded_funcs.size() << endl;
2182
2183           metric_cerr << "pdf->funcCalls() returned the following call sites:" << endl;
2184           for (unsigned u = 0; u < calls.size(); u++) { // calls.size() can change!
2185              metric_cerr << u << ") ";
2186
2187              instPoint *point = calls[u];
2188              function_base *callee = (function_base*)point->iPgetCallee();
2189                 // cast discards const
2190
2191              const char *callee_name=NULL;
2192
2193              if (callee == NULL) {
2194                 // call Tia's new process::findCallee() to fill in point->callee
2195                 if (!global_proc->findCallee(*point, callee)) {
2196                    // an unanalyzable function call; sorry.
2197                    callee_name = NULL;
2198                    metric_cerr << "-unanalyzable-" << endl;
2199                 }
2200                 else {
2201                    // success -- either (a) the call has been bound already, in which
2202                    // case the instPoint is updated _and_ callee is set, or (b) the
2203                    // call hasn't yet been bound, in which case the instPoint isn't
2204                    // updated but callee *is* updated.
2205                    callee_name = callee->prettyName().string_of();
2206                    metric_cerr << "(successful findCallee() was required) "
2207                                 << callee_name << endl;
2208                 }
2209              }
2210              else {
2211                 callee_name = callee->prettyName().string_of();
2212                 metric_cerr << "(easy case) " << callee->prettyName() << endl;
2213              }
2214
2215              // If this callee is in global_excluded_funcs for this metric (a global
2216              // vrble...sorry for that), then it's not really a callee (for this
2217              // metric, at least), and thus, it should be removed from whatever
2218              // we eventually pass to "ret.set()" below.
2219
2220              if (callee_name != NULL) // could be NULL (e.g. indirect fn call)
2221                 for (unsigned lcv=0; lcv < global_excluded_funcs.size(); lcv++) {
2222                   if (0==strcmp(global_excluded_funcs[lcv].string_of(), callee_name)) {
2223                       anythingRemoved = true;
2224
2225                       // remove calls[u] from calls.  To do this, swap
2226                       // calls[u] with calls[maxndx], and resize-1.
2227                       const unsigned maxndx = calls.size()-1;
2228                       calls[u] = calls[maxndx];
2229                       calls.resize(maxndx);
2230
2231                       metric_cerr << "removed something! -- " << callee_name << endl;
2232
2233                       break;
2234                   }
2235                 }
2236           }
2237
2238           if (!anythingRemoved) {
2239              metric_cerr << "nothing was removed -- doing set() now" << endl;
2240              vector<instPoint*> *setMe = (vector<instPoint*> *) &pdf->funcCalls(global_proc);
2241              if (!ret.set(setMe))
2242                 return false;
2243           }
2244           else {
2245              metric_cerr << "something was removed! -- doing set() now" << endl;
2246              vector<instPoint*> *setMe = new vector<instPoint*>(calls);
2247              assert(setMe);
2248              
2249              if (!ret.set(setMe))
2250                 return false;
2251
2252              // WARNING: "setMe" will now be leaked memory!  The culprit is
2253              // "ret", which can only take in a _pointer_ to a vector of instPoint*'s;
2254              // it can't take in a vector of instPoints*'s, which we'd prefer.
2255           }
2256         }
2257         break;
2258       case 2: 
2259         if (!ret.set((instPoint *)pdf->funcEntry(global_proc)))
2260         return false; 
2261         break;
2262       case 3:
2263         if (!ret.set((vector<instPoint *>*)&pdf->funcExits(global_proc)))
2264           return false;
2265         break;
2266       case 4:
2267         if (!ret.set((int)pdf->tag()))
2268           return false;
2269         break;
2270       default:
2271         assert(0);
2272         break;
2273       }
2274       break;
2275     case MDL_T_MODULE:
2276       module *mod;
2277       if (!ret.get(mod)) return false;
2278       switch (next_field) {
2279       case 0: { string fileName = mod->fileName();
2280                 if (!ret.set(fileName)) return false; 
2281               } break;
2282       case 1: {
2283         if (global_proc) {
2284             // this is the correct thing to do...get only the included funcs
2285             // associated with this module, but since we seem to be testing
2286             // for global_proc elsewhere in this file I guess we will here too
2287             if (!ret.set(global_proc->getIncludedFunctions(mod))) return false; 
2288         }
2289         else {
2290             // if there is not a global_proc, then just get all functions
2291             // associtated with this module....under what circumstances
2292             // would global_proc == 0 ???
2293             if (!ret.set(mod->getFunctions())) return false; 
2294         }
2295         break;
2296       }
2297       default: assert(0); break;               
2298       }
2299       break;
2300     default:
2301       assert(0); return false;
2302     }
2303   }
2304   return true;
2305 }
2306
2307
2308 bool mdl_get_initial(string flavor, pdRPC *connection) {
2309   mdl_init(flavor);
2310   while (!(mdl_met && mdl_cons && mdl_stmt && mdl_libs)) {
2311     switch (connection->waitLoop()) {
2312     case T_dyninstRPC::error:
2313       cerr << "mdl_get_initial flavor = " << flavor.string_of() \
2314           << " connection = " << connection << \
2315           "  error in connection->waitLoop()" << endl;
2316       return false;
2317     default:
2318       break;
2319     }
2320     while (connection->buffered_requests()) {
2321       switch (connection->process_buffered()) {
2322       case T_dyninstRPC::error:
2323         cerr << "mdl_get_initial flavor = " << flavor.string_of() \
2324           << " connection = " << connection << \
2325           "  error in connection->processBuffered()" << endl;
2326         return false;
2327       default:
2328         break;
2329       }
2330     }
2331   }
2332   return true;
2333 }
2334
2335 bool mdl_get_lib_constraints(vector<string> &lc){
2336     for(u_int i=0; i < mdl_data::lib_constraints.size(); i++){
2337         lc += mdl_data::lib_constraints[i];
2338     }
2339     return (lc.size()>0);
2340 }
2341
2342 void mdl_get_info(vector<T_dyninstRPC::metricInfo>& metInfo) {
2343   unsigned size = mdl_data::all_metrics.size();
2344   T_dyninstRPC::metricInfo element;
2345   for (unsigned u=0; u<size; u++) {
2346     element.name = mdl_data::all_metrics[u]->name_;
2347     element.style = mdl_data::all_metrics[u]->style_;
2348     element.aggregate = mdl_data::all_metrics[u]->agg_op_;
2349     element.units = mdl_data::all_metrics[u]->units_;
2350     element.developerMode = mdl_data::all_metrics[u]->developerMode_;
2351     element.unitstype = mdl_data::all_metrics[u]->unitstype_;
2352     metInfo += element;
2353   }
2354 }
2355
2356 bool mdl_metric_data(const string& met_name, mdl_inst_data& md) {
2357   unsigned size = mdl_data::all_metrics.size();
2358   for (unsigned u=0; u<size; u++)
2359     if (mdl_data::all_metrics[u]->name_ == met_name) {
2360       md.aggregate = mdl_data::all_metrics[u]->agg_op_;
2361       md.style = (metricStyle) mdl_data::all_metrics[u]->style_;
2362       return true;
2363     }
2364   return false;
2365 }
2366
2367 //
2368 // Compute the list of excluded functions recursively. 
2369 // The mk_list functions are similar to apply, but they make a list
2370 // of the excluded functions
2371 // 
2372
2373 bool T_dyninstRPC::mdl_list_stmt::mk_list(vector<string> &funcs);
2374 bool T_dyninstRPC::mdl_for_stmt::mk_list(vector<string> &funcs);
2375 bool T_dyninstRPC::mdl_if_stmt::mk_list(vector<string> &funcs);
2376 bool T_dyninstRPC::mdl_seq_stmt::mk_list(vector<string> &funcs);
2377 bool T_dyninstRPC::mdl_instr_stmt::mk_list(vector<string> &funcs);
2378
2379 bool T_dyninstRPC::mdl_v_expr::mk_list(vector<string> &funcs);
2380
2381 bool T_dyninstRPC::mdl_v_expr::mk_list(vector<string> &funcs) {
2382   switch (type_) {
2383   case MDL_RVAL_INT: 
2384   case MDL_RVAL_STRING:
2385     return true;
2386   case MDL_RVAL_ARRAY:
2387     {
2388       mdl_var array(false);
2389       mdl_var elem(false);
2390       if (!mdl_env::get(array, var_)) return false;
2391       if (!array.is_list()) return false;
2392       if (arg_ >= array.list_size()) return false;
2393       if (!array.get_ith_element(elem, arg_)) return false;
2394       if (elem.get_type() == MDL_T_PROCEDURE_NAME) {
2395         functionName *fn;
2396         elem.get(fn);
2397         funcs += fn->get();
2398       }
2399       return true;
2400     }
2401   case MDL_RVAL_EXPR: {
2402       if (!left_ || !right_) return false;
2403       if (!left_->mk_list(funcs)) return false;
2404       if (!right_->mk_list(funcs)) return false;
2405       return true;
2406   }
2407   case MDL_RVAL_FUNC:
2408     return true;
2409     // TODO: should we add anything to the list here?
2410     // It seems that lookupFunction and lookupModule are useless, they can never
2411     // be used in a valid MDL expression.
2412 #ifdef notdef
2413     switch (arg_) {
2414     case 0:
2415       // lookupFunction
2416       {
2417        mdl_var arg0(false);
2418        if (!(*args_)[0]->apply(arg0)) return false;
2419        string func_name;
2420        if (!arg0.get(func_name)) return false;
2421        if (global_proc) {
2422           // TODO -- what if the function is not found ?
2423          function_base *pdf = global_proc->findOneFunction(func_name);
2424          return (ret.set(pdf));
2425        } else {
2426          assert(0); return false;
2427        }
2428       }
2429     case 1:
2430       // lookupModule
2431       {
2432        mdl_var arg0(false);
2433        if (!(*args_)[0]->apply(arg0)) return false;
2434        string mod_name;
2435        if (!arg0.get(mod_name)) return false;
2436        if (global_proc) {
2437          // TODO -- what if the function is not found ?
2438          module *mod = global_proc->findModule(mod_name,false);
2439          if (!mod) { assert(0); return false; }
2440          return (ret.set(mod));
2441        } else {
2442          assert(0); return false;
2443        }
2444       }
2445     case 2:
2446       break;
2447     default:
2448       return false;
2449  }
2450 #endif
2451   case MDL_RVAL_DEREF:
2452     return true;
2453     break;
2454   default:
2455     return false;
2456  }
2457   return true;
2458 }
2459
2460
2461 bool T_dyninstRPC::mdl_list_stmt::mk_list(vector<string> &funcs) {
2462   if (type_ == MDL_T_PROCEDURE_NAME) {
2463     unsigned size = elements_->size();
2464     for (unsigned u = 0; u < size; u++)
2465       funcs += (*elements_)[u];
2466   }
2467   return true;
2468 }
2469
2470 bool T_dyninstRPC::mdl_for_stmt::mk_list(vector<string> &funcs) {
2471   mdl_env::push();
2472   mdl_var list_var(false);
2473
2474   if (!list_expr_->apply(list_var)) {
2475     mdl_env::pop();
2476    return false;
2477   }
2478   if (!list_var.is_list()) {
2479     mdl_env::pop();
2480     return false;
2481   }
2482
2483   if (list_var.element_type() == MDL_T_PROCEDURE_NAME) {
2484     vector<functionName *> *funcNames;
2485     if (!list_var.get(funcNames)) {
2486       mdl_env::pop();
2487       return false;
2488     }    
2489     for (unsigned u = 0; u < funcNames->size(); u++)
2490        funcs += (*funcNames)[u]->get();
2491   }
2492
2493   if (!for_body_->mk_list(funcs)) {
2494     mdl_env::pop();
2495     return false;
2496   }
2497   mdl_env::pop();
2498   return true;
2499 }
2500
2501 bool T_dyninstRPC::mdl_if_stmt::mk_list(vector<string> &funcs) {
2502   return expr_->mk_list(funcs) && body_->mk_list(funcs);
2503 }
2504
2505 bool T_dyninstRPC::mdl_seq_stmt::mk_list(vector<string> &funcs) {
2506   for (unsigned u = 0; u < stmts_->size(); u++) {
2507     if (!(*stmts_)[u]->mk_list(funcs))
2508       return false;
2509   }
2510   return true;
2511 }
2512
2513 bool T_dyninstRPC::mdl_instr_stmt::mk_list(vector<string> &funcs) {
2514   return point_expr_->mk_list(funcs);
2515 }
2516
2517 bool T_dyninstRPC::mdl_constraint::mk_list(vector<string> &funcs) {
2518   for (unsigned u = 0; u < stmts_->size(); u++)
2519     (*stmts_)[u]->mk_list(funcs);
2520   return true;
2521 }