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