]> sourceware.org Git - systemtap.git/blobdiff - tapset-perfmon.cxx
NEWS :: mention BPF tapset functions
[systemtap.git] / tapset-perfmon.cxx
index 2d9b6555be1a356c7bbc3f66790e14ff0f2663a1..d00d97edeac3b2b5a72f49df1dcd56b6291d776e 100644 (file)
@@ -28,6 +28,7 @@ static const string TOK_PERF("perf");
 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");
 
@@ -45,16 +46,20 @@ struct perf_derived_probe: public derived_probe
   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);
@@ -67,13 +72,14 @@ perf_derived_probe::perf_derived_probe (probe* p, probe_point* l,
                                         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();
@@ -94,6 +100,7 @@ perf_derived_probe::join_group (systemtap_session& s)
   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);
@@ -164,8 +171,17 @@ perf_derived_probe_group::emit_module_decls (systemtap_session& 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]) << ", ";
 
@@ -228,7 +244,7 @@ perf_derived_probe_group::emit_module_decls (systemtap_session& s)
   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)
@@ -266,6 +282,8 @@ struct perf_builder: public derived_probe_builder
                        vector<derived_probe *> & finished_results);
 
     static void register_patterns(systemtap_session& s);
+
+    virtual string name() { return "perf builder"; }
 };
 
 
@@ -299,7 +317,10 @@ perf_builder::build(systemtap_session & sess,
     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"));
@@ -309,7 +330,12 @@ perf_builder::build(systemtap_session & sess,
        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
@@ -320,12 +346,21 @@ perf_builder::build(systemtap_session & sess,
     }
 
   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);
@@ -333,14 +368,22 @@ perf_builder::build(systemtap_session & sess,
     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));
 }
 
 
@@ -355,10 +398,35 @@ register_tapset_perf(systemtap_session& s)
   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 : */
This page took 0.031067 seconds and 5 git commands to generate.