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