xref: /petsc/src/benchmarks/benchmarkExample.py (revision 423d130b0e825ad0ada97df2a000548dc9be8a25)
1#!/usr/bin/env python
2import os
3
4class PETSc(object):
5  def __init__(self):
6    return
7
8  def dir(self):
9    '''Return the root directory for the PETSc tree (usually $PETSC_DIR)'''
10    # This should search for a valid PETSc
11    return os.environ['PETSC_DIR']
12
13  def arch(self):
14    '''Return the PETSc build label (usually $PETSC_ARCH)'''
15    # This should be configurable
16    return os.environ['PETSC_ARCH']
17
18  def mpiexec(self):
19    '''Return the path for the mpi launch executable'''
20    mpiexec = os.path.join(self.dir(), self.arch(), 'bin', 'mpiexec')
21    if not os.path.isfile(mpiexec):
22      return None
23    return mpiexec
24
25  def example(self, num):
26    '''Return the path to the executable for a given example number'''
27    return os.path.join(self.dir(), self.arch(), 'lib', 'ex'+str(num)+'-obj', 'ex'+str(num))
28
29class PETScExample(object):
30  def __init__(self, library, num, **defaultOptions):
31    self.petsc   = PETSc()
32    self.library = library
33    self.num     = num
34    self.opts    = defaultOptions
35    return
36
37  @staticmethod
38  def runShellCommand(command, cwd = None):
39    import subprocess
40
41    Popen = subprocess.Popen
42    PIPE  = subprocess.PIPE
43    print 'Executing: %s\n' % (command,)
44    pipe = Popen(command, cwd=cwd, stdin=None, stdout=PIPE, stderr=PIPE, bufsize=-1, shell=True, universal_newlines=True)
45    (out, err) = pipe.communicate()
46    ret = pipe.returncode
47    return (out, err, ret)
48
49  def optionsToString(self, **opts):
50    '''Convert a dictionary of options to a command line argument string'''
51    a = []
52    for key,value in opts.iteritems():
53      if value is None:
54        a.append('-'+key)
55      else:
56        a.append('-'+key+' '+str(value))
57    return ' '.join(a)
58
59  def run(self, **opts):
60    if self.petsc.mpiexec() is None:
61      cmd = self.petsc.example(self.num)
62    else:
63      cmd = ' '.join([self.petsc.mpiexec(), '-n 1', self.petsc.example(self.num)])
64    cmd += ' '+self.optionsToString(**self.opts)+' '+self.optionsToString(**opts)
65    out, err, ret = self.runShellCommand(cmd)
66    if ret:
67      print err
68      print out
69    return
70
71def processSummary(moduleName, times, events):
72  '''Process the Python log summary into plot data'''
73  m = __import__(moduleName)
74  reload(m)
75  # Total Time
76  times.append(m.Time[0])
77  # Common events
78  #   VecMAXPY and VecMDot essentially give KSPGMRESOrthog
79  #   Add the time and flop rate
80  for name in ['VecMDot', 'VecMAXPY', 'KSPGMRESOrthog', 'MatMult']:
81    if not name in events:
82      events[name] = []
83    events[name].append((m.Solve.event[name].Time[0], m.Solve.event[name].Flops[0]/(m.Solve.event[name].Time[0] * 1e6)))
84  # Particular events
85  for name in ['VecCUSPCopyTo', 'VecCUSPCopyFrom', 'MatCUSPCopyTo']:
86    if name in m.Solve.event:
87      if not name in events:
88        events[name] = []
89      events[name].append((m.Solve.event[name].Time[0], m.Solve.event[name].Flops[0]/(m.Solve.event[name].Time[0] * 1e6)))
90  return
91
92def plotSummaryLine(library, num, sizes, times, events):
93  from pylab import legend, plot, show, title, xlabel, ylabel
94  import numpy as np
95  showTime       = False
96  showEventTime  = True
97  showEventFlops = True
98  arches         = sizes.keys()
99  # Time
100  if showTime:
101    data = []
102    for arch in arches:
103      data.append(sizes[arch])
104      data.append(times[arch])
105    plot(*data)
106    title('Performance on '+library+' Example '+str(num))
107    xlabel('Number of Dof')
108    ylabel('Time (s)')
109    legend(arches, 'upper left', shadow = True)
110    show()
111  # Common event time
112  #   We could make a stacked plot like Rio uses here
113  if showEventTime:
114    data  = []
115    names = []
116    for event, color in [('VecMDot', 'b'), ('VecMAXPY', 'g'), ('MatMult', 'r')]:
117      for arch, style in zip(arches, ['-', ':']):
118        names.append(arch+' '+event)
119        data.append(sizes[arch])
120        data.append(np.array(events[arch][event])[:,0])
121        data.append(color+style)
122    plot(*data)
123    title('Performance on '+library+' Example '+str(num))
124    xlabel('Number of Dof')
125    ylabel('Time (s)')
126    legend(names, 'upper left', shadow = True)
127    show()
128  # Common event flops
129  #   We could make a stacked plot like Rio uses here
130  if showEventFlops:
131    data  = []
132    names = []
133    for event, color in [('VecMDot', 'b'), ('VecMAXPY', 'g'), ('MatMult', 'r')]:
134      for arch, style in zip(arches, ['-', ':']):
135        names.append(arch+' '+event)
136        data.append(sizes[arch])
137        data.append(np.array(events[arch][event])[:,1])
138        data.append(color+style)
139    plot(*data)
140    title('Performance on '+library+' Example '+str(num))
141    xlabel('Number of Dof')
142    ylabel('Computation Rate (MF/s)')
143    legend(names, 'upper left', shadow = True)
144    show()
145  return
146
147def plotSummaryBar(library, num, sizes, times, events):
148  import numpy as np
149  import matplotlib.pyplot as plt
150
151  eventNames  = ['VecMDot', 'VecMAXPY', 'MatMult']
152  eventColors = ['b',       'g',        'r']
153  arches = sizes.keys()
154  names  = []
155  N      = len(sizes[arches[0]])
156  width  = 0.2
157  ind    = np.arange(N) - 0.25
158  bars   = {}
159  for arch in arches:
160    bars[arch] = []
161    bottom = np.zeros(N)
162    for event, color in zip(eventNames, eventColors):
163      names.append(arch+' '+event)
164      times = np.array(events[arch][event])[:,0]
165      bars[arch].append(plt.bar(ind, times, width, color=color, bottom=bottom))
166      bottom += times
167    ind += 0.3
168
169  plt.xlabel('Number of Dof')
170  plt.ylabel('Time (s)')
171  plt.title('GPU vs. CPU Performance on '+library+' Example '+str(num))
172  plt.xticks(np.arange(N), map(str, sizes[arches[0]]))
173  #plt.yticks(np.arange(0,81,10))
174  #plt.legend( (p1[0], p2[0]), ('Men', 'Women') )
175  plt.legend([bar[0] for bar in bars[arches[0]]], eventNames, 'upper right', shadow = True)
176
177  plt.show()
178  return
179
180if __name__ == '__main__':
181  library = 'SNES'
182  num     = 19
183  ex      = PETScExample(library, num, pc_type='none', dmmg_nlevels=1, log_summary='summary.dat', log_summary_python='summary.py', mat_no_inode=None, preload='off')
184  sizes   = {}
185  times   = {}
186  events  = {}
187  for name, vecType, matType, opts in [('CPU', 'seq', 'seqaij', {}), ('GPU', 'seqcusp', 'seqaijcusp', {'cusp_synchronize': None})]:
188    sizes[name]  = []
189    times[name]  = []
190    events[name] = {}
191    #for n in [10, 20, 50, 100, 150, 200]:
192    for n in [10, 20]:
193      ex.run(da_grid_x=n, da_grid_y=n, da_vec_type=vecType, da_mat_type=matType, **opts)
194      sizes[name].append(n*n * 4)
195      processSummary('summary', times[name], events[name])
196  plotSummaryLine(library, num, sizes, times, events)
197