trace.py revision c278c2343c7f25083a80cb164b6bdc761d50050b
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
18b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio""" Trace Parser Module """
19b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio
208e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport numpy as np
218e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport os
228e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport pandas as pd
238e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport sys
248e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport trappy
2579a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasiimport json
26fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasiimport warnings
27691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgioimport operator
28c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasiimport logging
2979a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi
306721d173e18d3c56a33fd3f2eb9b50acd675ec27Patrick Bellasifrom analysis_register import AnalysisRegister
31691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgiofrom collections import namedtuple
32691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgiofrom devlib.utils.misc import memoized
3379a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasifrom trappy.utils import listify
348e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
358e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
36691fc118e5dff4df885a039cc855a746de4b7556Michele Di GiorgioNON_IDLE_STATE = 4294967295
37691fc118e5dff4df885a039cc855a746de4b7556Michele Di GiorgioResidencyTime = namedtuple('ResidencyTime', ['total', 'active'])
38691fc118e5dff4df885a039cc855a746de4b7556Michele Di GiorgioResidencyData = namedtuple('ResidencyData', ['label', 'residency'])
39b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio
408e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiclass Trace(object):
41f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    """
42f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    The Trace object is the LISA trace events parser.
43f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
44f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :param platform: a dictionary containing information about the target
45f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        platform
46f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :type platform: dict
47f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
48f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :param data_dir: folder containing all trace data
49f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :type data_dir: str
50f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
51f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :param events: events to be parsed (everything in the trace by default)
52f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :type events: list(str)
53f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
54aa9f74b7a17e863acbfa558aee6b5a3ac997c0b8Brendan Jackman    :param tasks: filter data for the specified tasks only. If None (default),
55aa9f74b7a17e863acbfa558aee6b5a3ac997c0b8Brendan Jackman        use data for all tasks found in the trace.
56aa9f74b7a17e863acbfa558aee6b5a3ac997c0b8Brendan Jackman    :type tasks: list(str) or NoneType
57f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
58f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :param window: time window to consider when parsing the trace
59f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :type window: tuple(int, int)
60f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
61f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :param normalize_time: normalize trace time stamps
62f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :type normalize_time: bool
63f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
64f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :param trace_format: format of the trace. Possible values are:
65f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        - FTrace
66f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        - SysTrace
67f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :type trace_format: str
68f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
69f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :param plots_dir: directory where to save plots
70f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :type plots_dir: str
71f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
72f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :param plots_prefix: prefix for plots file names
73f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    :type plots_prefix: str
74f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio    """
758e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
76f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi    def __init__(self, platform, data_dir, events,
77b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio                 tasks=None, window=(0, None),
78b4ab05a5cc9630963cdfafeab214dcf1661167c7Javi Merino                 normalize_time=True,
7969a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi                 trace_format='FTrace',
8069a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi                 plots_dir=None,
8169a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi                 plots_prefix=''):
828e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
838e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # The platform used to run the experiments
8450b5967280ce939d80f2d8b74253a0130ba16561Patrick Bellasi        self.platform = platform
858e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
8634f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi        # TRAPpy Trace object
879c42a5ae0f2a627860e5cc68dc7626da0c5b232fPatrick Bellasi        self.ftrace = None
888e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
8934f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi        # Trace format
9034f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi        self.trace_format = trace_format
9134f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi
92a8fdc5fe3719b498318e0451f5b4cdfac1f5015ePatrick Bellasi        # The time window used to limit trace parsing to
93a8fdc5fe3719b498318e0451f5b4cdfac1f5015ePatrick Bellasi        self.window = window
94a8fdc5fe3719b498318e0451f5b4cdfac1f5015ePatrick Bellasi
958e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Dynamically registered TRAPpy events
968e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.trappy_cls = {}
978e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
988e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Maximum timespan for all collected events
998e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.time_range = 0
1008e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
101877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        # Time the system was overutilzied
102877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        self.overutilized_time = 0
103877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        self.overutilized_prc = 0
104877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi
1058e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # The dictionary of tasks descriptors available in the dataset
1068e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.tasks = {}
1078e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
108e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        # List of events required by user
109e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        self.events = []
110e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi
1118e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # List of events available in the parsed trace
1128e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.available_events = []
1138e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1149e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio        # Cluster frequency coherency flag
1159e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio        self.freq_coherency = True
1169e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio
117f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi        # Folder containing all trace data
118f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi        self.data_dir = None
119f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi
120c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi        # Setup logging
121c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi        self._log = logging.getLogger('Trace')
122c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi
1238e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Folder containing trace
124f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi        if not os.path.isdir(data_dir):
125f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi            self.data_dir = os.path.dirname(data_dir)
126881f14cdb8b78ad422f739fe28cbce2525020430Patrick Bellasi        else:
127f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi            self.data_dir = data_dir
1288e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
12969a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi        # By deafult, use the trace dir to save plots
13069a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi        self.plots_dir = plots_dir
13169a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi        if self.plots_dir is None:
13269a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi            self.plots_dir = self.data_dir
13369a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi        self.plots_prefix = plots_prefix
13469a445cdc130949aa54b84fb9b3dfbcb55fa2d53Patrick Bellasi
135e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        self.__registerTraceEvents(events)
136b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio        self.__parseTrace(data_dir, tasks, window, normalize_time,
137b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio                          trace_format)
1388e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.__computeTimeSpan()
1398e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1408224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        # Minimum and Maximum x_time to use for all plots
1418224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        self.x_min = 0
1428224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        self.x_max = self.time_range
1438224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi
1448224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        # Reset x axis time range to full scale
1458224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        t_min = self.window[0]
1468224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        t_max = self.window[1]
1478224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        self.setXTimeRange(t_min, t_max)
1488224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi
149f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasi        self.data_frame = TraceData()
150f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasi        self._registerDataFrameGetters(self)
151f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasi
1526721d173e18d3c56a33fd3f2eb9b50acd675ec27Patrick Bellasi        self.analysis = AnalysisRegister(self)
1536721d173e18d3c56a33fd3f2eb9b50acd675ec27Patrick Bellasi
154f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasi    def _registerDataFrameGetters(self, module):
155f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
156f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Internal utility function that looks up getter functions with a "_dfg_"
157f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        prefix in their name and bounds them to the specified module.
158f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
159f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param module: module to which the function is added
160f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type module: class
161f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
162c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi        self._log.debug('Registering [%s] local data frames', module)
163f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasi        for func in dir(module):
164f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasi            if not func.startswith('_dfg_'):
165f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasi                continue
166f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasi            dfg_name = func.replace('_dfg_', '')
167f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasi            dfg_func = getattr(module, func)
168c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi            self._log.debug('   %s', dfg_name)
169f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasi            setattr(self.data_frame, dfg_name, dfg_func)
1708224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi
1718224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi    def setXTimeRange(self, t_min=None, t_max=None):
172f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
173f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Set x axis time range to the specified values.
174f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
175f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param t_min: lower bound
176f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type t_min: int or float
177f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
178f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param t_max: upper bound
179f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type t_max: int or float
180f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
1818224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        if t_min is None:
1828224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi            self.x_min = 0
1838224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        else:
1848224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi            self.x_min = t_min
1858224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        if t_max is None:
1868224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi            self.x_max = self.time_range
1878224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi        else:
1888224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi            self.x_max = t_max
189c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi        self._log.info('Set plots time range to (%.6f, %.6f)[s]',
190c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi                       self.x_min, self.x_max)
1918224360b6dbfe7e28c28ef7a06fa100b2556c656Patrick Bellasi
192e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi    def __registerTraceEvents(self, events):
193f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
194f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Save a copy of the parsed events.
195e09821241ca9697b75c8a53fb0813212202d1c65Patrick Bellasi
196f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param events: single event name or list of events names
197f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type events: str or list(str)
198f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
199e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        if isinstance(events, basestring):
200e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi            self.events = events.split(' ')
201e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        elif isinstance(events, list):
202e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi            self.events = events
203e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        else:
204e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi            raise ValueError('Events must be a string or a list of strings')
2058e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
206b4ab05a5cc9630963cdfafeab214dcf1661167c7Javi Merino    def __parseTrace(self, path, tasks, window, normalize_time, trace_format):
207f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
208f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Internal method in charge of performing the actual parsing of the
209f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        trace.
210f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
211f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param path: path to the trace folder (or trace file)
212f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type path: str
213f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
214f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param tasks: filter data for the specified tasks only
215f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type tasks: list(str)
216f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
217f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param window: time window to consider when parsing the trace
218f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type window: tuple(int, int)
219f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
220f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param normalize_time: normalize trace time stamps
221f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type normalize_time: bool
222f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
223f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param trace_format: format of the trace. Possible values are:
224f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio            - FTrace
225f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio            - SysTrace
226f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type trace_format: str
227f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
228c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi        self._log.debug('Loading [sched] events from trace in [%s]...', path)
229c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi        self._log.debug('Parsing events: %s', self.events)
23034f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi        if trace_format.upper() == 'SYSTRACE' or path.endswith('html'):
231c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi            self._log.info('Parsing SysTrace format...')
232edc53078c056df33a9872fd170d6a66c2acd82d8Javi Merino            trace_class = trappy.SysTrace
23334f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi            self.trace_format = 'SysTrace'
23434f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi        elif trace_format.upper() == 'FTRACE':
235c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi            self._log.info('Parsing FTrace format...')
236edc53078c056df33a9872fd170d6a66c2acd82d8Javi Merino            trace_class = trappy.FTrace
23734f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi            self.trace_format = 'FTrace'
238d02408964a1d1042b99f51ba01989e8cf02478faJavi Merino        else:
239d02408964a1d1042b99f51ba01989e8cf02478faJavi Merino            raise ValueError("Unknown trace format {}".format(trace_format))
2408e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
241edc53078c056df33a9872fd170d6a66c2acd82d8Javi Merino        self.ftrace = trace_class(path, scope="custom", events=self.events,
242b4ab05a5cc9630963cdfafeab214dcf1661167c7Javi Merino                                  window=window, normalize_time=normalize_time)
243edc53078c056df33a9872fd170d6a66c2acd82d8Javi Merino
24479a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        # Load Functions profiling data
24579a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi        has_function_stats = self._loadFunctionsStats(path)
24679a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi
2478e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Check for events available on the parsed trace
2488e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.__checkAvailableEvents()
2498e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if len(self.available_events) == 0:
25079a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi            if has_function_stats:
251c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi                self._log.info('Trace contains only functions stats')
25279a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi                return
25379a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi            raise ValueError('The trace does not contain useful events '
25479a153ae2cea469af80c9d5324c479365980a3adPatrick Bellasi                             'nor function stats')
2558e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
2568e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Setup internal data reference to interesting events/dataframes
2578e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
25866b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        self._sanitize_SchedLoadAvgCpu()
25966b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        self._sanitize_SchedLoadAvgTask()
26066b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        self._sanitize_SchedCpuCapacity()
26166b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        self._sanitize_SchedBoostCpu()
26266b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        self._sanitize_SchedBoostTask()
26366b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        self._sanitize_SchedEnergyDiff()
26466b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        self._sanitize_SchedOverutilized()
26547895783a9a4b581c1c7aa15caf2a407201948dbPatrick Bellasi        self._sanitize_CpuFrequency()
2668e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
2678e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.__loadTasksNames(tasks)
2688e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
269db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio        # Compute plot window
270db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio        if not normalize_time:
271db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio            start = self.window[0]
272db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio            if self.window[1]:
273db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio                duration = min(self.ftrace.get_duration(), self.window[1])
274db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio            else:
275db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio                duration = self.ftrace.get_duration()
276db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio            self.window = (self.ftrace.basetime + start,
277db6e903112f0f5b2c5c66a63a5d3cdf35d0a6f55Michele Di Giorgio                           self.ftrace.basetime + duration)
2788e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
27934f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi    def __checkAvailableEvents(self, key=""):
280f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
281f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Internal method used to build a list of available events.
282f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
283f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param key: key to be used for TRAPpy filtering
284f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type key: str
285f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
28634f5d28c5ef4415709f75afcc636c37a210f4d02Patrick Bellasi        for val in self.ftrace.get_filters(key):
2879c42a5ae0f2a627860e5cc68dc7626da0c5b232fPatrick Bellasi            obj = getattr(self.ftrace, val)
2888e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if len(obj.data_frame):
2898e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.available_events.append(val)
290c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi        self._log.debug('Events found on trace:')
2918e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        for evt in self.available_events:
292c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi            self._log.debug(' - %s', evt)
2938e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
2948e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def __loadTasksNames(self, tasks):
295f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
296f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Try to load tasks names using one of the supported events.
297f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
298aa9f74b7a17e863acbfa558aee6b5a3ac997c0b8Brendan Jackman        :param tasks: list of task names. If None, load all tasks found.
299aa9f74b7a17e863acbfa558aee6b5a3ac997c0b8Brendan Jackman        :type tasks: list(str) or NoneType
300f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
30167d14d05928174971c4b583efebe17e83fa7067aBrendan Jackman        def load(tasks, event, name_key, pid_key):
30267d14d05928174971c4b583efebe17e83fa7067aBrendan Jackman            df = self._dfg_trace_event(event)
303aa9f74b7a17e863acbfa558aee6b5a3ac997c0b8Brendan Jackman            if tasks is None:
304aa9f74b7a17e863acbfa558aee6b5a3ac997c0b8Brendan Jackman                tasks = df[name_key].unique()
30567d14d05928174971c4b583efebe17e83fa7067aBrendan Jackman            self.getTasks(df, tasks, name_key=name_key, pid_key=pid_key)
30667d14d05928174971c4b583efebe17e83fa7067aBrendan Jackman            self._scanTasks(df, name_key=name_key, pid_key=pid_key)
30767d14d05928174971c4b583efebe17e83fa7067aBrendan Jackman
3088e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if 'sched_switch' in self.available_events:
30967d14d05928174971c4b583efebe17e83fa7067aBrendan Jackman            load(tasks, 'sched_switch', 'next_comm', 'next_pid')
31067d14d05928174971c4b583efebe17e83fa7067aBrendan Jackman        elif 'sched_load_avg_task' in self.available_events:
31167d14d05928174971c4b583efebe17e83fa7067aBrendan Jackman            load(tasks, 'sched_load_avg_task', 'comm', 'pid')
31267d14d05928174971c4b583efebe17e83fa7067aBrendan Jackman        else:
313c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi            self._log.warning('Failed to load tasks names from trace events')
3148e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
3158e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def hasEvents(self, dataset):
316f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
317f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Returns True if the specified event is present in the parsed trace,
318f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        False otherwise.
319f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
320f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param dataset: trace event name or list of trace events
321f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type dataset: str or list(str)
322f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
3238e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if dataset in self.available_events:
3248e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            return True
3258e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        return False
3268e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
3278e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def __computeTimeSpan(self):
328f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
329f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Compute time axis range, considering all the parsed events.
330f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
3318e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        ts = sys.maxint
3328e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        te = 0
3338e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
33466b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        for events in self.available_events:
335fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi            df = self._dfg_trace_event(events)
3368e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if len(df) == 0:
3378e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                continue
3388e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if (df.index[0]) < ts:
3398e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                ts = df.index[0]
3408e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if (df.index[-1]) > te:
3418e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                te = df.index[-1]
3428e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.time_range = te - ts
3438e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
344c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi        self._log.info('Collected events spans a %.3f [s] time interval',
345c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi                       self.time_range)
3468e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
347877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        # Build a stat on trace overutilization
348877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        if self.hasEvents('sched_overutilized'):
349fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi            df = self._dfg_trace_event('sched_overutilized')
350877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi            self.overutilized_time = df[df.overutilized == 1].len.sum()
351877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi            self.overutilized_prc = 100. * self.overutilized_time / self.time_range
352877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi
353c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi            self._log.info('Overutilized time: %.6f [s] (%.3f%% of trace time)',
354c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi                           self.overutilized_time, self.overutilized_prc)
355877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi
3563a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi    def _scanTasks(self, df, name_key='comm', pid_key='pid'):
357f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
358f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Extract tasks names and PIDs from the input data frame. The data frame
359f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        should contain a task name column and PID column.
360f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
361f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param df: data frame containing trace events from which tasks names
362f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio            and PIDs will be extracted
363f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type df: :mod:`pandas.DataFrame`
364f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
365b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio        :param name_key: The name of the dataframe columns containing task
366b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            names
367f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type name_key: str
368f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
369f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param pid_key: The name of the dataframe columns containing task PIDs
370f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type pid_key: str
371f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
372b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio        df = df[[name_key, pid_key]]
3733a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        self._tasks_by_name = df.set_index(name_key)
374b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio        self._tasks_by_pid = df.set_index(pid_key)
3753a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi
3763a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi    def getTaskByName(self, name):
377f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
378f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Get the PIDs of all tasks with the specified name.
379f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
380f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param name: task name
381f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type name: str
382f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
3833a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        if name not in self._tasks_by_name.index:
3843a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi            return []
3853a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        if len(self._tasks_by_name.ix[name].values) > 1:
3863a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi            return list({task[0] for task in
3873a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi                         self._tasks_by_name.ix[name].values})
3883a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        return [self._tasks_by_name.ix[name].values[0]]
3893a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi
3903a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi    def getTaskByPid(self, pid):
391f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
392f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Get the names of all tasks with the specified PID.
393f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
394f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param name: task PID
395f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type name: int
396f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
3973a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        if pid not in self._tasks_by_pid.index:
3983a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi            return []
3993a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        if len(self._tasks_by_pid.ix[pid].values) > 1:
4003a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi            return list({task[0] for task in
4013a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi                         self._tasks_by_pid.ix[pid].values})
4023a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi        return [self._tasks_by_pid.ix[pid].values[0]]
4033a044edddce5a950d10a2ed95d96c9bd72d2363aPatrick Bellasi
4048e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def getTasks(self, dataframe=None,
405b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio                 task_names=None, name_key='comm', pid_key='pid'):
406f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
407f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Helper function to get PIDs of specified tasks.
408f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
40907785500fa9f857ba507fc3357ee13636c3e6129Brendan Jackman        This method can take a Pandas dataset in input to be used to fiter out
410f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        the PIDs of all the specified tasks. If a dataset is not provided,
411f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        previously filtered PIDs are returned.
412f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
41307785500fa9f857ba507fc3357ee13636c3e6129Brendan Jackman        If a list of task names is not provided, all tasks detected in the trace
41407785500fa9f857ba507fc3357ee13636c3e6129Brendan Jackman        will be used. The specified dataframe must provide at least two columns
41507785500fa9f857ba507fc3357ee13636c3e6129Brendan Jackman        reporting the task name and the task PID. The default values of this
41607785500fa9f857ba507fc3357ee13636c3e6129Brendan Jackman        colums could be specified using the provided parameters.
417f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
418aa9f74b7a17e863acbfa558aee6b5a3ac997c0b8Brendan Jackman        :param dataframe: A Pandas dataframe containing at least 'name_key' and
419aa9f74b7a17e863acbfa558aee6b5a3ac997c0b8Brendan Jackman            'pid_key' columns. If None, the all PIDs are returned.
420f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type dataframe: :mod:`pandas.DataFrame`
421f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
422aa9f74b7a17e863acbfa558aee6b5a3ac997c0b8Brendan Jackman        :param task_names: The list of tasks to get the PID of (default: all
423aa9f74b7a17e863acbfa558aee6b5a3ac997c0b8Brendan Jackman            tasks)
424f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type task_names: list(str)
425f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
426b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio        :param name_key: The name of the dataframe columns containing task
427b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            names
428f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type name_key: str
429f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
430f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param pid_key: The name of the dataframe columns containing task PIDs
431f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type pid_key: str
432f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
4338e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if task_names is None:
4348e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            task_names = self.tasks.keys()
435b196b8cd11030c4353903f18deb30905e406074fBrendan Jackman        if dataframe is None:
436b196b8cd11030c4353903f18deb30905e406074fBrendan Jackman            return {k: v for k, v in  self.tasks.iteritems() if k in task_names}
437b196b8cd11030c4353903f18deb30905e406074fBrendan Jackman        df = dataframe
438c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi        self._log.debug('Lookup dataset for tasks...')
4398e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        for tname in task_names:
440c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi            self._log.debug('Lookup for task [%s]...', tname)
441b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            results = df[df[name_key] == tname][[name_key, pid_key]]
442b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            if len(results) == 0:
443c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi                self._log.error('  task %16s NOT found', tname)
4448e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                continue
4458e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            (name, pid) = results.head(1).values[0]
446b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            if name != tname:
447c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi                self._log.error('  task %16s NOT found', tname)
4488e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                continue
449b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            if tname not in self.tasks:
4508e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.tasks[tname] = {}
4518e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            pids = list(results[pid_key].unique())
4528e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.tasks[tname]['pid'] = pids
453c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi            self._log.debug('  task %16s found, pid: %s',
454c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi                            tname, self.tasks[tname]['pid'])
4558e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        return self.tasks
4568e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
457fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi
458b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio###############################################################################
459fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi# DataFrame Getter Methods
460b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio###############################################################################
461fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi
4628e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def df(self, event):
463f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
464f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Get a dataframe containing all occurrences of the specified trace event
465f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        in the parsed trace.
466f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
467f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param event: Trace event name
468f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type event: str
469f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
470fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi        warnings.simplefilter('always', DeprecationWarning) #turn off filter
471fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi        warnings.warn("\n\tUse of Trace::df() is deprecated and will be soon removed."
472fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi                      "\n\tUse Trace::data_frame.trace_event(event_name) instead.",
473fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi                      category=DeprecationWarning)
474fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi        warnings.simplefilter('default', DeprecationWarning) #reset filter
475fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi        return self._dfg_trace_event(event)
476fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi
477fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi    def _dfg_trace_event(self, event):
4788e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        """
479f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Get a dataframe containing all occurrences of the specified trace event
480f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        in the parsed trace.
481f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
482f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param event: Trace event name
483f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type event: str
4848e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        """
485f0ca15ec410a73b8f223a48e1be234c8561c6c2cPatrick Bellasi        if self.data_dir is None:
4868e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            raise ValueError("trace data not (yet) loaded")
4879c42a5ae0f2a627860e5cc68dc7626da0c5b232fPatrick Bellasi        if self.ftrace and hasattr(self.ftrace, event):
4889c42a5ae0f2a627860e5cc68dc7626da0c5b232fPatrick Bellasi            return getattr(self.ftrace, event).data_frame
489b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio        raise ValueError('Event [{}] not supported. '
490b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio                         'Supported events are: {}'
49166b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi                         .format(event, self.available_events))
4928e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
493ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi    def _dfg_functions_stats(self, functions=None):
494ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        """
495ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        Get a DataFrame of specified kernel functions profile data
496ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi
497ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        For each profiled function a DataFrame is returned which reports stats
498ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        on kernel functions execution time. The reported stats are per-CPU and
499ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        includes: number of times the function has been executed (hits),
500ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        average execution time (avg), overall execution time (time) and samples
501ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        variance (s_2).
502ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        By default returns a DataFrame of all the functions profiled.
503ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi
504ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        :param functions: the name of the function or a list of function names
505ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi                          to report
506f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type functions: str or list(str)
507ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        """
508ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        if not hasattr(self, '_functions_stats_df'):
509ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi            return None
510ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        df = self._functions_stats_df
511ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        if not functions:
512ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi            return df
513ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        return df.loc[df.index.get_level_values(1).isin(listify(functions))]
514ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi
5155824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi
516b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio###############################################################################
517fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi# Trace Events Sanitize Methods
518b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio###############################################################################
519fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi
520c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedCpuCapacity(self):
521f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
522f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Add more columns to cpu_capacity data frame if the energy model is
523f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        available.
524f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
52566b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        if not self.hasEvents('cpu_capacity') \
52666b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi           or 'nrg_model' not in self.platform:
527680ad8b9c70754064b686e1fcea6db022bc5e152Patrick Bellasi            return
528680ad8b9c70754064b686e1fcea6db022bc5e152Patrick Bellasi
529fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi        df = self._dfg_trace_event('cpu_capacity')
53066b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi
5318e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Add column with LITTLE and big CPUs max capacities
5328e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        nrg_model = self.platform['nrg_model']
5338e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        max_lcap = nrg_model['little']['cpu']['cap_max']
5348e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        max_bcap = nrg_model['big']['cpu']['cap_max']
5358e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['max_capacity'] = np.select(
5368e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [df.cpu.isin(self.platform['clusters']['little'])],
5378e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [max_lcap], max_bcap)
5388e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Add LITTLE and big CPUs "tipping point" threshold
5398e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        tip_lcap = 0.8 * max_lcap
5408e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        tip_bcap = 0.8 * max_bcap
5418e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['tip_capacity'] = np.select(
5428e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [df.cpu.isin(self.platform['clusters']['little'])],
5438e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [tip_lcap], tip_bcap)
5448e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
545997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi    def _sanitize_SchedLoadAvgCpu(self):
546f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
547f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        If necessary, rename certain signal names from v5.0 to v5.1 format.
548f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
54966b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        if not self.hasEvents('sched_load_avg_cpu'):
55066b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi            return
551fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi        df = self._dfg_trace_event('sched_load_avg_cpu')
552997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi        if 'utilization' in df:
553b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            df.rename(columns={'utilization': 'util_avg'}, inplace=True)
554b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            df.rename(columns={'load': 'load_avg'}, inplace=True)
555997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi
556c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedLoadAvgTask(self):
557f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
558f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        If necessary, rename certain signal names from v5.0 to v5.1 format.
559f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
56066b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        if not self.hasEvents('sched_load_avg_task'):
56166b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi            return
562fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi        df = self._dfg_trace_event('sched_load_avg_task')
56317c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi        if 'utilization' in df:
564b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            df.rename(columns={'utilization': 'util_avg'}, inplace=True)
565b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            df.rename(columns={'load': 'load_avg'}, inplace=True)
566b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            df.rename(columns={'avg_period': 'period_contrib'}, inplace=True)
567b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            df.rename(columns={'runnable_avg_sum': 'load_sum'}, inplace=True)
568b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            df.rename(columns={'running_avg_sum': 'util_sum'}, inplace=True)
5698e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['cluster'] = np.select(
5708e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [df.cpu.isin(self.platform['clusters']['little'])],
5718e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                ['LITTLE'], 'big')
5729d69537e219bc1052a28be114cb14ad47cc22c8fPatrick Bellasi        # Add a column which represents the max capacity of the smallest
5739d69537e219bc1052a28be114cb14ad47cc22c8fPatrick Bellasi        # clustre which can accomodate the task utilization
574b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio        little_cap = self.platform['nrg_model']['little']['cpu']['cap_max']
575b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio        big_cap = self.platform['nrg_model']['big']['cpu']['cap_max']
5769d69537e219bc1052a28be114cb14ad47cc22c8fPatrick Bellasi        df['min_cluster_cap'] = df.util_avg.map(
577b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            lambda util_avg: big_cap if util_avg > little_cap else little_cap
578b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio        )
5798e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
580c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedBoostCpu(self):
581f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
582f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Add a boosted utilization signal as the sum of utilization and margin.
583f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
584f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Also, if necessary, rename certain signal names from v5.0 to v5.1
585f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        format.
586f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
58766b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        if not self.hasEvents('sched_boost_cpu'):
58866b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi            return
589fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi        df = self._dfg_trace_event('sched_boost_cpu')
59017c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi        if 'usage' in df:
591b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            df.rename(columns={'usage': 'util'}, inplace=True)
59217c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi        df['boosted_util'] = df['util'] + df['margin']
59317c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi
594c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedBoostTask(self):
595f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
596f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Add a boosted utilization signal as the sum of utilization and margin.
597f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
598f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Also, if necessary, rename certain signal names from v5.0 to v5.1
599f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        format.
600f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
60166b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        if not self.hasEvents('sched_boost_task'):
60266b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi            return
603fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi        df = self._dfg_trace_event('sched_boost_task')
604418cfb6405256f744cc3023fd7a5fcbff1f757a7Patrick Bellasi        if 'utilization' in df:
605418cfb6405256f744cc3023fd7a5fcbff1f757a7Patrick Bellasi            # Convert signals name from to v5.1 format
606b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            df.rename(columns={'utilization': 'util'}, inplace=True)
607418cfb6405256f744cc3023fd7a5fcbff1f757a7Patrick Bellasi        df['boosted_util'] = df['util'] + df['margin']
6088e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
609c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedEnergyDiff(self):
610f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
611f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        If a energy model is provided, some signals are added to the
612f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        sched_energy_diff trace event data frame.
613f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
61466b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi        if not self.hasEvents('sched_energy_diff') \
61566b843f6127403f8a6933f8d9f90576a11ac998dPatrick Bellasi           or 'nrg_model' not in self.platform:
616680ad8b9c70754064b686e1fcea6db022bc5e152Patrick Bellasi            return
6178e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        nrg_model = self.platform['nrg_model']
6188e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        em_lcluster = nrg_model['little']['cluster']
6198e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        em_bcluster = nrg_model['big']['cluster']
6208e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        em_lcpu = nrg_model['little']['cpu']
6218e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        em_bcpu = nrg_model['big']['cpu']
6228e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        lcpus = len(self.platform['clusters']['little'])
6238e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        bcpus = len(self.platform['clusters']['big'])
6248e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        SCHED_LOAD_SCALE = 1024
6258e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
6268e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        power_max = em_lcpu['nrg_max'] * lcpus + em_bcpu['nrg_max'] * bcpus + \
627b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            em_lcluster['nrg_max'] + em_bcluster['nrg_max']
6288e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        print "Maximum estimated system energy: {0:d}".format(power_max)
6298e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
630fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi        df = self._dfg_trace_event('sched_energy_diff')
6318e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['nrg_diff_pct'] = SCHED_LOAD_SCALE * df.nrg_diff / power_max
6328e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
6338e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Tag columns by usage_delta
6348e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        ccol = df.usage_delta
6358e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['usage_delta_group'] = np.select(
6368e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            [ccol < 150, ccol < 400, ccol < 600],
6378e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            ['< 150', '< 400', '< 600'], '>= 600')
6388e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
6398e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Tag columns by nrg_payoff
6408e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        ccol = df.nrg_payoff
6418e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['nrg_payoff_group'] = np.select(
6428e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            [ccol > 2e9, ccol > 0, ccol > -2e9],
643b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            ['Optimal Accept', 'SchedTune Accept', 'SchedTune Reject'],
644b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio            'Suboptimal Reject')
6458e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
646877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi    def _sanitize_SchedOverutilized(self):
647f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """ Add a column with overutilized status duration. """
648877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        if not self.hasEvents('sched_overutilized'):
649877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi            return
650fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi        df = self._dfg_trace_event('sched_overutilized')
651877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        df['start'] = df.index
652877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        df['len'] = (df.start - df.start.shift()).fillna(0).shift(-1)
653877f3408c7f7705157f6c533957c30275e6972a2Patrick Bellasi        df.drop('start', axis=1, inplace=True)
6549e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio
65547895783a9a4b581c1c7aa15caf2a407201948dbPatrick Bellasi    def _chunker(self, seq, size):
656f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
657f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Given a data frame or a series, generate a sequence of chunks of the
658f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        given size.
659f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
660f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param seq: data to be split into chunks
661f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type seq: :mod:`pandas.Series` or :mod:`pandas.DataFrame`
662f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
663f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param size: size of each chunk
664f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type size: int
665f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
6669e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio        return (seq.iloc[pos:pos + size] for pos in range(0, len(seq), size))
6679e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio
66847895783a9a4b581c1c7aa15caf2a407201948dbPatrick Bellasi    def _sanitize_CpuFrequency(self):
669f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
670f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Verify that all platform reported clusters are frequency coherent (i.e.
671f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        frequency scaling is performed at a cluster level).
672f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
6739e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio        if not self.hasEvents('cpu_frequency'):
6749e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio            return
675fae44f68c443723378b83ab146fc20bc5a844a7dPatrick Bellasi        df = self._dfg_trace_event('cpu_frequency')
6769e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio        clusters = self.platform['clusters']
677b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio        for _, cpus in clusters.iteritems():
6789e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio            cluster_df = df[df.cpu.isin(cpus)]
67947895783a9a4b581c1c7aa15caf2a407201948dbPatrick Bellasi            for chunk in self._chunker(cluster_df, len(cpus)):
6809e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio                f = chunk.iloc[0].frequency
6819e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio                if any(chunk.frequency != f):
682c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi                    self._log.warning('Cluster Frequency is not coherent! '
683c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi                                      'Failure in [cpu_frequency] events at:')
684c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi                    self._log.warning(chunk)
6859e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio                    self.freq_coherency = False
6869e7a48bf52c1e0cf136dfdce5ba7ecc12768a092Michele Di Giorgio                    return
687c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi        self._log.info('Platform clusters verified to be Frequency coherent')
68847895783a9a4b581c1c7aa15caf2a407201948dbPatrick Bellasi
689b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio###############################################################################
690f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasi# Utility Methods
691b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio###############################################################################
692f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasi
6935824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi    def integrate_square_wave(self, sq_wave):
6945824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi        """
6955824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi        Compute the integral of a square wave time series.
6965824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi
6975824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi        :param sq_wave: square wave assuming only 1.0 and 0.0 values
6985824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi        :type sq_wave: :mod:`pandas.Series`
6995824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi        """
7005824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi        sq_wave.iloc[-1] = 0.0
7015824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi        # Compact signal to obtain only 1-0-1-0 sequences
7025824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi        comp_sig = sq_wave.loc[sq_wave.shift() != sq_wave]
7035824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi        # First value for computing the difference must be a 1
7045824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi        if comp_sig.iloc[0] == 0.0:
7055824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi            return sum(comp_sig.iloc[2::2].index - comp_sig.iloc[1:-1:2].index)
7065824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi        else:
7075824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi            return sum(comp_sig.iloc[1::2].index - comp_sig.iloc[:-1:2].index)
7085824ef082910363b2258cedecdabc60f6a2ea4c7Patrick Bellasi
709ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi    def _loadFunctionsStats(self, path='trace.stats'):
710f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
711f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        Read functions profiling file and build a data frame containing all
712f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        relevant data.
713f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio
714f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :param path: path to the functions profiling trace file
715f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        :type path: str
716f93efbe21b68cf8f422a221d81fcd723a2ced356Michele Di Giorgio        """
717ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        if os.path.isdir(path):
718ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi            path = os.path.join(path, 'trace.stats')
719ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        if path.endswith('dat') or path.endswith('html'):
720ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi            pre, ext = os.path.splitext(path)
721ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi            path = pre + '.stats'
722ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        if not os.path.isfile(path):
723ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi            return False
724ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi
725ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        # Opening functions profiling JSON data file
726c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi        self._log.debug('Loading functions profiling data from [%s]...', path)
727ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        with open(os.path.join(path), 'r') as fh:
728ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi            trace_stats = json.load(fh)
729ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi
730ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        # Build DataFrame of function stats
731ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        frames = {}
732ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        for cpu, data in trace_stats.iteritems():
733ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi            frames[int(cpu)] = pd.DataFrame.from_dict(data, orient='index')
734ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi
735ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        # Build and keep track of the DataFrame
736b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio        self._functions_stats_df = pd.concat(frames.values(),
737b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio                                             keys=frames.keys())
738ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi
739ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi        return len(self._functions_stats_df) > 0
740ff49ae1f0c3dcf5eba2b063c3571b692355f5320Patrick Bellasi
741691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio    @memoized
742691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio    def getCPUActiveSignal(self, cpu):
743691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        """
744691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        Build a square wave representing the active (i.e. non-idle) CPU time,
745691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        i.e.:
74606132f5606ea11cc7ec281595b9d9424c8d00e5fBrendan Jackman            cpu_active[t] == 1 if the CPU is reported to be non-idle by cpuidle
74706132f5606ea11cc7ec281595b9d9424c8d00e5fBrendan Jackman                             at time t
748691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio            cpu_active[t] == 0 otherwise
749691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio
750691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        :param cpu: CPU ID
751691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        :type cpu: int
752691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio
753691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        :returns: :mod:`pandas.Series`
754691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        """
755691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        if not self.hasEvents('cpu_idle'):
756c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi            self._log.warning('Events [cpu_idle] not found, '
757c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi                              'cannot compute CPU active signal!')
758691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio            return None
759691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio
760691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        idle_df = self._dfg_trace_event('cpu_idle')
761691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        cpu_df = idle_df[idle_df.cpu_id == cpu]
762691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio
763691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        cpu_active = cpu_df.state.apply(
764691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio            lambda s: 1 if s == NON_IDLE_STATE else 0
765691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        )
766691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio
767691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        start_time = 0.0
768691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        if not self.ftrace.normalized_time:
769691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio            start_time = self.ftrace.basetime
77020a1ac25fb898bd3b045b3aecf894df04c93fc80Brendan Jackman
77120a1ac25fb898bd3b045b3aecf894df04c93fc80Brendan Jackman        if cpu_active.empty:
77220a1ac25fb898bd3b045b3aecf894df04c93fc80Brendan Jackman            cpu_active = pd.Series([0], index=[start_time])
77320a1ac25fb898bd3b045b3aecf894df04c93fc80Brendan Jackman        elif cpu_active.index[0] != start_time:
774691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio            entry_0 = pd.Series(cpu_active.iloc[0] ^ 1, index=[start_time])
775691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio            cpu_active = pd.concat([entry_0, cpu_active])
776691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio
777691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        return cpu_active
778691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio
779691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio    @memoized
780691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio    def getClusterActiveSignal(self, cluster):
781691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        """
782691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        Build a square wave representing the active (i.e. non-idle) cluster
783691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        time, i.e.:
784691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio            cluster_active[t] == 1 if at least one CPU is reported to be
785691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio                                   non-idle by CPUFreq at time t
786691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio            cluster_active[t] == 0 otherwise
787691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio
788691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        :param cluster: list of CPU IDs belonging to a cluster
789691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        :type cluster: list(int)
790691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio
791691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        :returns: :mod:`pandas.Series`
792691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        """
793691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        if not self.hasEvents('cpu_idle'):
794c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi            self._log.warning('Events [cpu_idle] not found, '
795c278c2343c7f25083a80cb164b6bdc761d50050bPatrick Bellasi                              'cannot compute cluster active signal!')
796691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio            return None
797691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio
798403a36f57d676a98b3632847e5655f9128a50216Michele Di Giorgio        active = self.getCPUActiveSignal(cluster[0]).to_frame(name=cluster[0])
799403a36f57d676a98b3632847e5655f9128a50216Michele Di Giorgio        for cpu in cluster[1:]:
800403a36f57d676a98b3632847e5655f9128a50216Michele Di Giorgio            active = active.join(
801403a36f57d676a98b3632847e5655f9128a50216Michele Di Giorgio                self.getCPUActiveSignal(cpu).to_frame(name=cpu),
802403a36f57d676a98b3632847e5655f9128a50216Michele Di Giorgio                how='outer'
803403a36f57d676a98b3632847e5655f9128a50216Michele Di Giorgio            )
804691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio
805691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        active.fillna(method='ffill', inplace=True)
806691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio
807691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        # Cluster active is the OR between the actives on each CPU
808691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        # belonging to that specific cluster
809691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        cluster_active = reduce(
810691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio            operator.or_,
811691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio            [cpu_active.astype(int) for _, cpu_active in
812691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio             active.iteritems()]
813691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        )
814691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio
815691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio        return cluster_active
816691fc118e5dff4df885a039cc855a746de4b7556Michele Di Giorgio
817b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio
818f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasiclass TraceData:
819b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio    """ A DataFrame collector exposed to Trace's clients """
820f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasi    pass
821f493b3388f11c03a2ad4522d69aaf49c82da787fPatrick Bellasi
822b9c02fe3f7682ceb9e1c703d218bb4c9449358a1Michele Di Giorgio# vim :set tabstop=4 shiftwidth=4 expandtab
823