Home | History | Annotate | Download | only in analysis
      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 
     20 import matplotlib.gridspec as gridspec
     21 import matplotlib.pyplot as plt
     22 import pylab as pl
     23 
     24 from analysis_module import AnalysisModule
     25 
     26 
     27 class 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