thermal: learn to plot weighted request power

Change-Id: I128f57f82895c9503323302692165acee8a859e9
diff --git a/cr2/plot_utils.py b/cr2/plot_utils.py
index b76d14f..f97aa49 100644
--- a/cr2/plot_utils.py
+++ b/cr2/plot_utils.py
@@ -16,6 +16,10 @@
 """Small functions to help with plots"""
 
 from matplotlib import pyplot as plt
+import os
+import re
+
+from cr2.wa import SysfsExtractor
 
 GOLDEN_RATIO = 1.618034
 
@@ -209,6 +213,37 @@
     for ax, run in zip(axis, runs):
         run.pid_controller.plot_controller(title=run.name, ax=ax)
 
+def plot_weighted_input_power(runs, actor_order, width=None, height=None):
+    """Make a multicolumn plot of the weighted input power of each run"""
+
+    actor_weights = []
+    for run in runs:
+        run_path = os.path.dirname(run.trace_path)
+        sysfs = SysfsExtractor(run_path)
+
+        thermal_params = sysfs.get_parameters()
+
+        sorted_weights = []
+        for param in sorted(thermal_params):
+            if re.match(r"cdev\d+_weight", param):
+                sorted_weights.append(thermal_params[param])
+
+        actor_weights.append(zip(actor_order, sorted_weights))
+
+    # Do nothing if we don't have actor weights for any run
+    if not any(actor_weights):
+        return
+
+    num_runs = len(runs)
+    axis = pre_plot_setup(width=width, height=height, ncols=num_runs)
+
+    if num_runs == 1:
+        axis = [axis]
+
+    for ax, run, weights in zip(axis, runs, actor_weights):
+        run.thermal_governor.plot_weighted_input_power(weights, title=run.name,
+                                                       ax=ax)
+
 def plot_input_power(runs, actor_order, width=None, height=None):
     """Make a multicolumn plot of the input power of each run"""
     num_runs = len(runs)
@@ -220,6 +255,8 @@
     for ax, run in zip(axis, runs):
         run.thermal_governor.plot_input_power(actor_order, title=run.name, ax=ax)
 
+    plot_weighted_input_power(runs, actor_order, width, height)
+
 def plot_output_power(runs, actor_order, width=None, height=None):
     """Make a multicolumn plot of the output power of each run"""
     num_runs = len(runs)
diff --git a/cr2/thermal.py b/cr2/thermal.py
index 03939f6..b183b71 100644
--- a/cr2/thermal.py
+++ b/cr2/thermal.py
@@ -16,7 +16,9 @@
 """Process the output of the power allocator trace in the current
 directory's trace.dat"""
 
+from collections import OrderedDict
 import os
+import pandas as pd
 import re
 from matplotlib import pyplot as plt
 
@@ -133,6 +135,33 @@
         plot_dfr.plot(ax=ax)
         post_plot_setup(ax, title=title)
 
+    def plot_weighted_input_power(self, actor_weights, title="", width=None, height=None, ax=None):
+        """Plot weighted input power
+
+        actor_weights is an array of tuples.  First element of the
+        tuple is the name of the actor, the second is the weight.  The
+        array is in the same order as the req_power appear in the
+        trace.
+
+        """
+
+        dfr = self.data_frame
+        in_cols = [s for s in dfr.columns if re.match(r"req_power\d+", s)]
+
+        plot_dfr_dict = OrderedDict()
+        for in_col, (name, weight) in zip(in_cols, actor_weights):
+            plot_dfr_dict[name] = dfr[in_col] * weight / 1024
+
+        plot_dfr = pd.DataFrame(plot_dfr_dict)
+
+        title = normalize_title("Weighted Input Power", title)
+
+        if not ax:
+            ax = pre_plot_setup(width, height)
+
+        plot_dfr.plot(ax=ax)
+        post_plot_setup(ax, title=title)
+
     def plot_output_power(self, actor_order, title="", width=None, height=None, ax=None):
         """Plot output power
 
diff --git a/tests/test_thermal.py b/tests/test_thermal.py
index 7359c71..f0f7a5f 100644
--- a/tests/test_thermal.py
+++ b/tests/test_thermal.py
@@ -105,6 +105,16 @@
         gov.plot_input_power(self.actor_order, ax=ax)
         matplotlib.pyplot.close('all')
 
+    def test_plot_weighted_input_power(self):
+        """plot_weighted_input_power() doesn't bomb"""
+
+        gov = cr2.Run().thermal_governor
+        weights = zip(self.actor_order, [1024, 256, 512])
+
+        _, ax = matplotlib.pyplot.subplots()
+        gov.plot_weighted_input_power(weights, ax=ax)
+        matplotlib.pyplot.close('all')
+
     def test_plot_output_power(self):
         """Test plot_output_power()