2 * Copyright (c) 1996 Barton P. Miller
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.
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.
18 * (for other uses, please contact us at paradyn@cs.wisc.edu)
20 * All warranties, including without limitation, any warranty of
21 * merchantability or fitness for a particular purpose, are hereby
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.
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.
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"
58 // The following vrbles were defined in process.C:
59 extern debug_ostream attach_cerr;
60 extern debug_ostream inferiorrpc_cerr;
61 extern debug_ostream shmsample_cerr;
62 extern debug_ostream forkexec_cerr;
63 extern debug_ostream metric_cerr;
66 // Some global variables used to print error messages:
67 string currentMetric; // name of the metric that is being processed.
68 string currentFocus; // the focus
71 static string daemon_flavor;
72 static process *global_proc = NULL;
73 static bool mdl_met=false, mdl_cons=false, mdl_stmt=false, mdl_libs=false,mdl_funcs=false;
75 inline unsigned ui_hash(const unsigned &u) { return u; }
77 vector<unsigned> mdl_env::frames;
78 vector<mdl_var> mdl_env::all_vars;
80 vector<T_dyninstRPC::mdl_stmt*> mdl_data::stmts;
81 vector<T_dyninstRPC::mdl_metric*> mdl_data::all_metrics;
82 dictionary_hash<unsigned, vector<mdl_type_desc> > mdl_data::fields(ui_hash);
83 vector<mdl_focus_element> mdl_data::foci;
84 vector<T_dyninstRPC::mdl_constraint*> mdl_data::all_constraints;
85 vector<string> mdl_data::lib_constraints;
86 vector<string> mdl_data::func_constraints;
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);
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)
98 aflag=list_v.is_list();
101 element_type = list_v.element_type();
102 switch(element_type) {
104 aflag=list_v.get(int_iter); assert(aflag);
105 max_index = int_iter->size(); break;
107 aflag=list_v.get(float_iter); assert(aflag);
108 max_index = float_iter->size(); break;
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();
116 case MDL_T_PROCEDURE:
117 aflag=list_v.get(func_iter); assert(aflag);
118 max_index = func_iter->size();
121 aflag=list_v.get(mod_iter); assert(aflag);
122 max_index = mod_iter->size();
125 aflag=list_v.get(point_iter); assert(aflag);
126 max_index = point_iter->size();
135 function_base *pdf; module *m;
139 if (index >= max_index) return false;
140 switch(element_type) {
142 i = (*int_iter)[index++]; return (mdl_env::set(i, index_name));
144 f = (*float_iter)[index++]; return (mdl_env::set(f, index_name));
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
152 functionName *fn = (*funcName_iter)[index++];
153 pdf = global_proc->findOneFunction(fn->get());
154 } while (pdf == NULL && index < max_index);
157 return (mdl_env::set(pdf, index_name));
158 case MDL_T_PROCEDURE:
159 pdf = (*func_iter)[index++];
161 return (mdl_env::set(pdf, index_name));
163 m = (*mod_iter)[index++]; return (mdl_env::set(m, index_name));
165 ip = (*point_iter)[index++]; return (mdl_env::set(ip, index_name));
174 unsigned element_type;
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;
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,
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) { }
200 T_dyninstRPC::mdl_metric::mdl_metric() { }
202 T_dyninstRPC::mdl_metric::~mdl_metric() {
204 unsigned size = stmts_->size();
205 for (unsigned u=0; u<size; u++)
212 unsigned size = constraints_->size();
213 for (unsigned u=0; u<size; u++)
214 delete (*constraints_)[u];
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,
228 T_dyninstRPC::mdl_metric *m = new T_dyninstRPC::mdl_metric(id, name,
243 static bool other_machine_specified(vector< vector<string> > &focus,
245 assert(focus[resource::machine][0] == "Machine");
247 switch (focus[resource::machine].size()) {
250 if (machine != focus[resource::machine][1]) return true;
258 static void add_processes(vector< vector<string> > &focus,
259 vector<process*> procs,
260 vector<process*> &ip) {
261 assert(focus[resource::process][0] == "Process");
264 switch(focus[resource::process].size()) {
269 #if defined(MT_THREAD)
273 for (pi=0; pi<ps; pi++)
274 if (procs[pi]->rid->part_name() == focus[resource::process][1]) {
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();
288 if ((mp_size < 1) || (f_size < 2) || (mp_size != (f_size-1))) {
292 for (unsigned u = 0; u < mp_size; u++) {
293 if(((*match_path)[u] != "*") && (focus[u] != (*match_path)[u])) {
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,
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)
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
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();
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
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
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;
351 if ((mc = flag_matches(focus[fi], (*cons)[ci], is_default))) {
354 flag_cons += mc; flag_dex += fi;
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_)) {
363 base_used = (*cons)[ci]; base_dex = fi;
368 if (!matched && (el_size>1)) {
378 // update the interpreter environment for this processor
379 // Variable updated: $procedures, $modules, $exit, $start
380 static bool update_environment(process *proc) {
382 // for cases when libc is dynamically linked, the exit symbol is not
384 string vname = "$exit";
385 function_base *pdf = proc->findOneFunction(string(EXIT_NAME));
387 mdl_env::add(vname, false, MDL_T_PROCEDURE);
388 mdl_env::set(pdf, vname);
392 pdf = proc->getMainFunction();
393 if (!pdf) return false;
396 mdl_env::add(vname, false, MDL_T_PROCEDURE);
397 mdl_env::set(pdf, vname);
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
403 mdl_env::set(proc->getIncludedFunctions(), vname);
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);
413 mdl_env::add(vname, false, MDL_T_INT);
414 mdl_env::set(theMemory->getGlobalMin(), vname);
417 mdl_env::add(vname, false, MDL_T_INT);
418 mdl_env::set(theMemory->getGlobalMax(), vname);
421 mdl_env::add(vname, false, MDL_T_INT);
422 mdl_env::set(theMemory->getCurrentMin(), vname);
425 mdl_env::add(vname, false, MDL_T_INT);
426 mdl_env::set(theMemory->getCurrentMax(), vname);
432 dataReqNode *create_data_object(unsigned mdl_data_type,
433 metricDefinitionNode *mn,
434 bool computingCost) {
435 switch (mdl_data_type) {
437 return (mn->addSampledIntCounter(0, computingCost));
439 case MDL_T_WALL_TIMER:
440 return (mn->addWallTimer(computingCost));
442 case MDL_T_PROC_TIMER:
443 return (mn->addProcessTimer(computingCost));
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));
454 return (mn->addUnSampledIntCounter(0, computingCost));
464 metricDefinitionNode *
465 apply_to_process(process *proc,
466 string& id, string& name,
467 vector< vector<string> >& focus,
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,
475 vector<string> *temp_ctr,
476 bool replace_component,
477 bool computingCost) {
479 if (!update_environment(proc)) return NULL;
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
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();
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();
505 for (unsigned u2 = 0; u2 < focus[u1].size(); u2++)
506 component_flat_name += focus[u1][u2];
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));
514 metricDefinitionNode *existingMI;
515 const bool alreadyThere = allMIComponents.find(component_flat_name, existingMI);
517 if (replace_component) {
519 metric_cerr << "apply_to_process: found " << component_flat_name
520 << " but continuing anyway since replace_component flag set"
522 // note that we don't call 'delete'.
523 allMIComponents.undef(component_flat_name);
526 metric_cerr << "mdl apply_to_process: found component for "
527 << component_flat_name << "...reusing it" << endl;
533 metric_cerr << "MDL: creating new component mi since flatname "
534 << component_flat_name << " doesn't exist" << endl;
536 // If the component exists, then we've either already returned, or fried it.
537 assert(!allMIComponents.defines(component_flat_name));
539 // TODO -- Using aggOp value for this metric -- what about folds
540 metricDefinitionNode *mn = new metricDefinitionNode(proc, name, focus,
542 component_flat_name, agg_op);
545 assert(!allMIComponents.defines(component_flat_name));
546 allMIComponents[component_flat_name] = mn;
548 // Create the timer, counter
549 dataReqNode *the_node = create_data_object(type, mn, computingCost);
551 mdl_env::set(the_node, id);
553 // Create the temporary counters - are these useful
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);
564 dataReqNode *temp_node=mn->addUnSampledIntCounter(0,computingCost);
566 mdl_env::set(temp_node, (*temp_ctr)[tc]);
570 unsigned flag_size = flag_cons.size();
571 vector<dataReqNode*> flags;
573 for (unsigned fs=0; fs<flag_size; fs++) {
574 // TODO -- cache these created flags
575 dataReqNode *flag = NULL;
576 if (! (flag_cons[fs]->apply(mn, flag, focus[flag_dex[fs]], proc, computingCost))) {
583 // cout << "Applying constraint for " << flag_cons[fs]->id_ << endl;
588 dataReqNode *flag = NULL;
589 if (!base_use->apply(mn, flag, focus[base_dex], proc, computingCost)) {
590 // cout << "apply of " << name << " failed\n";
596 unsigned size = stmts->size();
597 for (unsigned u=0; u<size; u++) {
598 if (!(*stmts)[u]->apply(mn, flags)) { // virtual fn call depending on the statement type
599 // cout << "apply of " << name << " failed\n";
607 if (!mn->nonNull()) {
616 static bool apply_to_process_list(vector<process*>& instProcess,
617 vector<metricDefinitionNode*>& parts,
618 string& id, string& name,
619 vector< vector<string> >& focus,
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,
627 vector<string> *temp_ctr,
628 bool replace_components_if_present,
629 bool computingCost) {
631 timer loadTimer, totalTimer;
632 static ofstream *of=NULL;
635 ostrstream osb(buffer, 100, ios::out);
636 osb << "mdl_" << "__" << getpid() << ends;
637 of = new ofstream(buffer, ios::app);
640 (*of) << "Instrumenting for " << name << " " << instProcess.size() << " processes\n";
643 unsigned psize = instProcess.size();
645 totalTimer.clear(); totalTimer.start();
647 for (unsigned p=0; p<psize; p++) {
649 loadTimer.clear(); loadTimer.start(); // TIMER
651 process *proc = instProcess[p]; assert(proc);
652 global_proc = proc; // TODO -- global
654 // skip neonatal and exited processes.
655 if (proc->status() == exited || proc->status() == neonatal) continue;
657 metricDefinitionNode *comp = apply_to_process(proc, id, name, focus,
659 flag_cons, base_use, stmts,
662 replace_components_if_present,
665 // we have another component (i.e. process-specific) mi
671 sprintf(timeMsg, "%f::%f ", (float) loadTimer.usecs(), (float) loadTimer.wsecs());
672 // tp->applicationIO(10, strlen(timeMsg), timeMsg);
673 (*of) << name << ":" << timeMsg << endl;
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;
686 if (parts.size() == 0)
693 metricDefinitionNode *T_dyninstRPC::mdl_metric::apply(vector< vector<string> > &focus,
695 vector<process *> procs,
696 bool replace_components_if_present,
697 bool computingCost) {
698 // TODO -- check to see if this is active ?
699 // TODO -- create counter or timer
700 // TODO -- put it into the environment ?
701 // TODO -- this can be passed directly -- faster - later
702 // TODO -- internal metrics
703 // TODO -- assume no constraints, all processes instrumented
704 // TODO -- support two-level aggregation: one at the daemon, one at paradyn
705 // TODO -- how is folding specified ?
706 // TODO -- are lists updated here ?
709 mdl_env::add(id_, false, MDL_T_DRN);
712 const unsigned tc_size = temp_ctr_->size();
713 for (unsigned tc=0; tc<tc_size; tc++) {
714 mdl_env::add((*temp_ctr_)[tc], false, MDL_T_DRN);
717 static string machine;
718 static bool machine_init= false;
721 machine = getHostName();
724 // TODO -- I am assuming that a canonical resource list is
725 // machine, procedure, process, syncobject
727 if (other_machine_specified(focus, machine)) return NULL;
728 vector<process*> instProcess;
729 add_processes(focus, procs, instProcess);
731 if (!instProcess.size()) return NULL;
733 // build the list of constraints to use
734 vector<T_dyninstRPC::mdl_constraint*> flag_cons;
736 // the first replace constraint that matches, if any
737 T_dyninstRPC::mdl_constraint *base_used=NULL;
739 // build list of global constraints that match and choose local replace constraint
740 unsigned base_dex; vector<unsigned> flag_dex;
741 if (!check_constraints(flag_cons, base_used, focus, constraints_, flag_dex, base_dex))
744 // build the instrumentation request
745 vector<metricDefinitionNode*> parts; // one per process
746 if (!apply_to_process_list(instProcess, parts, id_, name_, focus,
747 agg_op_, type_, flag_cons, base_used,
748 stmts_, flag_dex, base_dex, temp_ctr_,
749 replace_components_if_present,
753 // construct aggregate for the metric instance parts
754 metricDefinitionNode *ret = NULL;
757 // create aggregate mi, containing the process components "parts"
758 ret = new metricDefinitionNode(name_, focus, flat_name, parts, agg_op_);
760 // cout << "apply of " << name_ << " ok\n";
765 T_dyninstRPC::mdl_constraint::mdl_constraint() { }
766 T_dyninstRPC::mdl_constraint::mdl_constraint(string id, vector<string> *match_path,
767 vector<T_dyninstRPC::mdl_stmt*> *stmts,
768 bool replace, u_int d_type, bool& error)
769 : id_(id), match_path_(match_path), stmts_(stmts), replace_(replace),
770 data_type_(d_type), hierarchy_(0), type_(0) { error = false; }
771 T_dyninstRPC::mdl_constraint::~mdl_constraint() {
774 for (unsigned u=0; u<stmts_->size(); u++)
781 static bool do_trailing_resources(vector<string>& resource_,
784 vector<string> resPath;
786 for(int pLen = 0; pLen < resource_.size(); pLen++) {
787 string caStr = string("$constraint") +
788 string(resource_.size()-pLen-1);
789 string trailingRes = resource_[pLen];
791 resPath += resource_[pLen];
792 assert(resPath.size() == (pLen+1));
794 resource *r = resource::findResource(resPath);
799 const char* p = trailingRes.string_of();
801 int val = (int) strtol(p, &q, 0);
803 string msg = string("unable to convert resource '") + trailingRes +
804 string("' to integer.");
805 showErrorCallback(92,msg.string_of());
808 mdl_env::add(caStr, false, MDL_T_INT);
809 mdl_env::set(val, caStr);
813 mdl_env::add(caStr, false, MDL_T_STRING);
814 mdl_env::set(trailingRes, caStr);
816 case MDL_T_PROCEDURE: {
817 // find the resource corresponding to this function's module
818 vector<string> m_vec;
819 for(u_int i=0; i < resPath.size()-1; i++){
822 assert(m_vec.size());
823 assert(m_vec.size() == (resPath.size()-1));
824 resource *m_resource = resource::findResource(m_vec);
825 if(!m_resource) return(false);
827 function_base *pdf = proc->findOneFunction(r,m_resource);
828 if (!pdf) return(false);
829 mdl_env::add(caStr, false, MDL_T_PROCEDURE);
830 mdl_env::set(pdf, caStr);
834 module *mod = proc->findModule(trailingRes,true);
835 if (!mod) return(false);
836 mdl_env::add(caStr, false, MDL_T_MODULE);
837 mdl_env::set(mod, caStr);
842 case MDL_T_VARIABLE: {
843 //bounds is defined in metric.h
844 memory::bounds b = theMemory->getVariableBounds(trailingRes) ;
845 mdl_env::add(caStr, false, MDL_T_VARIABLE) ;
846 mdl_env::set(b, caStr) ;
858 // Replace constraints not working yet
859 // Flag constraints need to return a handle to a data request node -- the flag
860 bool T_dyninstRPC::mdl_constraint::apply(metricDefinitionNode *mn,
862 vector<string>& resource,
863 process *proc, bool computingCost) {
865 switch (data_type_) {
867 case MDL_T_WALL_TIMER:
868 case MDL_T_PROC_TIMER:
876 // create the counter used as a flag
877 mdl_env::add(id_, false, MDL_T_DRN);
878 #if defined(SHM_SAMPLING) && defined(MT_THREAD)
879 // "true" means that we are going to create a sampled int counter but
880 // we are *not* going to sample it, because it is just a temporary
881 // counter - naim 4/22/97
882 // By default, the last parameter is false - naim 4/23/97
883 dataReqNode *drn = mn->addSampledIntCounter(0,computingCost,true);
885 dataReqNode *drn = mn->addUnSampledIntCounter(0,computingCost);
887 // this flag will construct a predicate for the metric -- have to return it
890 mdl_env::set(drn, id_);
893 // put $constraint[X] in the environment
894 if(!do_trailing_resources(resource, proc)) {
899 // Now evaluate the constraint statements
900 unsigned size = stmts_->size();
901 vector<dataReqNode*> flags;
902 for (unsigned u=0; u<size; u++) {
903 if (!(*stmts_)[u]->apply(mn, flags)) {
904 // cout << "apply of constraint " << id_ << " failed\n";
912 T_dyninstRPC::mdl_constraint *mdl_data::new_constraint(string id, vector<string> *path,
913 vector<T_dyninstRPC::mdl_stmt*> *stmts,
914 bool replace, u_int d_type) {
916 return (new T_dyninstRPC::mdl_constraint(id, path, stmts, replace, d_type, error));
920 T_dyninstRPC::mdl_rand::mdl_rand() {}
922 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand() {}
924 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type): type_(type) {}
926 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type, u_int val)
927 : type_(type), val_(val) {}
929 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type, string name)
930 : type_(type), name_(name) {}
932 T_dyninstRPC::mdl_instr_rand::mdl_instr_rand(u_int type, string name, vector<mdl_instr_rand *>args)
933 : type_(type), name_(name) {
934 for (unsigned u = 0; u < args.size(); u++)
938 T_dyninstRPC::mdl_instr_rand::~mdl_instr_rand() { }
940 bool T_dyninstRPC::mdl_instr_rand::apply(AstNode *&ast) {
945 case MDL_T_RECORD://TO DO
949 mdl_env::get(get_record, string("$constraint0")) ;
950 unsigned type = mdl_env::get_type(string("$constraint0")) ;
955 if (!get_record.get(b))
960 if(!strncmp(name_.string_of(), "upper", 5))
961 value = (int)b.upper ;
963 value = (int)b.lower;
964 ast = new AstNode(AstNode::Constant, (void*) value);
973 if (name_.length()) {
974 // variable in the expression.
978 aflag=mdl_env::get(get_int, name_);
980 if (!get_int.get(value)) {
981 fprintf(stderr, "Unable to get value for %s\n", name_.string_of());
985 ast = new AstNode(AstNode::Constant, (void*) value);
988 ast = new AstNode(AstNode::Constant, (void*) val_);
992 ast = new AstNode(AstNode::Param, (void*) val_);
995 ast = new AstNode(AstNode::ReturnVal, (void*)0);
997 case MDL_READ_SYMBOL:
998 // TODO -- I am relying on global_proc to be set in mdl_metric::apply
1002 if (global_proc->getSymbolInfo(name_, info, baseAddr)) {
1003 Address adr = info.addr();
1004 ast = new AstNode(AstNode::DataAddr, (void*) adr);
1006 string msg = string("In metric '") + currentMetric + string("': ") +
1007 string("unable to find symbol '") + name_ + string("'");
1008 showErrorCallback(95, msg);
1013 case MDL_READ_ADDRESS:
1014 // TODO -- check on the range of this address!
1015 ast = new AstNode(AstNode::DataAddr, (void*) val_);
1017 case MDL_CALL_FUNC: {
1018 // don't confuse 'args' with 'args_' here!
1019 vector<AstNode *> args;
1020 for (unsigned u = 0; u < args_.size(); u++) {
1022 if (!args_[u]->apply(arg)) {
1027 args += assignAst(arg);
1030 string temp = string(name_);
1031 pdf = global_proc->findOneFunctionFromAll(temp);
1033 string msg = string("In metric '") + currentMetric + string("': ") +
1034 string("unable to find procedure '") + name_ + string("'");
1035 showErrorCallback(95, msg);
1038 ast = new AstNode(name_, args); //Cannot use simple assignment here!
1039 for (unsigned i=0;i<args.size();i++) removeAst(args[i]);
1042 case MDL_T_COUNTER_PTR:
1045 if (!mdl_env::get(get_drn, name_)) {
1046 string msg = string("In metric '") + currentMetric + string("' : ") +
1047 string("undefined variable '") + name_ + string("'");
1048 showErrorCallback(92, msg);
1052 aflag=get_drn.get(drn);
1054 #if defined(SHM_SAMPLING)
1055 #if defined(MT_THREAD)
1056 ast = computeAddress((void *)(drn->getAllocatedLevel()),
1057 (void *)(drn->getAllocatedIndex()),
1058 0); // 0 is for intCounter
1060 ast = new AstNode(AstNode::DataPtr, (void *)(drn->getInferiorPtr(global_proc)));
1063 ast = new AstNode(AstNode::DataPtr, (void *)(drn->getInferiorPtr()));
1072 aflag=mdl_env::get(get_drn, name_);
1075 // This code was added to support additional mdl evaluation time
1076 // variables. To keep it simple, I left the parser alone and so
1077 // any unknown identifier maps to MDL_T_COUNTER. We lookup the
1078 // variable's type here to generate the correct code. MDL
1079 // really should have a general type system and all functions
1080 // signatures. - jkh 7/5/95
1082 switch (get_drn.type()) {
1085 if (!get_drn.get(value)) {
1086 fprintf(stderr, "Unable to get value for %s\n",
1091 ast = new AstNode(AstNode::Constant, (void*) value);
1094 case MDL_T_COUNTER: // is MDL_T_COUNTER used here ??? jkh 7/31/95
1096 if (!get_drn.get(drn)) {
1097 fprintf(stderr, "Unable to find variable %s\n",
1102 #if defined(SHM_SAMPLING)
1103 #if defined(MT_THREAD)
1105 tmp_ast = computeAddress((void *)(drn->getAllocatedLevel()),
1106 (void *)(drn->getAllocatedIndex()),
1107 0); // 0 is for intCounter
1108 // First we get the address, and now we get the value...
1109 ast = new AstNode(AstNode::DataIndir,tmp_ast);
1112 ast = new AstNode(AstNode::DataValue,
1113 (void*)(drn->getInferiorPtr(global_proc)));
1116 // Note: getInferiorPtr could return a NULL pointer here if
1117 // we are just computing cost - naim 2/18/97
1118 ast = new AstNode(AstNode::DataValue,
1119 (void*)(drn->getInferiorPtr()));
1124 fprintf(stderr, "type of variable %s is not known\n",
1139 T_dyninstRPC::mdl_instr_req::mdl_instr_req(T_dyninstRPC::mdl_instr_rand *rand,
1140 u_int type, string obj_name)
1141 : type_(type), rand_(rand), timer_counter_name_(obj_name) { }
1143 T_dyninstRPC::mdl_instr_req::mdl_instr_req(u_int type, string obj_name)
1144 : type_(type), timer_counter_name_(obj_name) { }
1146 T_dyninstRPC::mdl_instr_req::mdl_instr_req(u_int type,
1147 T_dyninstRPC::mdl_instr_rand *rand)
1148 : type_(type), rand_(rand) { }
1150 T_dyninstRPC::mdl_instr_req::mdl_instr_req() : type_(0) { }
1151 T_dyninstRPC::mdl_instr_req::~mdl_instr_req() { }
1153 bool T_dyninstRPC::mdl_instr_req::apply(AstNode *&mn, AstNode *pred,
1154 bool mn_initialized) {
1155 // a return value of true implies that "mn" was written to
1156 AstNode *ast_arg=NULL;
1158 vector<AstNode *> ast_args;
1162 case MDL_SET_COUNTER:
1163 case MDL_ADD_COUNTER:
1164 case MDL_SUB_COUNTER:
1165 if (! rand_->apply(ast_arg))
1168 case MDL_START_WALL_TIMER:
1169 timer_fun = START_WALL_TIMER;
1171 case MDL_STOP_WALL_TIMER:
1172 timer_fun = STOP_WALL_TIMER;
1174 case MDL_START_PROC_TIMER:
1175 timer_fun = START_PROC_TIMER;
1177 case MDL_STOP_PROC_TIMER:
1178 timer_fun = STOP_PROC_TIMER;
1184 if (type_ != MDL_CALL_FUNC) {
1186 aflag=mdl_env::get(get_drn, timer_counter_name_);
1188 aflag=get_drn.get(drn);
1195 case MDL_SET_COUNTER:
1196 #if defined(SHM_SAMPLING)
1197 #if defined(MT_THREAD)
1198 code = createCounter("setCounter", (void *)(drn->getAllocatedLevel()),
1199 (void *)(drn->getAllocatedIndex()),ast_arg);
1201 code = createCounter("setCounter", (void *)(drn->getInferiorPtr(global_proc)), ast_arg);
1204 code = createCounter("setCounter", (void *)(drn->getInferiorPtr()), ast_arg);
1207 case MDL_ADD_COUNTER:
1208 #if defined(SHM_SAMPLING)
1209 #if defined(MT_THREAD)
1210 code = createCounter("addCounter", (void *)(drn->getAllocatedLevel()),
1211 (void *)(drn->getAllocatedIndex()), ast_arg);
1213 code = createCounter("addCounter", (void *)(drn->getInferiorPtr(global_proc)), ast_arg);
1216 code = createCounter("addCounter", (void *)(drn->getInferiorPtr()), ast_arg);
1219 case MDL_SUB_COUNTER:
1220 #if defined(SHM_SAMPLING)
1221 #if defined(MT_THREAD)
1222 code = createCounter("subCounter", (void *)(drn->getAllocatedLevel()),
1223 (void *)(drn->getAllocatedIndex()), ast_arg);
1225 code = createCounter("subCounter", (void *)(drn->getInferiorPtr(global_proc)), ast_arg);
1228 code = createCounter("subCounter", (void *)(drn->getInferiorPtr()), ast_arg);
1231 case MDL_START_WALL_TIMER:
1232 case MDL_STOP_WALL_TIMER:
1233 case MDL_START_PROC_TIMER:
1234 case MDL_STOP_PROC_TIMER:
1235 #if defined(SHM_SAMPLING)
1236 #if defined(MT_THREAD)
1237 code = createTimer(timer_fun, (void *)(drn->getAllocatedLevel()),
1238 (void *)(drn->getAllocatedIndex()), ast_args);
1240 code = createTimer(timer_fun, (void *)(drn->getInferiorPtr(global_proc)), ast_args);
1243 code = createTimer(timer_fun, (void *)(drn->getInferiorPtr()), ast_args);
1247 if (! rand_->apply(code))
1254 // Note: we don't use assignAst on purpose here
1256 code = createIf(pred, tmp);
1260 if (mn_initialized) {
1261 // Note: we don't use assignAst on purpose here
1263 mn = new AstNode(tmp, code);
1266 mn = assignAst(code);
1274 T_dyninstRPC::mdl_stmt::mdl_stmt() { }
1276 T_dyninstRPC::mdl_for_stmt::mdl_for_stmt(string index_name, T_dyninstRPC::mdl_expr *list_exp, T_dyninstRPC::mdl_stmt *body)
1277 : for_body_(body), index_name_(index_name), list_expr_(list_exp) { }
1278 T_dyninstRPC::mdl_for_stmt::mdl_for_stmt() { }
1279 T_dyninstRPC::mdl_for_stmt::~mdl_for_stmt() {
1284 bool T_dyninstRPC::mdl_for_stmt::apply(metricDefinitionNode *mn,
1285 vector<dataReqNode*>& flags) {
1287 mdl_env::add(index_name_, false);
1288 mdl_var list_var(false);
1290 // TODO -- build iterator closure here -- list may be vector or dictionary
1291 if (!list_expr_->apply(list_var))
1293 if (!list_var.is_list())
1297 // vector<function_base*> *vp;
1298 // list_var.get(vp);
1299 list_closure closure(index_name_, list_var);
1301 // mdl_env::set_type(list_var.element_type(), index_name_);
1302 while (closure.next()) {
1303 if (!for_body_->apply(mn, flags)) return false;
1310 T_dyninstRPC::mdl_icode::mdl_icode() { }
1311 T_dyninstRPC::mdl_icode::mdl_icode(T_dyninstRPC::mdl_instr_rand *iop1,
1312 T_dyninstRPC::mdl_instr_rand *iop2,
1313 u_int bin_op, bool use_if,
1314 T_dyninstRPC::mdl_instr_req *ireq)
1315 : if_op1_(iop1), if_op2_(iop2),
1316 bin_op_(bin_op), use_if_(use_if), req_(ireq) { }
1317 T_dyninstRPC::mdl_icode::~mdl_icode() { delete req_; }
1319 static AstNode *do_rel_op(opCode op, T_dyninstRPC::mdl_instr_rand *if_op2,
1320 AstNode *ast_left) {
1321 // NOTE: ast_left _must_ be defined
1322 AstNode *ast_right=NULL;
1324 if (!if_op2->apply(ast_right)) {
1325 removeAst(ast_right);
1326 return(new AstNode());
1328 tmp = new AstNode(op, ast_left, ast_right);
1329 removeAst(ast_right);
1333 bool T_dyninstRPC::mdl_icode::apply(AstNode *&mn, bool mn_initialized) {
1334 // a return value of true implies that "mn" has been written to
1335 // TODO -- handle the if case here
1336 // TODO -- call req_->apply() after building if
1342 AstNode *pred_ptr=NULL;
1346 if (!if_op1_->apply(ast1))
1350 pred = do_rel_op(lessOp, if_op2_, ast1);
1353 pred = do_rel_op(greaterOp, if_op2_, ast1);
1356 pred = do_rel_op(leOp, if_op2_, ast1);
1359 pred = do_rel_op(geOp, if_op2_, ast1);
1362 pred = do_rel_op(eqOp, if_op2_, ast1);
1365 pred = do_rel_op(neOp, if_op2_, ast1);
1368 pred = new AstNode(ast1);
1370 default: return false;
1373 pred_ptr = new AstNode(pred);
1378 bool result = req_->apply(mn, pred_ptr, mn_initialized);
1379 // note: a result of true implies that "mn" was written to
1380 // Hence, a result of true from this routine means the same.
1383 removeAst(pred_ptr);
1387 T_dyninstRPC::mdl_expr::mdl_expr() { }
1388 T_dyninstRPC::mdl_expr::~mdl_expr() { }
1390 T_dyninstRPC::mdl_v_expr::mdl_v_expr()
1391 : args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL), type_(MDL_T_NONE),
1392 do_type_walk_(false), ok_(false) { }
1394 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string var, vector<string> fields)
1395 : var_(var), fields_(fields),
1396 args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL),
1397 type_(MDL_RVAL_DEREF), do_type_walk_(false), ok_(false) { assert(0); }
1399 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string func_name,
1400 vector<T_dyninstRPC::mdl_expr *> *a)
1401 : var_(func_name), args_(a),
1402 literal_(0), arg_(100000), left_(NULL), right_(NULL),
1403 type_(MDL_RVAL_FUNC), do_type_walk_(false), ok_(false) { assert(0); }
1405 T_dyninstRPC::mdl_v_expr::mdl_v_expr(int int_lit)
1406 : args_(NULL), literal_(int_lit), arg_(0), left_(NULL), right_(NULL),
1407 type_(MDL_RVAL_INT), do_type_walk_(false), ok_(false) { assert(0); }
1409 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string string_lit)
1411 args_(NULL), literal_(0), arg_(0), left_(NULL), right_(NULL),
1412 type_(MDL_RVAL_STRING), do_type_walk_(false), ok_(false) { assert(0); }
1414 T_dyninstRPC::mdl_v_expr::mdl_v_expr(u_int bin_op, T_dyninstRPC::mdl_expr *left,
1415 T_dyninstRPC::mdl_expr *right)
1416 : args_(NULL), literal_(0),
1417 arg_(bin_op), left_(left), right_(right),
1418 type_(MDL_RVAL_EXPR), do_type_walk_(false), ok_(false) { assert(0); }
1420 T_dyninstRPC::mdl_v_expr::mdl_v_expr(string var, u_int array_index)
1421 : var_(var), args_(NULL), literal_(0), arg_(array_index), left_(NULL), right_(NULL),
1422 type_(MDL_RVAL_ARRAY), do_type_walk_(false), ok_(false) { assert(0); }
1424 T_dyninstRPC::mdl_v_expr::~mdl_v_expr() {
1425 delete args_; delete left_; delete right_;
1427 unsigned size = args_->size();
1428 for (unsigned u=0; u<size; u++)
1434 bool T_dyninstRPC::mdl_v_expr::apply(mdl_var& ret) {
1437 return (ret.set(literal_));
1438 case MDL_RVAL_STRING:
1439 return (ret.set(var_));
1440 case MDL_RVAL_ARRAY:
1442 mdl_var array(false);
1443 if (!mdl_env::get(array, var_)) return false;
1444 if (!array.is_list()) return false;
1445 if (arg_ >= array.list_size()) return false;
1446 return (array.get_ith_element(ret, arg_));
1450 mdl_var left_val(false), right_val(false);
1451 if (!left_ || !right_) return false;
1452 if (!left_->apply(left_val)) return false;
1453 if (!right_->apply(right_val)) return false;
1454 return (do_operation(ret, left_val, right_val, arg_));
1462 mdl_var arg0(false);
1463 if (!(*args_)[0]->apply(arg0)) return false;
1465 if (!arg0.get(func_name)) return false;
1467 // TODO -- what if the function is not found ?
1468 function_base *pdf = global_proc->findOneFunction(func_name);
1469 return (ret.set(pdf));
1471 assert(0); return false;
1477 mdl_var arg0(false);
1478 if (!(*args_)[0]->apply(arg0)) return false;
1480 if (!arg0.get(mod_name)) return false;
1482 // TODO -- what if the function is not found ?
1483 module *mod = global_proc->findModule(mod_name,false);
1484 if (!mod) { assert(0); return false; }
1485 return (ret.set(mod));
1487 assert(0); return false;
1493 mdl_var arg0(false);
1494 if (!(*args_)[0]->apply(arg0)) return false;
1496 if (!arg0.get(tag)) return false;
1497 int res = tag & TAG_LIB_FUNC;
1498 return (ret.set(res));
1503 case MDL_RVAL_DEREF:
1505 return (mdl_env::get(ret, var_));
1507 return (walk_deref(ret, type_walk, var_));
1514 T_dyninstRPC::mdl_if_stmt::mdl_if_stmt(T_dyninstRPC::mdl_expr *expr, T_dyninstRPC::mdl_stmt *body) : expr_(expr), body_(body) { }
1515 T_dyninstRPC::mdl_if_stmt::mdl_if_stmt() { }
1516 T_dyninstRPC::mdl_if_stmt::~mdl_if_stmt() {
1517 delete expr_; delete body_;
1520 bool T_dyninstRPC::mdl_if_stmt::apply(metricDefinitionNode *mn,
1521 vector<dataReqNode*>& flags) {
1522 // An if stmt is comprised of (1) the 'if' expr and (2) the body to
1525 if (!expr_->apply(res))
1529 switch (res.type()) {
1540 return body_->apply(mn, flags);
1543 T_dyninstRPC::mdl_seq_stmt::mdl_seq_stmt(vector<T_dyninstRPC::mdl_stmt*> *stmts) : stmts_(stmts) { }
1544 T_dyninstRPC::mdl_seq_stmt::mdl_seq_stmt() { }
1545 T_dyninstRPC::mdl_seq_stmt::~mdl_seq_stmt() {
1547 unsigned size = stmts_->size();
1548 for (unsigned u=0; u<size; u++)
1549 delete (*stmts_)[u];
1554 bool T_dyninstRPC::mdl_seq_stmt::apply(metricDefinitionNode *mn,
1555 vector<dataReqNode*>& flags) {
1556 // a seq_stmt is simply a sequence of statements; apply them all.
1560 unsigned size = stmts_->size();
1561 for (unsigned index=0; index<size; index++)
1562 if (!(*stmts_)[index]->apply(mn, flags)) // virtual fn call
1568 T_dyninstRPC::mdl_list_stmt::mdl_list_stmt(u_int type, string ident,
1569 vector<string> *elems,
1570 bool is_lib, vector<string>* flavor)
1571 : type_(type), id_(ident), elements_(elems), is_lib_(is_lib), flavor_(flavor) { }
1572 T_dyninstRPC::mdl_list_stmt::mdl_list_stmt() { }
1573 T_dyninstRPC::mdl_list_stmt::~mdl_list_stmt() { delete elements_; }
1575 bool T_dyninstRPC::mdl_list_stmt::apply(metricDefinitionNode * /*mn*/,
1576 vector<dataReqNode*>& /*flags*/) {
1578 for (unsigned u0 = 0; u0 < flavor_->size(); u0++) {
1579 if ((*flavor_)[u0] == daemon_flavor) {
1584 if (!found) return false;
1585 if (!elements_) return false;
1587 mdl_var list_var(id_, false);
1588 unsigned size = elements_->size();
1589 if (!list_var.make_list(type_)) return false;
1591 if (type_ == MDL_T_PROCEDURE_NAME) {
1592 vector<functionName*> *list_fn;
1594 aflag=list_var.get(list_fn);
1596 for (unsigned u=0; u<size; u++) {
1597 functionName *fn = new functionName((*elements_)[u]);
1600 } else if (type_ == MDL_T_PROCEDURE) {
1602 } else if (type_ == MDL_T_MODULE) {
1605 for (unsigned u=0; u<size; u++) {
1606 int i; float f; string s; mdl_var expr_var;
1609 if (sscanf((*elements_)[u].string_of(), "%d", &i) != 1) return false;
1610 if (!expr_var.set(i)) return false; break;
1612 if (sscanf((*elements_)[u].string_of(), "%f", &f) != 1) return false;
1613 if (!expr_var.set(f)) return false; break;
1615 if (!expr_var.set((*elements_)[u])) return false; break;
1619 if (!list_var.add_to_list(expr_var)) return false;
1622 return (mdl_env::add(list_var));
1625 T_dyninstRPC::mdl_instr_stmt::mdl_instr_stmt(unsigned pos, T_dyninstRPC::mdl_expr *expr,
1626 vector<T_dyninstRPC::mdl_icode*> *reqs,
1627 unsigned where, bool constrained)
1628 : position_(pos), point_expr_(expr), icode_reqs_(reqs),
1629 where_instr_(where), constrained_(constrained) { }
1630 T_dyninstRPC::mdl_instr_stmt::mdl_instr_stmt() { }
1631 T_dyninstRPC::mdl_instr_stmt::~mdl_instr_stmt() {
1634 unsigned size = icode_reqs_->size();
1635 for (unsigned u=0; u<size; u++)
1636 delete (*icode_reqs_)[u];
1641 bool T_dyninstRPC::mdl_instr_stmt::apply(metricDefinitionNode *mn,
1642 vector<dataReqNode*>& inFlags) {
1643 // An instr statement is like:
1644 // append preInsn $start.entry constrained (* startWallTimer(a_wallTime); *)
1645 // (note that there are other kinds of statements; i.e. there are other classes
1646 // derived from the base class mdl_stmt; see dyninstRPC.I)
1648 if (icode_reqs_ == NULL)
1649 return false; // no instrumentation code to put in!
1651 mdl_var pointsVar(false);
1652 if (!point_expr_->apply(pointsVar)) // process the 'point(s)' e.g. "$start.entry"
1655 vector<instPoint *> points;
1656 if (pointsVar.type() == MDL_T_LIST_POINT) {
1657 vector<instPoint *> *pts;
1658 if (!pointsVar.get(pts)) return false;
1660 } else if (pointsVar.type() == MDL_T_POINT) {
1662 if (!pointsVar.get(p)) return false; // where the point is located...
1668 // Let's generate the code now (we used to calculate it in the loop below,
1669 // which was a waste since the code is the same for all points).
1670 AstNode *code = NULL;
1671 unsigned size = icode_reqs_->size();
1672 for (unsigned u=0; u<size; u++) {
1673 if (!(*icode_reqs_)[u]->apply(code, u>0)) {
1674 // when u is 0, code is un-initialized
1680 // Instantiate all constraints (flags) here (if any)
1681 // (if !constrained_ then don't do the following)
1683 unsigned fsize = inFlags.size();
1684 for (int fi=fsize-1; fi>=0; fi--) { // any reason why we go backwards?
1685 #if defined(SHM_SAMPLING)
1686 #if defined(MT_THREAD)
1688 tmp_ast = computeAddress((void *)((inFlags[fi])->getAllocatedLevel()),(void *)((inFlags[fi])->getAllocatedIndex()), 0); // 0 is for intCounter
1689 AstNode *temp1 = new AstNode(AstNode::DataIndir,tmp_ast);
1692 // Note: getInferiorPtr could return a NULL pointer here if we are
1693 // just computing cost - naim 2/18/97
1694 AstNode *temp1 = new AstNode(AstNode::DataValue,
1695 (void*)((inFlags[fi])->getInferiorPtr(global_proc)));
1698 // Note: getInferiorPtr could return a NULL pointer here if we are
1699 // just computing cost - naim 2/18/97
1700 AstNode *temp1 = new AstNode(AstNode::DataValue,
1701 (void*)((inFlags[fi])->getInferiorPtr()));
1703 // Note: we don't use assignAst on purpose here
1704 AstNode *temp2 = code;
1705 code = createIf(temp1, temp2);
1712 // we are probably defining an empty metric
1713 code = new AstNode();
1717 switch (position_) {
1719 corder = orderFirstAtPoint;
1722 corder = orderLastAtPoint;
1728 switch (where_instr_) {
1730 cwhen = callPreInsn;
1733 cwhen = callPostInsn;
1738 // Here is where auto-activate should occur.
1739 // If there is 1 point and it is $start.entry then
1740 // do an inferiorRPC right now (of the ast 'code').
1741 // In this way, we can get metrics like cpu and exec-time for whole program
1742 // to work correctly even when the metrics are instantiated after
1743 // the entrypoint of main() is in execution.
1745 bool manuallyTrigger = false; // for now
1747 if (points.size() == 1) {
1748 // now look at the mdl variable to check for $start.entry.
1749 if (pointsVar.name() == "$start" && pointsVar.type()==MDL_T_POINT) {
1750 // having a type of MDL_T_POINT should mean $start.entry as opposed to
1751 // $start.exit, since $start.exit would yield a type of MDL_T_LIST_POINT,
1752 // since exit locations are always a list-of-points. Sorry for the kludge.
1754 instPoint *theVrbleInstPoint; // NOTE: instPoint is defined in arch-specific files!!!
1755 bool aflag = pointsVar.get(theVrbleInstPoint);
1756 // theVrbleInstPoint set to equiv of points[0]
1759 assert(theVrbleInstPoint == points[0]); // just a sanity check
1762 string varName = pointsVar.name();
1763 aflag=mdl_env::get(theVar, varName);
1766 function_base *theFunction;
1767 aflag=theVar.get(theFunction);
1770 // Make a note to do an inferiorRPC to manually execute this code.
1771 // if (!manuallyTrigger)
1772 // cerr << "mdl: found $start.entry; going to manually execute via inferior-RPC" << endl;
1774 manuallyTrigger = true;
1778 // for all of the inst points, insert the predicates and the code itself.
1779 for (unsigned i = 0; i < points.size(); i++) {
1780 mn->addInst(points[i], code, cwhen, corder,
1781 manuallyTrigger && (i==0)); // manually trigger at most once
1782 // appends an instReqNode to mn's instRequests; actual
1783 // instrumentation only
1784 // takes place when mn->insertInstrumentation() is later called.
1790 bool mdl_can_do(string& met_name) {
1791 // NOTE: We can do better if there's a dictionary of <metric-name> to <anything>
1792 unsigned size = mdl_data::all_metrics.size();
1793 for (unsigned u=0; u<size; u++)
1794 if (mdl_data::all_metrics[u]->name_ == met_name)
1800 metricDefinitionNode *mdl_do(vector< vector<string> >& canon_focus,
1803 vector<process *> procs,
1804 bool replace_components_if_present,
1805 bool computingCost) {
1806 currentMetric = met_name;
1807 unsigned size = mdl_data::all_metrics.size();
1808 // NOTE: We can do better if there's a dictionary of <metric-name> to <metric>!
1809 for (unsigned u=0; u<size; u++) {
1810 if (mdl_data::all_metrics[u]->name_ == met_name) {
1811 return (mdl_data::all_metrics[u]->apply(canon_focus, flat_name, procs,
1812 replace_components_if_present,
1814 // calls mdl_metric::apply()
1820 bool mdl_init(string& flavor) {
1822 daemon_flavor = flavor;
1825 vector<mdl_type_desc> kids;
1826 mdl_type_desc self, kid;
1827 mdl_focus_element fe;
1829 self.name = "SyncObject"; self.type = 0; self.end_allowed = false;
1830 kid.name = "Message"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1831 kid.name = "Barrier"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1832 kid.name = "Semaphore"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1833 kid.name = "SpinLock"; kid.type = MDL_T_INT; kid.end_allowed = true; kids += kid;
1834 fe.self = self; fe.kids = kids;
1835 mdl_data::foci += fe;
1838 // self.name = "Procedure"; self.type = MDL_T_MODULE; self.end_allowed = true;
1839 self.name = "Code"; self.type = MDL_T_MODULE; self.end_allowed = true;
1840 kid.name = "Module"; kid.type = MDL_T_PROCEDURE; self.end_allowed = true; kids += kids;
1841 fe.self = self; fe.kids = kids;
1842 mdl_data::foci += fe;
1845 self.name = "Process"; self.type = MDL_T_PROCESS; self.end_allowed = true;
1846 fe.self = self; fe.kids.resize(0);
1847 mdl_data::foci += fe;
1849 self.name = "Machine"; self.type = MDL_T_STRING; self.end_allowed = true;
1850 fe.self = self; fe.kids.resize(0);
1851 mdl_data::foci += fe;
1855 // These are pushed on per-process
1856 // mdl_env::add("$procedures", false, MDL_T_LIST_PROCEDURE);
1857 // mdl_env::add("$modules", false, MDL_T_LIST_MODULE);
1859 string vname = "$machine";
1860 mdl_env::add(vname, false, MDL_T_STRING);
1861 string nodename = getHostName();
1862 mdl_env::set(nodename, vname);
1864 /* Are these entered by hand at the new scope ? */
1867 vector<mdl_type_desc> field_list;
1869 desc.name = "name"; desc.type = MDL_T_STRING; field_list += desc;
1870 desc.name = "calls"; desc.type = MDL_T_LIST_POINT; field_list += desc;
1871 desc.name = "entry"; desc.type = MDL_T_POINT; field_list += desc;
1872 desc.name = "return"; desc.type = MDL_T_POINT; field_list += desc;
1873 desc.name = "tag"; desc.type = MDL_T_INT; field_list += desc;
1874 mdl_data::fields[MDL_T_PROCEDURE] = field_list;
1875 field_list.resize(0);
1877 desc.name = "name"; desc.type = MDL_T_STRING; field_list += desc;
1878 desc.name = "funcs"; desc.type = MDL_T_LIST_PROCEDURE; field_list += desc;
1879 mdl_data::fields[MDL_T_MODULE] = field_list;
1880 field_list.resize(0);
1882 desc.name = "upper"; desc.type = MDL_T_INT; field_list += desc;
1883 desc.name = "lower"; desc.type = MDL_T_INT; field_list += desc;
1884 mdl_data::fields[MDL_T_VARIABLE] = field_list;
1885 field_list.resize(0);
1890 void dynRPC::send_metrics(vector<T_dyninstRPC::mdl_metric*>* var_0) {
1894 unsigned var_size = var_0->size();
1895 for (unsigned v=0; v<var_size; v++) {
1896 // fprintf(stderr, "Got metric %s\n", (*var_0)[v]->name_.string_of());
1899 unsigned f_size = (*var_0)[v]->flavors_->size();
1901 bool flavor_found = false;
1902 for (unsigned f=0; f<f_size; f++) {
1903 if ((*(*var_0)[v]->flavors_)[f] == daemon_flavor) {
1904 flavor_found = true; break;
1908 unsigned size=mdl_data::all_metrics.size();
1909 for (unsigned u=0; u<size; u++)
1910 if (mdl_data::all_metrics[u]->id_ == (*var_0)[v]->id_) {
1911 delete mdl_data::all_metrics[u];
1912 mdl_data::all_metrics[u] = (*var_0)[v];
1916 T_dyninstRPC::mdl_metric *m = (*var_0)[v];
1917 mdl_data::all_metrics += m;
1922 fprintf(stderr, "no metric defined\n");
1927 void dynRPC::send_constraints(vector<T_dyninstRPC::mdl_constraint*> *cv) {
1931 unsigned var_size = cv->size();
1932 for (unsigned v=0; v<var_size; v++) {
1934 // cout << "Received " << (*cv)[v]->id_ << endl;
1935 for (unsigned u=0; u<mdl_data::all_constraints.size(); u++)
1936 if (mdl_data::all_constraints[u]->id_ == (*cv)[v]->id_) {
1937 delete mdl_data::all_constraints[u];
1938 mdl_data::all_constraints[u] = (*cv)[v];
1942 mdl_data::all_constraints += (*cv)[v];
1943 // cout << *(*cv)[v] << endl;
1950 // TODO -- are these executed immediately ?
1951 void dynRPC::send_stmts(vector<T_dyninstRPC::mdl_stmt*> *vs) {
1954 // ofstream of("other_out", (been_here ? ios::app : ios::out));
1955 // been_here = true;
1956 // of << "SEND_STMTS\n";
1957 // unsigned size = vs->size();
1958 // for (unsigned u=0; u<size; u++)
1959 // (*vs)[u]->print(of);
1960 mdl_data::stmts += *vs;
1962 // TODO -- handle errors here
1963 // TODO -- apply these statements without a metric definition node ?
1964 unsigned s_size = vs->size();
1965 vector<dataReqNode*> flags;
1967 // Application may fail if the list flavor is different than the flavor
1970 for (unsigned s=0; s<s_size; s++) {
1971 if (!(*vs)[s]->apply(NULL, flags))
1973 // (*vs)[s]->print(cout);
1979 // recieves the list of shared libraries to exclude
1980 void dynRPC::send_libs(vector<string> *libs) {
1983 for(u_int i=0; i < libs->size(); i++){
1984 mdl_data::lib_constraints += (*libs)[i];
1989 // recieves the list of functions from shared libraries to exclude
1990 void dynRPC::send_funcs(vector<string> *funcs) {
1993 for(u_int i=0; i < funcs->size(); i++){
1994 mdl_data::func_constraints += (*funcs)[i];
1998 // recieves notification that there are no excluded libraries
1999 void dynRPC::send_no_libs() {
2005 // recieves notification that there are no excluded functions
2006 void dynRPC::send_no_funcs() {
2011 static bool do_operation(mdl_var& ret, mdl_var& left_val,
2012 mdl_var& right_val, unsigned bin_op) {
2018 if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
2020 if (!left_val.get(v1)) return false;
2021 if (!right_val.get(v2)) return false;
2023 case MDL_PLUS: return (ret.set(v1+v2));
2024 case MDL_MINUS: return (ret.set(v1-v2));
2025 case MDL_DIV: return (ret.set(v1/v2));
2026 case MDL_MULT: return (ret.set(v1*v2));
2028 } else if (((left_val.type() == MDL_T_INT) || (left_val.type() == MDL_T_FLOAT)) &&
2029 ((right_val.type() == MDL_T_INT) || (right_val.type() == MDL_T_FLOAT))) {
2031 if (left_val.type() == MDL_T_INT) {
2032 int i1; if (!left_val.get(i1)) return false; v1 = (float)i1;
2034 if (!left_val.get(v1)) return false;
2036 if (right_val.type() == MDL_T_INT) {
2037 int i1; if (!right_val.get(i1)) return false; v2 = (float)i1;
2039 if (!right_val.get(v2)) return false;
2042 case MDL_PLUS: return (ret.set(v1+v2));
2043 case MDL_MINUS: return (ret.set(v1-v2));
2044 case MDL_DIV: return (ret.set(v1/v2));
2045 case MDL_MULT: return (ret.set(v1*v2));
2055 if ((left_val.type() == MDL_T_STRING) && (right_val.type() == MDL_T_STRING)) {
2057 if (!left_val.get(v1)) return false;
2058 if (!right_val.get(v2)) return false;
2060 case MDL_LT: return (ret.set(v1 < v2));
2061 case MDL_GT: return (ret.set(v1 > v2));
2062 case MDL_LE: return (ret.set(v1 <= v2));
2063 case MDL_GE: return (ret.set(v1 >= v2));
2064 case MDL_EQ: return (ret.set(v1 == v2));
2065 case MDL_NE: return (ret.set(v1 != v2));
2068 if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
2070 if (!left_val.get(v1)) return false;
2071 if (!right_val.get(v2)) return false;
2073 case MDL_LT: return (ret.set(v1 < v2));
2074 case MDL_GT: return (ret.set(v1 > v2));
2075 case MDL_LE: return (ret.set(v1 <= v2));
2076 case MDL_GE: return (ret.set(v1 >= v2));
2077 case MDL_EQ: return (ret.set(v1 == v2));
2078 case MDL_NE: return (ret.set(v1 != v2));
2080 } else if (((left_val.type() == MDL_T_INT) ||
2081 (left_val.type() == MDL_T_FLOAT)) &&
2082 ((right_val.type() == MDL_T_INT) ||
2083 (right_val.type() == MDL_T_FLOAT))) {
2085 if (left_val.type() == MDL_T_INT) {
2086 int i1; if (!left_val.get(i1)) return false; v1 = (float)i1;
2088 if (!left_val.get(v1)) return false;
2090 if (right_val.type() == MDL_T_INT) {
2091 int i1; if (!right_val.get(i1)) return false; v2 = (float)i1;
2093 if (!right_val.get(v2)) return false;
2096 case MDL_LT: return (ret.set(v1 < v2));
2097 case MDL_GT: return (ret.set(v1 > v2));
2098 case MDL_LE: return (ret.set(v1 <= v2));
2099 case MDL_GE: return (ret.set(v1 >= v2));
2100 case MDL_EQ: return (ret.set(v1 == v2));
2101 case MDL_NE: return (ret.set(v1 != v2));
2107 if ((left_val.type() == MDL_T_INT) && (right_val.type() == MDL_T_INT)) {
2109 if (!left_val.get(v1)) return false;
2110 if (!right_val.get(v2)) return false;
2112 case MDL_AND: return (ret.set(v1 && v2));
2113 case MDL_OR: return (ret.set(v1 || v2));
2123 static bool walk_deref(mdl_var& ret, vector<unsigned>& types, string& var_name) {
2125 function_base *pdf = 0;
2126 if (!mdl_env::get(ret, var_name)) return false;
2129 unsigned max = types.size();
2131 while (index < max) {
2132 unsigned current_type = types[index++];
2133 unsigned next_field = types[index++];
2135 switch (current_type) {
2136 case MDL_T_PROCEDURE:
2137 // function_base *pdf = 0;
2138 if (!ret.get(pdf)) return false;
2139 switch (next_field) {
2141 string prettyName = pdf->prettyName();
2142 if (!ret.set(prettyName)) return false;
2145 // TODO: should these be passed a process?
2147 if (!ret.set((vector<instPoint *>*)&pdf->funcCalls(global_proc)))
2151 if (!ret.set((instPoint *)pdf->funcEntry(global_proc)))
2155 if (!ret.set((vector<instPoint *>*)&pdf->funcExits(global_proc)))
2159 if (!ret.set((int)pdf->tag()))
2169 if (!ret.get(mod)) return false;
2170 switch (next_field) {
2171 case 0: { string fileName = mod->fileName();
2172 if (!ret.set(fileName)) return false;
2176 if (!ret.set(global_proc->getIncludedFunctions(mod))) return false;
2179 if (!ret.set(mod->getFunctions())) return false;
2183 default: assert(0); break;
2187 assert(0); return false;
2194 bool mdl_get_initial(string flavor, pdRPC *connection) {
2196 while (!(mdl_met && mdl_cons && mdl_stmt && mdl_libs && mdl_funcs)) {
2197 switch (connection->waitLoop()) {
2198 case T_dyninstRPC::error:
2203 while (connection->buffered_requests()) {
2204 switch (connection->process_buffered()) {
2205 case T_dyninstRPC::error:
2215 bool mdl_get_lib_constraints(vector<string> &lc){
2216 for(u_int i=0; i < mdl_data::lib_constraints.size(); i++){
2217 lc += mdl_data::lib_constraints[i];
2219 return (lc.size()>0);
2222 bool mdl_get_func_constraints(vector<string> &lc){
2223 for(u_int i=0; i < mdl_data::func_constraints.size(); i++){
2224 lc += mdl_data::func_constraints[i];
2226 return (lc.size()>0);
2229 void mdl_get_info(vector<T_dyninstRPC::metricInfo>& metInfo) {
2230 unsigned size = mdl_data::all_metrics.size();
2231 T_dyninstRPC::metricInfo element;
2232 for (unsigned u=0; u<size; u++) {
2233 element.name = mdl_data::all_metrics[u]->name_;
2234 element.style = mdl_data::all_metrics[u]->style_;
2235 element.aggregate = mdl_data::all_metrics[u]->agg_op_;
2236 element.units = mdl_data::all_metrics[u]->units_;
2237 element.developerMode = mdl_data::all_metrics[u]->developerMode_;
2238 element.unitstype = mdl_data::all_metrics[u]->unitstype_;
2243 bool mdl_metric_data(const string& met_name, mdl_inst_data& md) {
2244 unsigned size = mdl_data::all_metrics.size();
2245 for (unsigned u=0; u<size; u++)
2246 if (mdl_data::all_metrics[u]->name_ == met_name) {
2247 md.aggregate = mdl_data::all_metrics[u]->agg_op_;
2248 md.style = (metricStyle) mdl_data::all_metrics[u]->style_;