xref: /petsc/src/benchmarks/benchmarkExample.py (revision eda8839f7f4f9aece449cc99839a6694c04403f7)
13428b40fSMatthew G Knepley#!/usr/bin/env python
2*eda8839fSMatthew G Knepleyimport os,sys
319d5f70aSMatthew G Knepleyfrom benchmarkBatch import generateBatchScript
43428b40fSMatthew G Knepley
53428b40fSMatthew G Knepleyclass PETSc(object):
63428b40fSMatthew G Knepley  def __init__(self):
73428b40fSMatthew G Knepley    return
83428b40fSMatthew G Knepley
93428b40fSMatthew G Knepley  def dir(self):
103428b40fSMatthew G Knepley    '''Return the root directory for the PETSc tree (usually $PETSC_DIR)'''
113428b40fSMatthew G Knepley    # This should search for a valid PETSc
123428b40fSMatthew G Knepley    return os.environ['PETSC_DIR']
133428b40fSMatthew G Knepley
143428b40fSMatthew G Knepley  def arch(self):
153428b40fSMatthew G Knepley    '''Return the PETSc build label (usually $PETSC_ARCH)'''
163428b40fSMatthew G Knepley    # This should be configurable
173428b40fSMatthew G Knepley    return os.environ['PETSC_ARCH']
183428b40fSMatthew G Knepley
193428b40fSMatthew G Knepley  def mpiexec(self):
203428b40fSMatthew G Knepley    '''Return the path for the mpi launch executable'''
21e3da8a91SMatthew G Knepley    mpiexec = os.path.join(self.dir(), self.arch(), 'bin', 'mpiexec')
226cbfa02cSMatthew G Knepley    if not os.path.isfile(mpiexec):
23e3da8a91SMatthew G Knepley      return None
24e3da8a91SMatthew G Knepley    return mpiexec
253428b40fSMatthew G Knepley
263428b40fSMatthew G Knepley  def example(self, num):
273428b40fSMatthew G Knepley    '''Return the path to the executable for a given example number'''
283428b40fSMatthew G Knepley    return os.path.join(self.dir(), self.arch(), 'lib', 'ex'+str(num)+'-obj', 'ex'+str(num))
293428b40fSMatthew G Knepley
303428b40fSMatthew G Knepleyclass PETScExample(object):
313428b40fSMatthew G Knepley  def __init__(self, library, num, **defaultOptions):
323428b40fSMatthew G Knepley    self.petsc   = PETSc()
333428b40fSMatthew G Knepley    self.library = library
343428b40fSMatthew G Knepley    self.num     = num
353428b40fSMatthew G Knepley    self.opts    = defaultOptions
363428b40fSMatthew G Knepley    return
373428b40fSMatthew G Knepley
383428b40fSMatthew G Knepley  @staticmethod
393428b40fSMatthew G Knepley  def runShellCommand(command, cwd = None):
403428b40fSMatthew G Knepley    import subprocess
413428b40fSMatthew G Knepley
423428b40fSMatthew G Knepley    Popen = subprocess.Popen
433428b40fSMatthew G Knepley    PIPE  = subprocess.PIPE
443428b40fSMatthew G Knepley    print 'Executing: %s\n' % (command,)
453428b40fSMatthew G Knepley    pipe = Popen(command, cwd=cwd, stdin=None, stdout=PIPE, stderr=PIPE, bufsize=-1, shell=True, universal_newlines=True)
463428b40fSMatthew G Knepley    (out, err) = pipe.communicate()
473428b40fSMatthew G Knepley    ret = pipe.returncode
483428b40fSMatthew G Knepley    return (out, err, ret)
493428b40fSMatthew G Knepley
503428b40fSMatthew G Knepley  def optionsToString(self, **opts):
513428b40fSMatthew G Knepley    '''Convert a dictionary of options to a command line argument string'''
523428b40fSMatthew G Knepley    a = []
533428b40fSMatthew G Knepley    for key,value in opts.iteritems():
543428b40fSMatthew G Knepley      if value is None:
553428b40fSMatthew G Knepley        a.append('-'+key)
563428b40fSMatthew G Knepley      else:
573428b40fSMatthew G Knepley        a.append('-'+key+' '+str(value))
583428b40fSMatthew G Knepley    return ' '.join(a)
593428b40fSMatthew G Knepley
6019d5f70aSMatthew G Knepley  def run(self, numProcs = 1, **opts):
61e3da8a91SMatthew G Knepley    if self.petsc.mpiexec() is None:
62e3da8a91SMatthew G Knepley      cmd = self.petsc.example(self.num)
63e3da8a91SMatthew G Knepley    else:
6419d5f70aSMatthew G Knepley      cmd = ' '.join([self.petsc.mpiexec(), '-n', str(numProcs), self.petsc.example(self.num)])
65e3da8a91SMatthew G Knepley    cmd += ' '+self.optionsToString(**self.opts)+' '+self.optionsToString(**opts)
6619d5f70aSMatthew G Knepley    if 'batch' in opts and opts['batch']:
6719d5f70aSMatthew G Knepley      del opts['batch']
683849a283SMatthew G Knepley      filename = generateBatchScript(self.num, numProcs, 120, ' '+self.optionsToString(**self.opts)+' '+self.optionsToString(**opts))
693849a283SMatthew G Knepley      # Submit job
703849a283SMatthew G Knepley      out, err, ret = self.runShellCommand('qsub -q gpu '+filename)
713849a283SMatthew G Knepley      if ret:
723849a283SMatthew G Knepley        print err
733849a283SMatthew G Knepley        print out
7419d5f70aSMatthew G Knepley    else:
753428b40fSMatthew G Knepley      out, err, ret = self.runShellCommand(cmd)
763428b40fSMatthew G Knepley      if ret:
773428b40fSMatthew G Knepley        print err
783428b40fSMatthew G Knepley        print out
793428b40fSMatthew G Knepley    return
803428b40fSMatthew G Knepley
81*eda8839fSMatthew G Knepleydef processSummary(moduleName, defaultStage, eventNames, times, events):
823428b40fSMatthew G Knepley  '''Process the Python log summary into plot data'''
833428b40fSMatthew G Knepley  m = __import__(moduleName)
843428b40fSMatthew G Knepley  reload(m)
853428b40fSMatthew G Knepley  # Total Time
863428b40fSMatthew G Knepley  times.append(m.Time[0])
873428b40fSMatthew G Knepley  # Particular events
88*eda8839fSMatthew G Knepley  for name in eventNames:
89*eda8839fSMatthew G Knepley    if name.find(':') >= 0:
90*eda8839fSMatthew G Knepley      stageName, name = name.split(':', 1)
91*eda8839fSMatthew G Knepley      stage = getattr(m, stageName)
92*eda8839fSMatthew G Knepley    else:
93*eda8839fSMatthew G Knepley      stage = getattr(m, defaultStage)
94*eda8839fSMatthew G Knepley    if name in stage.event:
953428b40fSMatthew G Knepley      if not name in events:
963428b40fSMatthew G Knepley        events[name] = []
97*eda8839fSMatthew G Knepley      events[name].append((stage.event[name].Time[0], stage.event[name].Flops[0]/(stage.event[name].Time[0] * 1e6)))
983428b40fSMatthew G Knepley  return
993428b40fSMatthew G Knepley
100e3da8a91SMatthew G Knepleydef plotSummaryLine(library, num, sizes, times, events):
1013428b40fSMatthew G Knepley  from pylab import legend, plot, show, title, xlabel, ylabel
1023428b40fSMatthew G Knepley  import numpy as np
1033428b40fSMatthew G Knepley  showTime       = False
1043428b40fSMatthew G Knepley  showEventTime  = True
1053428b40fSMatthew G Knepley  showEventFlops = True
1063428b40fSMatthew G Knepley  arches         = sizes.keys()
1073428b40fSMatthew G Knepley  # Time
1083428b40fSMatthew G Knepley  if showTime:
1093428b40fSMatthew G Knepley    data = []
1103428b40fSMatthew G Knepley    for arch in arches:
1113428b40fSMatthew G Knepley      data.append(sizes[arch])
1123428b40fSMatthew G Knepley      data.append(times[arch])
1133428b40fSMatthew G Knepley    plot(*data)
1143428b40fSMatthew G Knepley    title('Performance on '+library+' Example '+str(num))
1153428b40fSMatthew G Knepley    xlabel('Number of Dof')
1163428b40fSMatthew G Knepley    ylabel('Time (s)')
1173428b40fSMatthew G Knepley    legend(arches, 'upper left', shadow = True)
1183428b40fSMatthew G Knepley    show()
1193428b40fSMatthew G Knepley  # Common event time
1203428b40fSMatthew G Knepley  #   We could make a stacked plot like Rio uses here
1213428b40fSMatthew G Knepley  if showEventTime:
1223428b40fSMatthew G Knepley    data  = []
1233428b40fSMatthew G Knepley    names = []
1243428b40fSMatthew G Knepley    for event, color in [('VecMDot', 'b'), ('VecMAXPY', 'g'), ('MatMult', 'r')]:
1253428b40fSMatthew G Knepley      for arch, style in zip(arches, ['-', ':']):
1263428b40fSMatthew G Knepley        names.append(arch+' '+event)
1273428b40fSMatthew G Knepley        data.append(sizes[arch])
1283428b40fSMatthew G Knepley        data.append(np.array(events[arch][event])[:,0])
1293428b40fSMatthew G Knepley        data.append(color+style)
1303428b40fSMatthew G Knepley    plot(*data)
1313428b40fSMatthew G Knepley    title('Performance on '+library+' Example '+str(num))
1323428b40fSMatthew G Knepley    xlabel('Number of Dof')
1333428b40fSMatthew G Knepley    ylabel('Time (s)')
1343428b40fSMatthew G Knepley    legend(names, 'upper left', shadow = True)
1353428b40fSMatthew G Knepley    show()
1363428b40fSMatthew G Knepley  # Common event flops
1373428b40fSMatthew G Knepley  #   We could make a stacked plot like Rio uses here
1383428b40fSMatthew G Knepley  if showEventFlops:
1393428b40fSMatthew G Knepley    data  = []
1403428b40fSMatthew G Knepley    names = []
1413428b40fSMatthew G Knepley    for event, color in [('VecMDot', 'b'), ('VecMAXPY', 'g'), ('MatMult', 'r')]:
1423428b40fSMatthew G Knepley      for arch, style in zip(arches, ['-', ':']):
1433428b40fSMatthew G Knepley        names.append(arch+' '+event)
1443428b40fSMatthew G Knepley        data.append(sizes[arch])
1453428b40fSMatthew G Knepley        data.append(np.array(events[arch][event])[:,1])
1463428b40fSMatthew G Knepley        data.append(color+style)
1473428b40fSMatthew G Knepley    plot(*data)
1483428b40fSMatthew G Knepley    title('Performance on '+library+' Example '+str(num))
1493428b40fSMatthew G Knepley    xlabel('Number of Dof')
1503428b40fSMatthew G Knepley    ylabel('Computation Rate (MF/s)')
1513428b40fSMatthew G Knepley    legend(names, 'upper left', shadow = True)
1523428b40fSMatthew G Knepley    show()
1533428b40fSMatthew G Knepley  return
1543428b40fSMatthew G Knepley
155e3da8a91SMatthew G Knepleydef plotSummaryBar(library, num, sizes, times, events):
156e3da8a91SMatthew G Knepley  import numpy as np
157e3da8a91SMatthew G Knepley  import matplotlib.pyplot as plt
158e3da8a91SMatthew G Knepley
159e3da8a91SMatthew G Knepley  eventNames  = ['VecMDot', 'VecMAXPY', 'MatMult']
160e3da8a91SMatthew G Knepley  eventColors = ['b',       'g',        'r']
161e3da8a91SMatthew G Knepley  arches = sizes.keys()
162e3da8a91SMatthew G Knepley  names  = []
163e3da8a91SMatthew G Knepley  N      = len(sizes[arches[0]])
164e3da8a91SMatthew G Knepley  width  = 0.2
165e3da8a91SMatthew G Knepley  ind    = np.arange(N) - 0.25
166e3da8a91SMatthew G Knepley  bars   = {}
167e3da8a91SMatthew G Knepley  for arch in arches:
168e3da8a91SMatthew G Knepley    bars[arch] = []
169e3da8a91SMatthew G Knepley    bottom = np.zeros(N)
170e3da8a91SMatthew G Knepley    for event, color in zip(eventNames, eventColors):
171e3da8a91SMatthew G Knepley      names.append(arch+' '+event)
172e3da8a91SMatthew G Knepley      times = np.array(events[arch][event])[:,0]
173e3da8a91SMatthew G Knepley      bars[arch].append(plt.bar(ind, times, width, color=color, bottom=bottom))
174e3da8a91SMatthew G Knepley      bottom += times
175e3da8a91SMatthew G Knepley    ind += 0.3
176e3da8a91SMatthew G Knepley
177e3da8a91SMatthew G Knepley  plt.xlabel('Number of Dof')
178e3da8a91SMatthew G Knepley  plt.ylabel('Time (s)')
179e3da8a91SMatthew G Knepley  plt.title('GPU vs. CPU Performance on '+library+' Example '+str(num))
180e3da8a91SMatthew G Knepley  plt.xticks(np.arange(N), map(str, sizes[arches[0]]))
181e3da8a91SMatthew G Knepley  #plt.yticks(np.arange(0,81,10))
182e3da8a91SMatthew G Knepley  #plt.legend( (p1[0], p2[0]), ('Men', 'Women') )
183e3da8a91SMatthew G Knepley  plt.legend([bar[0] for bar in bars[arches[0]]], eventNames, 'upper right', shadow = True)
184e3da8a91SMatthew G Knepley
185e3da8a91SMatthew G Knepley  plt.show()
186e3da8a91SMatthew G Knepley  return
187e3da8a91SMatthew G Knepley
1883428b40fSMatthew G Knepleyif __name__ == '__main__':
189*eda8839fSMatthew G Knepley  import argparse
190*eda8839fSMatthew G Knepley
191*eda8839fSMatthew G Knepley  parser = argparse.ArgumentParser(description     = 'PETSc Benchmarking',
192*eda8839fSMatthew G Knepley                                   epilog          = 'This script runs src/<library>/examples/tutorials/ex<num>, For more information, visit http://www.mcs.anl.gov/petsc',
193*eda8839fSMatthew G Knepley                                   formatter_class = argparse.ArgumentDefaultsHelpFormatter)
194*eda8839fSMatthew G Knepley  parser.add_argument('--library', default='SNES',             help='The PETSc library used in this example')
195*eda8839fSMatthew G Knepley  parser.add_argument('--num',     type = int, default='5',    help='The example number')
196*eda8839fSMatthew G Knepley  parser.add_argument('--module',  default='summary',          help='The module for timing output')
197*eda8839fSMatthew G Knepley  parser.add_argument('--scaling',                             help='Run parallel scaling test')
198*eda8839fSMatthew G Knepley  parser.add_argument('--size',    nargs='+',  default=['10'], help='Grid size (implementation dependent)')
199*eda8839fSMatthew G Knepley  parser.add_argument('--comp',    type = int, default='1',    help='Number of field components')
200*eda8839fSMatthew G Knepley  parser.add_argument('runs',      nargs='*',                  help='Run descriptions: <name>=<args>')
201*eda8839fSMatthew G Knepley  parser.add_argument('--stage',   default='Main_Stage',       help='The default logging stage')
202*eda8839fSMatthew G Knepley  parser.add_argument('--events',  nargs='+',                  help='Events to process')
203*eda8839fSMatthew G Knepley  parser.add_argument('--batch',   action='store_true', default=False, help='Generate batch files for the runs instead')
204*eda8839fSMatthew G Knepley
205*eda8839fSMatthew G Knepley  # Options for ex19: pc_type='none', dmmg_nlevels=1, mat_no_inode=None
206*eda8839fSMatthew G Knepley
207*eda8839fSMatthew G Knepley  args = parser.parse_args()
208*eda8839fSMatthew G Knepley  print(args)
209*eda8839fSMatthew G Knepley  ex     = PETScExample(args.library, args.num, log_summary='summary.dat', log_summary_python = None if args.batch else args.module+'.py', preload='off')
2103428b40fSMatthew G Knepley  sizes  = {}
2113428b40fSMatthew G Knepley  times  = {}
2123428b40fSMatthew G Knepley  events = {}
213*eda8839fSMatthew G Knepley  for run in args.runs:
214*eda8839fSMatthew G Knepley    name, stropts = run.split('=', 1)
215*eda8839fSMatthew G Knepley    opts = dict([t if len(t) == 2 else (t[0], None) for t in [arg.split('=', 1) for arg in stropts.split(' ')]])
2163428b40fSMatthew G Knepley    sizes[name]  = []
2173428b40fSMatthew G Knepley    times[name]  = []
2183428b40fSMatthew G Knepley    events[name] = {}
219*eda8839fSMatthew G Knepley    # DMDA implementation
220*eda8839fSMatthew G Knepley    #   Need a good way to get the DMDA info
221*eda8839fSMatthew G Knepley    for n in map(int, args.size):
222*eda8839fSMatthew G Knepley      print(name,opts)
223*eda8839fSMatthew G Knepley      ex.run(da_grid_x=n, da_grid_y=n, **opts)
224*eda8839fSMatthew G Knepley      sizes[name].append(n*n * args.comp)
225*eda8839fSMatthew G Knepley      processSummary('summary', args.stage, args.events, times[name], events[name])
226*eda8839fSMatthew G Knepley  print sizes
227*eda8839fSMatthew G Knepley  print times
228*eda8839fSMatthew G Knepley  print events
229*eda8839fSMatthew G Knepley  sys.exit(0)
230*eda8839fSMatthew G Knepley  if not args.batch: plotSummaryLine(args.library, args.num, sizes, times, events)
231*eda8839fSMatthew G Knepley# --num 19 --comp 4 --size 10 20 50 100 --events VecMDot VecMAXPY KSPGMRESOrthog MatMult VecCUSPCopyTo VecCUSPCopyFrom MatCUSPCopyTo --stage Solve CPU='da_vec_type=seq da_mat_type=seqaij' GPU='da_vec_type=seqcusp da_mat_type=seqaijcusp cusp_synchronize'
232