From ecf50edad53cb651b3de3631fc16c9e17f765b62 Mon Sep 17 00:00:00 2001 From: Jonathan Lebon Date: Mon, 2 Jun 2014 10:49:04 -0400 Subject: [PATCH] semantic_pass_conditions(): collect affected probes In anticipation for on-the-fly probe arming/disarming, we change semantic_pass_conditions() to not only inline the probe condition into its body, but also to collect, for each probe, the set of probes whose conditions may change after the probe's handler is run. That set is stored in the new derived_probe::probes_with_affected_conditions. These sets will be used by the translator to emit code that will check whether affected probes should be armed/disarmed after a handler is run. We also introduce the STP_ON_THE_FLY define which will gate all on-the-fly related code and will be emitted only if required. Finally, we have STP_ON_THE_FLY_DISABLED which can be used to disable all on-the-fly arming/disarming. --- elaborate.cxx | 120 +++++++++++++++++++++++++++++++++++++++----------- elaborate.h | 4 ++ translate.cxx | 4 ++ 3 files changed, 102 insertions(+), 26 deletions(-) diff --git a/elaborate.cxx b/elaborate.cxx index 4dc8b26a0..29d160d58 100644 --- a/elaborate.cxx +++ b/elaborate.cxx @@ -1384,53 +1384,121 @@ semantic_pass_vars (systemtap_session & sess) // // becomes: // -// probe begin(MAX) { if (! (g1 || g2)) %{ disable_probe_foo %} } // probe foo { if (! (g1 || g2)) next; ... } // probe bar { ... g1 ++ ...; // if (g1 || g2) %{ enable_probe_foo %} else %{ disable_probe_foo %} // } // -// XXX: As a first cut, do only the "inline probe condition" part of the -// transform. +// In other words, we perform two transformations: +// (1) Inline probe condition into its body. +// (2) For each probe that modifies a global var in use in any probe's +// condition, re-evaluate those probes' condition at the end of that +// probe's body. +// +// Here, we do all of (1), and half of (2): we simply collect the dependency +// info between probes, which the translator will use to emit the affected +// probes' condition re-evaluation. The translator will also ensure that the +// conditions are evaluated using the globals' starting values prior to any +// probes starting. + +// Adds the condition expression to the front of the probe's body +static void +derived_probe_condition_inline (derived_probe *p) +{ + expression* e = p->sole_location()->condition; + assert(e); + + if_statement *ifs = new if_statement (); + ifs->tok = e->tok; + ifs->thenblock = new next_statement (); + ifs->thenblock->tok = e->tok; + ifs->elseblock = NULL; + unary_expression *notex = new unary_expression (); + notex->op = "!"; + notex->tok = e->tok; + notex->operand = e; + ifs->condition = notex; + p->body = new block (ifs, p->body); +} static int semantic_pass_conditions (systemtap_session & sess) { + map > vars_read_in_cond; + map > vars_written_in_body; + + // do a first pass through the probes to ensure safety, inline any condition, + // and collect var usage for (unsigned i = 0; i < sess.probes.size(); ++i) { derived_probe* p = sess.probes[i]; expression* e = p->sole_location()->condition; + if (e) { - varuse_collecting_visitor vut(sess); - e->visit (& vut); + varuse_collecting_visitor vcv_cond(sess); + e->visit (& vcv_cond); + + if (!vcv_cond.written.empty()) + sess.print_error (SEMANTIC_ERROR (_("probe condition must not " + "modify any variables"), + e->tok)); + else if (vcv_cond.embedded_seen) + sess.print_error (SEMANTIC_ERROR (_("probe condition must not " + "include impure embedded-C"), + e->tok)); + + derived_probe_condition_inline(p); + + vars_read_in_cond[p].insert(vcv_cond.read.begin(), + vcv_cond.read.end()); + } - if (! vut.written.empty()) - { - string err = (_("probe condition must not modify any variables")); - sess.print_error (SEMANTIC_ERROR (err, e->tok)); - } - else if (vut.embedded_seen) + varuse_collecting_visitor vcv_body(sess); + p->body->visit (& vcv_body); + + vars_written_in_body[p].insert(vcv_body.written.begin(), + vcv_body.written.end()); + } + + // do a second pass to collect affected probes + bool need_on_the_fly = false; + for (unsigned i = 0; i < sess.probes.size(); ++i) + { + derived_probe *p = sess.probes[i]; + + // for each variable this probe modifies... + set::const_iterator var; + for (var = vars_written_in_body[p].begin(); + var != vars_written_in_body[p].end(); ++var) + { + // collect probes which could be affected + for (unsigned j = 0; j < sess.probes.size(); ++j) { - sess.print_error (SEMANTIC_ERROR (_("probe condition must not include impure embedded-C"), e->tok)); + if (vars_read_in_cond[sess.probes[j]].count(*var)) + { + if (!p->probes_with_affected_conditions.count(sess.probes[j])) + { + p->probes_with_affected_conditions.insert(sess.probes[j]); + if (sess.verbose > 2) + clog << "probe " << i << " can affect condition of " + "probe " << j << endl; + } + need_on_the_fly = true; + } } - - // Add the condition expression to the front of the - // derived_probe body. - if_statement *ifs = new if_statement (); - ifs->tok = e->tok; - ifs->thenblock = new next_statement (); - ifs->thenblock->tok = e->tok; - ifs->elseblock = NULL; - unary_expression *notex = new unary_expression (); - notex->op = "!"; - notex->tok = e->tok; - notex->operand = e; - ifs->condition = notex; - p->body = new block (ifs, p->body); } } + // Emit STP_ON_THE_FLY macro if needed. + if (need_on_the_fly && !sess.runtime_usermode_p()) + sess.c_macros.push_back("STP_ON_THE_FLY"); + + // As an extra precaution, explicitly disable STP_ON_THE_FLY if in usermode in + // case user provided -D STP_ON_THE_FLY. + else if (sess.runtime_usermode_p()) + sess.c_macros.push_back("STP_ON_THE_FLY_DISABLED"); + return sess.num_errors(); } diff --git a/elaborate.h b/elaborate.h index 6c50cceb8..91102baed 100644 --- a/elaborate.h +++ b/elaborate.h @@ -228,6 +228,10 @@ public: // index into session.probes[], set and used during translation unsigned session_index; + + // List of other derived probes whose conditions may be affected by + // this probe. + std::set probes_with_affected_conditions; }; // ------------------------------------------------------------------------ diff --git a/translate.cxx b/translate.cxx index da3935130..be4f48b54 100644 --- a/translate.cxx +++ b/translate.cxx @@ -6947,6 +6947,10 @@ translate_pass (systemtap_session& s) // Emit the total number of probes (not regarding merged probe handlers) s.op->newline() << "#define STP_PROBE_COUNT " << s.probes.size(); + s.op->newline() << "#ifdef STP_ON_THE_FLY_DISABLED"; + s.op->newline() << "#undef STP_ON_THE_FLY"; + s.op->newline() << "#endif"; + s.op->newline() << "#include \"runtime.h\""; // Emit embeds ahead of time, in case they affect context layout -- 2.43.5