• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# SPDX-License-Identifier: Apache-2.0
2#
3# Copyright (C) 2015, ARM Limited and contributors.
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may
6# not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18""" EAS-specific Analysis Module """
19
20import matplotlib.gridspec as gridspec
21import matplotlib.pyplot as plt
22import pylab as pl
23
24from analysis_module import AnalysisModule
25
26
27class EasAnalysis(AnalysisModule):
28    """
29    Support for EAS signals anaysis
30
31    :param trace: input Trace object
32    :type trace: :mod:`libs.utils.Trace`
33    """
34
35    def __init__(self, trace):
36        super(EasAnalysis, self).__init__(trace)
37
38###############################################################################
39# DataFrame Getter Methods
40###############################################################################
41
42
43###############################################################################
44# Plotting Methods
45###############################################################################
46
47    def plotEDiffTime(self, tasks=None,
48                      min_usage_delta=None, max_usage_delta=None,
49                      min_cap_delta=None, max_cap_delta=None,
50                      min_nrg_delta=None, max_nrg_delta=None,
51                      min_nrg_diff=None, max_nrg_diff=None):
52        """
53        Plot energy_diff()-related signals on time axes.
54        """
55        if not self._trace.hasEvents('sched_energy_diff'):
56            self._log.warning('Event [sched_energy_diff] not found, plot DISABLED!')
57            return
58        df = self._dfg_trace_event('sched_energy_diff')
59
60        # Filter on 'tasks'
61        if tasks is not None:
62            self._log.info('Plotting EDiff data just for task(s) [%s]', tasks)
63            df = df[df['comm'].isin(tasks)]
64
65        # Filter on 'usage_delta'
66        if min_usage_delta is not None:
67            self._log.info('Plotting EDiff data just with minimum '
68                           'usage_delta of [%d]', min_usage_delta)
69            df = df[abs(df['usage_delta']) >= min_usage_delta]
70        if max_usage_delta is not None:
71            self._log.info('Plotting EDiff data just with maximum '
72                           'usage_delta of [%d]', max_usage_delta)
73            df = df[abs(df['usage_delta']) <= max_usage_delta]
74
75        # Filter on 'cap_delta'
76        if min_cap_delta is not None:
77            self._log.info('Plotting EDiff data just with minimum '
78                           'cap_delta of [%d]', min_cap_delta)
79            df = df[abs(df['cap_delta']) >= min_cap_delta]
80        if max_cap_delta is not None:
81            self._log.info('Plotting EDiff data just with maximum '
82                           'cap_delta of [%d]', max_cap_delta)
83            df = df[abs(df['cap_delta']) <= max_cap_delta]
84
85        # Filter on 'nrg_delta'
86        if min_nrg_delta is not None:
87            self._log.info('Plotting EDiff data just with minimum '
88                           'nrg_delta of [%d]', min_nrg_delta)
89            df = df[abs(df['nrg_delta']) >= min_nrg_delta]
90        if max_nrg_delta is not None:
91            self._log.info('Plotting EDiff data just with maximum '
92                           'nrg_delta of [%d]', max_nrg_delta)
93            df = df[abs(df['nrg_delta']) <= max_nrg_delta]
94
95        # Filter on 'nrg_diff'
96        if min_nrg_diff is not None:
97            self._log.info('Plotting EDiff data just with minimum '
98                           'nrg_diff of [%d]', min_nrg_diff)
99            df = df[abs(df['nrg_diff']) >= min_nrg_diff]
100        if max_nrg_diff is not None:
101            self._log.info('Plotting EDiff data just with maximum '
102                           'nrg_diff of [%d]', max_nrg_diff)
103            df = df[abs(df['nrg_diff']) <= max_nrg_diff]
104
105        # Grid: setup stats for gris
106        gs = gridspec.GridSpec(4, 3, height_ratios=[2, 4, 2, 4])
107        gs.update(wspace=0.1, hspace=0.1)
108
109        # Configure plot
110        fig = plt.figure(figsize=(16, 8*2+4*2+2))
111        plt.suptitle("EnergyDiff Data",
112                     y=.92, fontsize=16, horizontalalignment='center')
113
114        # Plot1: src and dst CPUs
115        axes = plt.subplot(gs[0, :])
116        axes.set_title('Source and Destination CPUs')
117        df[['src_cpu', 'dst_cpu']].plot(ax=axes, style=['bo', 'r+'])
118        axes.set_ylim(-1, self._platform['cpus_count']+1)
119        axes.set_xlim(self._trace.x_min, self._trace.x_max)
120        axes.grid(True)
121        axes.set_xticklabels([])
122        axes.set_xlabel('')
123        self._trace.analysis.status.plotOverutilized(axes)
124
125        # Plot2: energy and capacity variations
126        axes = plt.subplot(gs[1, :])
127        axes.set_title('Energy vs Capacity Variations')
128
129        colors_labels = zip('gbyr', ['Optimal Accept', 'SchedTune Accept',
130                                     'SchedTune Reject', 'Suboptimal Reject'])
131        for color, label in colors_labels:
132            subset = df[df.nrg_payoff_group == label]
133            if len(subset) == 0:
134                continue
135            subset[['nrg_diff_pct']].plot(ax=axes, style=[color+'o'])
136        axes.set_xlim(self._trace.x_min, self._trace.x_max)
137        axes.set_yscale('symlog')
138        axes.grid(True)
139        axes.set_xticklabels([])
140        axes.set_xlabel('')
141        self._trace.analysis.status.plotOverutilized(axes)
142
143        # Plot3: energy payoff
144        axes = plt.subplot(gs[2, :])
145        axes.set_title('Energy Payoff Values')
146        for color, label in colors_labels:
147            subset = df[df.nrg_payoff_group == label]
148            if len(subset) == 0:
149                continue
150            subset[['nrg_payoff']].plot(ax=axes, style=[color+'o'])
151        axes.set_xlim(self._trace.x_min, self._trace.x_max)
152        axes.set_yscale('symlog')
153        axes.grid(True)
154        axes.set_xticklabels([])
155        axes.set_xlabel('')
156        self._trace.analysis.status.plotOverutilized(axes)
157
158        # Plot4: energy deltas (kernel and host computed values)
159        axes = plt.subplot(gs[3, :])
160        axes.set_title('Energy Deltas Values')
161        df[['nrg_delta', 'nrg_diff_pct']].plot(ax=axes, style=['ro', 'b+'])
162        axes.set_xlim(self._trace.x_min, self._trace.x_max)
163        axes.grid(True)
164        self._trace.analysis.status.plotOverutilized(axes)
165
166        # Save generated plots into datadir
167        figname = '{}/{}ediff_time.png'\
168                  .format(self._trace.plots_dir, self._trace.plots_prefix)
169        pl.savefig(figname, bbox_inches='tight')
170
171        # Grid: setup stats for gris
172        gs = gridspec.GridSpec(1, 3, height_ratios=[2])
173        gs.update(wspace=0.1, hspace=0.1)
174
175        fig = plt.figure(figsize=(16, 4))
176
177        # Plot: usage, capacity and energy distributuions
178        axes = plt.subplot(gs[0, 0])
179        df[['usage_delta']].hist(ax=axes, bins=60)
180        axes = plt.subplot(gs[0, 1])
181        df[['cap_delta']].hist(ax=axes, bins=60)
182        axes = plt.subplot(gs[0, 2])
183        df[['nrg_delta']].hist(ax=axes, bins=60)
184
185        # Save generated plots into datadir
186        figname = '{}/{}ediff_stats.png'\
187                  .format(self._trace.plots_dir, self._trace.plots_prefix)
188        pl.savefig(figname, bbox_inches='tight')
189
190    def plotEDiffSpace(self, tasks=None,
191                       min_usage_delta=None, max_usage_delta=None,
192                       min_cap_delta=None, max_cap_delta=None,
193                       min_nrg_delta=None, max_nrg_delta=None,
194                       min_nrg_diff=None, max_nrg_diff=None):
195        """
196        Plot energy_diff()-related signals on the Performance-Energy space
197        (PxE).
198        """
199        if not self._trace.hasEvents('sched_energy_diff'):
200            self._log.warning('Event [sched_energy_diff] not found, plot DISABLED!')
201            return
202        df = self._dfg_trace_event('sched_energy_diff')
203
204        # Filter on 'tasks'
205        if tasks is not None:
206            self._log.info('Plotting EDiff data just for task(s) [%s]', tasks)
207            df = df[df['comm'].isin(tasks)]
208
209        # Filter on 'usage_delta'
210        if min_usage_delta is not None:
211            self._log.info('Plotting EDiff data just with minimum '
212                           'usage_delta of [%d]', min_usage_delta)
213            df = df[abs(df['usage_delta']) >= min_usage_delta]
214        if max_usage_delta is not None:
215            self._log.info('Plotting EDiff data just with maximum '
216                           'usage_delta of [%d]', max_usage_delta)
217            df = df[abs(df['usage_delta']) <= max_usage_delta]
218
219        # Filter on 'cap_delta'
220        if min_cap_delta is not None:
221            self._log.info('Plotting EDiff data just with minimum '
222                           'cap_delta of [%d]', min_cap_delta)
223            df = df[abs(df['cap_delta']) >= min_cap_delta]
224        if max_cap_delta is not None:
225            self._log.info('Plotting EDiff data just with maximum '
226                           'cap_delta of [%d]', max_cap_delta)
227            df = df[abs(df['cap_delta']) <= max_cap_delta]
228
229        # Filter on 'nrg_delta'
230        if min_nrg_delta is not None:
231            self._log.info('Plotting EDiff data just with minimum '
232                           'nrg_delta of [%d]', min_nrg_delta)
233            df = df[abs(df['nrg_delta']) >= min_nrg_delta]
234        if max_nrg_delta is not None:
235            self._log.info('Plotting EDiff data just with maximum '
236                           'nrg_delta of [%d]', max_nrg_delta)
237            df = df[abs(df['nrg_delta']) <= max_nrg_delta]
238
239        # Filter on 'nrg_diff'
240        if min_nrg_diff is not None:
241            self._log.info('Plotting EDiff data just with minimum '
242                           'nrg_diff of [%d]', min_nrg_diff)
243            df = df[abs(df['nrg_diff']) >= min_nrg_diff]
244        if max_nrg_diff is not None:
245            self._log.info('Plotting EDiff data just with maximum '
246                           'nrg_diff of [%d]', max_nrg_diff)
247            df = df[abs(df['nrg_diff']) <= max_nrg_diff]
248
249        # Grid: setup grid for P-E space
250        gs = gridspec.GridSpec(1, 2, height_ratios=[2])
251        gs.update(wspace=0.1, hspace=0.1)
252
253        fig = plt.figure(figsize=(16, 8))
254
255        # Get min-max of each axes
256        x_min = df.nrg_diff_pct.min()
257        x_max = df.nrg_diff_pct.max()
258        y_min = df.cap_delta.min()
259        y_max = df.cap_delta.max()
260        axes_min = min(x_min, y_min)
261        axes_max = max(x_max, y_max)
262
263        # # Tag columns by usage_delta
264        # ccol = df.usage_delta
265        # df['usage_delta_group'] = np.select(
266        #     [ccol < 150, ccol < 400, ccol < 600],
267        #     ['< 150', '< 400', '< 600'], '>= 600')
268        #
269        # # Tag columns by nrg_payoff
270        # ccol = df.nrg_payoff
271        # df['nrg_payoff_group'] = np.select(
272        #     [ccol > 2e9, ccol > 0, ccol > -2e9],
273        #     ['Optimal Accept', 'SchedTune Accept', 'SchedTune Reject'],
274        #     'Suboptimal Reject')
275
276        # Plot: per usage_delta values
277        axes = plt.subplot(gs[0, 0])
278
279        for color, label in zip('bgyr', ['< 150', '< 400', '< 600', '>= 600']):
280            subset = df[df.usage_delta_group == label]
281            if len(subset) == 0:
282                continue
283            plt.scatter(subset.nrg_diff_pct, subset.cap_delta,
284                        s=subset.usage_delta,
285                        c=color, label='task_usage ' + str(label),
286                        axes=axes)
287
288        # Plot space axes
289        plt.plot((0, 0), (-1025, 1025), 'y--', axes=axes)
290        plt.plot((-1025, 1025), (0, 0), 'y--', axes=axes)
291
292        # # Perf cuts
293        # plt.plot((0, 100), (0, 100*delta_pb), 'b--',
294        #          label='PB (Perf Boost)')
295        # plt.plot((0, -100), (0, -100*delta_pc), 'r--',
296        #          label='PC (Perf Constraint)')
297        #
298        # # Perf boost setups
299        # for y in range(0,6):
300        #     plt.plot((0, 500), (0,y*100), 'g:')
301        # for x in range(0,5):
302        #     plt.plot((0, x*100), (0,500), 'g:')
303
304        axes.legend(loc=4, borderpad=1)
305
306        plt.xlim(1.1*axes_min, 1.1*axes_max)
307        plt.ylim(1.1*axes_min, 1.1*axes_max)
308
309        # axes.title('Performance-Energy Space')
310        axes.set_xlabel('Energy diff [%]')
311        axes.set_ylabel('Capacity diff [%]')
312
313        # Plot: per usage_delta values
314        axes = plt.subplot(gs[0, 1])
315
316        colors_labels = zip('gbyr', ['Optimal Accept', 'SchedTune Accept',
317                                     'SchedTune Reject', 'Suboptimal Reject'])
318        for color, label in colors_labels:
319            subset = df[df.nrg_payoff_group == label]
320            if len(subset) == 0:
321                continue
322            plt.scatter(subset.nrg_diff_pct, subset.cap_delta,
323                        s=60,
324                        c=color,
325                        marker='+',
326                        label='{} Region'.format(label),
327                        axes=axes)
328                        # s=subset.usage_delta,
329
330        # Plot space axes
331        plt.plot((0, 0), (-1025, 1025), 'y--', axes=axes)
332        plt.plot((-1025, 1025), (0, 0), 'y--', axes=axes)
333
334        # # Perf cuts
335        # plt.plot((0, 100), (0, 100*delta_pb), 'b--',
336        #          label='PB (Perf Boost)')
337        # plt.plot((0, -100), (0, -100*delta_pc), 'r--',
338        #          label='PC (Perf Constraint)')
339        #
340        # # Perf boost setups
341        # for y in range(0,6):
342        #     plt.plot((0, 500), (0,y*100), 'g:')
343        # for x in range(0,5):
344        #     plt.plot((0, x*100), (0,500), 'g:')
345
346        axes.legend(loc=4, borderpad=1)
347
348        plt.xlim(1.1*axes_min, 1.1*axes_max)
349        plt.ylim(1.1*axes_min, 1.1*axes_max)
350
351        # axes.title('Performance-Energy Space')
352        axes.set_xlabel('Energy diff [%]')
353        axes.set_ylabel('Capacity diff [%]')
354
355        plt.title('Performance-Energy Space')
356
357        # Save generated plots into datadir
358        figname = '{}/{}ediff_space.png'\
359                  .format(self._trace.plots_dir, self._trace.plots_prefix)
360        pl.savefig(figname, bbox_inches='tight')
361
362    def plotSchedTuneConf(self):
363        """
364        Plot the configuration of SchedTune.
365        """
366        if not self._trace.hasEvents('sched_tune_config'):
367            self._log.warning('Event [sched_tune_config] not found, plot DISABLED!')
368            return
369        # Grid
370        gs = gridspec.GridSpec(2, 1, height_ratios=[4, 1])
371        gs.update(wspace=0.1, hspace=0.1)
372
373        # Figure
374        plt.figure(figsize=(16, 2*6))
375        plt.suptitle("SchedTune Configuration",
376                     y=.97, fontsize=16, horizontalalignment='center')
377
378        # Plot: Margin
379        axes = plt.subplot(gs[0, 0])
380        axes.set_title('Margin')
381        data = self._dfg_trace_event('sched_tune_config')[['margin']]
382        data.plot(ax=axes, drawstyle='steps-post', style=['b'])
383        axes.set_ylim(0, 110)
384        axes.set_xlim(self._trace.x_min, self._trace.x_max)
385        axes.xaxis.set_visible(False)
386
387        # Plot: Boost mode
388        axes = plt.subplot(gs[1, 0])
389        axes.set_title('Boost mode')
390        data = self._dfg_trace_event('sched_tune_config')[['boostmode']]
391        data.plot(ax=axes, drawstyle='steps-post')
392        axes.set_ylim(0, 4)
393        axes.set_xlim(self._trace.x_min, self._trace.x_max)
394        axes.xaxis.set_visible(True)
395
396        # Save generated plots into datadir
397        figname = '{}/{}schedtune_conf.png'\
398                  .format(self._trace.plots_dir, self._trace.plots_prefix)
399        pl.savefig(figname, bbox_inches='tight')
400
401# vim :set tabstop=4 shiftwidth=4 expandtab
402