trace.py revision 8224360b6dbfe7e28c28ef7a06fa100b2556c656
1d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi# SPDX-License-Identifier: Apache-2.0
2d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi#
3d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi# Copyright (C) 2015, ARM Limited and contributors.
4d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi#
5d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi# Licensed under the Apache License, Version 2.0 (the "License"); you may
6d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi# not use this file except in compliance with the License.
7d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi# You may obtain a copy of the License at
8d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi#
9d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi# http://www.apache.org/licenses/LICENSE-2.0
10d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi#
11d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi# Unless required by applicable law or agreed to in writing, software
12d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi# See the License for the specific language governing permissions and
15d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi# limitations under the License.
16d95e98d88a6cf4347853427dc4ef6fd0222a3881Patrick Bellasi#
178e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
188e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport glob
198e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport matplotlib.gridspec as gridspec
208e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport matplotlib.pyplot as plt
218e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport numpy as np
228e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport os
238e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport pandas as pd
248e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport pylab as pl
258e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport re
268e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport sys
278e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport trappy
2879a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasiimport json
2979a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi
3079a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasifrom trappy.utils import listify
318e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
328e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi# Configure logging
338e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport logging
348e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
358e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiclass Trace(object):
368e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
37f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi    def __init__(self, platform, data_dir, events,
3834f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi                 tasks=None, window=(0,None),
39b4ab05a5cc9630963cdfafeab214dcf1661167c7Javi Merino                 normalize_time=True,
4069a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi                 trace_format='FTrace',
4169a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi                 plots_dir=None,
4269a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi                 plots_prefix=''):
438e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
448e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # The platform used to run the experiments
4550b5967280ce939d80f2d8b74253a0130ba16561Patrick Bellasi        self.platform = platform
468e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
4734f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi        # TRAPpy Trace object
489c42a5ae0f2a627860e5cc68dc7626da0c5b232fPatrick Bellasi        self.ftrace = None
498e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
5034f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi        # Trace format
5134f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi        self.trace_format = trace_format
5234f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi
53a8fdc5fe3719b498318e0451f5b4cdfac1f5015ePatrick Bellasi        # The time window used to limit trace parsing to
54a8fdc5fe3719b498318e0451f5b4cdfac1f5015ePatrick Bellasi        self.window = window
55a8fdc5fe3719b498318e0451f5b4cdfac1f5015ePatrick Bellasi
568e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Dynamically registered TRAPpy events
578e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.trappy_cls = {}
588e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
598e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Maximum timespan for all collected events
608e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.time_range = 0
618e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
62877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        # Time the system was overutilzied
63877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        self.overutilized_time = 0
64877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        self.overutilized_prc = 0
65877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi
668e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # The dictionary of tasks descriptors available in the dataset
678e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.tasks = {}
688e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
69e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        # List of events required by user
70e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        self.events = []
71e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi
728e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # List of events available in the parsed trace
738e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.available_events = []
748e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
759e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio        # Cluster frequency coherency flag
769e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio        self.freq_coherency = True
779e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio
78f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi        # Folder containing all trace data
79f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi        self.data_dir = None
80f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi
818e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Folder containing trace
82f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi        if not os.path.isdir(data_dir):
83f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi            self.data_dir = os.path.dirname(data_dir)
84881f14cdb8b78ad422f739fe28cbce2525020430Patrick Bellasi        else:
85f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi            self.data_dir = data_dir
868e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
8769a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi        # By deafult, use the trace dir to save plots
8869a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi        self.plots_dir = plots_dir
8969a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi        if self.plots_dir is None:
9069a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi            self.plots_dir = self.data_dir
9169a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi        self.plots_prefix = plots_prefix
9269a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi
93e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        self.__registerTraceEvents(events)
94f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi        self.__parseTrace(data_dir, tasks, window, normalize_time, trace_format)
958e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.__computeTimeSpan()
968e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
978224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        # Minimum and Maximum x_time to use for all plots
988224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        self.x_min = 0
998224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        self.x_max = self.time_range
1008224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi
1018224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        # Reset x axis time range to full scale
1028224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        t_min = self.window[0]
1038224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        t_max = self.window[1]
1048224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        self.setXTimeRange(t_min, t_max)
1058224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi
1068224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        # Initialize supported analysis modules
1078224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi
1088224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi    def setXTimeRange(self, t_min=None, t_max=None):
1098224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        if t_min is None:
1108224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi            self.x_min = 0
1118224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        else:
1128224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi            self.x_min = t_min
1138224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        if t_max is None:
1148224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi            self.x_max = self.time_range
1158224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        else:
1168224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi            self.x_max = t_max
1178224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        logging.info('Set plots time range to (%.6f, %.6f)[s]',
1188224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi                self.x_min, self.x_max)
1198224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi
120e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi    def __registerTraceEvents(self, events):
121e09821241ca9697b75c8a53fb0813212202d1c65Patrick Bellasi
122e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        if isinstance(events, basestring):
123e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi            self.events = events.split(' ')
124e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        elif isinstance(events, list):
125e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi            self.events = events
126e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        else:
127e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi            raise ValueError('Events must be a string or a list of strings')
1288e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1298e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
130b4ab05a5cc9630963cdfafeab214dcf1661167c7Javi Merino    def __parseTrace(self, path, tasks, window, normalize_time, trace_format):
131881f14cdb8b78ad422f739fe28cbce2525020430Patrick Bellasi        logging.debug('Loading [sched] events from trace in [%s]...', path)
132e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        logging.debug("Parsing events: %s", self.events)
13334f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi        if trace_format.upper() == 'SYSTRACE' or path.endswith('html'):
13434f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi            logging.info('Parsing SysTrace format...')
135edc53078c056df33a9872fd170d6a66c2acd82d8Javi Merino            trace_class = trappy.SysTrace
13634f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi            self.trace_format = 'SysTrace'
13734f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi        elif trace_format.upper() == 'FTRACE':
13834f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi            logging.info('Parsing FTrace format...')
139edc53078c056df33a9872fd170d6a66c2acd82d8Javi Merino            trace_class = trappy.FTrace
14034f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi            self.trace_format = 'FTrace'
141d02408964a1d1042b99f51ba01989e8cf02478faJavi Merino        else:
142d02408964a1d1042b99f51ba01989e8cf02478faJavi Merino            raise ValueError("Unknown trace format {}".format(trace_format))
1438e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
144edc53078c056df33a9872fd170d6a66c2acd82d8Javi Merino        self.ftrace = trace_class(path, scope="custom", events=self.events,
145b4ab05a5cc9630963cdfafeab214dcf1661167c7Javi Merino                                  window=window, normalize_time=normalize_time)
146edc53078c056df33a9872fd170d6a66c2acd82d8Javi Merino
14779a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        # Load Functions profiling data
14879a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        has_function_stats = self._loadFunctionsStats(path)
14979a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi
1508e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Check for events available on the parsed trace
1518e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.__checkAvailableEvents()
1528e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if len(self.available_events) == 0:
15379a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi            if has_function_stats:
15479a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi                logging.info('Trace contains only functions stats')
15579a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi                return
15679a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi            raise ValueError('The trace does not contain useful events '
15779a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi                             'nor function stats')
1588e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1598e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Setup internal data reference to interesting events/dataframes
1608e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
16166b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        self._sanitize_SchedLoadAvgCpu()
16266b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        self._sanitize_SchedLoadAvgTask()
16366b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        self._sanitize_SchedCpuCapacity()
16466b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        self._sanitize_SchedBoostCpu()
16566b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        self._sanitize_SchedBoostTask()
16666b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        self._sanitize_SchedEnergyDiff()
16766b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        self._sanitize_SchedOverutilized()
16847895783a9a4b581c1c7aa15caf2a407201948dbPatrick Bellasi        self._sanitize_CpuFrequency()
1698e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1708e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.__loadTasksNames(tasks)
1718e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1729e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio
173db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio        # Compute plot window
174db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio        if not normalize_time:
175db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio            start = self.window[0]
176db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio            if self.window[1]:
177db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio                duration = min(self.ftrace.get_duration(), self.window[1])
178db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio            else:
179db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio                duration = self.ftrace.get_duration()
180db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio            self.window = (self.ftrace.basetime + start,
181db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio                           self.ftrace.basetime + duration)
1828e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
18334f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi    def __checkAvailableEvents(self, key=""):
18434f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi        for val in self.ftrace.get_filters(key):
1859c42a5ae0f2a627860e5cc68dc7626da0c5b232fPatrick Bellasi            obj = getattr(self.ftrace, val)
1868e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if len(obj.data_frame):
1878e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.available_events.append(val)
1888e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        logging.debug('Events found on trace:')
1898e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        for evt in self.available_events:
1908e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            logging.debug(' - %s', evt)
1918e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1928e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1938e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def __loadTasksNames(self, tasks):
1948e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Try to load tasks names using one of the supported events
1958e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if 'sched_switch' in self.available_events:
19666b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi            self.getTasks(self.df('sched_switch'), tasks,
1978e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                name_key='next_comm', pid_key='next_pid')
1983a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi            self._scanTasks(self.df('sched_switch'),
1993a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi                            name_key='next_comm', pid_key='next_pid')
2008e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            return
2018e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if 'sched_load_avg_task' in self.available_events:
20266b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi            self.getTasks(self.df('sched_load_avg_task'), tasks)
2033a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi            self._scanTasks(self.df('sched_load_avg_task'))
2048e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            return
2058e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        logging.warning('Failed to load tasks names from trace events')
2068e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
2078e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def hasEvents(self, dataset):
2088e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if dataset in self.available_events:
2098e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            return True
2108e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        return False
2118e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
2128e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def __computeTimeSpan(self):
2138e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Compute time axis range, considering all the parsed events
2148e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        ts = sys.maxint
2158e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        te = 0
2168e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
21766b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        for events in self.available_events:
21866b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi            df = self.df(events)
2198e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if len(df) == 0:
2208e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                continue
2218e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if (df.index[0]) < ts:
2228e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                ts = df.index[0]
2238e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if (df.index[-1]) > te:
2248e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                te = df.index[-1]
2258e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.time_range = te - ts
2268e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
2278e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        logging.info('Collected events spans a %.3f [s] time interval',
2288e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.time_range)
2298e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
230877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        # Build a stat on trace overutilization
231877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        if self.hasEvents('sched_overutilized'):
232877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi            df = self.df('sched_overutilized')
233877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi            self.overutilized_time = df[df.overutilized == 1].len.sum()
234877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi            self.overutilized_prc = 100. * self.overutilized_time / self.time_range
235877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi
236877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi            logging.info('Overutilized time: %.6f [s] (%.3f%% of trace time)',
237877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi                    self.overutilized_time, self.overutilized_prc)
238877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi
23979a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi    def _loadFunctionsStats(self, path='trace.stats'):
24079a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        if os.path.isdir(path):
24179a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi            path = os.path.join(path, 'trace.stats')
24279a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        if path.endswith('dat') or path.endswith('html'):
24379a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi            pre, ext = os.path.splitext(path)
24479a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi            path = pre + '.stats'
24579a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        if not os.path.isfile(path):
24679a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi            return False
24779a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi
24879a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        # Opening functions profiling JSON data file
24979a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        logging.debug('Loading functions profiling data from [%s]...', path)
25079a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        with open(os.path.join(path), 'r') as fh:
25179a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi            trace_stats = json.load(fh)
25279a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi
25379a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        # Build DataFrame of function stats
25479a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        frames = {}
25579a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        for cpu, data in trace_stats.iteritems():
25679a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi            frames[int(cpu)] = pd.DataFrame.from_dict(data, orient='index')
25779a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi
25879a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        # Build and keep track of the DataFrame
25979a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        self._functions_stats_df = pd.concat(frames.values(), keys=frames.keys())
26079a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi
26179a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        return len(self._functions_stats_df) > 0
26279a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi
26379a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi    def functions_stats_df(self, functions=None):
26479a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        """
26579a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        Get a DataFrame of specified kernel functions profile data
26679a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi
26779a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        For each profiled function a DataFrame is returned which reports stats
26879a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        on kernel functions execution time. The reported stats are per-CPU and
26979a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        includes: number of times the function has been executed (hits),
27079a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        average execution time (avg), overall execution time (time) and samples
27179a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        variance (s_2).
27279a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        By default returns a DataFrame of all the functions profiled.
27379a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi
27479a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        :param functions: the name of the function or a list of function names
27579a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi                          to report
27679a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        :type functions: str or list
27779a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi
27879a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        """
27979a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        if not hasattr(self, '_functions_stats_df'):
28079a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi            return None
28179a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        df = self._functions_stats_df
28279a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        if not functions:
28379a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi            return df
28479a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        return df.loc[df.index.get_level_values(1).isin(listify(functions))]
28579a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi
2863a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi    def _scanTasks(self, df, name_key='comm', pid_key='pid'):
2873a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        df =  df[[name_key, pid_key]]
2883a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        self._tasks_by_name = df.set_index(name_key)
2893a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        self._tasks_by_pid  = df.set_index(pid_key)
2903a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi
2913a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi    def getTaskByName(self, name):
2923a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        if name not in self._tasks_by_name.index:
2933a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi            return []
2943a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        if len(self._tasks_by_name.ix[name].values) > 1:
2953a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi            return list({task[0] for task in
2963a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi                         self._tasks_by_name.ix[name].values})
2973a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        return [self._tasks_by_name.ix[name].values[0]]
2983a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi
2993a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi    def getTaskByPid(self, pid):
3003a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        if pid not in self._tasks_by_pid.index:
3013a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi            return []
3023a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        if len(self._tasks_by_pid.ix[pid].values) > 1:
3033a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi            return list({task[0] for task in
3043a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi                         self._tasks_by_pid.ix[pid].values})
3053a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        return [self._tasks_by_pid.ix[pid].values[0]]
3063a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi
3078e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def getTasks(self, dataframe=None,
3088e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            task_names=None, name_key='comm', pid_key='pid'):
3098e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # """ Helper function to get PIDs of specified tasks
3108e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #
3118e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     This method requires a Pandas dataset in input to be used to
3128e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     fiter out the PIDs of all the specified tasks.
3138e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     In a dataset is not provided, previouslt filtered PIDs are
3148e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     returned.
3158e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     If a list of task names is not provided, the workload defined
3168e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     task names is used instead.
3178e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     The specified dataframe must provide at least two columns
3188e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     reporting the task name and the task PID. The default values of
3198e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     this colums could be specified using the provided parameters.
3208e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #
3218e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     :param task_names: The list of tasks to get the PID of (by default
3228e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #                        the workload defined tasks)
3238e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     :param dataframe: A Pandas datafram containing at least 'pid' and
3248e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #                       'task name' columns. If None, the previously
3258e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #                       filtered PIDs are returned
3268e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     :param name_key: The name of the dataframe columns containing
3278e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #                      task names
3288e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     :param pid_key:  The name of the dataframe columns containing
3298e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #                      task PIDs
3308e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # """
3318e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if dataframe is None:
3328e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            return self.tasks
3338e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df = dataframe
3348e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if task_names is None:
3358e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            task_names = self.tasks.keys()
3368e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        logging.debug("Lookup dataset for tasks...")
3378e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        for tname in task_names:
3388e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            logging.debug("Lookup for task [%s]...", tname)
3398e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            results = df[df[name_key] == tname][[name_key,pid_key]]
3408e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if len(results)==0:
3418e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                logging.error('  task %16s NOT found', tname)
3428e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                continue
3438e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            (name, pid) = results.head(1).values[0]
3448e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if name!=tname:
3458e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                logging.error('  task %16s NOT found', tname)
3468e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                continue
3478e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if (tname not in self.tasks):
3488e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.tasks[tname] = {}
3498e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            pids = list(results[pid_key].unique())
3508e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.tasks[tname]['pid'] = pids
3518e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            logging.info('  task %16s found, pid: %s',
3528e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                    tname, self.tasks[tname]['pid'])
3538e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        return self.tasks
3548e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
3558e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def df(self, event):
3568e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        """
3578e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        Return the PANDAS dataframe with the performance data for the specified
3588e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        event
3598e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        """
360f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi        if self.data_dir is None:
3618e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            raise ValueError("trace data not (yet) loaded")
3629c42a5ae0f2a627860e5cc68dc7626da0c5b232fPatrick Bellasi        if self.ftrace and hasattr(self.ftrace, event):
3639c42a5ae0f2a627860e5cc68dc7626da0c5b232fPatrick Bellasi            return getattr(self.ftrace, event).data_frame
36466b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        raise ValueError('Event [{}] not supported. '\
36566b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi                         'Supported events are: {}'\
36666b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi                         .format(event, self.available_events))
3678e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
368c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedCpuCapacity(self):
369680ad8b9c70754064b686e1fcea6db022bc5e152Patrick Bellasi        # Add more columns if the energy model is available
37066b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        if not self.hasEvents('cpu_capacity') \
37166b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi           or 'nrg_model' not in self.platform:
372680ad8b9c70754064b686e1fcea6db022bc5e152Patrick Bellasi            return
373680ad8b9c70754064b686e1fcea6db022bc5e152Patrick Bellasi
37466b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        df = self.df('cpu_capacity')
37566b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi
3768e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Add column with LITTLE and big CPUs max capacities
3778e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        nrg_model = self.platform['nrg_model']
3788e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        max_lcap = nrg_model['little']['cpu']['cap_max']
3798e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        max_bcap = nrg_model['big']['cpu']['cap_max']
3808e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['max_capacity'] = np.select(
3818e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [df.cpu.isin(self.platform['clusters']['little'])],
3828e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [max_lcap], max_bcap)
3838e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Add LITTLE and big CPUs "tipping point" threshold
3848e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        tip_lcap = 0.8 * max_lcap
3858e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        tip_bcap = 0.8 * max_bcap
3868e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['tip_capacity'] = np.select(
3878e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [df.cpu.isin(self.platform['clusters']['little'])],
3888e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [tip_lcap], tip_bcap)
3898e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
390997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi    def _sanitize_SchedLoadAvgCpu(self):
39166b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        if not self.hasEvents('sched_load_avg_cpu'):
39266b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi            return
393c94900dcb499cd2a6df32b7c6532be4e589d0e8bPatrick Bellasi        df = self.df('sched_load_avg_cpu')
394997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi        if 'utilization' in df:
395997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi            # Convert signals name from v5.0 to v5.1 format
396997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi            df.rename(columns={'utilization':'util_avg'}, inplace=True)
397997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi            df.rename(columns={'load':'load_avg'}, inplace=True)
398997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi
399c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedLoadAvgTask(self):
40066b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        if not self.hasEvents('sched_load_avg_task'):
40166b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi            return
402c94900dcb499cd2a6df32b7c6532be4e589d0e8bPatrick Bellasi        df = self.df('sched_load_avg_task')
40317c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi        if 'utilization' in df:
40417c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            # Convert signals name from v5.0 to v5.1 format
40517c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            df.rename(columns={'utilization':'util_avg'}, inplace=True)
40617c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            df.rename(columns={'load':'load_avg'}, inplace=True)
40717c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            df.rename(columns={'avg_period':'period_contrib'}, inplace=True)
40817c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            df.rename(columns={'runnable_avg_sum':'load_sum'}, inplace=True)
40917c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            df.rename(columns={'running_avg_sum':'util_sum'}, inplace=True)
4108e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['cluster'] = np.select(
4118e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [df.cpu.isin(self.platform['clusters']['little'])],
4128e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                ['LITTLE'], 'big')
4138e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
414c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedBoostCpu(self):
41566b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        if not self.hasEvents('sched_boost_cpu'):
41666b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi            return
417c94900dcb499cd2a6df32b7c6532be4e589d0e8bPatrick Bellasi        df = self.df('sched_boost_cpu')
41817c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi        if 'usage' in df:
41917c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            # Convert signals name from to v5.1 format
42017c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            df.rename(columns={'usage':'util'}, inplace=True)
42117c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi        df['boosted_util'] = df['util'] + df['margin']
42217c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi
4238e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
424c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedBoostTask(self):
42566b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        if not self.hasEvents('sched_boost_task'):
42666b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi            return
427c94900dcb499cd2a6df32b7c6532be4e589d0e8bPatrick Bellasi        df = self.df('sched_boost_task')
428418cfb6405256f744cc3023fd7a5fcbff1f757a7Patrick Bellasi        if 'utilization' in df:
429418cfb6405256f744cc3023fd7a5fcbff1f757a7Patrick Bellasi            # Convert signals name from to v5.1 format
430418cfb6405256f744cc3023fd7a5fcbff1f757a7Patrick Bellasi            df.rename(columns={'utilization':'util'}, inplace=True)
431418cfb6405256f744cc3023fd7a5fcbff1f757a7Patrick Bellasi        df['boosted_util'] = df['util'] + df['margin']
4328e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
433c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedEnergyDiff(self):
43466b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        if not self.hasEvents('sched_energy_diff') \
43566b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi           or 'nrg_model' not in self.platform:
436680ad8b9c70754064b686e1fcea6db022bc5e152Patrick Bellasi            return
4378e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        nrg_model = self.platform['nrg_model']
4388e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        em_lcluster = nrg_model['little']['cluster']
4398e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        em_bcluster = nrg_model['big']['cluster']
4408e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        em_lcpu = nrg_model['little']['cpu']
4418e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        em_bcpu = nrg_model['big']['cpu']
4428e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        lcpus = len(self.platform['clusters']['little'])
4438e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        bcpus = len(self.platform['clusters']['big'])
4448e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        SCHED_LOAD_SCALE = 1024
4458e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
4468e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        power_max = em_lcpu['nrg_max'] * lcpus + em_bcpu['nrg_max'] * bcpus + \
4478e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                    em_lcluster['nrg_max'] + em_bcluster['nrg_max']
4488e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        print "Maximum estimated system energy: {0:d}".format(power_max)
4498e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
450c94900dcb499cd2a6df32b7c6532be4e589d0e8bPatrick Bellasi        df = self.df('sched_energy_diff')
4518e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['nrg_diff_pct'] = SCHED_LOAD_SCALE * df.nrg_diff / power_max
4528e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
4538e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Tag columns by usage_delta
4548e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        ccol = df.usage_delta
4558e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['usage_delta_group'] = np.select(
4568e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            [ccol < 150, ccol < 400, ccol < 600],
4578e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            ['< 150', '< 400', '< 600'], '>= 600')
4588e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
4598e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Tag columns by nrg_payoff
4608e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        ccol = df.nrg_payoff
4618e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['nrg_payoff_group'] = np.select(
4628e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            [ccol > 2e9, ccol > 0, ccol > -2e9],
4638e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            ['Optimal Accept', 'SchedTune Accept', 'SchedTune Reject'], 'Suboptimal Reject')
4648e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
465877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi    def _sanitize_SchedOverutilized(self):
466877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        if not self.hasEvents('sched_overutilized'):
467877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi            return
468877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        # Add a column with overutilized status duration
469877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        df = self.df('sched_overutilized')
470877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        df['start'] = df.index
471877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        df['len'] = (df.start - df.start.shift()).fillna(0).shift(-1)
472877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        df.drop('start', axis=1, inplace=True)
4739e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio
47447895783a9a4b581c1c7aa15caf2a407201948dbPatrick Bellasi    def _chunker(self, seq, size):
4759e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio        return (seq.iloc[pos:pos + size] for pos in range(0, len(seq), size))
4769e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio
47747895783a9a4b581c1c7aa15caf2a407201948dbPatrick Bellasi    def _sanitize_CpuFrequency(self):
4789e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio        if not self.hasEvents('cpu_frequency'):
4799e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio            return
48047895783a9a4b581c1c7aa15caf2a407201948dbPatrick Bellasi        # Verify that all platform reported clusters are frequency choerent
4819e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio        df = self.df('cpu_frequency')
4829e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio        clusters = self.platform['clusters']
4839e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio        for c, cpus in clusters.iteritems():
4849e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio            cluster_df = df[df.cpu.isin(cpus)]
48547895783a9a4b581c1c7aa15caf2a407201948dbPatrick Bellasi            for chunk in self._chunker(cluster_df, len(cpus)):
4869e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio                f = chunk.iloc[0].frequency
4879e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio                if any(chunk.frequency != f):
4889e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio                    logging.warn('Cluster Frequency is not coherent! '\
4899e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio                                'Failure in [cpu_frequency] events at:')
4909e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio                    logging.warn(chunk)
4919e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio                    self.freq_coherency = False
4929e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio                    return
49347895783a9a4b581c1c7aa15caf2a407201948dbPatrick Bellasi        logging.info("Platform clusters verified to be Frequency choerent")
49447895783a9a4b581c1c7aa15caf2a407201948dbPatrick Bellasi
495