trace.py revision a8fdc5fe3719b498318e0451f5b4cdfac1f5015e
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
288e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
298e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi# Configure logging
308e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiimport logging
318e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
328e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasiclass Trace(object):
338e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
34a8fdc5fe3719b498318e0451f5b4cdfac1f5015ePatrick Bellasi    def __init__(self, platform, datadir, events, tasks=None, window=(0,None)):
358e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
368e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # The platform used to run the experiments
378e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.platform = None
388e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
398e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Dataframe of all events data
408e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.trace_data = {}
418e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
428e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Folder containing all perf data
438e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.datadir = None
448e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
458e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # TRAPpy run object
468e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.run = None
478e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
48a8fdc5fe3719b498318e0451f5b4cdfac1f5015ePatrick Bellasi        # The time window used to limit trace parsing to
49a8fdc5fe3719b498318e0451f5b4cdfac1f5015ePatrick Bellasi        self.window = window
50a8fdc5fe3719b498318e0451f5b4cdfac1f5015ePatrick Bellasi
518e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Dynamically registered TRAPpy events
528e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.trappy_cls = {}
538e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
548e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Maximum timespan for all collected events
558e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.time_range = 0
568e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
578e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # The dictionary of tasks descriptors available in the dataset
588e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.tasks = {}
598e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
60e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        # List of events required by user
61e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        self.events = []
62e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi
638e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # List of events available in the parsed trace
648e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.available_events = []
658e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
668e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Folder containing trace
678e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.datadir = datadir
688e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
698e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Platform descriptor
708e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.platform = platform
718e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
72e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        self.__registerTraceEvents(events)
73a8fdc5fe3719b498318e0451f5b4cdfac1f5015ePatrick Bellasi        self.__parseTrace(datadir, tasks, window)
748e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.__computeTimeSpan()
758e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
76e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi    def __registerTraceEvents(self, events):
77e09821241ca9697b75c8a53fb0813212202d1c65Patrick Bellasi
78e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        if isinstance(events, basestring):
79e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi            self.events = events.split(' ')
80e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        elif isinstance(events, list):
81e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi            self.events = events
82e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        else:
83e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi            raise ValueError('Events must be a string or a list of strings')
848e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
858e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
86a8fdc5fe3719b498318e0451f5b4cdfac1f5015ePatrick Bellasi    def __parseTrace(self, datadir, tasks, window):
878e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        logging.debug('Loading [sched] events from trace in [%s]...', datadir)
88e24e02a9565a8ca8f948e15b573eeb808b8ece86Patrick Bellasi        logging.debug("Parsing events: %s", self.events)
89a8fdc5fe3719b498318e0451f5b4cdfac1f5015ePatrick Bellasi        self.run = trappy.Run(datadir, scope="custom", events=self.events, window=window)
908e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
918e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Check for events available on the parsed trace
928e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.__checkAvailableEvents()
938e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if len(self.available_events) == 0:
948e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            raise ValueError('The trace does not contain useful events')
958e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
968e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Setup internal data reference to interesting events/dataframes
978e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
988e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if self.hasEvents('sched_switch'):
998e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.trace_data['sswitch'] = \
1008e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.run.sched_switch.data_frame
1018e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
102e09821241ca9697b75c8a53fb0813212202d1c65Patrick Bellasi        if self.hasEvents('sched_wakeup'):
103e09821241ca9697b75c8a53fb0813212202d1c65Patrick Bellasi            self.trace_data['swkp'] = \
104e09821241ca9697b75c8a53fb0813212202d1c65Patrick Bellasi                self.run.sched_wakeup.data_frame
105e09821241ca9697b75c8a53fb0813212202d1c65Patrick Bellasi
106e09821241ca9697b75c8a53fb0813212202d1c65Patrick Bellasi        if self.hasEvents('sched_wakeup_new'):
107e09821241ca9697b75c8a53fb0813212202d1c65Patrick Bellasi            self.trace_data['swkpn'] = \
108e09821241ca9697b75c8a53fb0813212202d1c65Patrick Bellasi                self.run.sched_wakeup_new.data_frame
109e09821241ca9697b75c8a53fb0813212202d1c65Patrick Bellasi
110f53f85ec314a6ef54caa6ca199205f604ab99b99Patrick Bellasi        if self.hasEvents('cpu_frequency'):
1118e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.trace_data['pfreq'] = \
112f53f85ec314a6ef54caa6ca199205f604ab99b99Patrick Bellasi                self.run.cpu_frequency.data_frame
1138e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1148e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if self.hasEvents('sched_load_avg_cpu'):
1158e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.trace_data['cload'] = \
1168e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.run.sched_load_avg_cpu.data_frame
117997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi            self._sanitize_SchedLoadAvgCpu()
1188e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1198e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if self.hasEvents('sched_load_avg_task'):
1208e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.trace_data['tload'] = \
1218e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.run.sched_load_avg_task.data_frame
122c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi            self._sanitize_SchedLoadAvgTask()
1238e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1248e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if self.hasEvents('cpu_capacity'):
1258e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.trace_data['ccap'] = \
1268e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.run.cpu_capacity.data_frame
127c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi            self._sanitize_SchedCpuCapacity()
1288e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1298e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if self.hasEvents('sched_boost_cpu'):
1308e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.trace_data['cboost'] = \
1318e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.run.sched_boost_cpu.data_frame
132c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi            self._sanitize_SchedBoostCpu()
1338e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1348e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if self.hasEvents('sched_boost_task'):
1358e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.trace_data['tboost'] = \
1368e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.run.sched_boost_task.data_frame
137c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi            self._sanitize_SchedBoostTask()
1388e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1398e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if self.hasEvents('sched_contrib_scale_f'):
1408e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.trace_data['scalef'] = \
1418e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.run.sched_contrib_scale_f.data_frame
1428e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1438e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if self.hasEvents('sched_energy_diff'):
1448e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.trace_data['ediff'] = \
1458e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                    self.run.sched_energy_diff.data_frame
146c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi            self._sanitize_SchedEnergyDiff()
1478e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1488e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if self.hasEvents('sched_tune_config'):
1498e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.trace_data['stune'] = \
1508e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                    self.run.sched_tune_config.data_frame
1518e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1528e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if self.hasEvents('sched_tune_tasks_update'):
1538e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.trace_data['utask'] = \
1548e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                    self.run.sched_tune_tasks_update.data_frame
1558e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1568e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        self.__loadTasksNames(tasks)
1578e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1588e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1598e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def __checkAvailableEvents(self):
1608e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        for val in trappy.Run.get_filters(self.run):
1618e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            obj = getattr(self.run, val)
1628e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if len(obj.data_frame):
1638e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.available_events.append(val)
1648e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        logging.debug('Events found on trace:')
1658e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        for evt in self.available_events:
1668e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            logging.debug(' - %s', evt)
1678e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1688e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1698e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def __loadTasksNames(self, tasks):
1708e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Try to load tasks names using one of the supported events
1718e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if 'sched_switch' in self.available_events:
1728e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.getTasks(self.trace_data['sswitch'], tasks,
1738e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                name_key='next_comm', pid_key='next_pid')
1748e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            return
1758e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if 'sched_load_avg_task' in self.available_events:
1768e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.getTasks(self.trace_data['tload'], tasks)
1778e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            return
1788e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        logging.warning('Failed to load tasks names from trace events')
1798e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1808e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def hasEvents(self, dataset):
1818e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if dataset in self.available_events:
1828e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            return True
1838e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        return False
1848e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1858e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def __computeTimeSpan(self):
1868e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Compute time axis range, considering all the parsed events
1878e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        ts = sys.maxint
1888e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        te = 0
1898e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
1908e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        for key in self.trace_data.keys():
1918e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            df = self.trace_data[key]
1928e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if len(df) == 0:
1938e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                continue
1948e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if (df.index[0]) < ts:
1958e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                ts = df.index[0]
1968e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if (df.index[-1]) > te:
1978e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                te = df.index[-1]
1988e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.time_range = te - ts
1998e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
2008e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        logging.info('Collected events spans a %.3f [s] time interval',
2018e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.time_range)
2028e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
2038e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def getTasks(self, dataframe=None,
2048e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            task_names=None, name_key='comm', pid_key='pid'):
2058e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # """ Helper function to get PIDs of specified tasks
2068e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #
2078e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     This method requires a Pandas dataset in input to be used to
2088e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     fiter out the PIDs of all the specified tasks.
2098e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     In a dataset is not provided, previouslt filtered PIDs are
2108e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     returned.
2118e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     If a list of task names is not provided, the workload defined
2128e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     task names is used instead.
2138e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     The specified dataframe must provide at least two columns
2148e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     reporting the task name and the task PID. The default values of
2158e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     this colums could be specified using the provided parameters.
2168e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #
2178e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     :param task_names: The list of tasks to get the PID of (by default
2188e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #                        the workload defined tasks)
2198e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     :param dataframe: A Pandas datafram containing at least 'pid' and
2208e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #                       'task name' columns. If None, the previously
2218e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #                       filtered PIDs are returned
2228e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     :param name_key: The name of the dataframe columns containing
2238e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #                      task names
2248e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #     :param pid_key:  The name of the dataframe columns containing
2258e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        #                      task PIDs
2268e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # """
2278e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if dataframe is None:
2288e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            return self.tasks
2298e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df = dataframe
2308e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if task_names is None:
2318e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            task_names = self.tasks.keys()
2328e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        logging.debug("Lookup dataset for tasks...")
2338e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        for tname in task_names:
2348e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            logging.debug("Lookup for task [%s]...", tname)
2358e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            results = df[df[name_key] == tname][[name_key,pid_key]]
2368e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if len(results)==0:
2378e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                logging.error('  task %16s NOT found', tname)
2388e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                continue
2398e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            (name, pid) = results.head(1).values[0]
2408e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if name!=tname:
2418e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                logging.error('  task %16s NOT found', tname)
2428e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                continue
2438e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            if (tname not in self.tasks):
2448e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                self.tasks[tname] = {}
2458e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            pids = list(results[pid_key].unique())
2468e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            self.tasks[tname]['pid'] = pids
2478e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            logging.info('  task %16s found, pid: %s',
2488e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                    tname, self.tasks[tname]['pid'])
2498e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        return self.tasks
2508e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
2518e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi    def df(self, event):
2528e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        """
2538e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        Return the PANDAS dataframe with the performance data for the specified
2548e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        event
2558e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        """
2568e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if self.datadir is None:
2578e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            raise ValueError("trace data not (yet) loaded")
2588e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        if event not in self.trace_data:
2598e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            raise ValueError('Event [{}] not supported. '\
2608e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                    'Supported events are: {}'\
2618e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                    .format(event, self.trace_data.keys()))
2628e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        return self.trace_data[event]
2638e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
264c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedCpuCapacity(self):
2658e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df = self.df('ccap')
266680ad8b9c70754064b686e1fcea6db022bc5e152Patrick Bellasi
267680ad8b9c70754064b686e1fcea6db022bc5e152Patrick Bellasi        # Add more columns if the energy model is available
268680ad8b9c70754064b686e1fcea6db022bc5e152Patrick Bellasi        if 'nrg_model' not in self.platform:
269680ad8b9c70754064b686e1fcea6db022bc5e152Patrick Bellasi            return
270680ad8b9c70754064b686e1fcea6db022bc5e152Patrick Bellasi
2718e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Add column with LITTLE and big CPUs max capacities
2728e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        nrg_model = self.platform['nrg_model']
2738e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        max_lcap = nrg_model['little']['cpu']['cap_max']
2748e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        max_bcap = nrg_model['big']['cpu']['cap_max']
2758e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['max_capacity'] = np.select(
2768e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [df.cpu.isin(self.platform['clusters']['little'])],
2778e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [max_lcap], max_bcap)
2788e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Add LITTLE and big CPUs "tipping point" threshold
2798e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        tip_lcap = 0.8 * max_lcap
2808e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        tip_bcap = 0.8 * max_bcap
2818e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['tip_capacity'] = np.select(
2828e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [df.cpu.isin(self.platform['clusters']['little'])],
2838e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [tip_lcap], tip_bcap)
2848e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
285997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi    def _sanitize_SchedLoadAvgCpu(self):
286997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi        df = self.df('cload')
287997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi        if 'utilization' in df:
288997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi            # Convert signals name from v5.0 to v5.1 format
289997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi            df.rename(columns={'utilization':'util_avg'}, inplace=True)
290997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi            df.rename(columns={'load':'load_avg'}, inplace=True)
291997f0ca86a715c99bd1adce42c1812d650ea516cPatrick Bellasi
292c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedLoadAvgTask(self):
2938e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df = self.df('tload')
29417c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi        if 'utilization' in df:
29517c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            # Convert signals name from v5.0 to v5.1 format
29617c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            df.rename(columns={'utilization':'util_avg'}, inplace=True)
29717c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            df.rename(columns={'load':'load_avg'}, inplace=True)
29817c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            df.rename(columns={'avg_period':'period_contrib'}, inplace=True)
29917c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            df.rename(columns={'runnable_avg_sum':'load_sum'}, inplace=True)
30017c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            df.rename(columns={'running_avg_sum':'util_sum'}, inplace=True)
3018e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['cluster'] = np.select(
3028e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                [df.cpu.isin(self.platform['clusters']['little'])],
3038e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                ['LITTLE'], 'big')
3048e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
305c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedBoostCpu(self):
3068e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df = self.df('cboost')
30717c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi        if 'usage' in df:
30817c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            # Convert signals name from to v5.1 format
30917c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi            df.rename(columns={'usage':'util'}, inplace=True)
31017c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi        df['boosted_util'] = df['util'] + df['margin']
31117c7721066c57695ba43bac0c4170c324093d693Patrick Bellasi
3128e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
313c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedBoostTask(self):
3148e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df = self.df('tboost')
315418cfb6405256f744cc3023fd7a5fcbff1f757a7Patrick Bellasi        if 'utilization' in df:
316418cfb6405256f744cc3023fd7a5fcbff1f757a7Patrick Bellasi            # Convert signals name from to v5.1 format
317418cfb6405256f744cc3023fd7a5fcbff1f757a7Patrick Bellasi            df.rename(columns={'utilization':'util'}, inplace=True)
318418cfb6405256f744cc3023fd7a5fcbff1f757a7Patrick Bellasi        df['boosted_util'] = df['util'] + df['margin']
3198e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
320c5d46e8caeb638b88b75557a30262a6912a86629Patrick Bellasi    def _sanitize_SchedEnergyDiff(self):
321680ad8b9c70754064b686e1fcea6db022bc5e152Patrick Bellasi        if 'nrg_model' not in self.platform:
322680ad8b9c70754064b686e1fcea6db022bc5e152Patrick Bellasi            return
3238e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        nrg_model = self.platform['nrg_model']
3248e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        em_lcluster = nrg_model['little']['cluster']
3258e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        em_bcluster = nrg_model['big']['cluster']
3268e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        em_lcpu = nrg_model['little']['cpu']
3278e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        em_bcpu = nrg_model['big']['cpu']
3288e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        lcpus = len(self.platform['clusters']['little'])
3298e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        bcpus = len(self.platform['clusters']['big'])
3308e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        SCHED_LOAD_SCALE = 1024
3318e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
3328e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        power_max = em_lcpu['nrg_max'] * lcpus + em_bcpu['nrg_max'] * bcpus + \
3338e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi                    em_lcluster['nrg_max'] + em_bcluster['nrg_max']
3348e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        print "Maximum estimated system energy: {0:d}".format(power_max)
3358e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
3368e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df = self.df('ediff')
3378e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['nrg_diff_pct'] = SCHED_LOAD_SCALE * df.nrg_diff / power_max
3388e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
3398e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Tag columns by usage_delta
3408e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        ccol = df.usage_delta
3418e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['usage_delta_group'] = np.select(
3428e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            [ccol < 150, ccol < 400, ccol < 600],
3438e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            ['< 150', '< 400', '< 600'], '>= 600')
3448e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
3458e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        # Tag columns by nrg_payoff
3468e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        ccol = df.nrg_payoff
3478e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi        df['nrg_payoff_group'] = np.select(
3488e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            [ccol > 2e9, ccol > 0, ccol > -2e9],
3498e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi            ['Optimal Accept', 'SchedTune Accept', 'SchedTune Reject'], 'Suboptimal Reject')
3508e6284e58870ec8b4e5fd02186668934287a22f5Patrick Bellasi
351