perf script: Add python support for stat events
authorJiri Olsa <jolsa@kernel.org>
Tue, 5 Jan 2016 21:09:11 +0000 (22:09 +0100)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 6 Jan 2016 23:11:16 +0000 (20:11 -0300)
Add support to get stat events data in perf python scripts.

The python script shall implement the following new interface to process
stat data:

  def stat__<event_name>_[<modifier>](cpu, thread, time, val, ena, run):

    - is called for every stat event for given counter,
      if user monitors 'cycles,instructions:u" following
      callbacks should be defined:

      def stat__cycles(cpu, thread, time, val, ena, run):
      def stat__instructions_u(cpu, thread, time, val, ena, run):

  def stat__interval(time):

    - is called for every interval with its time,
      in non interval mode it's called after last
      stat event with total measured time in ns

The rest of the current interface stays untouched..

Please check example CPI metrics script in following patch
with command line examples in changelogs.

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Tested-by: Kan Liang <kan.liang@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/1452028152-26762-8-git-send-email-jolsa@kernel.org
[ Rename 'time' parameters to 'tstamp', to fix the build in older distros ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/scripting-engines/trace-event-python.c

index a8e825fca42af9aeab46de300855e5e22ea8ffc0..d72fafc1c800db1a699ac37e4ecb4acd0f1e3326 100644 (file)
@@ -41,6 +41,9 @@
 #include "../thread-stack.h"
 #include "../trace-event.h"
 #include "../machine.h"
+#include "thread_map.h"
+#include "cpumap.h"
+#include "stat.h"
 
 PyMODINIT_FUNC initperf_trace_context(void);
 
@@ -859,6 +862,104 @@ static void python_process_event(union perf_event *event,
        }
 }
 
+static void get_handler_name(char *str, size_t size,
+                            struct perf_evsel *evsel)
+{
+       char *p = str;
+
+       scnprintf(str, size, "stat__%s", perf_evsel__name(evsel));
+
+       while ((p = strchr(p, ':'))) {
+               *p = '_';
+               p++;
+       }
+}
+
+static void
+process_stat(struct perf_evsel *counter, int cpu, int thread, u64 tstamp,
+            struct perf_counts_values *count)
+{
+       PyObject *handler, *t;
+       static char handler_name[256];
+       int n = 0;
+
+       t = PyTuple_New(MAX_FIELDS);
+       if (!t)
+               Py_FatalError("couldn't create Python tuple");
+
+       get_handler_name(handler_name, sizeof(handler_name),
+                        counter);
+
+       handler = get_handler(handler_name);
+       if (!handler) {
+               pr_debug("can't find python handler %s\n", handler_name);
+               return;
+       }
+
+       PyTuple_SetItem(t, n++, PyInt_FromLong(cpu));
+       PyTuple_SetItem(t, n++, PyInt_FromLong(thread));
+
+       tuple_set_u64(t, n++, tstamp);
+       tuple_set_u64(t, n++, count->val);
+       tuple_set_u64(t, n++, count->ena);
+       tuple_set_u64(t, n++, count->run);
+
+       if (_PyTuple_Resize(&t, n) == -1)
+               Py_FatalError("error resizing Python tuple");
+
+       call_object(handler, t, handler_name);
+
+       Py_DECREF(t);
+}
+
+static void python_process_stat(struct perf_stat_config *config,
+                               struct perf_evsel *counter, u64 tstamp)
+{
+       struct thread_map *threads = counter->threads;
+       struct cpu_map *cpus = counter->cpus;
+       int cpu, thread;
+
+       if (config->aggr_mode == AGGR_GLOBAL) {
+               process_stat(counter, -1, -1, tstamp,
+                            &counter->counts->aggr);
+               return;
+       }
+
+       for (thread = 0; thread < threads->nr; thread++) {
+               for (cpu = 0; cpu < cpus->nr; cpu++) {
+                       process_stat(counter, cpus->map[cpu],
+                                    thread_map__pid(threads, thread), tstamp,
+                                    perf_counts(counter->counts, cpu, thread));
+               }
+       }
+}
+
+static void python_process_stat_interval(u64 tstamp)
+{
+       PyObject *handler, *t;
+       static const char handler_name[] = "stat__interval";
+       int n = 0;
+
+       t = PyTuple_New(MAX_FIELDS);
+       if (!t)
+               Py_FatalError("couldn't create Python tuple");
+
+       handler = get_handler(handler_name);
+       if (!handler) {
+               pr_debug("can't find python handler %s\n", handler_name);
+               return;
+       }
+
+       tuple_set_u64(t, n++, tstamp);
+
+       if (_PyTuple_Resize(&t, n) == -1)
+               Py_FatalError("error resizing Python tuple");
+
+       call_object(handler, t, handler_name);
+
+       Py_DECREF(t);
+}
+
 static int run_start_sub(void)
 {
        main_module = PyImport_AddModule("__main__");
@@ -1201,10 +1302,12 @@ static int python_generate_script(struct pevent *pevent, const char *outfile)
 }
 
 struct scripting_ops python_scripting_ops = {
-       .name = "Python",
-       .start_script = python_start_script,
-       .flush_script = python_flush_script,
-       .stop_script = python_stop_script,
-       .process_event = python_process_event,
-       .generate_script = python_generate_script,
+       .name                   = "Python",
+       .start_script           = python_start_script,
+       .flush_script           = python_flush_script,
+       .stop_script            = python_stop_script,
+       .process_event          = python_process_event,
+       .process_stat           = python_process_stat,
+       .process_stat_interval  = python_process_stat_interval,
+       .generate_script        = python_generate_script,
 };