summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2009-05-07 14:49:08 -0700
committerJosh Stone <jistone@redhat.com>2009-05-07 14:52:49 -0700
commit01c2eefe76e5a0eb8dd5a9504b522cdcb11f2665 (patch)
tree4bad9b6ff586602718774470231243af8ed267ef
parentbae55db94d702c373cf66006d6736fb6adb69f23 (diff)
downloadsystemtap-steved-01c2eefe76e5a0eb8dd5a9504b522cdcb11f2665.tar.gz
systemtap-steved-01c2eefe76e5a0eb8dd5a9504b522cdcb11f2665.tar.xz
systemtap-steved-01c2eefe76e5a0eb8dd5a9504b522cdcb11f2665.zip
Separate the permon tapset
-rw-r--r--Makefile.am3
-rw-r--r--Makefile.in19
-rw-r--r--tapset-perfmon.cxx463
-rw-r--r--tapsets.cxx437
-rw-r--r--tapsets.h1
5 files changed, 484 insertions, 439 deletions
diff --git a/Makefile.am b/Makefile.am
index 08775a74..dc8f060d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -38,7 +38,8 @@ stap_SOURCES = main.cxx \
parse.cxx staptree.cxx elaborate.cxx translate.cxx \
tapsets.cxx buildrun.cxx loc2c.c hash.cxx mdfour.c \
cache.cxx util.cxx coveragedb.cxx dwarf_wrappers.cxx \
- tapset-been.cxx tapset-procfs.cxx tapset-timers.cxx
+ tapset-been.cxx tapset-procfs.cxx tapset-timers.cxx \
+ tapset-perfmon.cxx
stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@
BUILT_SOURCES =
diff --git a/Makefile.in b/Makefile.in
index 7d12e709..eded2636 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -123,7 +123,7 @@ am_stap_OBJECTS = stap-main.$(OBJEXT) stap-parse.$(OBJEXT) \
stap-util.$(OBJEXT) stap-coveragedb.$(OBJEXT) \
stap-dwarf_wrappers.$(OBJEXT) stap-tapset-been.$(OBJEXT) \
stap-tapset-procfs.$(OBJEXT) stap-tapset-timers.$(OBJEXT) \
- $(am__objects_1)
+ stap-tapset-perfmon.$(OBJEXT) $(am__objects_1)
stap_OBJECTS = $(am_stap_OBJECTS)
stap_LINK = $(CXXLD) $(stap_CXXFLAGS) $(CXXFLAGS) $(stap_LDFLAGS) \
$(LDFLAGS) -o $@
@@ -330,7 +330,7 @@ stap_SOURCES = main.cxx parse.cxx staptree.cxx elaborate.cxx \
translate.cxx tapsets.cxx buildrun.cxx loc2c.c hash.cxx \
mdfour.c cache.cxx util.cxx coveragedb.cxx dwarf_wrappers.cxx \
tapset-been.cxx tapset-procfs.cxx tapset-timers.cxx \
- $(am__append_4)
+ tapset-perfmon.cxx $(am__append_4)
stap_LDADD = @stap_LIBS@ @sqlite3_LIBS@ $(am__append_6)
# Arrange for git_version.h to be regenerated at every "make".
@@ -605,6 +605,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-parse.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-staptree.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-been.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-perfmon.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-procfs.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapset-timers.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stap-tapsets.Po@am__quote@
@@ -1129,6 +1130,20 @@ stap-tapset-timers.obj: tapset-timers.cxx
@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-timers.obj `if test -f 'tapset-timers.cxx'; then $(CYGPATH_W) 'tapset-timers.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-timers.cxx'; fi`
+stap-tapset-perfmon.o: tapset-perfmon.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-perfmon.o -MD -MP -MF $(DEPDIR)/stap-tapset-perfmon.Tpo -c -o stap-tapset-perfmon.o `test -f 'tapset-perfmon.cxx' || echo '$(srcdir)/'`tapset-perfmon.cxx
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-perfmon.Tpo $(DEPDIR)/stap-tapset-perfmon.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-perfmon.cxx' object='stap-tapset-perfmon.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-perfmon.o `test -f 'tapset-perfmon.cxx' || echo '$(srcdir)/'`tapset-perfmon.cxx
+
+stap-tapset-perfmon.obj: tapset-perfmon.cxx
+@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-tapset-perfmon.obj -MD -MP -MF $(DEPDIR)/stap-tapset-perfmon.Tpo -c -o stap-tapset-perfmon.obj `if test -f 'tapset-perfmon.cxx'; then $(CYGPATH_W) 'tapset-perfmon.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-perfmon.cxx'; fi`
+@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-tapset-perfmon.Tpo $(DEPDIR)/stap-tapset-perfmon.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='tapset-perfmon.cxx' object='stap-tapset-perfmon.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -c -o stap-tapset-perfmon.obj `if test -f 'tapset-perfmon.cxx'; then $(CYGPATH_W) 'tapset-perfmon.cxx'; else $(CYGPATH_W) '$(srcdir)/tapset-perfmon.cxx'; fi`
+
stap-modsign.o: modsign.cxx
@am__fastdepCXX_TRUE@ $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(stap_CPPFLAGS) $(CPPFLAGS) $(stap_CXXFLAGS) $(CXXFLAGS) -MT stap-modsign.o -MD -MP -MF $(DEPDIR)/stap-modsign.Tpo -c -o stap-modsign.o `test -f 'modsign.cxx' || echo '$(srcdir)/'`modsign.cxx
@am__fastdepCXX_TRUE@ mv -f $(DEPDIR)/stap-modsign.Tpo $(DEPDIR)/stap-modsign.Po
diff --git a/tapset-perfmon.cxx b/tapset-perfmon.cxx
new file mode 100644
index 00000000..e3f30ece
--- /dev/null
+++ b/tapset-perfmon.cxx
@@ -0,0 +1,463 @@
+// tapset for HW performance monitoring
+// Copyright (C) 2005-2009 Red Hat Inc.
+// Copyright (C) 2005-2007 Intel Corporation.
+// Copyright (C) 2008 James.Bottomley@HansenPartnership.com
+//
+// This file is part of systemtap, and is free software. You can
+// redistribute it and/or modify it under the terms of the GNU General
+// Public License (GPL); either version 2, or (at your option) any
+// later version.
+
+#include "session.h"
+#include "tapsets.h"
+#include "util.h"
+
+#include <string>
+
+#ifdef PERFMON
+#include <perfmon/pfmlib.h>
+#include <perfmon/perfmon.h>
+#endif
+
+
+using namespace std;
+using namespace __gnu_cxx;
+
+
+
+// ------------------------------------------------------------------------
+// perfmon derived probes
+// ------------------------------------------------------------------------
+// This is a new interface to the perfmon hw.
+//
+
+
+struct perfmon_var_expanding_visitor: public var_expanding_visitor
+{
+ systemtap_session & sess;
+ unsigned counter_number;
+ perfmon_var_expanding_visitor(systemtap_session & s, unsigned c):
+ sess(s), counter_number(c) {}
+ void visit_target_symbol (target_symbol* e);
+};
+
+
+void
+perfmon_var_expanding_visitor::visit_target_symbol (target_symbol *e)
+{
+ assert(e->base_name.size() > 0 && e->base_name[0] == '$');
+
+ // Synthesize a function.
+ functiondecl *fdecl = new functiondecl;
+ fdecl->tok = e->tok;
+ embeddedcode *ec = new embeddedcode;
+ ec->tok = e->tok;
+ bool lvalue = is_active_lvalue(e);
+
+ if (lvalue )
+ throw semantic_error("writes to $counter not permitted");
+
+ string fname = string("_perfmon_tvar_get")
+ + "_" + e->base_name.substr(1)
+ + "_" + lex_cast<string>(counter_number);
+
+ if (e->base_name != "$counter")
+ throw semantic_error ("target variables not available to perfmon probes");
+
+ if (e->components.size() > 0)
+ {
+ switch (e->components[0].first)
+ {
+ case target_symbol::comp_literal_array_index:
+ throw semantic_error("perfmon probe '$counter' variable may not be used as array",
+ e->tok);
+ break;
+ case target_symbol::comp_struct_member:
+ throw semantic_error("perfmon probe '$counter' variable may not be used as a structure",
+ e->tok);
+ break;
+ default:
+ throw semantic_error ("invalid use of perfmon probe '$counter' variable",
+ e->tok);
+ break;
+ }
+ }
+
+ ec->code = "THIS->__retvalue = _pfm_pmd_x[" +
+ lex_cast<string>(counter_number) + "].reg_num;";
+ ec->code += "/* pure */";
+ fdecl->name = fname;
+ fdecl->body = ec;
+ fdecl->type = pe_long;
+ sess.functions[fdecl->name]=fdecl;
+
+ // Synthesize a functioncall.
+ functioncall* n = new functioncall;
+ n->tok = e->tok;
+ n->function = fname;
+ n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
+
+ provide (n);
+}
+
+
+enum perfmon_mode
+{
+ perfmon_count,
+ perfmon_sample
+};
+
+
+struct perfmon_derived_probe: public derived_probe
+{
+protected:
+ static unsigned probes_allocated;
+
+public:
+ systemtap_session & sess;
+ string event;
+ perfmon_mode mode;
+
+ perfmon_derived_probe (probe* p, probe_point* l, systemtap_session &s,
+ string e, perfmon_mode m);
+ virtual void join_group (systemtap_session& s);
+};
+
+
+struct perfmon_derived_probe_group: public generic_dpg<perfmon_derived_probe>
+{
+public:
+ void emit_module_decls (systemtap_session&) {}
+ void emit_module_init (systemtap_session&) {}
+ void emit_module_exit (systemtap_session&) {}
+};
+
+
+struct perfmon_builder: public derived_probe_builder
+{
+ perfmon_builder() {}
+ virtual void build(systemtap_session & sess,
+ probe * base,
+ probe_point * location,
+ literal_map_t const & parameters,
+ vector<derived_probe *> & finished_results)
+ {
+ string event;
+ if (!get_param (parameters, "counter", event))
+ throw semantic_error("perfmon requires an event");
+
+ sess.perfmon++;
+
+ // XXX: need to revise when doing sampling
+ finished_results.push_back(new perfmon_derived_probe(base, location,
+ sess, event,
+ perfmon_count));
+ }
+};
+
+
+unsigned perfmon_derived_probe::probes_allocated;
+
+perfmon_derived_probe::perfmon_derived_probe (probe* p, probe_point* l,
+ systemtap_session &s,
+ string e, perfmon_mode m)
+ : derived_probe (p, l), sess(s), event(e), mode(m)
+{
+ ++probes_allocated;
+
+ // Now expand the local variables in the probe body
+ perfmon_var_expanding_visitor v (sess, probes_allocated-1);
+ this->body = v.require (this->body);
+
+ if (sess.verbose > 1)
+ clog << "perfmon-based probe" << endl;
+}
+
+
+void
+perfmon_derived_probe::join_group (systemtap_session& s)
+{
+ throw semantic_error ("incomplete", this->tok);
+
+ if (! s.perfmon_derived_probes)
+ s.perfmon_derived_probes = new perfmon_derived_probe_group ();
+ s.perfmon_derived_probes->enroll (this);
+}
+
+
+#if 0
+void
+perfmon_derived_probe::emit_registrations_start (translator_output* o,
+ unsigned index)
+{
+ for (unsigned i=0; i<locations.size(); i++)
+ o->newline() << "enter_" << name << "_" << i << " ();";
+}
+
+
+void
+perfmon_derived_probe::emit_registrations_end (translator_output * o,
+ unsigned index)
+{
+}
+
+
+void
+perfmon_derived_probe::emit_deregistrations (translator_output * o)
+{
+}
+
+
+void
+perfmon_derived_probe::emit_probe_entries (translator_output * o)
+{
+ o->newline() << "#ifdef STP_TIMING";
+ // NB: This variable may be multiply (but identically) defined.
+ o->newline() << "static __cacheline_aligned Stat " << "time_" << basest()->name << ";";
+ o->newline() << "#endif";
+
+ for (unsigned i=0; i<locations.size(); i++)
+ {
+ probe_point *l = locations[i];
+ o->newline() << "/* location " << i << ": " << *l << " */";
+ o->newline() << "static void enter_" << name << "_" << i << " (void) {";
+
+ o->indent(1);
+ o->newline() << "const char* probe_point = "
+ << lex_cast_qstring(*l) << ";";
+
+ o->newline() << "static struct pfarg_ctx _pfm_context;";
+ o->newline() << "static void *_pfm_desc;";
+ o->newline() << "static struct pfarg_pmc *_pfm_pmc_x;";
+ o->newline() << "static int _pfm_num_pmc_x;";
+ o->newline() << "static struct pfarg_pmd *_pfm_pmd_x;";
+ o->newline() << "static int _pfm_num_pmd_x;";
+
+ emit_probe_prologue (o,
+ (mode == perfmon_count ?
+ "STAP_SESSION_STARTING" :
+ "STAP_SESSION_RUNNING"),
+ "probe_point");
+
+ // NB: locals are initialized by probe function itself
+ o->newline() << name << " (c);";
+
+ emit_probe_epilogue (o);
+
+ o->newline(-1) << "}\n";
+ }
+}
+#endif
+
+
+#if 0
+void no_pfm_event_error (string s)
+{
+ string msg(string("Cannot find event:" + s));
+ throw semantic_error(msg);
+}
+
+
+void no_pfm_mask_error (string s)
+{
+ string msg(string("Cannot find mask:" + s));
+ throw semantic_error(msg);
+}
+
+
+void
+split(const string& s, vector<string>& v, const string & separator)
+{
+ string::size_type last_pos = s.find_first_not_of(separator, 0);
+ string::size_type pos = s.find_first_of(separator, last_pos);
+
+ while (string::npos != pos || string::npos != last_pos) {
+ v.push_back(s.substr(last_pos, pos - last_pos));
+ last_pos = s.find_first_not_of(separator, pos);
+ pos = s.find_first_of(separator, last_pos);
+ }
+}
+
+
+void
+perfmon_derived_probe_group::emit_probes (translator_output* op, unparser* up)
+{
+ for (unsigned i=0; i < probes.size(); i++)
+ {
+ op->newline ();
+ up->emit_probe (probes[i]);
+ }
+}
+
+
+void
+perfmon_derived_probe_group::emit_module_init (translator_output* o)
+{
+ int ret;
+ pfmlib_input_param_t inp;
+ pfmlib_output_param_t outp;
+ pfarg_pmd_t pd[PFMLIB_MAX_PMDS];
+ pfarg_pmc_t pc[PFMLIB_MAX_PMCS];
+ pfarg_ctx_t ctx;
+ pfarg_load_t load_args;
+ pfmlib_options_t pfmlib_options;
+ unsigned int max_counters;
+
+ if ( probes.size() == 0)
+ return;
+ ret = pfm_initialize();
+ if (ret != PFMLIB_SUCCESS)
+ throw semantic_error("Unable to generate performance monitoring events (no libpfm)");
+
+ pfm_get_num_counters(&max_counters);
+
+ memset(&pfmlib_options, 0, sizeof(pfmlib_options));
+ pfmlib_options.pfm_debug = 0; /* set to 1 for debug */
+ pfmlib_options.pfm_verbose = 0; /* set to 1 for debug */
+ pfm_set_options(&pfmlib_options);
+
+ memset(pd, 0, sizeof(pd));
+ memset(pc, 0, sizeof(pc));
+ memset(&ctx, 0, sizeof(ctx));
+ memset(&load_args, 0, sizeof(load_args));
+
+ /*
+ * prepare parameters to library.
+ */
+ memset(&inp,0, sizeof(inp));
+ memset(&outp,0, sizeof(outp));
+
+ /* figure out the events */
+ for (unsigned i=0; i<probes.size(); ++i)
+ {
+ if (probes[i]->event == "cycles") {
+ if (pfm_get_cycle_event( &inp.pfp_events[i].event) != PFMLIB_SUCCESS)
+ no_pfm_event_error(probes[i]->event);
+ } else if (probes[i]->event == "instructions") {
+ if (pfm_get_inst_retired_event( &inp.pfp_events[i].event) !=
+ PFMLIB_SUCCESS)
+ no_pfm_event_error(probes[i]->event);
+ } else {
+ unsigned int event_id = 0;
+ unsigned int mask_id = 0;
+ vector<string> event_spec;
+ split(probes[i]->event, event_spec, ":");
+ int num = event_spec.size();
+ int masks = num - 1;
+
+ if (num == 0)
+ throw semantic_error("No events found");
+
+ /* setup event */
+ if (pfm_find_event(event_spec[0].c_str(), &event_id) != PFMLIB_SUCCESS)
+ no_pfm_event_error(event_spec[0]);
+ inp.pfp_events[i].event = event_id;
+
+ /* set up masks */
+ if (masks > PFMLIB_MAX_MASKS_PER_EVENT)
+ throw semantic_error("Too many unit masks specified");
+
+ for (int j=0; j < masks; j++) {
+ if (pfm_find_event_mask(event_id, event_spec[j+1].c_str(),
+ &mask_id) != PFMLIB_SUCCESS)
+ no_pfm_mask_error(string(event_spec[j+1]));
+ inp.pfp_events[i].unit_masks[j] = mask_id;
+ }
+ inp.pfp_events[i].num_masks = masks;
+ }
+ }
+
+ /* number of counters in use */
+ inp.pfp_event_count = probes.size();
+
+ // XXX: no elimination of duplicated counters
+ if (inp.pfp_event_count>max_counters)
+ throw semantic_error("Too many performance monitoring events.");
+
+ /* count events both in kernel and user-space */
+ inp.pfp_dfl_plm = PFM_PLM0 | PFM_PLM3;
+
+ /* XXX: some cases a perfmon register might be used of watch dog
+ this code doesn't handle that case */
+
+ /* figure out the pmcs for the events */
+ if ((ret=pfm_dispatch_events(&inp, NULL, &outp, NULL)) != PFMLIB_SUCCESS)
+ throw semantic_error("Cannot configure events");
+
+ for (unsigned i=0; i < outp.pfp_pmc_count; i++) {
+ pc[i].reg_num = outp.pfp_pmcs[i].reg_num;
+ pc[i].reg_value = outp.pfp_pmcs[i].reg_value;
+ }
+
+ /*
+ * There could be more pmc settings than pmd.
+ * Figure out the actual pmds to use.
+ */
+ for (unsigned i=0, j=0; i < inp.pfp_event_count; i++) {
+ pd[i].reg_num = outp.pfp_pmcs[j].reg_pmd_num;
+ for(; j < outp.pfp_pmc_count; j++)
+ if (outp.pfp_pmcs[j].reg_evt_idx != i) break;
+ }
+
+ // Output the be probes create function
+ o->newline() << "static int register_perfmon_probes (void) {";
+ o->newline(1) << "int rc = 0;";
+
+ o->newline() << "/* data for perfmon */";
+ o->newline() << "static int _pfm_num_pmc = " << outp.pfp_pmc_count << ";";
+ o->newline() << "static struct pfarg_pmc _pfm_pmc[" << outp.pfp_pmc_count
+ << "] = {";
+ /* output the needed bits for pmc here */
+ for (unsigned i=0; i < outp.pfp_pmc_count; i++) {
+ o->newline() << "{.reg_num=" << pc[i].reg_num << ", "
+ << ".reg_value=" << lex_cast_hex<string>(pc[i].reg_value)
+ << "},";
+ }
+
+ o->newline() << "};";
+ o->newline() << "static int _pfm_num_pmd = " << inp.pfp_event_count << ";";
+ o->newline() << "static struct pfarg_pmd _pfm_pmd[" << inp.pfp_event_count
+ << "] = {";
+ /* output the needed bits for pmd here */
+ for (unsigned i=0; i < inp.pfp_event_count; i++) {
+ o->newline() << "{.reg_num=" << pd[i].reg_num << ", "
+ << ".reg_value=" << pd[i].reg_value << "},";
+ }
+ o->newline() << "};";
+ o->newline();
+
+ o->newline() << "_pfm_pmc_x=_pfm_pmc;";
+ o->newline() << "_pfm_num_pmc_x=_pfm_num_pmc;";
+ o->newline() << "_pfm_pmd_x=_pfm_pmd;";
+ o->newline() << "_pfm_num_pmd_x=_pfm_num_pmd;";
+
+ // call all the function bodies associated with perfcounters
+ for (unsigned i=0; i < probes.size (); i++)
+ probes[i]->emit_registrations_start (o,i);
+
+ /* generate call to turn on instrumentation */
+ o->newline() << "_pfm_context.ctx_flags |= PFM_FL_SYSTEM_WIDE;";
+ o->newline() << "rc = rc || _stp_perfmon_setup(&_pfm_desc, &_pfm_context,";
+ o->newline(1) << "_pfm_pmc, _pfm_num_pmc,";
+ o->newline() << "_pfm_pmd, _pfm_num_pmd);";
+ o->newline(-1);
+
+ o->newline() << "return rc;";
+ o->newline(-1) << "}\n";
+
+ // Output the be probes destroy function
+ o->newline() << "static void unregister_perfmon_probes (void) {";
+ o->newline(1) << "_stp_perfmon_shutdown(_pfm_desc);";
+ o->newline(-1) << "}\n";
+}
+#endif
+
+
+void
+register_tapset_perfmon(systemtap_session& s)
+{
+ s.pattern_root->bind("perfmon")->bind_str("counter")
+ ->bind(new perfmon_builder());
+}
+
+/* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
diff --git a/tapsets.cxx b/tapsets.cxx
index a943163e..b4b58292 100644
--- a/tapsets.cxx
+++ b/tapsets.cxx
@@ -58,11 +58,6 @@ extern "C" {
}
-#ifdef PERFMON
-#include <perfmon/pfmlib.h>
-#include <perfmon/perfmon.h>
-#endif
-
using namespace std;
using namespace __gnu_cxx;
@@ -86,15 +81,6 @@ common_probe_entryfn_prologue (translator_output* o, string statestr,
o->newline() << "cycles_t cycles_atstart = get_cycles ();";
o->newline() << "#endif";
-#if 0 /* XXX: PERFMON */
- o->newline() << "static struct pfarg_ctx _pfm_context;";
- o->newline() << "static void *_pfm_desc;";
- o->newline() << "static struct pfarg_pmc *_pfm_pmc_x;";
- o->newline() << "static int _pfm_num_pmc_x;";
- o->newline() << "static struct pfarg_pmd *_pfm_pmd_x;";
- o->newline() << "static int _pfm_num_pmd_x;";
-#endif
-
o->newline() << "#if INTERRUPTIBLE";
o->newline() << "preempt_disable ();";
o->newline() << "#else";
@@ -10047,426 +10033,6 @@ tracepoint_builder::build(systemtap_session& s,
// ------------------------------------------------------------------------
-// perfmon derived probes
-// ------------------------------------------------------------------------
-// This is a new interface to the perfmon hw.
-//
-
-
-struct perfmon_var_expanding_visitor: public var_expanding_visitor
-{
- systemtap_session & sess;
- unsigned counter_number;
- perfmon_var_expanding_visitor(systemtap_session & s, unsigned c):
- sess(s), counter_number(c) {}
- void visit_target_symbol (target_symbol* e);
-};
-
-
-void
-perfmon_var_expanding_visitor::visit_target_symbol (target_symbol *e)
-{
- assert(e->base_name.size() > 0 && e->base_name[0] == '$');
-
- // Synthesize a function.
- functiondecl *fdecl = new functiondecl;
- fdecl->tok = e->tok;
- embeddedcode *ec = new embeddedcode;
- ec->tok = e->tok;
- bool lvalue = is_active_lvalue(e);
-
- if (lvalue )
- throw semantic_error("writes to $counter not permitted");
-
- string fname = string("_perfmon_tvar_get")
- + "_" + e->base_name.substr(1)
- + "_" + lex_cast<string>(counter_number);
-
- if (e->base_name != "$counter")
- throw semantic_error ("target variables not available to perfmon probes");
-
- if (e->components.size() > 0)
- {
- switch (e->components[0].first)
- {
- case target_symbol::comp_literal_array_index:
- throw semantic_error("perfmon probe '$counter' variable may not be used as array",
- e->tok);
- break;
- case target_symbol::comp_struct_member:
- throw semantic_error("perfmon probe '$counter' variable may not be used as a structure",
- e->tok);
- break;
- default:
- throw semantic_error ("invalid use of perfmon probe '$counter' variable",
- e->tok);
- break;
- }
- }
-
- ec->code = "THIS->__retvalue = _pfm_pmd_x[" +
- lex_cast<string>(counter_number) + "].reg_num;";
- ec->code += "/* pure */";
- fdecl->name = fname;
- fdecl->body = ec;
- fdecl->type = pe_long;
- sess.functions[fdecl->name]=fdecl;
-
- // Synthesize a functioncall.
- functioncall* n = new functioncall;
- n->tok = e->tok;
- n->function = fname;
- n->referent = 0; // NB: must not resolve yet, to ensure inclusion in session
-
- provide (n);
-}
-
-
-enum perfmon_mode
-{
- perfmon_count,
- perfmon_sample
-};
-
-
-struct perfmon_derived_probe: public derived_probe
-{
-protected:
- static unsigned probes_allocated;
-
-public:
- systemtap_session & sess;
- string event;
- perfmon_mode mode;
-
- perfmon_derived_probe (probe* p, probe_point* l, systemtap_session &s,
- string e, perfmon_mode m);
- virtual void join_group (systemtap_session& s);
-};
-
-
-struct perfmon_derived_probe_group: public generic_dpg<perfmon_derived_probe>
-{
-public:
- void emit_module_decls (systemtap_session&) {}
- void emit_module_init (systemtap_session&) {}
- void emit_module_exit (systemtap_session&) {}
-};
-
-
-struct perfmon_builder: public derived_probe_builder
-{
- perfmon_builder() {}
- virtual void build(systemtap_session & sess,
- probe * base,
- probe_point * location,
- literal_map_t const & parameters,
- vector<derived_probe *> & finished_results)
- {
- string event;
- if (!get_param (parameters, "counter", event))
- throw semantic_error("perfmon requires an event");
-
- sess.perfmon++;
-
- // XXX: need to revise when doing sampling
- finished_results.push_back(new perfmon_derived_probe(base, location,
- sess, event,
- perfmon_count));
- }
-};
-
-
-unsigned perfmon_derived_probe::probes_allocated;
-
-perfmon_derived_probe::perfmon_derived_probe (probe* p, probe_point* l,
- systemtap_session &s,
- string e, perfmon_mode m)
- : derived_probe (p, l), sess(s), event(e), mode(m)
-{
- ++probes_allocated;
-
- // Now expand the local variables in the probe body
- perfmon_var_expanding_visitor v (sess, probes_allocated-1);
- this->body = v.require (this->body);
-
- if (sess.verbose > 1)
- clog << "perfmon-based probe" << endl;
-}
-
-
-void
-perfmon_derived_probe::join_group (systemtap_session& s)
-{
- throw semantic_error ("incomplete", this->tok);
-
- if (! s.perfmon_derived_probes)
- s.perfmon_derived_probes = new perfmon_derived_probe_group ();
- s.perfmon_derived_probes->enroll (this);
-}
-
-
-#if 0
-void
-perfmon_derived_probe::emit_registrations_start (translator_output* o,
- unsigned index)
-{
- for (unsigned i=0; i<locations.size(); i++)
- o->newline() << "enter_" << name << "_" << i << " ();";
-}
-
-
-void
-perfmon_derived_probe::emit_registrations_end (translator_output * o,
- unsigned index)
-{
-}
-
-
-void
-perfmon_derived_probe::emit_deregistrations (translator_output * o)
-{
-}
-
-
-void
-perfmon_derived_probe::emit_probe_entries (translator_output * o)
-{
- o->newline() << "#ifdef STP_TIMING";
- // NB: This variable may be multiply (but identically) defined.
- o->newline() << "static __cacheline_aligned Stat " << "time_" << basest()->name << ";";
- o->newline() << "#endif";
-
- for (unsigned i=0; i<locations.size(); i++)
- {
- probe_point *l = locations[i];
- o->newline() << "/* location " << i << ": " << *l << " */";
- o->newline() << "static void enter_" << name << "_" << i << " (void) {";
-
- o->indent(1);
- o->newline() << "const char* probe_point = "
- << lex_cast_qstring(*l) << ";";
- emit_probe_prologue (o,
- (mode == perfmon_count ?
- "STAP_SESSION_STARTING" :
- "STAP_SESSION_RUNNING"),
- "probe_point");
-
- // NB: locals are initialized by probe function itself
- o->newline() << name << " (c);";
-
- emit_probe_epilogue (o);
-
- o->newline(-1) << "}\n";
- }
-}
-#endif
-
-
-#if 0
-void no_pfm_event_error (string s)
-{
- string msg(string("Cannot find event:" + s));
- throw semantic_error(msg);
-}
-
-
-void no_pfm_mask_error (string s)
-{
- string msg(string("Cannot find mask:" + s));
- throw semantic_error(msg);
-}
-
-
-void
-split(const string& s, vector<string>& v, const string & separator)
-{
- string::size_type last_pos = s.find_first_not_of(separator, 0);
- string::size_type pos = s.find_first_of(separator, last_pos);
-
- while (string::npos != pos || string::npos != last_pos) {
- v.push_back(s.substr(last_pos, pos - last_pos));
- last_pos = s.find_first_not_of(separator, pos);
- pos = s.find_first_of(separator, last_pos);
- }
-}
-
-
-void
-perfmon_derived_probe_group::emit_probes (translator_output* op, unparser* up)
-{
- for (unsigned i=0; i < probes.size(); i++)
- {
- op->newline ();
- up->emit_probe (probes[i]);
- }
-}
-
-
-void
-perfmon_derived_probe_group::emit_module_init (translator_output* o)
-{
- int ret;
- pfmlib_input_param_t inp;
- pfmlib_output_param_t outp;
- pfarg_pmd_t pd[PFMLIB_MAX_PMDS];
- pfarg_pmc_t pc[PFMLIB_MAX_PMCS];
- pfarg_ctx_t ctx;
- pfarg_load_t load_args;
- pfmlib_options_t pfmlib_options;
- unsigned int max_counters;
-
- if ( probes.size() == 0)
- return;
- ret = pfm_initialize();
- if (ret != PFMLIB_SUCCESS)
- throw semantic_error("Unable to generate performance monitoring events (no libpfm)");
-
- pfm_get_num_counters(&max_counters);
-
- memset(&pfmlib_options, 0, sizeof(pfmlib_options));
- pfmlib_options.pfm_debug = 0; /* set to 1 for debug */
- pfmlib_options.pfm_verbose = 0; /* set to 1 for debug */
- pfm_set_options(&pfmlib_options);
-
- memset(pd, 0, sizeof(pd));
- memset(pc, 0, sizeof(pc));
- memset(&ctx, 0, sizeof(ctx));
- memset(&load_args, 0, sizeof(load_args));
-
- /*
- * prepare parameters to library.
- */
- memset(&inp,0, sizeof(inp));
- memset(&outp,0, sizeof(outp));
-
- /* figure out the events */
- for (unsigned i=0; i<probes.size(); ++i)
- {
- if (probes[i]->event == "cycles") {
- if (pfm_get_cycle_event( &inp.pfp_events[i].event) != PFMLIB_SUCCESS)
- no_pfm_event_error(probes[i]->event);
- } else if (probes[i]->event == "instructions") {
- if (pfm_get_inst_retired_event( &inp.pfp_events[i].event) !=
- PFMLIB_SUCCESS)
- no_pfm_event_error(probes[i]->event);
- } else {
- unsigned int event_id = 0;
- unsigned int mask_id = 0;
- vector<string> event_spec;
- split(probes[i]->event, event_spec, ":");
- int num = event_spec.size();
- int masks = num - 1;
-
- if (num == 0)
- throw semantic_error("No events found");
-
- /* setup event */
- if (pfm_find_event(event_spec[0].c_str(), &event_id) != PFMLIB_SUCCESS)
- no_pfm_event_error(event_spec[0]);
- inp.pfp_events[i].event = event_id;
-
- /* set up masks */
- if (masks > PFMLIB_MAX_MASKS_PER_EVENT)
- throw semantic_error("Too many unit masks specified");
-
- for (int j=0; j < masks; j++) {
- if (pfm_find_event_mask(event_id, event_spec[j+1].c_str(),
- &mask_id) != PFMLIB_SUCCESS)
- no_pfm_mask_error(string(event_spec[j+1]));
- inp.pfp_events[i].unit_masks[j] = mask_id;
- }
- inp.pfp_events[i].num_masks = masks;
- }
- }
-
- /* number of counters in use */
- inp.pfp_event_count = probes.size();
-
- // XXX: no elimination of duplicated counters
- if (inp.pfp_event_count>max_counters)
- throw semantic_error("Too many performance monitoring events.");
-
- /* count events both in kernel and user-space */
- inp.pfp_dfl_plm = PFM_PLM0 | PFM_PLM3;
-
- /* XXX: some cases a perfmon register might be used of watch dog
- this code doesn't handle that case */
-
- /* figure out the pmcs for the events */
- if ((ret=pfm_dispatch_events(&inp, NULL, &outp, NULL)) != PFMLIB_SUCCESS)
- throw semantic_error("Cannot configure events");
-
- for (unsigned i=0; i < outp.pfp_pmc_count; i++) {
- pc[i].reg_num = outp.pfp_pmcs[i].reg_num;
- pc[i].reg_value = outp.pfp_pmcs[i].reg_value;
- }
-
- /*
- * There could be more pmc settings than pmd.
- * Figure out the actual pmds to use.
- */
- for (unsigned i=0, j=0; i < inp.pfp_event_count; i++) {
- pd[i].reg_num = outp.pfp_pmcs[j].reg_pmd_num;
- for(; j < outp.pfp_pmc_count; j++)
- if (outp.pfp_pmcs[j].reg_evt_idx != i) break;
- }
-
- // Output the be probes create function
- o->newline() << "static int register_perfmon_probes (void) {";
- o->newline(1) << "int rc = 0;";
-
- o->newline() << "/* data for perfmon */";
- o->newline() << "static int _pfm_num_pmc = " << outp.pfp_pmc_count << ";";
- o->newline() << "static struct pfarg_pmc _pfm_pmc[" << outp.pfp_pmc_count
- << "] = {";
- /* output the needed bits for pmc here */
- for (unsigned i=0; i < outp.pfp_pmc_count; i++) {
- o->newline() << "{.reg_num=" << pc[i].reg_num << ", "
- << ".reg_value=" << lex_cast_hex<string>(pc[i].reg_value)
- << "},";
- }
-
- o->newline() << "};";
- o->newline() << "static int _pfm_num_pmd = " << inp.pfp_event_count << ";";
- o->newline() << "static struct pfarg_pmd _pfm_pmd[" << inp.pfp_event_count
- << "] = {";
- /* output the needed bits for pmd here */
- for (unsigned i=0; i < inp.pfp_event_count; i++) {
- o->newline() << "{.reg_num=" << pd[i].reg_num << ", "
- << ".reg_value=" << pd[i].reg_value << "},";
- }
- o->newline() << "};";
- o->newline();
-
- o->newline() << "_pfm_pmc_x=_pfm_pmc;";
- o->newline() << "_pfm_num_pmc_x=_pfm_num_pmc;";
- o->newline() << "_pfm_pmd_x=_pfm_pmd;";
- o->newline() << "_pfm_num_pmd_x=_pfm_num_pmd;";
-
- // call all the function bodies associated with perfcounters
- for (unsigned i=0; i < probes.size (); i++)
- probes[i]->emit_registrations_start (o,i);
-
- /* generate call to turn on instrumentation */
- o->newline() << "_pfm_context.ctx_flags |= PFM_FL_SYSTEM_WIDE;";
- o->newline() << "rc = rc || _stp_perfmon_setup(&_pfm_desc, &_pfm_context,";
- o->newline(1) << "_pfm_pmc, _pfm_num_pmc,";
- o->newline() << "_pfm_pmd, _pfm_num_pmd);";
- o->newline(-1);
-
- o->newline() << "return rc;";
- o->newline(-1) << "}\n";
-
- // Output the be probes destroy function
- o->newline() << "static void unregister_perfmon_probes (void) {";
- o->newline(1) << "_stp_perfmon_shutdown(_pfm_desc);";
- o->newline(-1) << "}\n";
-}
-#endif
-
-
-// ------------------------------------------------------------------------
// Standard tapset registry.
// ------------------------------------------------------------------------
@@ -10474,11 +10040,10 @@ void
register_standard_tapsets(systemtap_session & s)
{
register_tapset_been(s);
+ register_tapset_perfmon(s);
register_tapset_procfs(s);
register_tapset_timers(s);
- s.pattern_root->bind("perfmon")->bind_str("counter")
- ->bind(new perfmon_builder());
// dwarf-based kprobe/uprobe parts
dwarf_derived_probe::register_patterns(s);
diff --git a/tapsets.h b/tapsets.h
index ba322d44..f561aa59 100644
--- a/tapsets.h
+++ b/tapsets.h
@@ -21,6 +21,7 @@ void common_probe_entryfn_prologue (translator_output* o, std::string statestr,
void common_probe_entryfn_epilogue (translator_output* o, bool overload_processing = true);
void register_tapset_been(systemtap_session& sess);
+void register_tapset_perfmon(systemtap_session& sess);
void register_tapset_procfs(systemtap_session& sess);
void register_tapset_timers(systemtap_session& sess);