diff options
author | Connor O'Brien <connoro@google.com> | 2017-06-19 13:58:17 -0700 |
---|---|---|
committer | Joel Fernandes <joelaf@google.com> | 2017-06-21 16:53:11 -0700 |
commit | 2b9b25c74416328a0f68af5b60b73534e4ccbd02 (patch) | |
tree | c80628f62b2a15a70b2d9954a8b2c7dbe8bb34eb | |
parent | 3b53c5c5a4352d7e348e33bb08aaea828301e343 (diff) | |
download | trappy-2b9b25c74416328a0f68af5b60b73534e4ccbd02.tar.gz |
Add support for trace event processing using callacks
Some trace analysis tasks are most easily expressed by iterating over
events in chronological order. Add a run_event_callbacks() method to
the GenericFTrace class that will run user-defined functions on trace
events in the order they occurred.
Signed-off-by: Connor O'Brien <connoro@google.com>
-rw-r--r-- | tests/test_ftrace.py | 25 | ||||
-rw-r--r-- | trappy/ftrace.py | 49 |
2 files changed, 74 insertions, 0 deletions
diff --git a/tests/test_ftrace.py b/tests/test_ftrace.py index 1377c68..2488484 100644 --- a/tests/test_ftrace.py +++ b/tests/test_ftrace.py @@ -230,6 +230,31 @@ class TestFTrace(BaseTestThermal): # Make sure there are no NaNs in the middle of the array self.assertTrue(allfreqs[0][1]["A57_freq_in"].notnull().all()) + def test_run_event_callbacks(self): + """Test run_event_callbacks()""" + + counts = { + "cpu_in_power": 0, + "cpu_out_power": 0 + } + + def cpu_in_power_fn(data): + counts["cpu_in_power"] += 1 + + def cpu_out_power_fn(data): + counts["cpu_out_power"] += 1 + + fn_map = { + "cpu_in_power": cpu_in_power_fn, + "cpu_out_power": cpu_out_power_fn + } + trace = trappy.FTrace() + + trace.run_event_callbacks(fn_map) + + self.assertEqual(counts["cpu_in_power"], 134) + self.assertEqual(counts["cpu_out_power"], 134) + def test_plot_freq_hists(self): """Test that plot_freq_hists() doesn't bomb""" diff --git a/trappy/ftrace.py b/trappy/ftrace.py index 23189d1..cd4d8e2 100644 --- a/trappy/ftrace.py +++ b/trappy/ftrace.py @@ -311,6 +311,55 @@ is part of the trace. return ret + def run_event_callbacks(self, fn_map): + """ + Apply callback functions to trace events in chronological order. + + This method iterates over a user-specified subset of the available trace + event dataframes, calling different user-specified functions for each + event type. These functions are passed a dictionary mapping 'Index' and + the column names to their values for that row. + + For example, to iterate over trace t, applying your functions callback_fn1 + and callback_fn2 to each sched_switch and sched_wakeup event respectively: + + t.run_event_callbacks({ + "sched_switch": callback_fn1, + "sched_wakeup": callback_fn2 + }) + """ + dfs = {event: getattr(self, event).data_frame for event in fn_map.keys()} + events = [event for event in fn_map.keys() if not dfs[event].empty] + iters = {event: dfs[event].itertuples() for event in events} + next_rows = {event: iterator.next() for event,iterator in iters.iteritems()} + + # Column names beginning with underscore will not be preserved in tuples + # due to constraints on namedtuple field names, so store mappings from + # column name to column number for each trace event. + col_idxs = {event: { + name: idx for idx, name in enumerate( + ['Index'] + dfs[event].columns.tolist() + ) + } for event in events} + + def getLine(event): + line_col_idx = col_idxs[event]['__line'] + return next_rows[event][line_col_idx] + + while events: + event_name = min(events, key=getLine) + event_tuple = next_rows[event_name] + + event_dict = { + col: event_tuple[idx] for col, idx in col_idxs[event_name].iteritems() + } + fn_map[event_name](event_dict) + event_row = next(iters[event_name], None) + if event_row: + next_rows[event_name] = event_row + else: + events.remove(event_name) + def plot_freq_hists(self, map_label, ax): """Plot histograms for each actor input and output frequency |