diff options
author | dsmith <dsmith> | 2006-08-10 19:19:05 +0000 |
---|---|---|
committer | dsmith <dsmith> | 2006-08-10 19:19:05 +0000 |
commit | 88bbd60de43030f300649cd049ad87393c54a933 (patch) | |
tree | d866e76a2c0c12b75c1f1e64e168ce351b016ebf | |
parent | 408acea1833e4cdc2d303edf4295f9d04c21e2d2 (diff) | |
download | systemtap-steved-88bbd60de43030f300649cd049ad87393c54a933.tar.gz systemtap-steved-88bbd60de43030f300649cd049ad87393c54a933.tar.xz systemtap-steved-88bbd60de43030f300649cd049ad87393c54a933.zip |
2006-08-10 David Smith <dsmith@redhat.com>
* elaborate.cxx (duplicate_function_remover): Added class.
(get_functionsig): Added function.
(semantic_pass_opt5): New function merges duplicate identical
functions into one function.
(semantic_pass_optimize): Calls semantic_pass_opt5.
* translate.cxx (c_unparser::emit_probe): Changed to merge
duplicate probes bodies by making the duplicate probe just call
the original probe (BZ# 2421).
-rw-r--r-- | ChangeLog | 12 | ||||
-rw-r--r-- | elaborate.cxx | 89 | ||||
-rw-r--r-- | translate.cxx | 87 |
3 files changed, 159 insertions, 29 deletions
@@ -1,3 +1,15 @@ +2006-08-10 David Smith <dsmith@redhat.com> + + * elaborate.cxx (duplicate_function_remover): Added class. + (get_functionsig): Added function. + (semantic_pass_opt5): New function merges duplicate identical + functions into one function. + (semantic_pass_optimize): Calls semantic_pass_opt5. + + * translate.cxx (c_unparser::emit_probe): Changed to merge + duplicate probes bodies by making the duplicate probe just call + the original probe (BZ# 2421). + 2006-08-08 Li Guanglei <guanglei@cn.ibm.com> * stapprobes.5.in: document process.*, tcp.*, udp.* diff --git a/elaborate.cxx b/elaborate.cxx index b6d0f226..00a3a7c2 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -1550,6 +1550,94 @@ void semantic_pass_opt4 (systemtap_session& s, bool& relaxed_p) } } +struct duplicate_function_remover: public functioncall_traversing_visitor +{ + systemtap_session& s; + bool& relaxed_p; + map<functiondecl*, functiondecl*>& duplicate_function_map; + + duplicate_function_remover(systemtap_session& sess, bool& r, + map<functiondecl*, functiondecl*>&dfm): + s(sess), relaxed_p(r), duplicate_function_map(dfm) {}; + + void visit_functioncall (functioncall* e); +}; + +void +duplicate_function_remover::visit_functioncall (functioncall *e) +{ + functioncall_traversing_visitor::visit_functioncall (e); + + // If the current function call reference points to a function that + // is a duplicate, replace it. + if (duplicate_function_map.count(e->referent) != 0) + { + if (s.verbose>2) + clog << "Changing " << e->referent->name + << " reference to " + << duplicate_function_map[e->referent]->name + << " reference\n"; + e->tok = duplicate_function_map[e->referent]->tok; + e->function = duplicate_function_map[e->referent]->name; + e->referent = duplicate_function_map[e->referent]; + + relaxed_p = false; + } +} + +static string +get_functionsig (functiondecl* f) +{ + ostringstream s; + + // Get the "name:args body" of the function in s. We have to + // include the args since the function 'x1(a, b)' is different than + // the function 'x2(b, a)' even if the bodies of the two functions + // are exactly the same. + f->printsig(s); + f->body->print(s); + + // printsig puts f->name + ':' on the front. Remove this + // (otherwise, functions would never compare equal). + string str = s.str().erase(0, f->name.size() + 1); + + // Return the function signature. + return str; +} + +void semantic_pass_opt5 (systemtap_session& s, bool& relaxed_p) +{ + // Walk through all the functions, looking for duplicates. + map<string, functiondecl*> functionsig_map; + map<functiondecl*, functiondecl*> duplicate_function_map; + for (unsigned i=0; i < s.functions.size(); i++) + { + string functionsig = get_functionsig(s.functions[i]); + + if (functionsig_map.count(functionsig) == 0) + // This function is unique. Remember it. + functionsig_map[functionsig] = s.functions[i]; + else + // This function is a duplicate. + duplicate_function_map[s.functions[i]] + = functionsig_map[functionsig]; + } + + // If we have duplicate functions, traverse down the tree, replacing + // the appropriate function calls. + // duplicate_function_remover::visit_functioncall() handles the + // details of replacing the function calls. Note that we don't + // delete the duplicate functiondecl itself, we'll let pass 1 do + // that. + if (duplicate_function_map.size() != 0) + { + duplicate_function_remover dfr (s, relaxed_p, duplicate_function_map); + + for (unsigned i=0; i < s.probes.size(); i++) + s.probes[i]->body->visit(&dfr); + } +} + static int semantic_pass_optimize (systemtap_session& s) @@ -1571,6 +1659,7 @@ semantic_pass_optimize (systemtap_session& s) semantic_pass_opt2 (s, relaxed_p); semantic_pass_opt3 (s, relaxed_p); semantic_pass_opt4 (s, relaxed_p); + semantic_pass_opt5 (s, relaxed_p); } if (s.probes.size() == 0) diff --git a/translate.cxx b/translate.cxx index 967949a4..88eb9634 100644 --- a/translate.cxx +++ b/translate.cxx @@ -68,6 +68,8 @@ struct c_unparser: public unparser, public visitor unsigned tmpvar_counter; unsigned label_counter; + map<string, string> probe_contents; + c_unparser (systemtap_session* ss): session (ss), o (ss->op), current_probe(0), current_function (0), tmpvar_counter (0), label_counter (0) {} @@ -1270,40 +1272,67 @@ c_unparser::emit_probe (derived_probe* v) o->newline() << "static void " << v->name << " (struct context * __restrict__ c) {"; o->indent(1); - // initialize frame pointer - o->newline() << "struct " << v->name << "_locals * __restrict__ l ="; - o->newline(1) << "& c->locals[0]." << v->name << ";"; - o->newline(-1) << "(void) l;"; // make sure "l" is marked used - - // emit all read/write locks for global variables - varuse_collecting_visitor vut; - v->body->visit (& vut); - emit_locks (vut); + // If we about to emit a probe that is exactly the same as another + // probe previously emitted, make the second probe just call the + // first one. + // + // Notice we're using the probe body itself instead of the emitted C + // probe body to compare probes. We need to do this because the + // emitted C probe body has stuff in it like: + // + // c->last_stmt = "identifier 'printf' at foo.stp:<line>:<column>"; + // + // which would make comparisons impossible. + ostringstream oss; + v->body->print(oss); - // initialize locals - for (unsigned j=0; j<v->locals.size(); j++) - { - if (v->locals[j]->index_types.size() > 0) // array? - throw semantic_error ("array locals not supported", v->tok); - else if (v->locals[j]->type == pe_long) - o->newline() << "l->" << c_varname (v->locals[j]->name) - << " = 0;"; - else if (v->locals[j]->type == pe_string) - o->newline() << "l->" << c_varname (v->locals[j]->name) - << "[0] = '\\0';"; - else - throw semantic_error ("unsupported local variable type", - v->locals[j]->tok); + // If an identical probe has already been emitted, just call that + // one. + if (probe_contents.count(oss.str()) != 0) + { + o->newline() << probe_contents[oss.str()] << " (c);"; } + // This probe is unique. Remember it and output it. + else + { + probe_contents[oss.str()] = v->name; + + // initialize frame pointer + o->newline() << "struct " << v->name << "_locals * __restrict__ l ="; + o->newline(1) << "& c->locals[0]." << v->name << ";"; + o->newline(-1) << "(void) l;"; // make sure "l" is marked used + + // emit all read/write locks for global variables + varuse_collecting_visitor vut; + v->body->visit (& vut); + emit_locks (vut); + + // initialize locals + for (unsigned j=0; j<v->locals.size(); j++) + { + if (v->locals[j]->index_types.size() > 0) // array? + throw semantic_error ("array locals not supported", v->tok); + else if (v->locals[j]->type == pe_long) + o->newline() << "l->" << c_varname (v->locals[j]->name) + << " = 0;"; + else if (v->locals[j]->type == pe_string) + o->newline() << "l->" << c_varname (v->locals[j]->name) + << "[0] = '\\0';"; + else + throw semantic_error ("unsupported local variable type", + v->locals[j]->tok); + } - v->body->visit (this); + v->body->visit (this); - o->newline(-1) << "out:"; - // NB: no need to uninitialize locals, except if arrays can somedays be local - // XXX: do this flush only if the body included a print/printf/etc. routine! - o->newline(1) << "_stp_print_flush();"; + o->newline(-1) << "out:"; + // NB: no need to uninitialize locals, except if arrays can + // somedays be local XXX: do this flush only if the body + // included a print/printf/etc. routine! + o->newline(1) << "_stp_print_flush();"; - emit_unlocks (vut); + emit_unlocks (vut); + } o->newline(-1) << "}\n"; |