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