17b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# SPDX-License-Identifier: Apache-2.0 27b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# 37b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# Copyright (C) 2015, ARM Limited and contributors. 47b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# 57b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# Licensed under the Apache License, Version 2.0 (the "License"); you may 67b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# not use this file except in compliance with the License. 77b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# You may obtain a copy of the License at 87b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# 97b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# http://www.apache.org/licenses/LICENSE-2.0 107b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# 117b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# Unless required by applicable law or agreed to in writing, software 127b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 137b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 147b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# See the License for the specific language governing permissions and 157b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# limitations under the License. 167b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# 177b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 187b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio""" Idle Analysis Module """ 197b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 207b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgioimport matplotlib.gridspec as gridspec 217b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgioimport matplotlib.pyplot as plt 227b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgioimport pandas as pd 237b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgioimport pylab as pl 247b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 257b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgiofrom analysis_module import AnalysisModule 26a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgiofrom trace import ResidencyTime, ResidencyData 277b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgiofrom trappy.utils import listify 287b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 297b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 307b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgioclass IdleAnalysis(AnalysisModule): 317b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio """ 327b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio Support for plotting Idle Analysis data 337b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 347b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio :param trace: input Trace object 357b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio :type trace: :mod:`libs.utils.Trace` 367b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio """ 377b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 387b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio def __init__(self, trace): 397b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio super(IdleAnalysis, self).__init__(trace) 407b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 417b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio############################################################################### 427b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# DataFrame Getter Methods 437b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio############################################################################### 447b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 457b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio def _dfg_cpu_idle_state_residency(self, cpu): 467b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio """ 477b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio Compute time spent by a given CPU in each idle state. 487b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 497b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio :param entity: CPU ID 507b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio :type entity: int 517b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 527b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio :returns: :mod:`pandas.DataFrame` - idle state residency dataframe 537b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio """ 547b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio if not self._trace.hasEvents('cpu_idle'): 55c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi self._log.warning('Events [cpu_idle] not found, ' 56c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi 'idle state residency computation not possible!') 577b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio return None 587b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 597b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_df = self._dfg_trace_event('cpu_idle') 607b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio cpu_idle = idle_df[idle_df.cpu_id == cpu] 617b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 627b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio cpu_is_idle = self._trace.getCPUActiveSignal(cpu) ^ 1 637b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 647b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # In order to compute the time spent in each idle state we 657b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # multiply 2 square waves: 667b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # - cpu_idle 677b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # - idle_state, square wave of the form: 687b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # idle_state[t] == 1 if at time t CPU is in idle state i 697b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # idle_state[t] == 0 otherwise 707b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio available_idles = sorted(idle_df.state.unique()) 717b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # Remove non-idle state from availables 72d162fa6bab716eacb5b423f94e60c720993bbe5bBrendan Jackman available_idles = available_idles[1:] 737b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio cpu_idle = cpu_idle.join(cpu_is_idle.to_frame(name='is_idle'), 747b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio how='outer') 757b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio cpu_idle.fillna(method='ffill', inplace=True) 76181dd7b70747c83189afa450660a9ab746c53c8cBrendan Jackman 77181dd7b70747c83189afa450660a9ab746c53c8cBrendan Jackman # Extend the last cpu_idle event to the end of the time window under 78181dd7b70747c83189afa450660a9ab746c53c8cBrendan Jackman # consideration 79181dd7b70747c83189afa450660a9ab746c53c8cBrendan Jackman final_entry = pd.DataFrame([cpu_idle.iloc[-1]], index=[self._trace.x_max]) 80181dd7b70747c83189afa450660a9ab746c53c8cBrendan Jackman cpu_idle = cpu_idle.append(final_entry) 81181dd7b70747c83189afa450660a9ab746c53c8cBrendan Jackman 827b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_time = [] 837b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio for i in available_idles: 847b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_state = cpu_idle.state.apply( 857b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio lambda x: 1 if x == i else 0 867b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio ) 877b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_t = cpu_idle.is_idle * idle_state 887b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # Compute total time by integrating the square wave 897b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_time.append(self._trace.integrate_square_wave(idle_t)) 907b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 917b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_time_df = pd.DataFrame({'time' : idle_time}, index=available_idles) 927b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_time_df.index.name = 'idle_state' 937b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio return idle_time_df 947b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 957b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio def _dfg_cluster_idle_state_residency(self, cluster): 967b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio """ 977b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio Compute time spent by a given cluster in each idle state. 987b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 997b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio :param cluster: cluster name or list of CPU IDs 1007b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio :type cluster: str or list(int) 1017b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 1027b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio :returns: :mod:`pandas.DataFrame` - idle state residency dataframe 1037b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio """ 1047b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio if not self._trace.hasEvents('cpu_idle'): 105c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi self._log.warning('Events [cpu_idle] not found, ' 106c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi 'idle state residency computation not possible!') 1077b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio return None 1087b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 1097b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio _cluster = cluster 1107b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio if isinstance(cluster, str) or isinstance(cluster, unicode): 1117b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio try: 1127b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio _cluster = self._platform['clusters'][cluster.lower()] 1137b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio except KeyError: 114c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi self._log.warning('%s cluster not found!', cluster) 1157b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio return None 1167b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 1177b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_df = self._dfg_trace_event('cpu_idle') 1187b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # Each core in a cluster can be in a different idle state, but the 1197b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # cluster lies in the idle state with lowest ID, that is the shallowest 1207b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # idle state among the idle states of its CPUs 1217b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio cl_idle = idle_df[idle_df.cpu_id == _cluster[0]].state.to_frame( 1227b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio name=_cluster[0]) 1237b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio for cpu in _cluster[1:]: 1247b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio cl_idle = cl_idle.join( 1257b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_df[idle_df.cpu_id == cpu].state.to_frame(name=cpu), 1267b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio how='outer' 1277b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio ) 1287b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio cl_idle.fillna(method='ffill', inplace=True) 1297b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio cl_idle = pd.DataFrame(cl_idle.min(axis=1), columns=['state']) 1307b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 1317b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # Build a square wave of the form: 1327b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # cl_is_idle[t] == 1 if all CPUs in the cluster are reported 1337b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # to be idle by cpufreq at time t 1347b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # cl_is_idle[t] == 0 otherwise 1357b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio cl_is_idle = self._trace.getClusterActiveSignal(_cluster) ^ 1 1367b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 1377b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # In order to compute the time spent in each idle statefrequency we 1387b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # multiply 2 square waves: 1397b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # - cluster_is_idle 1407b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # - idle_state, square wave of the form: 1417b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # idle_state[t] == 1 if at time t cluster is in idle state i 1427b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # idle_state[t] == 0 otherwise 1437b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio available_idles = sorted(idle_df.state.unique()) 1447b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # Remove non-idle state from availables 145d162fa6bab716eacb5b423f94e60c720993bbe5bBrendan Jackman available_idles = available_idles[1:] 1467b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio cl_idle = cl_idle.join(cl_is_idle.to_frame(name='is_idle'), 1477b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio how='outer') 1487b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio cl_idle.fillna(method='ffill', inplace=True) 1497b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_time = [] 1507b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio for i in available_idles: 1517b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_state = cl_idle.state.apply( 1527b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio lambda x: 1 if x == i else 0 1537b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio ) 1547b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_t = cl_idle.is_idle * idle_state 1557b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio # Compute total time by integrating the square wave 1567b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_time.append(self._trace.integrate_square_wave(idle_t)) 1577b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 1587b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_time_df = pd.DataFrame({'time' : idle_time}, index=available_idles) 1597b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio idle_time_df.index.name = 'idle_state' 1607b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio return idle_time_df 1617b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 1627b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 1637b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio############################################################################### 1647b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# Plotting Methods 1657b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio############################################################################### 1667b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 167a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio def plotCPUIdleStateResidency(self, cpus=None, pct=False): 168a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio """ 169a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio Plot per-CPU idle state residency. big CPUs are plotted first and then 170a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio LITTLEs. 171a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 172a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio Requires cpu_idle trace events. 173a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 174a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio :param cpus: list of CPU IDs. By default plot all CPUs 175a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio :type cpus: list(int) or int 176a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 177a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio :param pct: plot residencies in percentage 178a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio :type pct: bool 179a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio """ 180a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio if not self._trace.hasEvents('cpu_idle'): 181c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi self._log.warning('Events [cpu_idle] not found, ' 182c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi 'plot DISABLED!') 183a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio return 184a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 185a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio if cpus is None: 186a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio # Generate plots only for available CPUs 187a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio cpuidle_data = self._dfg_trace_event('cpu_idle') 188a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio _cpus = range(cpuidle_data.cpu_id.max() + 1) 189a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio else: 190a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio _cpus = listify(cpus) 191a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 192a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio # Split between big and LITTLE CPUs ordered from higher to lower ID 193a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio _cpus.reverse() 194f2a93cfe4c1c35d5237810e7fed4f1330859a358Brendan Jackman big_cpus = [c for c in _cpus if c in self._big_cpus] 195f2a93cfe4c1c35d5237810e7fed4f1330859a358Brendan Jackman little_cpus = [c for c in _cpus if c in self._little_cpus] 196a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio _cpus = big_cpus + little_cpus 197a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 198a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio residencies = [] 199a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio xmax = 0.0 200a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio for cpu in _cpus: 201a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio r = self._dfg_cpu_idle_state_residency(cpu) 202a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio residencies.append(ResidencyData('CPU{}'.format(cpu), r)) 203a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 204a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio max_time = r.max().values[0] 205a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio if xmax < max_time: 206a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio xmax = max_time 207a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 208a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio self._plotIdleStateResidency(residencies, 'cpu', xmax, pct=pct) 209a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 210a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio def plotClusterIdleStateResidency(self, clusters=None, pct=False): 211a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio """ 212a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio Plot per-cluster idle state residency in a given cluster, i.e. the 213a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio amount of time cluster `cluster` spent in idle state `i`. By default, 214a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio both 'big' and 'LITTLE' clusters data are plotted. 215a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 216a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio Requires cpu_idle following trace events. 217a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio :param clusters: name of the clusters to be plotted (all of them by 218a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio default) 219a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio :type clusters: str ot list(str) 220a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio """ 221a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio if not self._trace.hasEvents('cpu_idle'): 222c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi self._log.warning('Events [cpu_idle] not found, plot DISABLED!') 223a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio return 224f2a93cfe4c1c35d5237810e7fed4f1330859a358Brendan Jackman if 'clusters' not in self._platform: 225f2a93cfe4c1c35d5237810e7fed4f1330859a358Brendan Jackman self._log.warning('No platform cluster info. Plot DISABLED!') 226f2a93cfe4c1c35d5237810e7fed4f1330859a358Brendan Jackman return 227a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 228a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio # Sanitize clusters 229a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio if clusters is None: 230a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio _clusters = self._platform['clusters'].keys() 231a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio else: 232a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio _clusters = listify(clusters) 233a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 234a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio # Precompute residencies for each cluster 235a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio residencies = [] 236a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio xmax = 0.0 237a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio for c in _clusters: 238a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio r = self._dfg_cluster_idle_state_residency(c.lower()) 239a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio residencies.append(ResidencyData('{} Cluster'.format(c), r)) 240a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 241a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio max_time = r.max().values[0] 242a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio if xmax < max_time: 243a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio xmax = max_time 244a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 245a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio self._plotIdleStateResidency(residencies, 'cluster', xmax, pct=pct) 2467b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 2477b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio############################################################################### 2487b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# Utility Methods 2497b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio############################################################################### 2507b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 251a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio def _plotIdleStateResidency(self, residencies, entity_name, xmax, 252a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio pct=False): 253a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio """ 254a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio Generate Idle state residency plots for the given entities. 255a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 256a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio :param residencies: list of residencies to be plot 257a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio :type residencies: list(namedtuple(ResidencyData)) - each tuple 258a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio contains: 259a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio - a label to be used as subplot title 260a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio - a dataframe with residency for each idle state 261a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 262a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio :param entity_name: name of the entity ('cpu' or 'cluster') used in the 263a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio figure name 264a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio :type entity_name: str 265a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 266a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio :param xmax: upper bound of x-axes 267a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio :type xmax: double 268a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 269a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio :param pct: plot residencies in percentage 270a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio :type pct: bool 271a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio """ 272a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio n_plots = len(residencies) 273a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio gs = gridspec.GridSpec(n_plots, 1) 274a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio fig = plt.figure() 275a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 276a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio for idx, data in enumerate(residencies): 277a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio r = data.residency 278a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio if r is None: 279a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio plt.close(fig) 280a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio return 281a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 282a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio axes = fig.add_subplot(gs[idx]) 283a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio is_first = idx == 0 284a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio is_last = idx+1 == n_plots 285a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio yrange = 0.4 * max(6, len(r)) * n_plots 286a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio if pct: 287a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio duration = r.time.sum() 288a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio r_pct = r.apply(lambda x: x*100/duration) 289a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio r_pct.columns = [data.label] 290a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio r_pct.T.plot.barh(ax=axes, stacked=True, figsize=(16, yrange)) 291a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 292a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio axes.legend(loc='lower center', ncol=7) 293a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio axes.set_xlim(0, 100) 294a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio else: 295a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio r.plot.barh(ax=axes, color='g', 296a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio legend=False, figsize=(16, yrange)) 297a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 298a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio axes.set_xlim(0, 1.05*xmax) 299a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio axes.set_ylabel('Idle State') 300a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio axes.set_title(data.label) 301a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 302a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio axes.grid(True) 303a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio if is_last: 304a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio if pct: 305a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio axes.set_xlabel('Residency [%]') 306a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio else: 307a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio axes.set_xlabel('Time [s]') 308a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio else: 309a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio axes.set_xticklabels([]) 310a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 311a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio if is_first: 312a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio legend_y = axes.get_ylim()[1] 313a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio axes.annotate('Idle State Residency Time', xy=(0, legend_y), 314a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio xytext=(-50, 45), textcoords='offset points', 315a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio fontsize=18) 316a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 317a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio figname = '{}/{}{}_idle_state_residency.png'\ 318a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio .format(self._trace.plots_dir, 319a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio self._trace.plots_prefix, 320a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio entity_name) 321a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio 322a5bc71881d8d8ff169006a09e19ca771dee26711Michele Di Giorgio pl.savefig(figname, bbox_inches='tight') 3237b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio 3247b789df5a17a406c64e0fb06553d4b60846ae36bMichele Di Giorgio# vim :set tabstop=4 shiftwidth=4 expandtab 325