static const string TOK_TYPE("type");
static const string TOK_CONFIG("config");
static const string TOK_SAMPLE("sample");
+static const string TOK_HZ("hz");
static const string TOK_PROCESS("process");
static const string TOK_COUNTER("counter");
int64_t interval;
bool has_process;
bool has_counter;
+ bool has_freq;
string process_name;
string counter;
perf_derived_probe (probe* p, probe_point* l, int64_t type, int64_t config,
- int64_t i, bool pp, bool cp, string pn, string cv);
+ int64_t i, bool pp, bool cp, bool freq, string pn, string cv);
virtual void join_group (systemtap_session& s);
};
struct perf_derived_probe_group: public generic_dpg<perf_derived_probe>
{
+ friend bool sort_for_bpf(perf_derived_probe_group *pg,
+ sort_for_bpf_probe_arg_vector &v);
+
void emit_module_decls (systemtap_session& s);
void emit_module_init (systemtap_session& s);
void emit_module_exit (systemtap_session& s);
int64_t i,
bool process_p,
bool counter_p,
+ bool freq,
string process_n,
string counter):
derived_probe (p, l, true /* .components soon rewritten */),
event_type (type), event_config (config), interval (i),
- has_process (process_p), has_counter (counter_p), process_name (process_n),
- counter (counter)
+ has_process (process_p), has_counter (counter_p), has_freq(freq),
+ process_name (process_n), counter (counter)
{
vector<probe_point::component*>& comps = this->sole_location()->components;
comps.clear();
if (! s.perf_derived_probes)
s.perf_derived_probes = new perf_derived_probe_group ();
s.perf_derived_probes->enroll (this);
+ this->group = s.perf_derived_probes;
if (has_process && !has_counter)
enable_task_finder(s);
s.op->newline() << "{";
s.op->newline(1) << ".attr={ "
<< ".type=" << probes[i]->event_type << "ULL, "
- << ".config=" << probes[i]->event_config << "ULL, "
- << "{ .sample_period=" << probes[i]->interval << "ULL }},";
+ << ".config=" << probes[i]->event_config << "ULL, ";
+ if (probes[i]->has_freq)
+ {
+ s.op->line() << "{ .sample_freq=" << probes[i]->interval << "ULL }, ";
+ s.op->line() << ".freq=1, ";
+ }
+ else
+ {
+ s.op->line() << "{ .sample_period=" << probes[i]->interval << "ULL }, ";
+ }
+ s.op->line() << "},";
s.op->newline() << ".callback=enter_perf_probe_" << i << ", ";
s.op->newline() << ".probe=" << common_probe_init (probes[i]) << ", ";
s.op->newline(-1) << "}";
s.op->newline() << "(*stp->probe->ph) (c);";
- common_probe_entryfn_epilogue (s, true);
+ common_probe_entryfn_epilogue (s, true, otf_safe_context(s));
s.op->newline(-1) << "}";
s.op->newline();
if (have_a_process_tag)
vector<derived_probe *> & finished_results);
static void register_patterns(systemtap_session& s);
+
+ virtual string name() { return "perf builder"; }
};
throw SEMANTIC_ERROR(_("invalid perf sample period ") + lex_cast(period),
parameters.find(TOK_SAMPLE)->second->tok);
- string var;
+ int64_t freq;
+ bool has_freq = get_param(parameters, TOK_HZ, freq);
+
+ interned_string var;
bool has_counter = get_param(parameters, TOK_COUNTER, var);
if (var.find_first_of("*?[") != string::npos)
throw SEMANTIC_ERROR(_("wildcard not allowed with perf probe counter component"));
throw SEMANTIC_ERROR(_("missing perf probe counter component name"));
period = 0; // perf_event_attr.sample_freq should be 0
- if (sess.perf_counters.count(var) > 0)
+ vector<std::pair<string,string> >:: iterator it;
+ for (it=sess.perf_counters.begin() ;
+ it != sess.perf_counters.end(); it++)
+ if ((*it).first == var)
+ break;
+ if (it != sess.perf_counters.end())
throw SEMANTIC_ERROR(_("duplicate counter name"));
// Splice a 'next' into the probe body, and then elaborate.cxx's
}
bool proc_p;
- string proc_n;
+ interned_string proc_n;
if ((proc_p = has_null_param(parameters, TOK_PROCESS)))
{
- proc_n = sess.cmd_file();
+ try
+ {
+ proc_n = sess.cmd_file();
+ }
+ catch (semantic_error& e)
+ {
+ throw SEMANTIC_ERROR(_("invalid -c command for unspecified process"
+ " probe [man stapprobes]"), NULL, NULL, &e);
+ }
if (proc_n.empty())
- throw SEMANTIC_ERROR(_("process probe is invalid without a -c COMMAND"));
+ throw SEMANTIC_ERROR(_("unspecified process probe is invalid without a "
+ "-c COMMAND [man stapprobes]"));
}
else
proc_p = get_param(parameters, TOK_PROCESS, proc_n);
proc_n = find_executable (proc_n, sess.sysroot, sess.sysenv);
if (sess.verbose > 1)
- clog << _F("perf probe type=%" PRId64 " config=%" PRId64 " period=%" PRId64 " process=%s counter=%s",
- type, config, period, proc_n.c_str(), var.c_str()) << endl;
+ clog << _F("perf probe type=%" PRId64 " config=%" PRId64 " %s=%" PRId64 " process=%s counter=%s",
+ type, config, has_freq ? "freq" : "period", has_freq ? freq : period,
+ proc_n.to_string().c_str(), var.to_string().c_str()) << endl;
+
+ // The user-provided pp is already well-formed. Let's add a copy on the chain
+ // and set it as the new base
+ probe_point *new_location = new probe_point(*location);
+ new_location->well_formed = true;
+ probe *new_base = new probe(base, new_location);
finished_results.push_back
- (new perf_derived_probe(base, location, type, config, period, proc_p,
- has_counter, proc_n, var));
+ (new perf_derived_probe(new_base, location, type, config,
+ has_freq ? freq : period, proc_p,
+ has_counter, has_freq, proc_n, var));
if (!var.empty())
- sess.perf_counters[var] = make_pair(proc_n,finished_results.back());
+ sess.perf_counters.push_back(make_pair (var, proc_n));
}
match_node* event = perf->bind_num(TOK_TYPE)->bind_num(TOK_CONFIG);
event->bind(builder);
event->bind_num(TOK_SAMPLE)->bind(builder);
+ event->bind_num(TOK_HZ)->bind(builder);
event->bind_str(TOK_PROCESS)->bind(builder);
event->bind(TOK_PROCESS)->bind(builder);
event->bind_str(TOK_COUNTER)->bind(builder);
event->bind_str(TOK_PROCESS)->bind_str(TOK_COUNTER)->bind(builder);
}
+bool
+sort_for_bpf(perf_derived_probe_group *pg, sort_for_bpf_probe_arg_vector &v)
+{
+ if (!pg)
+ return false;
+
+ for (auto i = pg->probes.begin(); i != pg->probes.end(); ++i)
+ {
+ perf_derived_probe *p = *i;
+ std::stringstream o;
+
+ o << "perf/" << p->event_type << "/" << p->event_config << "/";
+ if (p->has_freq)
+ o << "f/" << p->interval; // uses sample_freq (hz)
+ else
+ o << "p/" << p->interval; // uses sample_period
+
+ // XXX .process, .counter
+ v.push_back(std::pair<derived_probe *, std::string>(p, o.str()));
+ }
+
+ return v.empty();
+}
+
/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */