From d0e43e76188f4ccc8945b11eb27add3f911da34d Mon Sep 17 00:00:00 2001 From: Michele Di Giorgio Date: Mon, 27 Jun 2016 14:26:17 +0100 Subject: [PATCH 1/2] libs/utils/trace: refactor setXTimeRange() When setting x axis time range it is necessary to take into account non normalized traces as well by setting the boundaries to the plot window. Signed-off-by: Michele Di Giorgio --- libs/utils/trace.py | 48 ++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/libs/utils/trace.py b/libs/utils/trace.py index 209f60a93..3f3551daf 100644 --- a/libs/utils/trace.py +++ b/libs/utils/trace.py @@ -128,14 +128,13 @@ class Trace(object): trace_format) self.__computeTimeSpan() - # Minimum and Maximum x_time to use for all plots - self.x_min = 0 - self.x_max = self.time_range - # Reset x axis time range to full scale - t_min = self.window[0] - t_max = self.window[1] - self.setXTimeRange(t_min, t_max) + self.x_min = self.window[0] + if self.window[0] is None: + self.x_min = 0 + self.x_max = self.window[1] + if self.window[1] is None: + self.x_max = self.time_range self.data_frame = TraceData() self._registerDataFrameGetters(self) @@ -169,16 +168,37 @@ class Trace(object): :param t_max: upper bound :type t_max: int or float """ - if t_min is None: + self.x_min = self.window[0] + if self.window[0] is None: self.x_min = 0 - else: - self.x_min = t_min - if t_max is None: + self.x_max = self.window[1] + if self.window[1] is None: self.x_max = self.time_range - else: - self.x_max = t_max + + if t_min is not None: + if t_min < self.x_min: + logging.warning('t_min out of range: ' + 'capping to trace minimum %.6f [s]', + self.x_min) + elif t_min > self.x_max: + raise ValueError('t_min out of range: ' + 'trace boundaries are (%.6f, %.6f) [s]', + self.x_min, self.x_max) + else: + self.x_min = t_min + if t_max is not None: + if t_max > self.x_max: + logging.warning('t_max out of range: ' + 'capping to trace maximum %.6f [s]', + self.x_max) + elif t_max < self.x_min: + raise ValueError('t_max out of range: ' + 'trace boundaries are (%.6f, %.6f) [s]', + self.window[0], self.x_max) + else: + self.x_max = t_max logging.info('Set plots time range to (%.6f, %.6f)[s]', - self.x_min, self.x_max) + self.x_min, self.x_max) def __registerTraceEvents(self, events): """ -- GitLab From bc40ee7d4bc7d986c456fad94334aaf649649f61 Mon Sep 17 00:00:00 2001 From: Michele Di Giorgio Date: Mon, 27 Jun 2016 14:28:34 +0100 Subject: [PATCH 2/2] libs/utils/analysis: crop data used for analysis according to X range The user can specify a time range to limit the scope of the trace analysis by means of the function setXTimeRange(). This patch provides a private method to crop a pandas Series using the specified range (which by default corresponds to entire duration of the trace). In order to allow this, the memoized decorator must be removed from getClusterFrequencyResidency(). Signed-off-by: Michele Di Giorgio --- libs/utils/analysis/frequency_analysis.py | 3 +- libs/utils/trace.py | 37 +++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/libs/utils/analysis/frequency_analysis.py b/libs/utils/analysis/frequency_analysis.py index 1a2972c12..6220db229 100644 --- a/libs/utils/analysis/frequency_analysis.py +++ b/libs/utils/analysis/frequency_analysis.py @@ -383,7 +383,6 @@ class FrequencyAnalysis(AnalysisModule): return cluster_active - @memoized def _getClusterFrequencyResidency(self, cluster): """ Get a DataFrame with per cluster frequency residency, i.e. amount of @@ -427,6 +426,7 @@ class FrequencyAnalysis(AnalysisModule): 'cannot compute residency!') return None cluster_freqs = freq_df[freq_df.cpu == _cluster[0]].frequency + cluster_freqs = self._trace._cropToXTimeRange(cluster_freqs) # Compute TOTAL Time time_intervals = cluster_freqs.index[1:] - cluster_freqs.index[:-1] @@ -438,6 +438,7 @@ class FrequencyAnalysis(AnalysisModule): # Compute ACTIVE Time cluster_active = self._getClusterActiveSignal(_cluster) + cluster_active = self._trace._cropToXTimeRange(cluster_active) # In order to compute the active time spent at each frequency we # multiply 2 square waves: diff --git a/libs/utils/trace.py b/libs/utils/trace.py index 3f3551daf..b9c41f80f 100644 --- a/libs/utils/trace.py +++ b/libs/utils/trace.py @@ -748,6 +748,43 @@ class Trace(object): return len(self._functions_stats_df) > 0 + def _cropToXTimeRange(self, data): + """ + Crop a dataframe containing FTrace events to the X time range specified + by the user through setXTimeRange(). + + When cropping a series it might be necessary to include a first and + last element with timestamps equal to the boundaries of the X time + range. + + :param data: series to be cropped + :type data: :mod:`pandas.Series` + """ + if not isinstance(data, pd.Series): + msg = 'Cropping supported only for pandas.Series objects!' + raise ValueError(msg) + + first = None + # Avoid duplicate indexes in case the user specifies an x_min that + # corresponds to the time stamp of an existing event. + if self.x_min not in data.index: + # data[data.index < self.x_min] may return an empty series if x_min + # is lower than the lowest index of the data series. This will + # raise an exception that can be caught and leave first to None, as + # in this case a first element is not needed + try: + first = pd.Series([data[data.index < self.x_min].iloc[-1]], + index=[self.x_min]) + except: pass + last = None + if self.x_max not in data.index: + try: + last = pd.Series([data[data.index <= self.x_max].iloc[-1]], + index=[self.x_max]) + except: pass + data = data.loc[self.x_min:self.x_max] + return pd.concat([first, data, last]) + class TraceData: """ A DataFrame collector exposed to Trace's clients """ -- GitLab