Introduced START_NAME macro; usually set to "main", but paradyndCM5_blz
[dyninst.git] / paradynd / src / mdl.C
1
2
3
4 /* 
5  * $Log: mdl.C,v $
6  * Revision 1.16  1995/12/26 23:04:16  zhichen
7  * Introduced START_NAME macro; usually set to "main", but paradyndCM5_blz
8  * sets it to init_blk_acc.
9  *
10  * Revision 1.15  1995/12/18  23:27:02  newhall
11  * changed metric's units type to have one of three values (normalized,
12  * unnormalized, or sampled)
13  *
14  * Revision 1.14  1995/12/15 22:26:54  mjrg
15  * Merged paradynd and paradyndPVM
16  * Get module name for functions from symbol table in solaris
17  * Fixed code generation for multiple instrumentation statements
18  * Changed syntax of MDL resource lists
19  *
20  * Revision 1.13  1995/11/30 16:54:11  naim
21  * Minor fix - naim
22  *
23  * Revision 1.12  1995/11/28  15:55:45  naim
24  * Minor fix - naim
25  *
26  * Revision 1.11  1995/11/22  00:10:05  mjrg
27  * Fixed "constrained" feature of MDL (fixed by Jeff, commited by mjrg)
28  *
29  * Revision 1.10  1995/11/21 15:14:27  naim
30  * Changing the MDL grammar to allow more flexible metric definitions (i.e. we
31  * can specify all elements in any order). Additionally, the option "fold"
32  * has been removed - naim
33  *
34  * Revision 1.9  1995/11/17  17:24:26  newhall
35  * support for MDL "unitsType" option, added normalized member to metric class
36  *
37  * Revision 1.8  1995/11/13  14:52:55  naim
38  * Adding "mode" option to the Metric Description Language to allow specificacion
39  * of developer mode for metrics (default mode is "normal") - naim
40  *
41  * Revision 1.7  1995/09/26  20:28:47  naim
42  * Minor warning fixes and some other minor error messages fixes
43  *
44  * Revision 1.6  1995/09/18  18:31:01  newhall
45  * fixed switch stmt. scope problem
46  *
47  * Revision 1.5  1995/08/24  15:04:14  hollings
48  * AIX/SP-2 port (including option for split instruction/data heaps)
49  * Tracing of rexec (correctly spawns a paradynd if needed)
50  * Added rtinst function to read getrusage stats (can now be used in metrics)
51  * Critical Path
52  * Improved Error reporting in MDL sematic checks
53  * Fixed MDL Function call statement
54  * Fixed bugs in TK usage (strings passed where UID expected)
55  *
56  *
57  */
58
59 #include <iostream.h>
60 #include <stdio.h>
61 #include "dyninstRPC.xdr.SRVR.h"
62 #include "paradyn/src/met/globals.h"
63 #include "paradynd/src/metric.h"
64 #include "paradynd/src/inst.h"
65 #include "paradynd/src/ast.h"
66 #include "paradynd/src/main.h"
67 #include "paradynd/src/symtab.h"
68 #include "util/h/Timer.h"
69 #include <strstream.h>
70 #include "paradynd/src/mdld.h"
71
72 #ifdef paradyndCM5_blizzard
73 // START_NAME corresponds some routine with $start of your mdl
74 // Usually, main is what you want; blizzard needs something different
75 #define START_NAME "init_blk_acc" 
76 #else
77 #define START_NAME "main"
78 #endif
79
80 static string daemon_flavor;
81 static process *global_proc = NULL;
82 static bool mdl_met=false, mdl_cons=false, mdl_stmt=false;
83
84 inline unsigned ui_hash(const unsigned &u) { return u; }
85
86 vector<unsigned> mdl_env::frames;
87 vector<mdl_var> mdl_env::all_vars;
88
89 vector<T_dyninstRPC::mdl_stmt*> mdl_data::stmts;
90 vector<T_dyninstRPC::mdl_metric*> mdl_data::all_metrics;
91 dictionary_hash<unsigned, vector<mdl_type_desc> > mdl_data::fields(ui_hash);
92 vector<mdl_focus_element> mdl_data::foci;
93 vector<T_dyninstRPC::mdl_constraint*> mdl_data::all_constraints;
94
95 static bool walk_deref(mdl_var& ret, vector<unsigned>& types, string& var_name);
96 static bool do_operation(mdl_var& ret, mdl_var& left, mdl_var& right, unsigned bin_op);
97 static AstNode *do_instr_rand(u_int arg_type, u_int arg_val, string& arg_name, string& a2);
98
99 class list_closure {
100 public:
101   list_closure(string& i_name, mdl_var& list_v)
102     : index_name(i_name), element_type(0), index(0), int_iter(NULL), float_iter(NULL),
103   string_iter(NULL), bool_iter(NULL), func_iter(NULL), mod_iter(NULL), max(0)
104   {
105     assert(list_v.is_list());
106
107     element_type = list_v.element_type();
108     switch(element_type) {
109     case MDL_T_INT:
110       assert(list_v.get(int_iter)); max = int_iter->size(); break;
111     case MDL_T_FLOAT:
112       assert(list_v.get(float_iter)); max = float_iter->size(); break;
113     case MDL_T_STRING:
114       assert(list_v.get(string_iter)); max = string_iter->size(); break;
115     case MDL_T_PROCEDURE:
116       assert(list_v.get(func_iter));
117       max = func_iter->size();
118       break;
119     case MDL_T_MODULE:
120       assert(list_v.get(mod_iter));
121       max = mod_iter->size();
122       break;
123     case MDL_T_POINT:
124       assert(list_v.get(point_iter));
125       max = point_iter->size();
126       break;
127     default:
128       assert(0);
129     }
130   }
131   ~list_closure() { }
132   bool next() {
133     string s;
134     pdFunction *pdf; module *m;
135     float f; int i;
136     instPoint *ip;
137
138     if (index >= max) return false;
139     switch(element_type) {
140     case MDL_T_INT:
141       i = (*int_iter)[index++];      return (mdl_env::set(i, index_name));
142     case MDL_T_FLOAT:
143       f = (*float_iter)[index++];    return (mdl_env::set(f, index_name));
144     case MDL_T_STRING:
145       s = (*string_iter)[index++];   return (mdl_env::set(s, index_name));
146     case MDL_T_PROCEDURE:
147       pdf = (*func_iter)[index++];
148       // cout << "Function: " << pdf->prettyName() << endl;
149       return (mdl_env::set(pdf, index_name));
150     case MDL_T_MODULE: 
151       m = (*mod_iter)[index++];      return (mdl_env::set(m, index_name));
152     case MDL_T_POINT:
153       ip = (*point_iter)[index++];   return (mdl_env::set(ip, index_name));
154     default:
155       assert(0);
156     }
157     return false;
158   }
159
160 private:
161   string index_name;
162   unsigned element_type;
163   unsigned index;
164   vector<int> *int_iter;
165   vector<float> *float_iter;
166   vector<string> *string_iter;
167   vector<bool> *bool_iter;
168   vector<pdFunction*> *func_iter;
169   vector<module*> *mod_iter;
170   vector<instPoint*> *point_iter;
171   unsigned max;
172 };
173
174 T_dyninstRPC::mdl_metric::mdl_metric(string id, string name, string units, 
175                                     u_int agg, u_int sty, u_int type,
176                                     vector<T_dyninstRPC::mdl_stmt*> *mv, 
177                                     vector<string> *flav,
178                                     vector<T_dyninstRPC::mdl_constraint*> *cons,
179                                     vector<string> *temp_counters,
180                                     bool developerMode,
181                                     int unitstype)
182 : id_(id), name_(name), units_(units), agg_op_(agg), style_(sty),
183   type_(type), stmts_(mv), flavors_(flav), constraints_(cons),
184   temp_ctr_(temp_counters), developerMode_(developerMode),
185   unitstype_(unitstype) { }
186
187 T_dyninstRPC::mdl_metric::mdl_metric() { }
188
189 T_dyninstRPC::mdl_metric::~mdl_metric() {
190   if (stmts_) {
191     unsigned size = stmts_->size();
192     for (unsigned u=0; u<size; u++)
193       delete (*stmts_)[u];
194     delete stmts_;
195   }
196   delete flavors_;
197
198   if (constraints_) {
199     unsigned size = constraints_->size();
200     for (unsigned u=0; u<size; u++)
201       delete (*constraints_)[u];
202     delete constraints_;
203   }
204
205 }
206
207 bool mdl_data::new_metric(string id, string name, string units,
208                           u_int agg, u_int sty, u_int type,
209                           vector<T_dyninstRPC::mdl_stmt*> *mv,
210                           vector<string> *flav,
211                           vector<T_dyninstRPC::mdl_constraint*> *cons,
212                           vector<string> *temp_counters,
213                           bool developerMode,
214                           int unitstype) {
215   T_dyninstRPC::mdl_metric *m = new T_dyninstRPC::mdl_metric(id, name, 
216                                                              units, agg,
217                                                              sty, type, mv,
218                                                              flav, cons,
219                                                              temp_counters,
220                                                              developerMode,
221                                                              unitstype);
222   if (!m)
223     return false;
224   else {
225     all_metrics += m;
226     return true;
227   }
228 }
229
230 static inline bool other_machine_specified(vector< vector<string> > &focus,
231                                            string& machine) {
232   assert(focus[resource::machine][0] == "Machine");
233
234   switch (focus[resource::machine].size()) {
235   case 1: break;
236   case 2:
237     if (machine != focus[resource::machine][1]) return true;
238     break;
239   default:
240     assert(0);
241   }
242   return false;
243 }
244
245 static inline void add_processes(vector< vector<string> > &focus,
246                                  vector<process*> &ip) {
247   assert(focus[resource::process][0] == "Process");
248   unsigned pi, ps;
249
250   switch(focus[resource::process].size()) {
251   case 1:
252 #ifdef sparc_tmc_cmost7_3
253     assert(nodePseudoProcess);
254     ip += nodePseudoProcess;
255 #else
256     ip = processVec;
257 #endif    
258     break;
259   case 2:
260     ps = processVec.size();
261     for (pi=0; pi<ps; pi++) 
262       if (processVec[pi]->rid->part_name() == focus[resource::process][1]) {
263         ip += processVec[pi];
264         break;
265       }
266     break;
267   default:
268     assert(0);
269   }
270 }
271
272 // TODO -- determine if a focus matches
273 // What are the rules ?
274 static inline bool focus_matches(vector<string>& focus, vector<string> *match_path) {
275   unsigned mp_size = match_path->size();
276   unsigned f_size = focus.size();
277   if (!mp_size) return false;
278   if (f_size < 2) return false;
279   if (mp_size != (f_size - 1)) return false;
280
281   if (focus[0] == (*match_path)[0])
282     return true;
283   else
284     return false;
285
286   // TODO -- I am ignoring intermediate fields in the match path
287   //      -- I only care about the first and the last fields
288 }
289
290 // Global constraints are specified by giving their name within a metric def
291 // Find the real constraint by searching the dictionary using this name
292 static inline T_dyninstRPC::mdl_constraint *flag_matches(vector<string>& focus, 
293                                                          T_dyninstRPC::mdl_constraint *match_me,
294                                                          bool& is_default) {
295   unsigned c_size = mdl_data::all_constraints.size();
296   for (unsigned cs=0; cs<c_size; cs++) 
297     if (mdl_data::all_constraints[cs]->id_ == match_me->id_) {
298       match_me = mdl_data::all_constraints[cs];
299       if (focus_matches(focus, mdl_data::all_constraints[cs]->match_path_)) {
300         if (mdl_data::all_constraints[cs]->data_type_ == MDL_T_NONE)
301           is_default = true;
302         else
303           is_default = false;
304         return match_me;
305       }
306     }
307   return NULL;
308 }
309
310 // Determine if the global and local constraints are applicable
311 // Global constraints that are applicable are put on flag_cons
312 // base_used returns the ONE replace constraint that matches
313
314 static inline bool check_constraints(vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
315                                      T_dyninstRPC::mdl_constraint *&base_used,
316                                      vector< vector<string> >& focus,
317                                      vector<T_dyninstRPC::mdl_constraint*> *cons,
318                                      vector<unsigned>& flag_dex, unsigned& base_dex) {
319   unsigned size = cons->size();
320
321   unsigned foc_size = focus.size();
322   for (unsigned fi=0; fi<foc_size; fi++) {
323     unsigned el_size = focus[fi].size();
324     if ((focus[fi][0] == "Machine") || (focus[fi][0] == "Process")) {
325       // do nothing, can't specify constraints for machine or process
326       ;
327     } else if (el_size) {
328       bool matched = false;
329       // Hack allow constraints such as "/SyncObject"
330       // However, these don't have to match
331       // Otherwise a failure to match means that the metric is invalid for the resource
332       unsigned ci=0;
333       while ((ci < size) && !matched) {
334         if (!(*cons)[ci]->match_path_) {
335           // this is an external constraint, apply if applicable
336           T_dyninstRPC::mdl_constraint *mc;
337           bool is_default;
338           if ((mc = flag_matches(focus[fi], (*cons)[ci], is_default))) {
339             matched = true;
340             if (!is_default) {
341               flag_cons += mc; flag_dex += fi;
342             }
343           }
344         } else {
345           // this could be the real constraint to use
346           // this guarantees that the first match is used
347           // TODO -- first matching replace constraint wins
348           if (focus_matches(focus[fi], (*cons)[ci]->match_path_)) {
349             matched = true;
350             base_used = (*cons)[ci]; base_dex = fi; 
351           }
352         }
353         ci++;
354       }
355       if (!matched && (el_size>1)) return false;
356     } else {
357       return false;
358     }
359   }
360   return true;
361 }
362
363 // update the interpreter environment for this processor
364 // Variable updated: $procedures, $modules, $exit, $start
365
366 static inline bool update_environment(process *proc) {
367   string vname = "$exit";
368   pdFunction *pdf = proc->symbols->findOneFunction(string(EXIT_NAME));
369   if (!pdf) return false;
370   mdl_env::add(vname, false, MDL_T_PROCEDURE);
371   mdl_env::set(pdf, vname);
372
373   vname = "$start";
374   pdf = proc->symbols->findOneFunction(string(START_NAME));
375   if (!pdf) return false;
376   mdl_env::add(vname, false, MDL_T_PROCEDURE);
377   mdl_env::set(pdf, vname);
378
379   vname = "$procedures";
380   mdl_env::add(vname, false, MDL_T_LIST_PROCEDURE);
381   mdl_env::set(&proc->symbols->mdlNormal, vname);
382
383   vname = "$modules";
384   mdl_env::add(vname, false, MDL_T_LIST_MODULE);
385   mdl_env::set(&proc->symbols->mods, vname);
386   return true;
387 }
388
389 inline dataReqNode *create_data_object(unsigned mdl_data_type,
390                                        metricDefinitionNode *mn) {
391   switch (mdl_data_type) {
392   case MDL_T_COUNTER:
393     return (mn->addIntCounter(0, true));
394   case MDL_T_WALL_TIMER:
395     return (mn->addTimer(wallTime));
396   case MDL_T_PROC_TIMER:
397     return (mn->addTimer(processTime));
398   case MDL_T_NONE:
399     // just to keep mdl apply allocate a dummy un-sampled counter.
400     return (mn->addIntCounter(0, false));
401   default:
402     assert(0);
403     return NULL;
404   }
405 }
406
407 static inline bool apply_to_process_list(vector<process*>& instProcess,
408                                          vector<metricDefinitionNode*>& parts,
409                                          string& id, string& name,
410                                          vector< vector<string> >& focus,
411                                          string& flat_name,
412                                          unsigned& agg_op,
413                                          unsigned& type,
414                                          vector<T_dyninstRPC::mdl_constraint*>& flag_cons,
415                                          T_dyninstRPC::mdl_constraint *base_use,
416                                          vector<T_dyninstRPC::mdl_stmt*> *stmts,
417                                          vector<unsigned>& flag_dex,
418                                          unsigned& base_dex,
419                                          vector<string> *temp_ctr) {
420 #ifdef DEBUG_MDL
421   timer loadTimer, totalTimer;
422   static ofstream *of=NULL;
423   if (!of) {
424     char buffer[100];
425     ostrstream osb(buffer, 100, ios::out);
426     osb << "mdl_" << "__" << getpid() << ends;
427     of = new ofstream(buffer, ios::app);
428   }
429
430   (*of) << "Instrumenting for " << name << " " << instProcess.size() << " processes\n";
431 #endif
432
433   unsigned psize = instProcess.size();
434 #ifdef DEBUG_MDL
435   totalTimer.clear(); totalTimer.start();
436 #endif
437   for (unsigned p=0; p<psize; p++) {
438 #ifdef DEBUG_MDL
439     loadTimer.clear(); loadTimer.start();  // TIMER
440 #endif
441     process *proc = instProcess[p]; assert(proc);
442     global_proc = proc;     // TODO -- global
443
444     // skip exited processes.
445     if (proc->status() == exited) continue;
446
447     if (!update_environment(proc)) return false;
448
449     // TODO -- Using aggOp value for this metric -- what about folds
450     metricDefinitionNode *mn = new metricDefinitionNode(proc, name,
451                                                         focus, flat_name, agg_op);
452
453     // Create the timer, counter
454     dataReqNode *the_node = create_data_object(type, mn);
455     assert(the_node);
456     mdl_env::set(the_node, id);
457
458     // Create the temporary counters - are these useful
459     if (temp_ctr) {
460       unsigned tc_size = temp_ctr->size();
461       for (unsigned tc=0; tc<tc_size; tc++) {
462         dataReqNode *temp_node;
463         temp_node = mn->addIntCounter(0, false);
464         mdl_env::set(temp_node, (*temp_ctr)[tc]);
465       }
466     }
467
468     unsigned flag_size = flag_cons.size();
469     vector<dataReqNode*> flags;
470     if (flag_size) {
471       for (unsigned fs=0; fs<flag_size; fs++) {
472         // TODO -- cache these created flags
473         dataReqNode *flag = NULL;
474         assert(flag_cons[fs]->apply(mn, flag, focus[flag_dex[fs]], proc));
475         assert(flag);
476         flags += flag;
477         // cout << "Applying constraint for " << flag_cons[fs]->id_ << endl;
478       }
479     }
480
481     if (base_use) {
482       dataReqNode *flag = NULL;
483       if (!base_use->apply(mn, flag, focus[base_dex], proc)) {
484         // cout << "apply of " << name << " failed\n";
485         return false;
486       }
487     } else {
488       unsigned size = stmts->size();
489       for (unsigned u=0; u<size; u++) {
490         if (!(*stmts)[u]->apply(mn, flags)) {
491           // cout << "apply of " << name << " failed\n";
492           return false;
493         }
494       }
495     }
496
497     if (mn && mn->nonNull()) 
498       parts += mn;
499     else {
500       delete mn; mn = NULL;
501     }
502 #ifdef DEBUG_MDL
503     loadTimer.stop();
504     char timeMsg[500];
505     sprintf(timeMsg, "%f::%f  ", (float) loadTimer.usecs(), (float) loadTimer.wsecs());
506     // tp->applicationIO(10, strlen(timeMsg), timeMsg);
507     (*of) << name << ":" << timeMsg << endl;
508 #endif
509   }
510 #ifdef DEBUG_MDL
511   totalTimer.stop();
512   char timeMsg[500];
513   sprintf(timeMsg, "\nTotal:  %f:user\t%f:wall\n", (float) totalTimer.usecs(),
514           (float) totalTimer.wsecs());
515   // tp->applicationIO(10, strlen(timeMsg), timeMsg);
516   (*of) << name << ":" << timeMsg << endl;
517 #endif
518
519   return true;
520 }
521
522 metricDefinitionNode *T_dyninstRPC::mdl_metric::apply(vector< vector<string> > &focus,
523                                                       string& flat_name) {
524
525   // TODO -- check to see if this is active ?
526   // TODO -- create counter or timer
527   // TODO -- put it into the environment ?
528   // TODO -- this can be passed directly -- faster - later
529   // TODO -- internal metrics
530   // TODO -- what the heck is nodePseudoProcess, why should I care about it
531   // TODO -- assume no constraints, all processes instrumented
532   // TODO -- support two-level aggregation: one at the daemon, one at paradyn
533   // TODO -- how is folding specified ?
534   // TODO -- are lists updated here ?
535
536   mdl_env::push();
537   mdl_env::add(id_, false, MDL_T_DRN);
538   assert(stmts_);
539   vector<metricDefinitionNode*> parts;
540
541   const unsigned tc_size = temp_ctr_->size();
542   for (unsigned tc=0; tc<tc_size; tc++) {
543     mdl_env::add((*temp_ctr_)[tc], false, MDL_T_DRN);
544   }
545
546   static string machine;
547   static bool machine_init= false;
548   if (!machine_init) {
549     machine_init = true;
550     struct utsname un; assert(!P_uname(&un) != -1); machine = un.nodename;
551   }
552
553   // TODO -- I am assuming that a canonical resource list is
554   // machine, procedure, process, syncobject
555
556   if (other_machine_specified(focus, machine)) return NULL;
557   vector<process*> instProcess;
558   add_processes(focus, instProcess);
559   if (!instProcess.size()) return NULL;
560
561   // build the list of constraints to use
562   vector<T_dyninstRPC::mdl_constraint*> flag_cons;
563
564   // the first replace constraint that matches, if any
565   T_dyninstRPC::mdl_constraint *base_used=NULL;
566
567   // build list of global constraints that match and choose local replace constraint
568   unsigned base_dex; vector<unsigned> flag_dex;
569   if (!check_constraints(flag_cons, base_used, focus, constraints_, flag_dex, base_dex))
570     return NULL;
571
572   // build the instrumentation request
573   if (!apply_to_process_list(instProcess, parts, id_, name_, focus,
574                              flat_name, agg_op_, type_, flag_cons, base_used,
575                              stmts_, flag_dex, base_dex, temp_ctr_))
576     return NULL;
577
578   // construct aggregate for the metric instance parts
579   metricDefinitionNode *ret = NULL;
580   switch (parts.size()) {
581   case 0: break;
582   case 1: ret = parts[0]; break;
583   default: ret = new metricDefinitionNode(name_, focus, flat_name, parts);
584   }
585
586   if (ret) ret->set_inform(true);
587
588   // cout << "apply of " << name_ << " ok\n";
589   mdl_env::pop();
590   return ret;
591 }
592
593 T_dyninstRPC::mdl_constraint::mdl_constraint() { }
594 T_dyninstRPC::mdl_constraint::mdl_constraint(string id, vector<string> *match_path,
595                                              vector<T_dyninstRPC::mdl_stmt*> *stmts,
596                                              bool replace, u_int d_type, bool& error)
597 : id_(id), match_path_(match_path), stmts_(stmts), replace_(replace),
598   data_type_(d_type), hierarchy_(0), type_(0) { }
599 T_dyninstRPC::mdl_constraint::~mdl_constraint() {
600   delete match_path_;
601   if (stmts_) {
602     for (unsigned u=0; u<stmts_->size(); u++)
603       delete (*stmts_)[u];
604     delete stmts_;
605   }
606 }
607
608 // determine the type of the trailing part of the constraint's match path
609 // and put this into the environment
610 static inline bool do_trailing_resource(unsigned& type, unsigned& hierarchy,
611                                         vector<string>& resource, process *proc) {
612   string c_string = "$constraint";
613   switch (hierarchy) {
614   case MDL_RES_CODE:
615     if (type == MDL_T_PROCEDURE) {
616       if (resource.size() != 3) return false;
617       pdFunction *pdf = proc->symbols->findOneFunction(resource[2]);
618       if (!pdf) return false;
619       mdl_env::add(c_string, false, MDL_T_PROCEDURE);
620       mdl_env::set(pdf, c_string);
621     } else if (type == MDL_T_MODULE) {
622       if (resource.size() != 2) return false;
623       module *mod = proc->symbols->findModule(resource[1]);
624       if (!mod) return false;
625       mdl_env::add(c_string, false, MDL_T_MODULE);
626       mdl_env::set(mod, c_string);
627     } else {
628       assert(0);
629     }
630     break;
631   case MDL_RES_SYNCOBJECT:
632     {
633     if (resource.size() != 3) return false;
634     if (type != MDL_T_INT) assert(0);
635     mdl_env::add(c_string, false, MDL_T_INT);
636     int tag = atoi(resource[2].string_of());
637     if (tag < 0) return false;
638     mdl_env::set(tag, c_string);
639     break;
640     }
641   case MDL_RES_PROCESS:
642   case MDL_RES_MACHINE:
643   default:
644     assert(0);
645   }
646   return true;
647 }
648
649 // Replace constraints not working yet
650 // Flag constraints need to return a handle to a data request node -- the flag
651 bool T_dyninstRPC::mdl_constraint::apply(metricDefinitionNode *mn,
652                                          dataReqNode *&flag,
653                                          vector<string>& resource,
654                                          process *proc) {
655   assert(mn);
656   switch (data_type_) {
657   case MDL_T_COUNTER:
658   case MDL_T_WALL_TIMER:
659   case MDL_T_PROC_TIMER:
660     break;
661   default:
662     assert(0);
663   }
664   mdl_env::push();
665
666   if (!replace_) {
667     // create the counter used as a flag
668     mdl_env::add(id_, false, MDL_T_DRN);
669     dataReqNode *drn = mn->addIntCounter(0, false);
670     // this flag will construct a predicate for the metric -- have to return it
671     flag = drn;
672     assert(drn);
673     mdl_env::set(drn, id_);
674   }
675
676   // put "$constraint" into the environment
677   if (!do_trailing_resource(type_, hierarchy_, resource, proc)) {
678     mdl_env::pop();
679     return false;
680   }
681
682   // Now evaluate the constraint statements
683   unsigned size = stmts_->size();
684   vector<dataReqNode*> flags;
685   for (unsigned u=0; u<size; u++) {
686     if (!(*stmts_)[u]->apply(mn, flags)) {
687       // cout << "apply of constraint " << id_ << " failed\n";
688       return false;
689     }
690   }
691   mdl_env::pop();
692   return true;
693 }
694
695 T_dyninstRPC::mdl_constraint *mdl_data::new_constraint(string id, vector<string> *path,
696                                                 vector<T_dyninstRPC::mdl_stmt*> *stmts,
697                                                 bool replace, u_int d_type) {
698   bool error;
699   return (new T_dyninstRPC::mdl_constraint(id, path, stmts, replace, d_type, error));
700 }
701
702 T_dyninstRPC::mdl_instr_req::mdl_instr_req(u_int a_type, u_int a_val, string a_name,
703                                            string arg2, u_int type, string obj_name)
704 : arg_type_(a_type), arg_val_(a_val), arg_name_(a_name), arg_name_2_(arg2),
705   type_(type), timer_counter_name_(obj_name) { }
706
707 T_dyninstRPC::mdl_instr_req::mdl_instr_req(u_int type, string obj_name)
708 : type_(type), timer_counter_name_(obj_name) { }
709
710 T_dyninstRPC::mdl_instr_req::mdl_instr_req() : type_(0) { }
711 T_dyninstRPC::mdl_instr_req::~mdl_instr_req() { }
712
713 bool T_dyninstRPC::mdl_instr_req::apply(AstNode *&mn, AstNode *pred) {
714   AstNode *ast_arg = NULL;
715   // TODO -- args to calls
716   switch (type_) {
717   case MDL_SET_COUNTER:
718   case MDL_ADD_COUNTER:
719   case MDL_SUB_COUNTER:
720   case MDL_CALL_FUNC:
721   case MDL_CALL_FUNC_COUNTER:
722     if (!(ast_arg = do_instr_rand(arg_type_, arg_val_, arg_name_, arg_name_2_)))
723       return false;
724     break;
725   }
726
727   dataReqNode *drn;
728   mdl_var get_drn;
729   if (type_ != MDL_CALL_FUNC) {
730       assert(mdl_env::get(get_drn, timer_counter_name_));
731       assert(get_drn.get(drn));
732   }
733
734   AstNode *code = NULL;
735   pdFunction *pdf;
736   switch (type_) {
737   case MDL_SET_COUNTER:
738     code = createCall("setCounter", drn, ast_arg);
739     break;
740   case MDL_ADD_COUNTER:
741     code = createCall("addCounter", drn, ast_arg);
742     break;
743   case MDL_SUB_COUNTER:
744     code = createCall("subCounter", drn, ast_arg);
745     break;
746   case MDL_START_WALL_TIMER:
747     code = createPrimitiveCall("DYNINSTstartWallTimer", drn, 0);
748     break;
749   case MDL_STOP_WALL_TIMER:
750     code = createPrimitiveCall("DYNINSTstopWallTimer", drn, 0);
751     break;
752   case MDL_START_PROC_TIMER:
753     // TODO -- are these ok?
754     code = createPrimitiveCall("DYNINSTstartProcessTimer", drn, 0);
755     break;
756   case MDL_STOP_PROC_TIMER:
757     code = createPrimitiveCall("DYNINSTstopProcessTimer", drn, 0);
758     break;
759   case MDL_CALL_FUNC:
760     pdf = global_proc->symbols->findOneFunction(string(timer_counter_name_));
761     if (!pdf) {
762         fprintf(stderr, "Unable to locate procedure %s for metric definition\n",
763                 timer_counter_name_.string_of());
764         fflush(stderr);
765         return false;
766     }
767     code = new AstNode(timer_counter_name_, ast_arg, NULL);
768     break;
769   case MDL_CALL_FUNC_COUNTER:
770     pdf = global_proc->symbols->findOneFunction(string(arg_name_));
771     if (!pdf) return false;
772     code = createPrimitiveCall(arg_name_, drn, 0);
773     break;
774   default:
775     return false;
776   }
777
778   if (pred) code = createIf(pred, code);
779
780   if (mn)
781     mn = new AstNode(mn, code);
782   else
783     mn = code;
784   return true;
785 }
786
787 T_dyninstRPC::mdl_stmt::mdl_stmt() { }
788
789 T_dyninstRPC::mdl_for_stmt::mdl_for_stmt(string index_name, T_dyninstRPC::mdl_expr *list_exp, T_dyninstRPC::mdl_stmt *body) 
790 : for_body_(body), index_name_(index_name), list_expr_(list_exp) { }
791 T_dyninstRPC::mdl_for_stmt::mdl_for_stmt() { }
792 T_dyninstRPC::mdl_for_stmt::~mdl_for_stmt() {
793   delete for_body_;
794   delete list_expr_;
795 }
796
797 bool T_dyninstRPC::mdl_for_stmt::apply(metricDefinitionNode *mn,
798                                        vector<dataReqNode*>& flags) {
799   mdl_env::push();
800   mdl_env::add(index_name_, false);
801   mdl_var list_var(false);
802
803   // TODO -- build iterator closure here -- list may be vector or dictionary
804   if (!list_expr_->apply(list_var))
805     return false;
806   if (!list_var.is_list())
807     return false;
808
809   // TODO
810   vector<pdFunction*> *vp;
811   list_var.get(vp);
812   list_closure closure(index_name_, list_var);
813
814   // mdl_env::set_type(list_var.element_type(), index_name_);
815   while (closure.next()) {
816     if (!for_body_->apply(mn, flags)) return false;
817   }
818
819   mdl_env::pop();
820   return true;
821 }
822
823 T_dyninstRPC::mdl_icode::mdl_icode() { }
824 T_dyninstRPC::mdl_icode::mdl_icode(u_int iop1, u_int ival1, string str1,
825                                    u_int iop2, u_int ival2, string str2,
826                                    u_int bin_op, bool use_if,
827                                    T_dyninstRPC::mdl_instr_req *ireq)
828 : if_op1_(iop1), if_val1_(ival1), if_str1_(str1),
829   if_op2_(iop2), if_val2_(ival2), if_str2_(str2),
830   bin_op_(bin_op), use_if_(use_if), req_(ireq) { }
831 T_dyninstRPC::mdl_icode::~mdl_icode() { delete req_; }
832
833 static inline AstNode *do_rel_op(opCode op, u_int& if_op, u_int& if_val,
834                                  string& if_str, AstNode *ast_left) {
835   AstNode *ast_right, *rel_ast=NULL;
836   assert(ast_left);
837   string empty;
838   if (!(ast_right = do_instr_rand(if_op, if_val, if_str, empty))) {
839     delete ast_left; return NULL;
840   }
841   rel_ast = new AstNode(op, ast_left, ast_right);
842   assert(rel_ast);
843   return rel_ast;
844 }
845
846 bool T_dyninstRPC::mdl_icode::apply(AstNode *&mn) {
847   // TODO -- handle the if case here
848   // TODO -- call req_->apply() after building if
849   AstNode *ast1, *pred = NULL;
850   if (!req_) return false;
851   if (use_if_) {
852     string empty;
853     if (!(ast1 = do_instr_rand(if_op1_, if_val1_, if_str1_, empty))) {
854       delete ast1; return false;
855     }
856     switch (bin_op_) {
857     case MDL_LT:
858       if (!(pred = do_rel_op(lessOp, if_op2_, if_val2_, if_str2_, ast1)))
859         return false;
860       break;
861     case MDL_GT:
862       if (!(pred = do_rel_op(greaterOp, if_op2_, if_val2_, if_str2_, ast1)))
863         return false;
864       break;
865     case MDL_LE:
866       if (!(pred = do_rel_op(leOp, if_op2_, if_val2_, if_str2_, ast1)))
867         return false;
868       break;
869     case MDL_GE:
870       if (!(pred = do_rel_op(geOp, if_op2_, if_val2_, if_str2_, ast1)))
871         return false;
872       break;
873     case MDL_EQ:
874       if (!(pred = do_rel_op(eqOp, if_op2_, if_val2_, if_str2_, ast1)))
875         return false;
876       break;
877     case MDL_NE:
878       if (!(pred = do_rel_op(neOp, if_op2_, if_val2_, if_str2_, ast1)))
879         return false;
880       break;
881     case MDL_T_NONE: pred = ast1; break;
882     default: return false;
883     }
884   }
885   return (req_->apply(mn, pred));
886 }
887
888 T_dyninstRPC::mdl_expr::mdl_expr() { }
889 T_dyninstRPC::mdl_expr::~mdl_expr() { }
890
891 T_dyninstRPC::mdl_v_expr::mdl_v_expr() 
892 : args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL), type_(MDL_T_NONE),
893   do_type_walk_(false), ok_(false) { }
894
895 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string var, vector<string> fields) 
896 : var_(var), fields_(fields),
897   args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL),
898   type_(MDL_RVAL_DEREF), do_type_walk_(false), ok_(false) { assert(0); }
899
900 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string func_name,
901                                      vector<T_dyninstRPC::mdl_expr *> *a) 
902 : var_(func_name), args_(a),
903   literal_(0), arg_(100000), left_(NULL), right_(NULL),
904   type_(MDL_RVAL_FUNC), do_type_walk_(false), ok_(false) { assert(0); }
905
906 T_dyninstRPC::mdl_v_expr::mdl_v_expr(int int_lit) 
907 : args_(NULL), literal_(int_lit), arg_(0), left_(NULL), right_(NULL),
908   type_(MDL_RVAL_INT), do_type_walk_(false), ok_(false) { assert(0); }
909
910 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string string_lit) 
911 : var_(string_lit),
912   args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL),
913   type_(MDL_RVAL_STRING), do_type_walk_(false), ok_(false) { assert(0); }
914
915 T_dyninstRPC::mdl_v_expr::mdl_v_expr(u_int bin_op, T_dyninstRPC::mdl_expr *left,
916                                  T_dyninstRPC::mdl_expr *right) 
917 : args_(NULL), literal_(0),
918   arg_(bin_op), left_(left), right_(right),
919   type_(MDL_RVAL_EXPR), do_type_walk_(false), ok_(false) { assert(0); }
920
921 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string var, u_int array_index) 
922 : var_(var), args_(NULL), literal_(0), arg_(array_index), left_(NULL), right_(NULL),
923   type_(MDL_RVAL_ARRAY), do_type_walk_(false), ok_(false) { assert(0); }
924
925 T_dyninstRPC::mdl_v_expr::~mdl_v_expr() {
926   delete args_; delete left_; delete right_;
927   if (args_) {
928     unsigned size = args_->size();
929     for (unsigned u=0; u<size; u++)
930       delete (*args_)[u];
931     delete args_;
932   }
933 }
934
935 bool T_dyninstRPC::mdl_v_expr::apply(mdl_var& ret) {
936   switch (type_) {
937   case MDL_RVAL_INT: 
938     return (ret.set(literal_));
939   case MDL_RVAL_STRING:
940     return (ret.set(var_));
941   case MDL_RVAL_ARRAY:
942     {
943       mdl_var array(false);
944       if (!mdl_env::get(array, var_)) return false;
945       if (!array.is_list()) return false;  
946       if (arg_ >= array.list_size()) return false;
947       return (array.get_ith_element(ret, arg_));
948     }
949   case MDL_RVAL_EXPR:
950     {
951       mdl_var left_val(false), right_val(false);
952       if (!left_ || !right_) return false;
953       if (!left_->apply(left_val)) return false;
954       if (!right_->apply(right_val)) return false;
955       return (do_operation(ret, left_val, right_val, arg_));
956     }
957   case MDL_RVAL_FUNC:
958     // TODO
959     switch (arg_) {
960     case 0:
961       // lookupFunction
962       {
963         mdl_var arg0(false);
964         if (!(*args_)[0]->apply(arg0)) return false;
965         string func_name;
966         if (!arg0.get(func_name)) return false;
967         if (global_proc) {
968           // TODO -- what if the function is not found ?
969           pdFunction *pdf = global_proc->symbols->findOneFunction(func_name);
970           return (ret.set(pdf));
971         } else {
972           assert(0); return false;
973         }
974       }
975     case 1:
976       // lookupModule
977       {
978         mdl_var arg0(false);
979         if (!(*args_)[0]->apply(arg0)) return false;
980         string mod_name;
981         if (!arg0.get(mod_name)) return false;
982         if (global_proc) {
983           // TODO -- what if the function is not found ?
984           module *mod = global_proc->symbols->findModule(mod_name);
985           return (ret.set(mod));
986         } else {
987           assert(0); return false;
988         }
989       }
990     case 2:
991       // libraryTag
992       {
993         mdl_var arg0(false);
994         if (!(*args_)[0]->apply(arg0)) return false;
995         int tag;
996         if (!arg0.get(tag)) return false;
997         int res = tag & TAG_LIB_FUNC;
998         return (ret.set(res));
999       }
1000     default:
1001       return false;
1002     }
1003   case MDL_RVAL_DEREF:
1004     if (!do_type_walk_)
1005       return (mdl_env::get(ret, var_));
1006     else
1007       return (walk_deref(ret, type_walk, var_)); 
1008   default:
1009     return false;
1010   }
1011   return true;
1012 }
1013
1014 T_dyninstRPC::mdl_if_stmt::mdl_if_stmt(T_dyninstRPC::mdl_expr *expr, T_dyninstRPC::mdl_stmt *body) : expr_(expr), body_(body) { }
1015 T_dyninstRPC::mdl_if_stmt::mdl_if_stmt() { }
1016 T_dyninstRPC::mdl_if_stmt::~mdl_if_stmt() {
1017   delete expr_; delete body_;
1018 }
1019
1020 bool T_dyninstRPC::mdl_if_stmt::apply(metricDefinitionNode *mn,
1021                                       vector<dataReqNode*>& flags) {
1022   mdl_var res(false); int iv;
1023   if (!expr_->apply(res))
1024     return false;
1025   switch (res.type()) {
1026   case MDL_T_INT:
1027     if (!res.get(iv))
1028       return false;
1029     if (!iv)
1030       return true;
1031     break;
1032   default:
1033     return false;
1034   }
1035   bool ret = body_->apply(mn, flags);
1036   return ret;
1037 }
1038
1039 T_dyninstRPC::mdl_seq_stmt::mdl_seq_stmt(vector<T_dyninstRPC::mdl_stmt*> *stmts) : stmts_(stmts) { }
1040 T_dyninstRPC::mdl_seq_stmt::mdl_seq_stmt() { }
1041 T_dyninstRPC::mdl_seq_stmt::~mdl_seq_stmt() {
1042   if (stmts_) {
1043     unsigned size = stmts_->size();
1044     for (unsigned u=0; u<size; u++)
1045       delete (*stmts_)[u];
1046     delete stmts_;
1047   }
1048 }
1049
1050 bool T_dyninstRPC::mdl_seq_stmt::apply(metricDefinitionNode *mn,
1051                                        vector<dataReqNode*>& flags) {
1052   if (!stmts_)
1053     return true;
1054   unsigned size = stmts_->size();
1055   for (unsigned index=0; index<size; index++)
1056     if (!(*stmts_)[index]->apply(mn, flags))
1057       return false;
1058   return true;
1059 }
1060
1061 T_dyninstRPC::mdl_list_stmt::mdl_list_stmt(u_int type, string ident,
1062                                            vector<string> *elems,
1063                                            bool is_lib, vector<string>* flavor) 
1064 : type_(type), id_(ident), elements_(elems), is_lib_(is_lib), flavor_(flavor) { }
1065 T_dyninstRPC::mdl_list_stmt::mdl_list_stmt() { }
1066 T_dyninstRPC::mdl_list_stmt::~mdl_list_stmt() { delete elements_; }
1067
1068 bool T_dyninstRPC::mdl_list_stmt::apply(metricDefinitionNode *mn,
1069                                         vector<dataReqNode*>& flags) {
1070   bool found = false;
1071   for (unsigned u0 = 0; u0 < flavor_->size(); u0++) {
1072     if ((*flavor_)[u0] == daemon_flavor) {
1073       found = true;
1074       break;
1075     }
1076   }
1077   if (!found) return false;
1078   if (!elements_) return false;
1079   mdl_var expr_var;
1080   mdl_var list_var(id_, false);
1081   unsigned size = elements_->size();
1082   if (!list_var.make_list(type_)) return false;
1083
1084   // make call to symtab code to watch for these procedures/modules
1085   if (type_ == MDL_T_PROCEDURE) {
1086     vector<pdFunction*> *pdict;
1087     assert(list_var.get(pdict)); assert(pdict);
1088     image::watch_functions(id_, elements_, is_lib_, pdict);
1089   } else if (type_ == MDL_T_MODULE) {
1090     // vector<module*> *mdict;
1091     // assert(list_var.get(mdict)); assert(mdict);
1092     // image::watch_modules(id_, elements_, is_lib_, mdict);
1093     // TODO
1094     assert(0);
1095   } else {
1096     for (unsigned u=0; u<size; u++) {
1097       int i; float f; string s; mdl_var expr_var;
1098       switch (type_) {
1099       case MDL_T_INT:
1100         if (sscanf((*elements_)[u].string_of(), "%d", &i) != 1) return false;
1101         if (!expr_var.set(i)) return false; break;
1102       case MDL_T_FLOAT:
1103         if (sscanf((*elements_)[u].string_of(), "%f", &f) != 1) return false;
1104         if (!expr_var.set(f)) return false; break;
1105       case MDL_T_STRING: 
1106         if (!expr_var.set((*elements_)[u])) return false; break;
1107       default:
1108         return false;
1109       }
1110       if (!list_var.add_to_list(expr_var)) return false;
1111     }
1112   }
1113   return (mdl_env::add(list_var));
1114 }
1115
1116 T_dyninstRPC::mdl_instr_stmt::mdl_instr_stmt(unsigned pos, T_dyninstRPC::mdl_expr *expr,
1117                                       vector<T_dyninstRPC::mdl_icode*> *reqs,
1118                                       unsigned where, bool constrained) 
1119 : position_(pos), point_expr_(expr), icode_reqs_(reqs),
1120   where_instr_(where), constrained_(constrained) { }
1121 T_dyninstRPC::mdl_instr_stmt::mdl_instr_stmt() { }
1122 T_dyninstRPC::mdl_instr_stmt::~mdl_instr_stmt() {
1123   delete point_expr_;
1124   if (icode_reqs_) {
1125     unsigned size = icode_reqs_->size();
1126     for (unsigned u=0; u<size; u++)
1127       delete (*icode_reqs_)[u];
1128     delete icode_reqs_;
1129   }
1130 }
1131
1132 bool T_dyninstRPC::mdl_instr_stmt::apply(metricDefinitionNode *mn,
1133                                         vector<dataReqNode*>& inFlags) {
1134  
1135    // check to see if this is constrained or not 
1136    vector<dataReqNode*> flags;
1137    if (constrained_) {
1138        // we are constrained so use the flags (boolean constraint variables
1139        flags = inFlags;
1140    }
1141   mdl_var temp(false);
1142   if (!icode_reqs_)
1143     return false;
1144   if (!point_expr_->apply(temp))
1145     return false;
1146   if (temp.type() != MDL_T_POINT)
1147     return false;
1148   instPoint *p;
1149   if (!temp.get(p))
1150     return false;
1151   unsigned size = icode_reqs_->size();
1152
1153   AstNode *code = NULL;
1154   for (unsigned u=0; u<size; u++)
1155     if (!(*icode_reqs_)[u]->apply(code))
1156       return false;
1157
1158   enum callWhen cwhen; enum callOrder corder;
1159   switch (position_) {
1160   case MDL_PREPEND: corder = orderFirstAtPoint; break;
1161   case MDL_APPEND: corder = orderLastAtPoint; break;
1162   default: assert(0);
1163   }
1164   switch (where_instr_) {
1165   case MDL_PRE_INSN: cwhen = callPreInsn; break;
1166   case MDL_POST_INSN: cwhen = callPostInsn; break;
1167   default: assert(0);
1168   }
1169
1170   // Instantiate all constraints (flags) here
1171   unsigned fsize = flags.size();
1172   for (int fi=fsize-1; fi>=0; fi--) {
1173     AstNode *temp = new AstNode(DataValue, flags[fi]);
1174     code = createIf(temp, code);
1175   }
1176
1177   mn->addInst(p, code, cwhen, corder);
1178
1179   return true;
1180 }
1181
1182 bool mdl_can_do(string& met_name) {
1183   unsigned size = mdl_data::all_metrics.size();
1184   for (unsigned u=0; u<size; u++) 
1185     if (mdl_data::all_metrics[u]->name_ == met_name)
1186       return true;
1187
1188   return false;
1189 }
1190
1191 metricDefinitionNode *mdl_do(vector< vector<string> >& canon_focus, string& met_name,
1192                              string& flat_name) {
1193   unsigned size = mdl_data::all_metrics.size();
1194   for (unsigned u=0; u<size; u++) 
1195     if (mdl_data::all_metrics[u]->name_ == met_name) {
1196       return (mdl_data::all_metrics[u]->apply(canon_focus, flat_name));
1197     }
1198   return NULL;
1199 }
1200
1201 bool mdl_init(string& flavor) { 
1202
1203   daemon_flavor = flavor;
1204   vector<mdl_type_desc> kids;
1205   mdl_type_desc self, kid;
1206   mdl_focus_element fe;
1207
1208   self.name = "SyncObject"; self.type = 0; self.end_allowed = false; 
1209   kid.name = "MsgTag"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1210   kid.name = "Barrier"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1211   kid.name = "Semaphore"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1212   kid.name = "SpinLock"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1213   fe.self = self; fe.kids = kids;
1214   mdl_data::foci += fe;
1215   kids.resize(0);
1216
1217 //  self.name = "Procedure"; self.type = MDL_T_MODULE; self.end_allowed = true;
1218   self.name = "Code"; self.type = MDL_T_MODULE; self.end_allowed = true;
1219   kid.name = "Module"; kid.type = MDL_T_PROCEDURE; self.end_allowed = true; kids += kids;
1220   fe.self = self; fe.kids = kids;
1221   mdl_data::foci += fe;
1222   kids.resize(0);
1223
1224   self.name = "Process"; self.type = MDL_T_PROCESS; self.end_allowed = true;
1225   fe.self = self; fe.kids.resize(0);
1226   mdl_data::foci += fe;
1227
1228   self.name = "Machine"; self.type = MDL_T_STRING; self.end_allowed = true;
1229   fe.self = self; fe.kids.resize(0);
1230   mdl_data::foci += fe;
1231
1232   mdl_env::push();
1233   // These are pushed on per-process
1234   // mdl_env::add("$procedures", false, MDL_T_LIST_PROCEDURE);
1235   // mdl_env::add("$modules", false, MDL_T_LIST_MODULE);
1236
1237   struct utsname unm;
1238   if (P_uname(&unm) == -1) assert(0);
1239   string vname = "$machine";
1240   mdl_env::add(vname, false, MDL_T_STRING);
1241   mdl_env::set(string(unm.nodename), vname);
1242
1243   /* Are these entered by hand at the new scope ? */
1244   /* $arg, $return */
1245
1246   vector<mdl_type_desc> field_list;
1247   mdl_type_desc desc;
1248   desc.name = "name"; desc.type = MDL_T_STRING; field_list += desc;
1249   desc.name = "calls"; desc.type = MDL_T_LIST_POINT; field_list += desc;
1250   desc.name = "entry"; desc.type = MDL_T_POINT; field_list += desc;
1251   desc.name = "return"; desc.type = MDL_T_POINT; field_list += desc;
1252   desc.name = "tag"; desc.type = MDL_T_INT; field_list += desc;
1253   mdl_data::fields[MDL_T_PROCEDURE] = field_list;
1254   field_list.resize(0);
1255
1256   desc.name = "name"; desc.type = MDL_T_STRING; field_list += desc;
1257   desc.name = "funcs"; desc.type = MDL_T_LIST_PROCEDURE; field_list += desc;
1258   mdl_data::fields[MDL_T_MODULE] = field_list;
1259   field_list.resize(0);
1260
1261   return true;
1262 }
1263
1264 void dynRPC::send_metrics(vector<T_dyninstRPC::mdl_metric*>* var_0) {
1265   mdl_met = true;
1266
1267   static bool been_here = false;
1268   if (!been_here) {
1269     been_here = true;
1270     // Kludge -- declare observed cost
1271     // I don't want to attempt to define this using the current mdl
1272     string obs_cost = "observed_cost";
1273     assert(mdl_data::new_metric("observedCost", obs_cost, "CPUs",
1274                                 aggMax, EventCounter, 0,
1275                                 NULL, NULL, NULL, NULL, true, true));
1276   }
1277
1278   if (var_0) {
1279     unsigned var_size = var_0->size();
1280     for (unsigned v=0; v<var_size; v++) {
1281       // fprintf(stderr, "Got metric %s\n", (*var_0)[v]->name_.string_of());
1282       // fflush(stderr);
1283       bool found = false;
1284       unsigned f_size = (*var_0)[v]->flavors_->size();
1285
1286       bool flavor_found = false;
1287       for (unsigned f=0; f<f_size; f++) {
1288         if ((*(*var_0)[v]->flavors_)[f] == daemon_flavor) {
1289           flavor_found = true; break;
1290         }
1291       }
1292       if (flavor_found) {
1293         unsigned size=mdl_data::all_metrics.size();
1294         for (unsigned u=0; u<size; u++) 
1295           if (mdl_data::all_metrics[u]->id_ == (*var_0)[v]->id_) {
1296             delete mdl_data::all_metrics[u];
1297             mdl_data::all_metrics[u] = (*var_0)[v];
1298             found = true;
1299           }
1300         if (!found) {
1301           T_dyninstRPC::mdl_metric *m = (*var_0)[v];
1302           mdl_data::all_metrics += m;
1303         }
1304       }
1305     }
1306   } else {
1307      fprintf(stderr, "no metric defined\n");
1308      fflush(stderr);
1309   }
1310 }
1311
1312 void dynRPC::send_constraints(vector<T_dyninstRPC::mdl_constraint*> *cv) {
1313
1314   mdl_cons = true;
1315   if (cv) {
1316     unsigned var_size = cv->size();
1317     for (unsigned v=0; v<var_size; v++) {
1318       bool found = false;
1319       // cout << "Received " << (*cv)[v]->id_ << endl;
1320       for (unsigned u=0; u<mdl_data::all_constraints.size(); u++) 
1321         if (mdl_data::all_constraints[u]->id_ == (*cv)[v]->id_) {
1322           delete mdl_data::all_constraints[u];
1323           mdl_data::all_constraints[u] = (*cv)[v];
1324           found = true;
1325         }
1326       if (!found) {
1327         mdl_data::all_constraints += (*cv)[v];
1328         // cout << *(*cv)[v] << endl;
1329       }
1330     }
1331   }
1332 }
1333
1334
1335 // TODO -- are these executed immediately ?
1336 void dynRPC::send_stmts(vector<T_dyninstRPC::mdl_stmt*> *vs) {
1337   mdl_stmt = true;
1338   if (vs) {
1339     // ofstream of("other_out", (been_here ? ios::app : ios::out));
1340     // been_here = true;
1341     // of << "SEND_STMTS\n";
1342     // unsigned size = vs->size();
1343     // for (unsigned u=0; u<size; u++) 
1344     // (*vs)[u]->print(of);
1345     mdl_data::stmts += *vs;
1346
1347     // TODO -- handle errors here
1348     // TODO -- apply these statements without a metric definition node ?
1349     unsigned s_size = vs->size();
1350     vector<dataReqNode*> flags;
1351
1352     // Application may fail if the list flavor is different than the flavor
1353     // of this daemon
1354
1355     for (unsigned s=0; s<s_size; s++) {
1356       if (!(*vs)[s]->apply(NULL, flags)) 
1357         ;
1358       // (*vs)[s]->print(cout);
1359       // cout << endl;
1360     }
1361   }
1362 }
1363
1364 static bool do_operation(mdl_var& ret, mdl_var& left_val,
1365                          mdl_var& right_val, unsigned bin_op) {
1366   switch (bin_op) {
1367   case MDL_PLUS:
1368   case MDL_MINUS:
1369   case MDL_DIV:
1370   case MDL_MULT:
1371     if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
1372       int v1, v2;
1373       if (!left_val.get(v1)) return false;
1374       if (!right_val.get(v2)) return false;
1375       switch (bin_op) {
1376       case MDL_PLUS: return (ret.set(v1+v2));
1377       case MDL_MINUS: return (ret.set(v1-v2));
1378       case MDL_DIV: return (ret.set(v1/v2));
1379       case MDL_MULT: return (ret.set(v1*v2));
1380       }
1381     } else if (((left_val.type() == MDL_T_INT) || (left_val.type() == MDL_T_FLOAT)) &&
1382                ((right_val.type() == MDL_T_INT) || (right_val.type() == MDL_T_FLOAT))) {
1383       float v1, v2;
1384       if (left_val.type() == MDL_T_INT) {
1385         int i1; if (!left_val.get(i1)) return false; v1 = i1;
1386       } else {
1387         if (!left_val.get(v1)) return false;
1388       }
1389       if (right_val.type() == MDL_T_INT) {
1390         int i1; if (!right_val.get(i1)) return false; v2 = i1;
1391       } else {
1392         if (!right_val.get(v2)) return false;
1393       }
1394       switch (bin_op) {
1395       case MDL_PLUS: return (ret.set(v1+v2));
1396       case MDL_MINUS: return (ret.set(v1-v2));
1397       case MDL_DIV: return (ret.set(v1/v2));
1398       case MDL_MULT: return (ret.set(v1*v2));
1399       }
1400     } else
1401       return false;
1402   case MDL_LT:
1403   case MDL_GT:
1404   case MDL_LE:
1405   case MDL_GE:
1406   case MDL_EQ:
1407   case MDL_NE:
1408     if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
1409       int v1, v2;
1410       if (!left_val.get(v1)) return false;
1411       if (!right_val.get(v2)) return false;
1412       switch (bin_op) {
1413       case MDL_LT: return (ret.set(v1 < v2));
1414       case MDL_GT: return (ret.set(v1 > v2));
1415       case MDL_LE: return (ret.set(v1 <= v2));
1416       case MDL_GE: return (ret.set(v1 >= v2));
1417       case MDL_EQ: return (ret.set(v1 == v2));
1418       case MDL_NE: return (ret.set(v1 != v2));
1419       }
1420     } else if (((left_val.type() == MDL_T_INT) ||
1421                 (left_val.type() == MDL_T_FLOAT)) &&
1422                ((right_val.type() == MDL_T_INT) ||
1423                 (right_val.type() == MDL_T_FLOAT))) {
1424       float v1, v2;
1425       if (left_val.type() == MDL_T_INT) {
1426         int i1; if (!left_val.get(i1)) return false; v1 = i1;
1427       } else {
1428         if (!left_val.get(v1)) return false;
1429       }
1430       if (right_val.type() == MDL_T_INT) {
1431         int i1; if (!right_val.get(i1)) return false; v2 = i1;
1432       } else {
1433         if (!right_val.get(v2)) return false;
1434       }
1435       switch (bin_op) {
1436       case MDL_LT: return (ret.set(v1 < v2));
1437       case MDL_GT: return (ret.set(v1 > v2));
1438       case MDL_LE: return (ret.set(v1 <= v2));
1439       case MDL_GE: return (ret.set(v1 >= v2));
1440       case MDL_EQ: return (ret.set(v1 == v2));
1441       case MDL_NE: return (ret.set(v1 != v2));
1442       }
1443     } else
1444       return false;
1445   case MDL_AND:
1446   case MDL_OR:
1447     if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
1448       int v1, v2;
1449       if (!left_val.get(v1)) return false;
1450       if (!right_val.get(v2)) return false;
1451       switch (bin_op) {
1452       case MDL_AND: return (ret.set(v1 && v2));
1453       case MDL_OR: return (ret.set(v1 || v2));
1454       }
1455     } else
1456       return false;
1457   default:
1458       return false;
1459   }
1460   return false;
1461 }
1462
1463 static bool walk_deref(mdl_var& ret, vector<unsigned>& types, string& var_name) {
1464
1465   if (!mdl_env::get(ret, var_name)) return false;
1466   
1467   unsigned index=0;
1468   unsigned max = types.size();
1469
1470   while (index < max) {
1471     unsigned current_type = types[index++];
1472     unsigned next_field = types[index++];
1473
1474     switch (current_type) {
1475     case MDL_T_PROCEDURE:
1476       pdFunction *pdf;
1477       if (!ret.get(pdf)) return false;
1478       switch (next_field) {
1479       case 0: if (!ret.set(pdf->prettyName())) return false; break;
1480       case 1: if (!ret.set(&pdf->calls)) return false; break;
1481       case 2: if (!ret.set(pdf->funcEntry())) return false; break;
1482       case 3: if (!ret.set(pdf->funcReturn())) return false; break;
1483       case 4: if (!ret.set((int)pdf->tag())) return false; break;
1484       default: assert(0); break;
1485       }
1486       break;
1487     case MDL_T_MODULE:
1488       module *mod;
1489       if (!ret.get(mod)) return false;
1490       switch (next_field) {
1491       case 0: if (!ret.set(mod->fileName())) return false; break;
1492       case 1: if (!ret.set(&mod->funcs)) return false; break;
1493       default: assert(0); break;               
1494       }
1495       break;
1496     default:
1497       assert(0); return false;
1498     }
1499   }
1500   return true;
1501 }
1502
1503 AstNode *do_instr_rand(u_int arg_type, u_int arg_val, string& arg_name, string& arg2) {
1504   AstNode *ret=NULL;
1505   pdFunction *pdf;
1506   mdl_var get_drn;
1507
1508   switch (arg_type) {
1509   case MDL_T_INT:
1510     if (arg_name.prefixed_by("$")) {
1511       // variable in the expression.
1512       mdl_var get_int;
1513       int value;
1514       assert(mdl_env::get(get_int, arg_name));
1515       if (!get_int.get(value)) {
1516           fprintf(stderr, "Unable to get value for %s\n", arg_name.string_of());
1517           fflush(stderr);
1518           return NULL;
1519       } else {
1520           ret = new AstNode(Constant, (void*) value);
1521       }
1522     } else {
1523       ret = new AstNode(Constant, (void*) arg_val);
1524     }
1525     break;
1526   case MDL_ARG:
1527     ret = new AstNode(Param, (void*) arg_val);
1528     break;
1529   case MDL_RETURN:
1530     break;
1531   case MDL_READ_SYMBOL:
1532     // TODO -- I am relying on global_proc to be set in mdl_metric::apply
1533     if (global_proc) {
1534       Symbol info;
1535       if (global_proc->symbols->symbol_info(arg_name, info)) {
1536         Address adr = info.addr();
1537         ret = new AstNode(DataAddr, (void*) adr);
1538       }
1539     }
1540     break;
1541   case MDL_READ_ADDRESS:
1542     // TODO -- check on the range of this address!
1543     ret = new AstNode(DataAddr, (void*) arg_val);
1544     break;
1545   case MDL_CALL_FUNC:
1546     // call a function with either and integer or a counter argument
1547     //    XXXX This code should generalized function call.  - jkh 7/31/95.
1548     //         Also should handle multiple arguments.
1549     //
1550     pdf = global_proc->symbols->findOneFunction(string(arg_name));
1551     if (!pdf) {
1552         fprintf(stderr, "Unable to locate procedure %s for metric definition\n",
1553                 arg_name.string_of());
1554         fflush(stderr);
1555         return NULL;
1556     }
1557     // Hack to tell counter from timer.
1558     if (arg2 == "s") {
1559         ret = new AstNode(arg_name,
1560                           new AstNode(Constant, (void*) arg_val),
1561                           new AstNode(Constant, (void*) 0));
1562     } else {
1563         mdl_var get_drn;
1564         dataReqNode *drn;
1565
1566         if (!mdl_env::get(get_drn, arg2)) {
1567             fprintf(stderr,"Unable to find variable %s for metric definition\n",
1568                 arg2.string_of());
1569             return NULL;
1570         }
1571         assert(get_drn.get(drn));
1572         ret = createPrimitiveCall(arg_name, drn, 0);
1573     }
1574     break;
1575   case MDL_T_COUNTER:
1576     {
1577       mdl_var get_drn;
1578       dataReqNode *drn;
1579       assert(mdl_env::get(get_drn, arg_name));
1580       //
1581       // This code was added to support additional mdl evaluation time 
1582       //     variables.  To keep it simple, I left the parser alone and so
1583       //     any unknown identifier maps to MDL_T_COUNTER.  We lookup the
1584       //     variable's type here to generate the correct code.  MDL
1585       //     really should have a general type system and all functions
1586       //     signatures. - jkh 7/5/95
1587       //
1588       switch (get_drn.type()) {
1589           case MDL_T_INT:
1590               int value;
1591               if (!get_drn.get(value)) {
1592                   fprintf(stderr, "Unable to get value for %s\n", 
1593                       arg_name.string_of());
1594                   fflush(stderr);
1595                   return NULL;
1596               } else {
1597                   ret = new AstNode(Constant, (void*) value);
1598               }
1599               break;
1600           case MDL_T_COUNTER:   // is MDL_T_COUNTER used here ??? jkh 7/31/95
1601           case MDL_T_DRN:
1602               if (!get_drn.get(drn)) {
1603                   fprintf(stderr, "Unable to find variable %s\n", 
1604                       arg_name.string_of());
1605                   fflush(stderr);
1606                   return NULL;
1607               } else {
1608                   ret = new AstNode(DataValue, (void*) drn);
1609               }
1610               break;
1611           default:
1612               fprintf(stderr, "type of variable %s is not known\n",
1613                   arg_name.string_of());
1614               fflush(stderr);
1615               return NULL;
1616       }
1617     }
1618     break;
1619   default:
1620     break;
1621   }
1622   return ret;
1623 }
1624
1625 metricDefinitionNode *mdl_observed_cost(vector< vector<string> >& canon_focus,
1626                                         string& met_name,
1627                                         string& flat_name) {
1628   pdFunction *sampler;
1629   AstNode *reportNode;
1630   dataReqNode *dataPtr;
1631   string name("observed_cost");
1632   static string machine;
1633   static bool machine_init= false;
1634   if (!machine_init) {
1635     machine_init = true;
1636     struct utsname un; assert(!P_uname(&un) != -1); machine = un.nodename;
1637   }
1638
1639   if (other_machine_specified(canon_focus, machine)) return NULL;
1640   vector<process*> ip;
1641   add_processes(canon_focus, ip);
1642   unsigned ip_size, index;
1643   if (!(ip_size = ip.size())) return NULL;
1644
1645   // Can't refine procedure or sync object
1646   if (canon_focus[resource::sync_object].size() > 1) return NULL;
1647   if (canon_focus[resource::procedure].size() > 1) return NULL;
1648
1649   vector<metricDefinitionNode*> parts;
1650
1651   for (index=0; index<ip_size; index++) {
1652     process *proc = ip[index];
1653     metricDefinitionNode *mn =
1654       new metricDefinitionNode(proc, name, canon_focus, flat_name, aggMax);
1655     assert(mn);
1656     dataPtr = mn->addIntCounter(0, false);
1657     assert(dataPtr);
1658
1659     sampler = ((mn->proc())->symbols)->findOneFunction("DYNINSTsampleValues");
1660     assert(sampler);
1661     reportNode = new AstNode("DYNINSTreportCost", 
1662                              new AstNode(DataPtr, dataPtr), new AstNode(Constant, 0));
1663     assert(reportNode);
1664     mn->addInst(sampler->funcEntry(), reportNode, callPreInsn, orderLastAtPoint);
1665
1666     if (mn && mn->nonNull()) 
1667       parts += mn;
1668     else {
1669       delete mn; mn = NULL;
1670     }
1671   }
1672
1673   metricDefinitionNode *ret = NULL;
1674   switch (parts.size()) {
1675   case 0: break;
1676   case 1: ret = parts[0]; break;
1677   default: ret = new metricDefinitionNode(name, canon_focus, flat_name, parts);
1678   }
1679   if (ret) ret->set_inform(true);
1680   return ret;
1681 }
1682
1683 bool mdl_get_initial(string flavor, pdRPC *connection) {
1684   mdl_init(flavor);
1685   while (!(mdl_met && mdl_cons && mdl_stmt)) {
1686     switch (connection->waitLoop()) {
1687     case T_dyninstRPC::error:
1688       return false;
1689     default:
1690       break;
1691     }
1692     while (connection->buffered_requests()) {
1693       switch (connection->process_buffered()) {
1694       case T_dyninstRPC::error:
1695         return false;
1696       default:
1697         break;
1698       }
1699     }
1700   }
1701   return true;
1702 }
1703
1704 void mdl_get_info(vector<T_dyninstRPC::metricInfo>& metInfo) {
1705   unsigned size = mdl_data::all_metrics.size();
1706   T_dyninstRPC::metricInfo element;
1707   for (unsigned u=0; u<size; u++) {
1708     element.name = mdl_data::all_metrics[u]->name_;
1709     element.style = mdl_data::all_metrics[u]->style_;
1710     element.aggregate = mdl_data::all_metrics[u]->agg_op_;
1711     element.units = mdl_data::all_metrics[u]->units_;
1712     element.developerMode = mdl_data::all_metrics[u]->developerMode_;
1713     element.unitstype = mdl_data::all_metrics[u]->unitstype_;
1714     metInfo += element;
1715   }
1716 }
1717
1718 bool mdl_metric_data(string& met_name, mdl_inst_data& md) {
1719   unsigned size = mdl_data::all_metrics.size();
1720   for (unsigned u=0; u<size; u++)
1721     if (mdl_data::all_metrics[u]->name_ == met_name) {
1722       md.aggregate = mdl_data::all_metrics[u]->agg_op_;
1723       md.style = (enum metricStyle) mdl_data::all_metrics[u]->style_;
1724       return true;
1725     }
1726   return false;
1727 }