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