xref: /petsc/src/benchmarks/benchmarkExample.py (revision 2247410dcb7f1dc155341c92d86930ca6b32b5cb)
13428b40fSMatthew G Knepley#!/usr/bin/env python
25b6bfdb9SJed Brownfrom __future__ import print_function
3eda8839fSMatthew G Knepleyimport os,sys
4683aebbfSMatthew G Knepleysys.path.append(os.path.join(os.environ['PETSC_DIR'], 'config'))
590dfb094SAndy R. Terrelsys.path.append(os.getcwd())
6*2247410dSMatthew G. Knepley
7*2247410dSMatthew G. Knepleyclass CSVLog(object): pass
83428b40fSMatthew G Knepley
93428b40fSMatthew G Knepleyclass PETSc(object):
103428b40fSMatthew G Knepley  def __init__(self):
113428b40fSMatthew G Knepley    return
123428b40fSMatthew G Knepley
133428b40fSMatthew G Knepley  def dir(self):
143428b40fSMatthew G Knepley    '''Return the root directory for the PETSc tree (usually $PETSC_DIR)'''
153428b40fSMatthew G Knepley    # This should search for a valid PETSc
163428b40fSMatthew G Knepley    return os.environ['PETSC_DIR']
173428b40fSMatthew G Knepley
183428b40fSMatthew G Knepley  def arch(self):
193428b40fSMatthew G Knepley    '''Return the PETSc build label (usually $PETSC_ARCH)'''
203428b40fSMatthew G Knepley    # This should be configurable
213428b40fSMatthew G Knepley    return os.environ['PETSC_ARCH']
223428b40fSMatthew G Knepley
233428b40fSMatthew G Knepley  def mpiexec(self):
243428b40fSMatthew G Knepley    '''Return the path for the mpi launch executable'''
25e3da8a91SMatthew G Knepley    mpiexec = os.path.join(self.dir(), self.arch(), 'bin', 'mpiexec')
266cbfa02cSMatthew G Knepley    if not os.path.isfile(mpiexec):
27e3da8a91SMatthew G Knepley      return None
28e3da8a91SMatthew G Knepley    return mpiexec
293428b40fSMatthew G Knepley
30d37947eaSMatthew G. Knepley  def example(self, library, num):
313428b40fSMatthew G Knepley    '''Return the path to the executable for a given example number'''
32d37947eaSMatthew G. Knepley    return os.path.join(self.dir(), self.arch(), 'lib', library.lower(), 'ex'+str(num))
333428b40fSMatthew G Knepley
343973d8daSKarl Rupp  def source(self, library, num, filenametail):
350790b1abSMatthew G Knepley    '''Return the path to the sources for a given example number'''
360790b1abSMatthew G Knepley    d = os.path.join(self.dir(), 'src', library.lower(), 'examples', 'tutorials')
370790b1abSMatthew G Knepley    name = 'ex'+str(num)
380790b1abSMatthew G Knepley    sources = []
390790b1abSMatthew G Knepley    for f in os.listdir(d):
400790b1abSMatthew G Knepley      if f == name+'.c':
412642ea08SMatthew G Knepley        sources.insert(0, f)
423973d8daSKarl Rupp      elif f.startswith(name) and f.endswith(filenametail):
430790b1abSMatthew G Knepley        sources.append(f)
440790b1abSMatthew G Knepley    return map(lambda f: os.path.join(d, f), sources)
450790b1abSMatthew G Knepley
463428b40fSMatthew G Knepleyclass PETScExample(object):
473428b40fSMatthew G Knepley  def __init__(self, library, num, **defaultOptions):
483428b40fSMatthew G Knepley    self.petsc   = PETSc()
493428b40fSMatthew G Knepley    self.library = library
503428b40fSMatthew G Knepley    self.num     = num
513428b40fSMatthew G Knepley    self.opts    = defaultOptions
523428b40fSMatthew G Knepley    return
533428b40fSMatthew G Knepley
543428b40fSMatthew G Knepley  @staticmethod
55d006b754SMatthew G Knepley  def runShellCommand(command, cwd = None, log = True):
563428b40fSMatthew G Knepley    import subprocess
573428b40fSMatthew G Knepley
583428b40fSMatthew G Knepley    Popen = subprocess.Popen
593428b40fSMatthew G Knepley    PIPE  = subprocess.PIPE
605b6bfdb9SJed Brown    if log: print('Executing: %s\n' % (command,))
613428b40fSMatthew G Knepley    pipe = Popen(command, cwd=cwd, stdin=None, stdout=PIPE, stderr=PIPE, bufsize=-1, shell=True, universal_newlines=True)
623428b40fSMatthew G Knepley    (out, err) = pipe.communicate()
633428b40fSMatthew G Knepley    ret = pipe.returncode
643428b40fSMatthew G Knepley    return (out, err, ret)
653428b40fSMatthew G Knepley
663428b40fSMatthew G Knepley  def optionsToString(self, **opts):
673428b40fSMatthew G Knepley    '''Convert a dictionary of options to a command line argument string'''
683428b40fSMatthew G Knepley    a = []
69a01632ecSJed Brown    for key,value in opts.items():
703428b40fSMatthew G Knepley      if value is None:
713428b40fSMatthew G Knepley        a.append('-'+key)
723428b40fSMatthew G Knepley      else:
733428b40fSMatthew G Knepley        a.append('-'+key+' '+str(value))
743428b40fSMatthew G Knepley    return ' '.join(a)
753428b40fSMatthew G Knepley
76d37947eaSMatthew G. Knepley  def build(self, log = True):
77d37947eaSMatthew G. Knepley    sdir = os.path.join(self.petsc.dir(), 'src', self.library.lower(), 'examples', 'tutorials')
78d37947eaSMatthew G. Knepley    odir = os.getcwd()
79d37947eaSMatthew G. Knepley    os.chdir(sdir)
80d37947eaSMatthew G. Knepley    cmd = 'make ex'+str(self.num)
81d37947eaSMatthew G. Knepley    out, err, ret = self.runShellCommand(cmd, cwd = sdir, log = log)
82d37947eaSMatthew G. Knepley    if err:
83d37947eaSMatthew G. Knepley      raise RuntimeError('Unable to build example:\n'+err+out)
84d37947eaSMatthew G. Knepley    os.chdir(odir)
85d37947eaSMatthew G. Knepley    bdir = os.path.dirname(self.petsc.example(self.library, self.num))
86d37947eaSMatthew G. Knepley    try:
87d37947eaSMatthew G. Knepley      os.makedirs(bdir)
88d37947eaSMatthew G. Knepley    except OSError:
89d37947eaSMatthew G. Knepley      if not os.path.isdir(bdir):
90d37947eaSMatthew G. Knepley        raise
91d37947eaSMatthew G. Knepley    cmd = 'mv '+os.path.join(sdir, 'ex'+str(self.num))+' '+self.petsc.example(self.library, self.num)
92d37947eaSMatthew G. Knepley    out, err, ret = self.runShellCommand(cmd, log = log)
93d37947eaSMatthew G. Knepley    if ret:
945b6bfdb9SJed Brown      print(err)
955b6bfdb9SJed Brown      print(out)
96d37947eaSMatthew G. Knepley    return
97d37947eaSMatthew G. Knepley
98d006b754SMatthew G Knepley  def run(self, numProcs = 1, log = True, **opts):
99b3efd4cdSAndy R. Terrel    cmd = ''
100b3efd4cdSAndy R. Terrel    if self.petsc.mpiexec() is not None:
101b3efd4cdSAndy R. Terrel      cmd += self.petsc.mpiexec() + ' '
102b3efd4cdSAndy R. Terrel      numProcs = os.environ.get('NUM_RANKS', numProcs)
103b3efd4cdSAndy R. Terrel      cmd += ' -n ' + str(numProcs) + ' '
1045b6bfdb9SJed Brown      if 'PE_HOSTFILE' in os.environ:
105b3efd4cdSAndy R. Terrel        cmd += ' -hostfile hostfile '
106d37947eaSMatthew G. Knepley    cmd += ' '.join([self.petsc.example(self.library, self.num), self.optionsToString(**self.opts), self.optionsToString(**opts)])
10719d5f70aSMatthew G Knepley    if 'batch' in opts and opts['batch']:
10819d5f70aSMatthew G Knepley      del opts['batch']
109*2247410dSMatthew G. Knepley      from benchmarkBatch import generateBatchScript
1103849a283SMatthew G Knepley      filename = generateBatchScript(self.num, numProcs, 120, ' '+self.optionsToString(**self.opts)+' '+self.optionsToString(**opts))
1113849a283SMatthew G Knepley      # Submit job
112d006b754SMatthew G Knepley      out, err, ret = self.runShellCommand('qsub -q gpu '+filename, log = log)
1133849a283SMatthew G Knepley      if ret:
1145b6bfdb9SJed Brown        print(err)
1155b6bfdb9SJed Brown        print(out)
11619d5f70aSMatthew G Knepley    else:
117d006b754SMatthew G Knepley      out, err, ret = self.runShellCommand(cmd, log = log)
1183428b40fSMatthew G Knepley      if ret:
1195b6bfdb9SJed Brown        print(err)
1205b6bfdb9SJed Brown        print(out)
1210790b1abSMatthew G Knepley    return out
1223428b40fSMatthew G Knepley
123*2247410dSMatthew G. Knepleydef processSummaryCSV(filename, defaultStage, eventNames, sizes, times, errors, events):
124*2247410dSMatthew G. Knepley  '''Process the CSV log summary into plot data'''
125*2247410dSMatthew G. Knepley  import csv
126*2247410dSMatthew G. Knepley  m = CSVLog()
127*2247410dSMatthew G. Knepley  setattr(m, 'Stages', {})
128*2247410dSMatthew G. Knepley  with open(filename) as csvfile:
129*2247410dSMatthew G. Knepley    reader = csv.DictReader(csvfile)
130*2247410dSMatthew G. Knepley    for row in reader:
131*2247410dSMatthew G. Knepley      stageName = row["Stage Name"]
132*2247410dSMatthew G. Knepley      eventName = row["Event Name"]
133*2247410dSMatthew G. Knepley      rank      = int(row["Rank"])
134*2247410dSMatthew G. Knepley      if not stageName in m.Stages: m.Stages[stageName] = {}
135*2247410dSMatthew G. Knepley      if not eventName in m.Stages[stageName]: m.Stages[stageName][eventName] = {}
136*2247410dSMatthew G. Knepley      m.Stages[stageName][eventName][rank] = {"time" : float(row["Time"]), "numMessages": float(row["Num Messages"]), "messageLength": float(row["Message Length"]), "numReductions" : float(row["Num Reductions"]), "flop" : float(row["FLOP"])}
137*2247410dSMatthew G. Knepley      for i in range(8):
138*2247410dSMatthew G. Knepley        dname = "dof"+str(i)
139*2247410dSMatthew G. Knepley        ename = "e"+str(i)
140*2247410dSMatthew G. Knepley        if row[dname]:
141*2247410dSMatthew G. Knepley          if not "dof" in m.Stages[stageName][eventName][rank]:
142*2247410dSMatthew G. Knepley            m.Stages[stageName][eventName][rank]["dof"] = []
143*2247410dSMatthew G. Knepley            m.Stages[stageName][eventName][rank]["error"] = []
144*2247410dSMatthew G. Knepley          m.Stages[stageName][eventName][rank]["dof"].append(int(float(row[dname])))
145*2247410dSMatthew G. Knepley          m.Stages[stageName][eventName][rank]["error"].append(float(row[ename]))
146*2247410dSMatthew G. Knepley  return m
147*2247410dSMatthew G. Knepley
148*2247410dSMatthew G. Knepleydef processSummary(moduleName, defaultStage, eventNames, sizes, times, errors, events):
1493428b40fSMatthew G Knepley  '''Process the Python log summary into plot data'''
150*2247410dSMatthew G. Knepley  if os.path.isfile(moduleName+'.csv'):
151*2247410dSMatthew G. Knepley    m = processSummaryCSV(moduleName+'.csv', defaultStage, eventNames, sizes, times, errors, events)
152*2247410dSMatthew G. Knepley  else:
1533428b40fSMatthew G Knepley    m = __import__(moduleName)
1543428b40fSMatthew G Knepley  # Total Time
155*2247410dSMatthew G. Knepley  times.append(m.Stages[defaultStage]["summary"][0]["time"])
1563428b40fSMatthew G Knepley  # Particular events
157eda8839fSMatthew G Knepley  for name in eventNames:
158eda8839fSMatthew G Knepley    if name.find(':') >= 0:
159eda8839fSMatthew G Knepley      stageName, name = name.split(':', 1)
160eda8839fSMatthew G Knepley    else:
161*2247410dSMatthew G. Knepley      stageName = defaultStage
162*2247410dSMatthew G. Knepley    stage = m.Stages[stageName]
163*2247410dSMatthew G. Knepley    if name in stage:
1643428b40fSMatthew G Knepley      if not name in events:
1653428b40fSMatthew G Knepley        events[name] = []
166*2247410dSMatthew G. Knepley      event  = stage[name][0]
167*2247410dSMatthew G. Knepley      etimes = [stage[name][p]["time"] for p in stage[name]]
168*2247410dSMatthew G. Knepley      eflops = [stage[name][p]["flop"] for p in stage[name]]
169*2247410dSMatthew G. Knepley      if "dof" in event:
170*2247410dSMatthew G. Knepley        sizes.append(event["dof"][0])
171*2247410dSMatthew G. Knepley        errors.append(event["error"][0])
172df494a56SMatthew G Knepley      try:
173*2247410dSMatthew G. Knepley        events[name].append((max(etimes), sum(eflops)/(max(etimes) * 1e6)))
174df494a56SMatthew G Knepley      except ZeroDivisionError:
175*2247410dSMatthew G. Knepley        events[name].append((max(etimes), 0))
1763428b40fSMatthew G Knepley  return
1773428b40fSMatthew G Knepley
1786e25a272SMatthew G Knepleydef plotTime(library, num, eventNames, sizes, times, events):
1796e25a272SMatthew G Knepley  from pylab import legend, plot, show, title, xlabel, ylabel
1806e25a272SMatthew G Knepley  import numpy as np
1816e25a272SMatthew G Knepley
1826e25a272SMatthew G Knepley  arches = sizes.keys()
1836e25a272SMatthew G Knepley  data   = []
1846e25a272SMatthew G Knepley  for arch in arches:
1856e25a272SMatthew G Knepley    data.append(sizes[arch])
1866e25a272SMatthew G Knepley    data.append(times[arch])
1876e25a272SMatthew G Knepley  plot(*data)
1886e25a272SMatthew G Knepley  title('Performance on '+library+' Example '+str(num))
1896e25a272SMatthew G Knepley  xlabel('Number of Dof')
1906e25a272SMatthew G Knepley  ylabel('Time (s)')
1916e25a272SMatthew G Knepley  legend(arches, 'upper left', shadow = True)
1926e25a272SMatthew G Knepley  show()
1936e25a272SMatthew G Knepley  return
1946e25a272SMatthew G Knepley
1956e25a272SMatthew G Knepleydef plotEventTime(library, num, eventNames, sizes, times, events, filename = None):
1966e25a272SMatthew G Knepley  from pylab import close, legend, plot, savefig, show, title, xlabel, ylabel
1976e25a272SMatthew G Knepley  import numpy as np
1986e25a272SMatthew G Knepley
1996e25a272SMatthew G Knepley  close()
2006e25a272SMatthew G Knepley  arches = sizes.keys()
2016e25a272SMatthew G Knepley  bs     = events[arches[0]].keys()[0]
2026e25a272SMatthew G Knepley  data   = []
2036e25a272SMatthew G Knepley  names  = []
2046e25a272SMatthew G Knepley  for event, color in zip(eventNames, ['b', 'g', 'r', 'y']):
2056e25a272SMatthew G Knepley    for arch, style in zip(arches, ['-', ':']):
2066e25a272SMatthew G Knepley      if event in events[arch][bs]:
2076e25a272SMatthew G Knepley        names.append(arch+'-'+str(bs)+' '+event)
2086e25a272SMatthew G Knepley        data.append(sizes[arch][bs])
2096e25a272SMatthew G Knepley        data.append(np.array(events[arch][bs][event])[:,0])
2106e25a272SMatthew G Knepley        data.append(color+style)
2116e25a272SMatthew G Knepley      else:
2125b6bfdb9SJed Brown        print('Could not find %s in %s-%d events' % (event, arch, bs))
2135b6bfdb9SJed Brown  print(data)
2146e25a272SMatthew G Knepley  plot(*data)
2156e25a272SMatthew G Knepley  title('Performance on '+library+' Example '+str(num))
2166e25a272SMatthew G Knepley  xlabel('Number of Dof')
2176e25a272SMatthew G Knepley  ylabel('Time (s)')
2186e25a272SMatthew G Knepley  legend(names, 'upper left', shadow = True)
2196e25a272SMatthew G Knepley  if filename is None:
2206e25a272SMatthew G Knepley    show()
2216e25a272SMatthew G Knepley  else:
2226e25a272SMatthew G Knepley    savefig(filename)
2236e25a272SMatthew G Knepley  return
2246e25a272SMatthew G Knepley
2256e25a272SMatthew G Knepleydef plotEventFlop(library, num, eventNames, sizes, times, events, filename = None):
2266e25a272SMatthew G Knepley  from pylab import legend, plot, savefig, semilogy, show, title, xlabel, ylabel
2276e25a272SMatthew G Knepley  import numpy as np
2286e25a272SMatthew G Knepley
2296e25a272SMatthew G Knepley  arches = sizes.keys()
2306e25a272SMatthew G Knepley  bs     = events[arches[0]].keys()[0]
2316e25a272SMatthew G Knepley  data   = []
2326e25a272SMatthew G Knepley  names  = []
2336e25a272SMatthew G Knepley  for event, color in zip(eventNames, ['b', 'g', 'r', 'y']):
2346e25a272SMatthew G Knepley    for arch, style in zip(arches, ['-', ':']):
2356e25a272SMatthew G Knepley      if event in events[arch][bs]:
2366e25a272SMatthew G Knepley        names.append(arch+'-'+str(bs)+' '+event)
2376e25a272SMatthew G Knepley        data.append(sizes[arch][bs])
2386e25a272SMatthew G Knepley        data.append(1e-3*np.array(events[arch][bs][event])[:,1])
2396e25a272SMatthew G Knepley        data.append(color+style)
2406e25a272SMatthew G Knepley      else:
2415b6bfdb9SJed Brown        print('Could not find %s in %s-%d events' % (event, arch, bs))
2426e25a272SMatthew G Knepley  semilogy(*data)
2436e25a272SMatthew G Knepley  title('Performance on '+library+' Example '+str(num))
2446e25a272SMatthew G Knepley  xlabel('Number of Dof')
2456e25a272SMatthew G Knepley  ylabel('Computation Rate (GF/s)')
2466e25a272SMatthew G Knepley  legend(names, 'upper left', shadow = True)
2476e25a272SMatthew G Knepley  if filename is None:
2486e25a272SMatthew G Knepley    show()
2496e25a272SMatthew G Knepley  else:
2506e25a272SMatthew G Knepley    savefig(filename)
2516e25a272SMatthew G Knepley  return
2526e25a272SMatthew G Knepley
253929aa6beSMatthew G. Knepleydef plotEventScaling(library, num, eventNames, procs, events, filename = None):
254929aa6beSMatthew G. Knepley  from pylab import legend, plot, savefig, semilogy, show, title, xlabel, ylabel
255929aa6beSMatthew G. Knepley  import numpy as np
256929aa6beSMatthew G. Knepley
257929aa6beSMatthew G. Knepley  arches = procs.keys()
258929aa6beSMatthew G. Knepley  bs     = events[arches[0]].keys()[0]
259929aa6beSMatthew G. Knepley  data   = []
260929aa6beSMatthew G. Knepley  names  = []
261929aa6beSMatthew G. Knepley  for arch, style in zip(arches, ['-', ':']):
262929aa6beSMatthew G. Knepley    for event, color in zip(eventNames, ['b', 'g', 'r', 'y']):
263929aa6beSMatthew G. Knepley      if event in events[arch][bs]:
264929aa6beSMatthew G. Knepley        names.append(arch+'-'+str(bs)+' '+event)
265929aa6beSMatthew G. Knepley        data.append(procs[arch][bs])
266929aa6beSMatthew G. Knepley        data.append(1e-3*np.array(events[arch][bs][event])[:,1])
267929aa6beSMatthew G. Knepley        data.append(color+style)
268929aa6beSMatthew G. Knepley      else:
2695b6bfdb9SJed Brown        print('Could not find %s in %s-%d events' % (event, arch, bs))
270929aa6beSMatthew G. Knepley  plot(*data)
271929aa6beSMatthew G. Knepley  title('Performance on '+library+' Example '+str(num))
272929aa6beSMatthew G. Knepley  xlabel('Number of Processors')
273929aa6beSMatthew G. Knepley  ylabel('Computation Rate (GF/s)')
274929aa6beSMatthew G. Knepley  legend(names, 'upper left', shadow = True)
275929aa6beSMatthew G. Knepley  if filename is None:
276929aa6beSMatthew G. Knepley    show()
277929aa6beSMatthew G. Knepley  else:
278929aa6beSMatthew G. Knepley    savefig(filename)
279929aa6beSMatthew G. Knepley  return
280929aa6beSMatthew G. Knepley
281303b7b21SMatthew G Knepleydef plotSummaryLine(library, num, eventNames, sizes, times, events):
2823428b40fSMatthew G Knepley  from pylab import legend, plot, show, title, xlabel, ylabel
2833428b40fSMatthew G Knepley  import numpy as np
2843428b40fSMatthew G Knepley  showTime       = False
2853428b40fSMatthew G Knepley  showEventTime  = True
2863428b40fSMatthew G Knepley  showEventFlops = True
2873428b40fSMatthew G Knepley  arches         = sizes.keys()
2883428b40fSMatthew G Knepley  # Time
2893428b40fSMatthew G Knepley  if showTime:
2903428b40fSMatthew G Knepley    data = []
2913428b40fSMatthew G Knepley    for arch in arches:
2923428b40fSMatthew G Knepley      data.append(sizes[arch])
2933428b40fSMatthew G Knepley      data.append(times[arch])
2943428b40fSMatthew G Knepley    plot(*data)
2953428b40fSMatthew G Knepley    title('Performance on '+library+' Example '+str(num))
2963428b40fSMatthew G Knepley    xlabel('Number of Dof')
2973428b40fSMatthew G Knepley    ylabel('Time (s)')
2983428b40fSMatthew G Knepley    legend(arches, 'upper left', shadow = True)
2993428b40fSMatthew G Knepley    show()
3003428b40fSMatthew G Knepley  # Common event time
3013428b40fSMatthew G Knepley  #   We could make a stacked plot like Rio uses here
3023428b40fSMatthew G Knepley  if showEventTime:
3033428b40fSMatthew G Knepley    data  = []
3043428b40fSMatthew G Knepley    names = []
305df494a56SMatthew G Knepley    for event, color in zip(eventNames, ['b', 'g', 'r', 'y']):
3063428b40fSMatthew G Knepley      for arch, style in zip(arches, ['-', ':']):
307*2247410dSMatthew G. Knepley        if event in events[arch]:
308*2247410dSMatthew G. Knepley          names.append(arch+' '+event)
309*2247410dSMatthew G. Knepley          data.append(sizes[arch])
310*2247410dSMatthew G. Knepley          data.append(np.array(events[arch][event])[:,0])
3113428b40fSMatthew G Knepley          data.append(color+style)
312df494a56SMatthew G Knepley        else:
313*2247410dSMatthew G. Knepley          print('Could not find %s in %s events' % (event, arch))
3145b6bfdb9SJed Brown    print(data)
3153428b40fSMatthew G Knepley    plot(*data)
3163428b40fSMatthew G Knepley    title('Performance on '+library+' Example '+str(num))
3173428b40fSMatthew G Knepley    xlabel('Number of Dof')
3183428b40fSMatthew G Knepley    ylabel('Time (s)')
3193428b40fSMatthew G Knepley    legend(names, 'upper left', shadow = True)
3203428b40fSMatthew G Knepley    show()
3213428b40fSMatthew G Knepley  # Common event flops
3223428b40fSMatthew G Knepley  #   We could make a stacked plot like Rio uses here
3233428b40fSMatthew G Knepley  if showEventFlops:
3243428b40fSMatthew G Knepley    data  = []
3253428b40fSMatthew G Knepley    names = []
326df494a56SMatthew G Knepley    for event, color in zip(eventNames, ['b', 'g', 'r', 'y']):
3273428b40fSMatthew G Knepley      for arch, style in zip(arches, ['-', ':']):
328*2247410dSMatthew G. Knepley        if event in events[arch]:
329*2247410dSMatthew G. Knepley          names.append(arch+' '+event)
330*2247410dSMatthew G. Knepley          data.append(sizes[arch])
331*2247410dSMatthew G. Knepley          data.append(np.array(events[arch][event])[:,1])
3323428b40fSMatthew G Knepley          data.append(color+style)
333df494a56SMatthew G Knepley        else:
334*2247410dSMatthew G. Knepley          print('Could not find %s in %s events' % (event, arch))
3353428b40fSMatthew G Knepley    plot(*data)
3363428b40fSMatthew G Knepley    title('Performance on '+library+' Example '+str(num))
3373428b40fSMatthew G Knepley    xlabel('Number of Dof')
3383428b40fSMatthew G Knepley    ylabel('Computation Rate (MF/s)')
3393428b40fSMatthew G Knepley    legend(names, 'upper left', shadow = True)
3403428b40fSMatthew G Knepley    show()
3413428b40fSMatthew G Knepley  return
3423428b40fSMatthew G Knepley
343*2247410dSMatthew G. Knepleydef plotMeshConvergence(library, num, eventNames, sizes, times, errors, events):
344*2247410dSMatthew G. Knepley  import numpy as np
345*2247410dSMatthew G. Knepley  import matplotlib.pyplot as plt
346*2247410dSMatthew G. Knepley  data    = []
347*2247410dSMatthew G. Knepley  legends = []
348*2247410dSMatthew G. Knepley  print(sizes)
349*2247410dSMatthew G. Knepley  print(errors)
350*2247410dSMatthew G. Knepley  for run in sizes:
351*2247410dSMatthew G. Knepley    rsizes = np.array(sizes[run])
352*2247410dSMatthew G. Knepley    data.extend([rsizes, errors[run], rsizes, (errors[run][0]*rsizes[0]*2)*rsizes**(meshExp[run]/-2.0)])
353*2247410dSMatthew G. Knepley    legends.extend(['Experiment '+run, r'Synthetic '+run+r' $\alpha = '+str(meshExp[run])+'$'])
354*2247410dSMatthew G. Knepley  SizeError = plt.loglog(*data)
355*2247410dSMatthew G. Knepley  plt.title(library+' ex'+str(num)+' Mesh Convergence')
356*2247410dSMatthew G. Knepley  plt.xlabel('Size')
357*2247410dSMatthew G. Knepley  plt.ylabel(r'Error $\|x - x^*\|_2$')
358*2247410dSMatthew G. Knepley  plt.legend(legends)
359*2247410dSMatthew G. Knepley  plt.show()
360*2247410dSMatthew G. Knepley  return
361*2247410dSMatthew G. Knepley
362*2247410dSMatthew G. Knepleydef plotWorkPrecision(library, num, eventNames, sizes, times, errors, events):
363*2247410dSMatthew G. Knepley  import numpy as np
364*2247410dSMatthew G. Knepley  import matplotlib.pyplot as plt
365*2247410dSMatthew G. Knepley  data    = []
366*2247410dSMatthew G. Knepley  legends = []
367*2247410dSMatthew G. Knepley  for run in times:
368*2247410dSMatthew G. Knepley    rtimes = np.array(times[run])
369*2247410dSMatthew G. Knepley    data.extend([rtimes, errors[run], rtimes, (errors[run][0]*rtimes[0]*2)*rtimes**(timeExp[run])])
370*2247410dSMatthew G. Knepley    legends.extend(['Experiment '+run, 'Synthetic '+run+' exponent '+str(timeExp[run])])
371*2247410dSMatthew G. Knepley  TimeError = plt.loglog(*data)
372*2247410dSMatthew G. Knepley  plt.title(library+' ex'+str(num)+' Work Precision')
373*2247410dSMatthew G. Knepley  plt.xlabel('Time (s)')
374*2247410dSMatthew G. Knepley  plt.ylabel(r'Error $\|x - x^*\|_2$')
375*2247410dSMatthew G. Knepley  plt.legend(legends)
376*2247410dSMatthew G. Knepley  plt.show()
377*2247410dSMatthew G. Knepley  return
378*2247410dSMatthew G. Knepley
379*2247410dSMatthew G. Knepleydef plotWorkPrecisionPareto(library, num, eventNames, sizes, times, errors, events):
380*2247410dSMatthew G. Knepley  import numpy as np
381*2247410dSMatthew G. Knepley  import matplotlib.pyplot as plt
382*2247410dSMatthew G. Knepley  data    = []
383*2247410dSMatthew G. Knepley  legends = []
384*2247410dSMatthew G. Knepley  for run in times:
385*2247410dSMatthew G. Knepley    rtimes = np.array(times[run])
386*2247410dSMatthew G. Knepley    data.extend([rtimes, errors[run]])
387*2247410dSMatthew G. Knepley    legends.append('Experiment '+run)
388*2247410dSMatthew G. Knepley  TimeErrorPareto = plt.semilogy(*data)
389*2247410dSMatthew G. Knepley  plt.title(library+' ex'+str(num)+' Work Precision: Pareto Front')
390*2247410dSMatthew G. Knepley  plt.xlabel('Time (s)')
391*2247410dSMatthew G. Knepley  plt.ylabel(r'Error $\|x - x^*\|_2$')
392*2247410dSMatthew G. Knepley  plt.legend(legends)
393*2247410dSMatthew G. Knepley  plt.show()
394*2247410dSMatthew G. Knepley  return
395*2247410dSMatthew G. Knepley
396303b7b21SMatthew G Knepleydef plotSummaryBar(library, num, eventNames, sizes, times, events):
397e3da8a91SMatthew G Knepley  import numpy as np
398e3da8a91SMatthew G Knepley  import matplotlib.pyplot as plt
399e3da8a91SMatthew G Knepley
400303b7b21SMatthew G Knepley  eventColors = ['b', 'g', 'r', 'y']
401e3da8a91SMatthew G Knepley  arches = sizes.keys()
402e3da8a91SMatthew G Knepley  names  = []
403e3da8a91SMatthew G Knepley  N      = len(sizes[arches[0]])
404e3da8a91SMatthew G Knepley  width  = 0.2
405e3da8a91SMatthew G Knepley  ind    = np.arange(N) - 0.25
406e3da8a91SMatthew G Knepley  bars   = {}
407e3da8a91SMatthew G Knepley  for arch in arches:
408e3da8a91SMatthew G Knepley    bars[arch] = []
409e3da8a91SMatthew G Knepley    bottom = np.zeros(N)
410e3da8a91SMatthew G Knepley    for event, color in zip(eventNames, eventColors):
411e3da8a91SMatthew G Knepley      names.append(arch+' '+event)
412e3da8a91SMatthew G Knepley      times = np.array(events[arch][event])[:,0]
413e3da8a91SMatthew G Knepley      bars[arch].append(plt.bar(ind, times, width, color=color, bottom=bottom))
414e3da8a91SMatthew G Knepley      bottom += times
415e3da8a91SMatthew G Knepley    ind += 0.3
416e3da8a91SMatthew G Knepley
417e3da8a91SMatthew G Knepley  plt.xlabel('Number of Dof')
418e3da8a91SMatthew G Knepley  plt.ylabel('Time (s)')
419e3da8a91SMatthew G Knepley  plt.title('GPU vs. CPU Performance on '+library+' Example '+str(num))
420e3da8a91SMatthew G Knepley  plt.xticks(np.arange(N), map(str, sizes[arches[0]]))
421e3da8a91SMatthew G Knepley  #plt.yticks(np.arange(0,81,10))
422e3da8a91SMatthew G Knepley  #plt.legend( (p1[0], p2[0]), ('Men', 'Women') )
423e3da8a91SMatthew G Knepley  plt.legend([bar[0] for bar in bars[arches[0]]], eventNames, 'upper right', shadow = True)
424e3da8a91SMatthew G Knepley
425e3da8a91SMatthew G Knepley  plt.show()
426e3da8a91SMatthew G Knepley  return
427e3da8a91SMatthew G Knepley
428*2247410dSMatthew G. Knepleydef processOptions(opts, name, n):
429*2247410dSMatthew G. Knepley  newopts = {}
430*2247410dSMatthew G. Knepley  for key, val in opts.items():
431*2247410dSMatthew G. Knepley    val = opts[key]
432*2247410dSMatthew G. Knepley    if val and val.find('%') >= 0:
433*2247410dSMatthew G. Knepley      newval = val % (name.replace('/', '-'), n)
434*2247410dSMatthew G. Knepley      newopts[key] = newval
435*2247410dSMatthew G. Knepley    else:
436*2247410dSMatthew G. Knepley      newopts[key] = val
437*2247410dSMatthew G. Knepley  return newopts
438*2247410dSMatthew G. Knepley
439*2247410dSMatthew G. Knepleydef getLogName(opts):
440*2247410dSMatthew G. Knepley  if 'log_view' in opts:
441*2247410dSMatthew G. Knepley    val = opts['log_view']
442*2247410dSMatthew G. Knepley    s   = val.find(':')
443*2247410dSMatthew G. Knepley    e   = val.find(':', s+1)
444*2247410dSMatthew G. Knepley    logName = os.path.splitext(val[s+1:e])[0]
445*2247410dSMatthew G. Knepley    return logName
446*2247410dSMatthew G. Knepley  return None
447683aebbfSMatthew G Knepley
448d006b754SMatthew G Knepleydef run_DMDA(ex, name, opts, args, sizes, times, events, log=True):
449683aebbfSMatthew G Knepley  for n in map(int, args.size):
450*2247410dSMatthew G. Knepley    newopts = processOptions(opts, name, n)
451*2247410dSMatthew G. Knepley    ex.run(log=log, da_grid_x=n, da_grid_y=n, **newopts)
452*2247410dSMatthew G. Knepley    processSummary(getLogName(newopts), args.stage, args.events, sizes[name], times[name], errors[name], events[name])
453683aebbfSMatthew G Knepley  return
454683aebbfSMatthew G Knepley
455*2247410dSMatthew G. Knepleydef run_DMPlex(ex, name, opts, args, sizes, times, events, log=True):
456*2247410dSMatthew G. Knepley  newopts = processOptions(opts, name, args.refine)
457*2247410dSMatthew G. Knepley  ex.run(log=log, dim=args.dim, snes_convergence_estimate=None, convest_num_refine=args.refine, interpolate=1, **newopts)
458*2247410dSMatthew G. Knepley  for r in range(args.refine+1):
459*2247410dSMatthew G. Knepley    stage = args.stage
460*2247410dSMatthew G. Knepley    if stage.find('%') >= 0: stage = stage % (r)
461*2247410dSMatthew G. Knepley    processSummary(getLogName(newopts), stage, args.events, sizes[name], times[name], errors[name], events[name])
462683aebbfSMatthew G Knepley  return
463683aebbfSMatthew G Knepley
464d006b754SMatthew G Knepleydef outputData(sizes, times, events, name = 'output.py'):
465d006b754SMatthew G Knepley  if os.path.exists(name):
466d006b754SMatthew G Knepley    base, ext = os.path.splitext(name)
467d006b754SMatthew G Knepley    num = 1
468d006b754SMatthew G Knepley    while os.path.exists(base+str(num)+ext):
469d006b754SMatthew G Knepley      num += 1
470d006b754SMatthew G Knepley    name = base+str(num)+ext
471d006b754SMatthew G Knepley  with file(name, 'w') as f:
472d006b754SMatthew G Knepley    f.write('#PETSC_ARCH='+os.environ['PETSC_ARCH']+' '+' '.join(sys.argv)+'\n')
473d006b754SMatthew G Knepley    f.write('sizes  = '+repr(sizes)+'\n')
474d006b754SMatthew G Knepley    f.write('times  = '+repr(times)+'\n')
475d006b754SMatthew G Knepley    f.write('events = '+repr(events)+'\n')
476d006b754SMatthew G Knepley  return
477d006b754SMatthew G Knepley
4783428b40fSMatthew G Knepleyif __name__ == '__main__':
479eda8839fSMatthew G Knepley  import argparse
480*2247410dSMatthew G. Knepley  import __main__
481eda8839fSMatthew G Knepley
482eda8839fSMatthew G Knepley  parser = argparse.ArgumentParser(description     = 'PETSc Benchmarking',
483a8d69d7bSBarry Smith                                   epilog          = 'This script runs src/<library>/examples/tutorials/ex<num>, For more information, visit https://www.mcs.anl.gov/petsc',
484eda8839fSMatthew G Knepley                                   formatter_class = argparse.ArgumentDefaultsHelpFormatter)
485eda8839fSMatthew G Knepley  parser.add_argument('--library', default='SNES',                     help='The PETSc library used in this example')
486eda8839fSMatthew G Knepley  parser.add_argument('--num',     type = int, default='5',            help='The example number')
487eda8839fSMatthew G Knepley  parser.add_argument('--module',  default='summary',                  help='The module for timing output')
488*2247410dSMatthew G. Knepley  parser.add_argument('--stage',   default='Main Stage',               help='The default logging stage')
489eda8839fSMatthew G Knepley  parser.add_argument('--events',  nargs='+',                          help='Events to process')
490eda8839fSMatthew G Knepley  parser.add_argument('--batch',   action='store_true', default=False, help='Generate batch files for the runs instead')
491d006b754SMatthew G Knepley  parser.add_argument('--daemon',  action='store_true', default=False, help='Run as a daemon')
4923973d8daSKarl Rupp  parser.add_argument('--gpulang', default='OpenCL',                   help='GPU Language to use: Either CUDA or OpenCL (default)')
493*2247410dSMatthew G. Knepley  parser.add_argument('--plots',   nargs='+',                          help='List of plots to show')
494683aebbfSMatthew G Knepley  subparsers = parser.add_subparsers(help='DM types')
495eda8839fSMatthew G Knepley
496683aebbfSMatthew G Knepley  parser_dmda = subparsers.add_parser('DMDA', help='Use a DMDA for the problem geometry')
497683aebbfSMatthew G Knepley  parser_dmda.add_argument('--size', nargs='+',  default=['10'], help='Grid size (implementation dependent)')
498683aebbfSMatthew G Knepley  parser_dmda.add_argument('--comp', type = int, default='1',    help='Number of field components')
499683aebbfSMatthew G Knepley  parser_dmda.add_argument('runs',   nargs='*',                  help='Run descriptions: <name>=<args>')
500683aebbfSMatthew G Knepley
501*2247410dSMatthew G. Knepley  parser_dmmesh = subparsers.add_parser('DMPlex', help='Use a DMPlex for the problem geometry')
502683aebbfSMatthew G Knepley  parser_dmmesh.add_argument('--dim',      type = int, default='2',        help='Spatial dimension')
503*2247410dSMatthew G. Knepley  parser_dmmesh.add_argument('--refine',   type = int, default='0',        help='Number of refinements')
504683aebbfSMatthew G Knepley  parser_dmmesh.add_argument('runs',       nargs='*',                      help='Run descriptions: <name>=<args>')
505eda8839fSMatthew G Knepley
506eda8839fSMatthew G Knepley  args = parser.parse_args()
507683aebbfSMatthew G Knepley  if hasattr(args, 'comp'):
508683aebbfSMatthew G Knepley    args.dmType = 'DMDA'
509683aebbfSMatthew G Knepley  else:
510*2247410dSMatthew G. Knepley    args.dmType = 'DMPlex'
511683aebbfSMatthew G Knepley
512*2247410dSMatthew G. Knepley  ex = PETScExample(args.library, args.num, preload='off')
5133973d8daSKarl Rupp  if args.gpulang == 'CUDA':
5143973d8daSKarl Rupp    source = ex.petsc.source(args.library, args.num, '.cu')
5153973d8daSKarl Rupp  else:
5163973d8daSKarl Rupp    source = ex.petsc.source(args.library, args.num, 'OpenCL.c')  # Using the convention of OpenCL code residing in source files ending in 'OpenCL.c' (at least for snes/ex52)
5173428b40fSMatthew G Knepley  sizes   = {}
5183428b40fSMatthew G Knepley  times   = {}
519*2247410dSMatthew G. Knepley  errors  = {}
520*2247410dSMatthew G. Knepley  meshExp = {}
521*2247410dSMatthew G. Knepley  timeExp = {}
5223428b40fSMatthew G Knepley  events  = {}
523d006b754SMatthew G Knepley  log     = not args.daemon
524d006b754SMatthew G Knepley
525d006b754SMatthew G Knepley  if args.daemon:
526d006b754SMatthew G Knepley    import daemon
5275b6bfdb9SJed Brown    print('Starting daemon')
528d006b754SMatthew G Knepley    daemon.createDaemon('.')
529683aebbfSMatthew G Knepley
530eda8839fSMatthew G Knepley  for run in args.runs:
531eda8839fSMatthew G Knepley    name, stropts = run.split('=', 1)
532eda8839fSMatthew G Knepley    opts = dict([t if len(t) == 2 else (t[0], None) for t in [arg.split('=', 1) for arg in stropts.split(' ')]])
533*2247410dSMatthew G. Knepley    #opts['log_view'] = 'summary.dat' if args.batch else ':'+args.module+'%s%d.py:ascii_info_detail'
534*2247410dSMatthew G. Knepley    opts['log_view'] = 'summary.dat' if args.batch else ':'+args.module+'%s%d.csv:ascii_csv'
535*2247410dSMatthew G. Knepley    meshExp[name] = float(opts['meshExp'])
536*2247410dSMatthew G. Knepley    timeExp[name] = float(opts['timeExp'])
5373428b40fSMatthew G Knepley    sizes[name]   = []
5383428b40fSMatthew G Knepley    times[name]   = []
539*2247410dSMatthew G. Knepley    errors[name]  = []
5403428b40fSMatthew G Knepley    events[name]  = {}
541*2247410dSMatthew G. Knepley    getattr(__main__, 'run_'+args.dmType)(ex, name, opts, args, sizes, times, events, log=log)
542d006b754SMatthew G Knepley  outputData(sizes, times, events)
543*2247410dSMatthew G. Knepley  if not args.batch and log:
544*2247410dSMatthew G. Knepley    for plot in args.plots:
545*2247410dSMatthew G. Knepley      print('Plotting ',plot)
546*2247410dSMatthew G. Knepley      getattr(__main__, 'plot'+plot)(args.library, args.num, args.events, sizes, times, errors, events)
547*2247410dSMatthew G. Knepley
548*2247410dSMatthew G. Knepley# ./src/benchmarks/benchmarkExample.py --events SNESSolve --plots MeshConvergence WorkPrecision WorkPrecisionPareto --num 5 DMDA --size 32 64 128 256 512 1024 --comp 1 GMRES/ILU0="snes_monitor par=0.0 ksp_rtol=1.0e-9 mms=2 ksp_type=gmres pc_type=ilu meshExp=2.0 timeExp=-0.5" GMRES/LU="snes_monitor par=0.0 ksp_rtol=1.0e-9 mms=2 ksp_type=gmres pc_type=lu meshExp=2.0 timeExp=-0.75" GMRES/GAMG="snes_monitor par=0.0 ksp_rtol=1.0e-9 mms=2 ksp_type=gmres pc_type=gamg meshExp=2.0 timeExp=-1.0"
549*2247410dSMatthew G. Knepley# ./src/benchmarks/benchmarkExample.py --stage "ConvEst Refinement Level %d" --events SNESSolve "ConvEst Error" --plots MeshConvergence WorkPrecision WorkPrecisionPareto --num 13 DMPlex --refine 5 --dim 2 GMRES/ILU0="snes_monitor ksp_rtol=1.0e-9 ksp_type=gmres pc_type=ilu meshExp=2.0 timeExp=-0.75 dm_refine=4 potential_petscspace_order=1" GMRES/LU="snes_monitor ksp_rtol=1.0e-9 ksp_type=gmres pc_type=lu meshExp=2.0 timeExp=-0.75 dm_refine=4 potential_petscspace_order=1" GMRES/GAMG="snes_monitor ksp_rtol=1.0e-9 ksp_type=gmres pc_type=gamg meshExp=2.0 timeExp=-1.0 dm_refine=4 potential_petscspace_order=1"
550*2247410dSMatthew G. Knepley# ./src/benchmarks/benchmarkExample.py --stage "ConvEst Refinement Level %d" --events SNESSolve "ConvEst Error" --plots MeshConvergence WorkPrecision WorkPrecisionPareto --num 13 DMPlex --refine 5 --dim 2 GMRES/ILU0="snes_monitor ksp_rtol=1.0e-9 ksp_type=gmres pc_type=ilu meshExp=3.0 timeExp=-0.75 dm_refine=3 potential_petscspace_order=2" GMRES/LU="snes_monitor ksp_rtol=1.0e-9 ksp_type=gmres pc_type=lu meshExp=3.0 timeExp=-0.75 dm_refine=3 potential_petscspace_order=2" GMRES/GAMG="snes_monitor ksp_rtol=1.0e-9 ksp_type=gmres pc_type=gamg meshExp=3.0 timeExp=-1.0 dm_refine=3 potential_petscspace_order=2"
551*2247410dSMatthew G. Knepley# ./src/benchmarks/benchmarkExample.py --stage "ConvEst Refinement Level %d" --events SNESSolve "ConvEst Error" --plots MeshConvergence WorkPrecision WorkPrecisionPareto --num 13 DMPlex --refine 5 --dim 2 GMRES/ILU0="snes_monitor ksp_rtol=1.0e-9 ksp_type=gmres pc_type=ilu meshExp=3.0 timeExp=-0.75 dm_refine=3 potential_petscspace_order=2" GMRES/LU="snes_monitor ksp_rtol=1.0e-9 ksp_type=gmres pc_type=lu meshExp=3.0 timeExp=-0.75 dm_refine=3 potential_petscspace_order=2" GMRES/GAMG="snes_monitor ksp_rtol=1.0e-9 ksp_type=gmres pc_type=gamg meshExp=3.0 timeExp=-1.0 dm_refine=3 potential_petscspace_order=2"
552*2247410dSMatthew G. Knepley
553*2247410dSMatthew G. Knepley# Old GPU benchmarks
554683aebbfSMatthew G Knepley# Benchmark for ex50
555683aebbfSMatthew G Knepley# ./src/benchmarks/benchmarkExample.py --events VecMDot VecMAXPY KSPGMRESOrthog MatMult VecCUSPCopyTo VecCUSPCopyFrom MatCUSPCopyTo --num 50 DMDA --size 10 20 50 100 --comp 4 CPU='pc_type=none mat_no_inode dm_vec_type=seq dm_mat_type=seqaij' GPU='pc_type=none mat_no_inode dm_vec_type=seqcusp dm_mat_type=seqaijcusp cusp_synchronize'
556683aebbfSMatthew G Knepley# Benchmark for ex52
557*2247410dSMatthew G. Knepley# ./src/benchmarks/benchmarkExample.py --events IntegBatchCPU IntegBatchGPU IntegGPUOnly --num 52 DMPlex --refine 0.0625 0.00625 0.000625 0.0000625 --blockExp 4 --order=1 CPU='dm_view show_residual=0 compute_function batch' GPU='dm_view show_residual=0 compute_function batch gpu gpu_batches=8'
558*2247410dSMatthew G. Knepley# ./src/benchmarks/benchmarkExample.py --events IntegBatchCPU IntegBatchGPU IntegGPUOnly --num 52 DMPlex --refine 0.0625 0.00625 0.000625 0.0000625 --blockExp 4 --order=1 --operator=elasticity CPU='dm_view op_type=elasticity show_residual=0 compute_function batch' GPU='dm_view op_type=elasticity show_residual=0 compute_function batch gpu gpu_batches=8'
559*2247410dSMatthew G. Knepley# ./src/benchmarks/benchmarkExample.py --events IntegBatchCPU IntegBatchGPU IntegGPUOnly --num 52 DMPlex --dim=3 --refine 0.0625 0.00625 0.000625 0.0000625 --blockExp 4 --order=1 CPU='dim=3 dm_view show_residual=0 compute_function batch' GPU='dim=3 dm_view show_residual=0 compute_function batch gpu gpu_batches=8'
560