xref: /petsc/src/benchmarks/benchmarkExample.py (revision 0c70c2260e0527b03a5e4ec06d73be022f6146cc)
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    return os.path.join(self.dir(), self.arch(), 'bin', 'mpiexec')
21
22  def example(self, num):
23    '''Return the path to the executable for a given example number'''
24    return os.path.join(self.dir(), self.arch(), 'lib', 'ex'+str(num)+'-obj', 'ex'+str(num))
25
26class PETScExample(object):
27  def __init__(self, library, num, **defaultOptions):
28    self.petsc   = PETSc()
29    self.library = library
30    self.num     = num
31    self.opts    = defaultOptions
32    return
33
34  @staticmethod
35  def runShellCommand(command, cwd = None):
36    import subprocess
37
38    Popen = subprocess.Popen
39    PIPE  = subprocess.PIPE
40    print 'Executing: %s\n' % (command,)
41    pipe = Popen(command, cwd=cwd, stdin=None, stdout=PIPE, stderr=PIPE, bufsize=-1, shell=True, universal_newlines=True)
42    (out, err) = pipe.communicate()
43    ret = pipe.returncode
44    return (out, err, ret)
45
46  def optionsToString(self, **opts):
47    '''Convert a dictionary of options to a command line argument string'''
48    a = []
49    for key,value in opts.iteritems():
50      if value is None:
51        a.append('-'+key)
52      else:
53        a.append('-'+key+' '+str(value))
54    return ' '.join(a)
55
56  def run(self, **opts):
57    cmd = ' '.join([self.petsc.mpiexec(), '-n 1', self.petsc.example(self.num)])+' '+self.optionsToString(**self.opts)+' '+self.optionsToString(**opts)
58    out, err, ret = self.runShellCommand(cmd)
59    if ret:
60      print err
61      print out
62    return
63
64def processSummary(moduleName, times, events):
65  '''Process the Python log summary into plot data'''
66  m = __import__(moduleName)
67  reload(m)
68  # Total Time
69  times.append(m.Time[0])
70  # Common events
71  #   VecMAXPY and VecMDot essentially give KSPGMRESOrthog
72  #   Add the time and flop rate
73  for name in ['VecMDot', 'VecMAXPY', 'KSPGMRESOrthog', 'MatMult']:
74    if not name in events:
75      events[name] = []
76    events[name].append((m.Solve.event[name].Time[0], m.Solve.event[name].Flops[0]/(m.Solve.event[name].Time[0] * 1e6)))
77  # Particular events
78  for name in ['VecCUSPCopyTo', 'VecCUSPCopyFrom', 'MatCUSPCopyTo']:
79    if name in m.Solve.event:
80      if not name in events:
81        events[name] = []
82      events[name].append((m.Solve.event[name].Time[0], m.Solve.event[name].Flops[0]/(m.Solve.event[name].Time[0] * 1e6)))
83  return
84
85def plotSummary(library, num, sizes, times, events):
86  from pylab import legend, plot, show, title, xlabel, ylabel
87  import numpy as np
88  showTime       = False
89  showEventTime  = True
90  showEventFlops = True
91  arches         = sizes.keys()
92  # Time
93  if showTime:
94    data = []
95    for arch in arches:
96      data.append(sizes[arch])
97      data.append(times[arch])
98    plot(*data)
99    title('Performance on '+library+' Example '+str(num))
100    xlabel('Number of Dof')
101    ylabel('Time (s)')
102    legend(arches, 'upper left', shadow = True)
103    show()
104  # Common event time
105  #   We could make a stacked plot like Rio uses here
106  if showEventTime:
107    data  = []
108    names = []
109    for event, color in [('VecMDot', 'b'), ('VecMAXPY', 'g'), ('MatMult', 'r')]:
110      for arch, style in zip(arches, ['-', ':']):
111        names.append(arch+' '+event)
112        data.append(sizes[arch])
113        data.append(np.array(events[arch][event])[:,0])
114        data.append(color+style)
115    plot(*data)
116    title('Performance on '+library+' Example '+str(num))
117    xlabel('Number of Dof')
118    ylabel('Time (s)')
119    legend(names, 'upper left', shadow = True)
120    show()
121  # Common event flops
122  #   We could make a stacked plot like Rio uses here
123  if showEventFlops:
124    data  = []
125    names = []
126    for event, color in [('VecMDot', 'b'), ('VecMAXPY', 'g'), ('MatMult', 'r')]:
127      for arch, style in zip(arches, ['-', ':']):
128        names.append(arch+' '+event)
129        data.append(sizes[arch])
130        data.append(np.array(events[arch][event])[:,1])
131        data.append(color+style)
132    plot(*data)
133    title('Performance on '+library+' Example '+str(num))
134    xlabel('Number of Dof')
135    ylabel('Computation Rate (MF/s)')
136    legend(names, 'upper left', shadow = True)
137    show()
138  return
139
140if __name__ == '__main__':
141  library = 'SNES'
142  num     = 19
143  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')
144  sizes   = {}
145  times   = {}
146  events  = {}
147  for name, vecType, matType, opts in [('CPU', 'seq', 'seqaij', {}), ('GPU', 'seqcusp', 'seqaijcusp', {'cusp_synchronize': None})]:
148    sizes[name]  = []
149    times[name]  = []
150    events[name] = {}
151    #for n in [10, 20, 50, 100, 150, 200]:
152    for n in [10, 20]:
153      ex.run(da_grid_x=n, da_grid_y=n, da_vec_type=vecType, da_mat_type=matType, **opts)
154      sizes[name].append(n*n * 4)
155      processSummary('summary', times[name], events[name])
156  plotSummary(library, num, sizes, times, events)
157