1#!/usr/bin/env python 2import os 3from benchmarkBatch import generateBatchScript 4 5class PETSc(object): 6 def __init__(self): 7 return 8 9 def dir(self): 10 '''Return the root directory for the PETSc tree (usually $PETSC_DIR)''' 11 # This should search for a valid PETSc 12 return os.environ['PETSC_DIR'] 13 14 def arch(self): 15 '''Return the PETSc build label (usually $PETSC_ARCH)''' 16 # This should be configurable 17 return os.environ['PETSC_ARCH'] 18 19 def mpiexec(self): 20 '''Return the path for the mpi launch executable''' 21 mpiexec = os.path.join(self.dir(), self.arch(), 'bin', 'mpiexec') 22 if not os.path.isfile(mpiexec): 23 return None 24 return mpiexec 25 26 def example(self, num): 27 '''Return the path to the executable for a given example number''' 28 return os.path.join(self.dir(), self.arch(), 'lib', 'ex'+str(num)+'-obj', 'ex'+str(num)) 29 30class PETScExample(object): 31 def __init__(self, library, num, **defaultOptions): 32 self.petsc = PETSc() 33 self.library = library 34 self.num = num 35 self.opts = defaultOptions 36 return 37 38 @staticmethod 39 def runShellCommand(command, cwd = None): 40 import subprocess 41 42 Popen = subprocess.Popen 43 PIPE = subprocess.PIPE 44 print 'Executing: %s\n' % (command,) 45 pipe = Popen(command, cwd=cwd, stdin=None, stdout=PIPE, stderr=PIPE, bufsize=-1, shell=True, universal_newlines=True) 46 (out, err) = pipe.communicate() 47 ret = pipe.returncode 48 return (out, err, ret) 49 50 def optionsToString(self, **opts): 51 '''Convert a dictionary of options to a command line argument string''' 52 a = [] 53 for key,value in opts.iteritems(): 54 if value is None: 55 a.append('-'+key) 56 else: 57 a.append('-'+key+' '+str(value)) 58 return ' '.join(a) 59 60 def run(self, numProcs = 1, **opts): 61 if self.petsc.mpiexec() is None: 62 cmd = self.petsc.example(self.num) 63 else: 64 cmd = ' '.join([self.petsc.mpiexec(), '-n', str(numProcs), self.petsc.example(self.num)]) 65 cmd += ' '+self.optionsToString(**self.opts)+' '+self.optionsToString(**opts) 66 if 'batch' in opts and opts['batch']: 67 del opts['batch'] 68 generateBatchScript(self.num, numProcs, 120, ' '+self.optionsToString(**self.opts)+' '+self.optionsToString(**opts)) 69 else: 70 out, err, ret = self.runShellCommand(cmd) 71 if ret: 72 print err 73 print out 74 return 75 76def processSummary(moduleName, times, events): 77 '''Process the Python log summary into plot data''' 78 m = __import__(moduleName) 79 reload(m) 80 # Total Time 81 times.append(m.Time[0]) 82 # Common events 83 # VecMAXPY and VecMDot essentially give KSPGMRESOrthog 84 # Add the time and flop rate 85 for name in ['VecMDot', 'VecMAXPY', 'KSPGMRESOrthog', 'MatMult']: 86 if not name in events: 87 events[name] = [] 88 events[name].append((m.Solve.event[name].Time[0], m.Solve.event[name].Flops[0]/(m.Solve.event[name].Time[0] * 1e6))) 89 # Particular events 90 for name in ['VecCUSPCopyTo', 'VecCUSPCopyFrom', 'MatCUSPCopyTo']: 91 if name in m.Solve.event: 92 if not name in events: 93 events[name] = [] 94 events[name].append((m.Solve.event[name].Time[0], m.Solve.event[name].Flops[0]/(m.Solve.event[name].Time[0] * 1e6))) 95 return 96 97def plotSummaryLine(library, num, sizes, times, events): 98 from pylab import legend, plot, show, title, xlabel, ylabel 99 import numpy as np 100 showTime = False 101 showEventTime = True 102 showEventFlops = True 103 arches = sizes.keys() 104 # Time 105 if showTime: 106 data = [] 107 for arch in arches: 108 data.append(sizes[arch]) 109 data.append(times[arch]) 110 plot(*data) 111 title('Performance on '+library+' Example '+str(num)) 112 xlabel('Number of Dof') 113 ylabel('Time (s)') 114 legend(arches, 'upper left', shadow = True) 115 show() 116 # Common event time 117 # We could make a stacked plot like Rio uses here 118 if showEventTime: 119 data = [] 120 names = [] 121 for event, color in [('VecMDot', 'b'), ('VecMAXPY', 'g'), ('MatMult', 'r')]: 122 for arch, style in zip(arches, ['-', ':']): 123 names.append(arch+' '+event) 124 data.append(sizes[arch]) 125 data.append(np.array(events[arch][event])[:,0]) 126 data.append(color+style) 127 plot(*data) 128 title('Performance on '+library+' Example '+str(num)) 129 xlabel('Number of Dof') 130 ylabel('Time (s)') 131 legend(names, 'upper left', shadow = True) 132 show() 133 # Common event flops 134 # We could make a stacked plot like Rio uses here 135 if showEventFlops: 136 data = [] 137 names = [] 138 for event, color in [('VecMDot', 'b'), ('VecMAXPY', 'g'), ('MatMult', 'r')]: 139 for arch, style in zip(arches, ['-', ':']): 140 names.append(arch+' '+event) 141 data.append(sizes[arch]) 142 data.append(np.array(events[arch][event])[:,1]) 143 data.append(color+style) 144 plot(*data) 145 title('Performance on '+library+' Example '+str(num)) 146 xlabel('Number of Dof') 147 ylabel('Computation Rate (MF/s)') 148 legend(names, 'upper left', shadow = True) 149 show() 150 return 151 152def plotSummaryBar(library, num, sizes, times, events): 153 import numpy as np 154 import matplotlib.pyplot as plt 155 156 eventNames = ['VecMDot', 'VecMAXPY', 'MatMult'] 157 eventColors = ['b', 'g', 'r'] 158 arches = sizes.keys() 159 names = [] 160 N = len(sizes[arches[0]]) 161 width = 0.2 162 ind = np.arange(N) - 0.25 163 bars = {} 164 for arch in arches: 165 bars[arch] = [] 166 bottom = np.zeros(N) 167 for event, color in zip(eventNames, eventColors): 168 names.append(arch+' '+event) 169 times = np.array(events[arch][event])[:,0] 170 bars[arch].append(plt.bar(ind, times, width, color=color, bottom=bottom)) 171 bottom += times 172 ind += 0.3 173 174 plt.xlabel('Number of Dof') 175 plt.ylabel('Time (s)') 176 plt.title('GPU vs. CPU Performance on '+library+' Example '+str(num)) 177 plt.xticks(np.arange(N), map(str, sizes[arches[0]])) 178 #plt.yticks(np.arange(0,81,10)) 179 #plt.legend( (p1[0], p2[0]), ('Men', 'Women') ) 180 plt.legend([bar[0] for bar in bars[arches[0]]], eventNames, 'upper right', shadow = True) 181 182 plt.show() 183 return 184 185if __name__ == '__main__': 186 library = 'SNES' 187 num = 19 188 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') 189 sizes = {} 190 times = {} 191 events = {} 192 for name, vecType, matType, opts in [('CPU', 'seq', 'seqaij', {}), ('GPU', 'seqcusp', 'seqaijcusp', {'cusp_synchronize': None})]: 193 sizes[name] = [] 194 times[name] = [] 195 events[name] = {} 196 #for n in [10, 20, 50, 100, 150, 200]: 197 for n in [10, 20]: 198 ex.run(da_grid_x=n, da_grid_y=n, da_vec_type=vecType, da_mat_type=matType, **opts) 199 sizes[name].append(n*n * 4) 200 processSummary('summary', times[name], events[name]) 201 plotSummaryLine(library, num, sizes, times, events) 202