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