1# Copyright 2015-2017 ARM Limited 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# 15 16"""Process the output of the power allocator trace in the current 17directory's trace.dat""" 18 19from collections import OrderedDict 20import pandas as pd 21import re 22 23from trappy.base import Base 24from trappy.dynamic import register_ftrace_parser 25 26class Thermal(Base): 27 """Process the thermal framework data in a FTrace dump""" 28 29 unique_word = "thermal_temperature:" 30 """The unique word that will be matched in a trace line""" 31 32 name = "thermal" 33 """The name of the :mod:`pandas.DataFrame` member that will be created in a 34 :mod:`trappy.ftrace.FTrace` object""" 35 36 pivot = "id" 37 """The Pivot along which the data is orthogonal""" 38 39 def plot_temperature(self, control_temperature=None, title="", width=None, 40 height=None, ylim="range", ax=None, legend_label="", 41 tz_id=None): 42 """Plot the temperature. 43 44 :param ax: Axis instance 45 :type ax: :mod:`matplotlib.Axis` 46 47 :param legend_label: Label for the legend 48 :type legend_label: str 49 50 :param title: The title of the plot 51 :type title: str 52 53 :param control_temperature: If control_temp is a 54 :mod:`pd.Series` representing the (possible) 55 variation of :code:`control_temp` during the 56 run, draw it using a dashed yellow line. 57 Otherwise, only the temperature is plotted. 58 :type control_temperature: :mod:`pandas.Series` 59 60 :param width: The width of the plot 61 :type width: int 62 63 :param height: The height of the plot 64 :type height: int 65 66 :param tz_id: thermal zone id as it appears in the id field of 67 the thermal_temperature trace event 68 :type tz_id: int 69 70 """ 71 from matplotlib import pyplot as plt 72 from trappy.plot_utils import normalize_title, pre_plot_setup, post_plot_setup 73 74 title = normalize_title("Temperature", title) 75 76 if len(self.data_frame) == 0: 77 raise ValueError("Empty DataFrame") 78 79 thermal_dfr = self.data_frame 80 if tz_id is not None: 81 thermal_dfr = thermal_dfr[thermal_dfr["id"] == tz_id] 82 if len(thermal_dfr) == 0: 83 raise ValueError("No thermal_temperature trace for thermal zone {}".format(tz_id)) 84 85 setup_plot = False 86 if not ax: 87 ax = pre_plot_setup(width, height) 88 setup_plot = True 89 90 temp_label = normalize_title("Temperature", legend_label) 91 (thermal_dfr["temp"] / 1000).plot(ax=ax, label=temp_label) 92 if control_temperature is not None: 93 ct_label = normalize_title("Control", legend_label) 94 control_temperature.plot(ax=ax, color="y", linestyle="--", 95 label=ct_label) 96 97 if setup_plot: 98 post_plot_setup(ax, title=title, ylim=ylim) 99 plt.legend() 100 101 def plot_temperature_hist(self, ax, title): 102 """Plot a temperature histogram 103 104 :param ax: Axis instance 105 :type ax: :mod:`matplotlib.Axis` 106 107 :param title: The title of the plot 108 :type title: str 109 """ 110 from trappy.plot_utils import normalize_title, plot_hist 111 112 temps = self.data_frame["temp"] / 1000 113 title = normalize_title("Temperature", title) 114 xlim = (0, temps.max()) 115 116 plot_hist(temps, ax, title, "C", 30, "Temperature", xlim, "default") 117 118register_ftrace_parser(Thermal, "thermal") 119 120class ThermalGovernor(Base): 121 """Process the power allocator data in a ftrace dump""" 122 123 unique_word = "thermal_power_allocator:" 124 """The unique word that will be matched in a trace line""" 125 126 name = "thermal_governor" 127 """The name of the :mod:`pandas.DataFrame` member that will be created in a 128 :mod:`trappy.ftrace.FTrace` object""" 129 130 pivot = "thermal_zone_id" 131 """The Pivot along which the data is orthogonal""" 132 133 def plot_temperature(self, title="", width=None, height=None, ylim="range", 134 ax=None, legend_label=""): 135 """Plot the temperature""" 136 from matplotlib import pyplot as plt 137 from trappy.plot_utils import normalize_title, pre_plot_setup, post_plot_setup 138 139 dfr = self.data_frame 140 curr_temp = dfr["current_temperature"] 141 control_temp_series = (curr_temp + dfr["delta_temperature"]) / 1000 142 title = normalize_title("Temperature", title) 143 144 setup_plot = False 145 if not ax: 146 ax = pre_plot_setup(width, height) 147 setup_plot = True 148 149 temp_label = normalize_title("Temperature", legend_label) 150 (curr_temp / 1000).plot(ax=ax, label=temp_label) 151 control_temp_series.plot(ax=ax, color="y", linestyle="--", 152 label="control temperature") 153 154 if setup_plot: 155 post_plot_setup(ax, title=title, ylim=ylim) 156 plt.legend() 157 158 def plot_input_power(self, actor_order, title="", width=None, height=None, 159 ax=None): 160 """Plot input power 161 162 :param ax: Axis instance 163 :type ax: :mod:`matplotlib.Axis` 164 165 :param title: The title of the plot 166 :type title: str 167 168 :param width: The width of the plot 169 :type width: int 170 171 :param height: The height of the plot 172 :type int: int 173 174 :param actor_order: An array showing the order in which the actors 175 were registered. The array values are the labels that 176 will be used in the input and output power plots. 177 178 For Example: 179 :: 180 181 ["GPU", "A15", "A7"] 182 183 :type actor_order: list 184 """ 185 from trappy.plot_utils import normalize_title, pre_plot_setup, post_plot_setup 186 187 dfr = self.data_frame 188 in_cols = [s for s in dfr.columns if re.match("req_power[0-9]+", s)] 189 190 plot_dfr = dfr[in_cols] 191 # Rename the columns from "req_power0" to "A15" or whatever is 192 # in actor_order. Note that we can do it just with an 193 # assignment because the columns are already sorted (i.e.: 194 # req_power0, req_power1...) 195 plot_dfr.columns = actor_order 196 197 title = normalize_title("Input Power", title) 198 199 if not ax: 200 ax = pre_plot_setup(width, height) 201 202 plot_dfr.plot(ax=ax) 203 post_plot_setup(ax, title=title) 204 205 def plot_weighted_input_power(self, actor_weights, title="", width=None, 206 height=None, ax=None): 207 """Plot weighted input power 208 209 :param actor_weights: An array of tuples. First element of the 210 tuple is the name of the actor, the second is the weight. The 211 array is in the same order as the :code:`req_power` appear in the 212 trace. 213 :type actor_weights: list 214 215 :param ax: Axis instance 216 :type ax: :mod:`matplotlib.Axis` 217 218 :param title: The title of the plot 219 :type title: str 220 221 :param width: The width of the plot 222 :type width: int 223 224 :param height: The height of the plot 225 :type int: int 226 """ 227 from trappy.plot_utils import normalize_title, pre_plot_setup, post_plot_setup 228 229 dfr = self.data_frame 230 in_cols = [s for s in dfr.columns if re.match(r"req_power\d+", s)] 231 232 plot_dfr_dict = OrderedDict() 233 for in_col, (name, weight) in zip(in_cols, actor_weights): 234 plot_dfr_dict[name] = dfr[in_col] * weight / 1024 235 236 plot_dfr = pd.DataFrame(plot_dfr_dict) 237 238 title = normalize_title("Weighted Input Power", title) 239 240 if not ax: 241 ax = pre_plot_setup(width, height) 242 243 plot_dfr.plot(ax=ax) 244 post_plot_setup(ax, title=title) 245 246 def plot_output_power(self, actor_order, title="", width=None, height=None, 247 ax=None): 248 """Plot output power 249 250 :param ax: Axis instance 251 :type ax: :mod:`matplotlib.Axis` 252 253 :param title: The title of the plot 254 :type title: str 255 256 :param width: The width of the plot 257 :type width: int 258 259 :param height: The height of the plot 260 :type int: int 261 262 :param actor_order: An array showing the order in which the actors 263 were registered. The array values are the labels that 264 will be used in the input and output power plots. 265 266 For Example: 267 :: 268 269 ["GPU", "A15", "A7"] 270 271 :type actor_order: list 272 """ 273 from trappy.plot_utils import normalize_title, pre_plot_setup, post_plot_setup 274 275 out_cols = [s for s in self.data_frame.columns 276 if re.match("granted_power[0-9]+", s)] 277 278 # See the note in plot_input_power() 279 plot_dfr = self.data_frame[out_cols] 280 plot_dfr.columns = actor_order 281 282 title = normalize_title("Output Power", title) 283 284 if not ax: 285 ax = pre_plot_setup(width, height) 286 287 plot_dfr.plot(ax=ax) 288 post_plot_setup(ax, title=title) 289 290 def plot_inout_power(self, title=""): 291 """Make multiple plots showing input and output power for each actor 292 293 :param title: The title of the plot 294 :type title: str 295 """ 296 from trappy.plot_utils import normalize_title 297 dfr = self.data_frame 298 299 actors = [] 300 for col in dfr.columns: 301 match = re.match("P(.*)_in", col) 302 if match and col != "Ptot_in": 303 actors.append(match.group(1)) 304 305 for actor in actors: 306 cols = ["P" + actor + "_in", "P" + actor + "_out"] 307 this_title = normalize_title(actor, title) 308 dfr[cols].plot(title=this_title) 309 310register_ftrace_parser(ThermalGovernor, "thermal") 311