Package PyFoam :: Package Applications :: Module Benchmark
[hide private]
[frames] | no frames]

Source Code for Module PyFoam.Applications.Benchmark

  1  #  ICE Revision: $Id: Benchmark.py 7832 2007-08-28 13:07:26Z bgschaid $  
  2  """ 
  3  Class that implements pyFoamBenchmark 
  4  """ 
  5   
  6  from PyFoamApplication import PyFoamApplication 
  7  from PyFoam.FoamInformation import changeFoamVersion 
  8   
  9  import sys,string,ConfigParser,csv 
 10   
 11  from os import path,uname 
 12  from time import time,localtime,asctime 
 13  from PyFoam.Execution.BasicRunner import BasicRunner 
 14  from PyFoam.FoamInformation import foamTutorials 
 15  from PyFoam.RunDictionary.SolutionDirectory import SolutionDirectory 
 16  from PyFoam.RunDictionary.SolutionFile import SolutionFile 
 17  from PyFoam.RunDictionary.ParameterFile import ParameterFile 
 18  from PyFoam.RunDictionary.BlockMesh import BlockMesh 
 19  from PyFoam.Execution.ParallelExecution import LAMMachine 
 20  from PyFoam.Basics.Utilities import execute 
 21   
22 -class Benchmark(PyFoamApplication):
23 - def __init__(self):
24 description=""" 25 Runs a set of benchmarks specified in a config files 26 """ 27 PyFoamApplication.__init__(self,description=description,usage="%prog [options] <specification>",interspersed=True,nr=1)
28
29 - def addOptions(self):
30 self.parser.add_option("--nameAddition", 31 action="store", 32 dest="nameAddition", 33 default=None, 34 help="Addition to the name that helps to distinguish different runs of the same configuration") 35 self.parser.add_option("--removeCases", 36 action="store_true", 37 dest="removeCases", 38 default=False, 39 help="Remove the case directories and log files for all successfully run cases") 40 self.parser.add_option("--foamVersion", 41 dest="foamVersion", 42 default=None,help="Change the OpenFOAM-version that is to be used")
43
44 - def run(self):
45 if self.opts.foamVersion!=None: 46 changeFoamVersion(self.opts.foamVersion) 47 48 config=ConfigParser.ConfigParser() 49 files=self.parser.getArgs() 50 51 good=config.read(files) 52 # will work with 2.4 53 # if len(good)!=len(files): 54 # print "Problem while trying to parse files",files 55 # print "Only ",good," could be parsed" 56 # sys.exit(-1) 57 58 benchName=config.get("General","name") 59 if self.opts.nameAddition!=None: 60 benchName+="_"+self.opts.nameAddition 61 if self.opts.foamVersion!=None: 62 benchName+="_v"+self.opts.foamVersion 63 64 isParallel=config.getboolean("General","parallel") 65 lam=None 66 67 if isParallel: 68 nrCpus=config.getint("General","nProcs") 69 machineFile=config.get("General","machines") 70 if not path.exists(machineFile): 71 print "Machine file ",machineFile,"needed for parallel run" 72 sys.exit(-1) 73 lam=LAMMachine(machineFile) 74 if lam.cpuNr()!=nrCpus: 75 print "Wrong number of CPUs: ",lam.cpuNr() 76 sys.exit(-1) 77 78 print "Running parallel on",lam.cpuNr(),"CPUs" 79 80 if config.has_option("General","casesDirectory"): 81 casesDirectory=path.expanduser(config.get("General","casesDirectory")) 82 else: 83 casesDirectory=foamTutorials() 84 85 if not path.exists(casesDirectory): 86 print "Directory",casesDirectory,"needed with the benchmark cases is missing" 87 sys.exit(-1) 88 else: 89 print "Using cases from directory",casesDirectory 90 91 benchCases=[] 92 config.remove_section("General") 93 94 for sec in config.sections(): 95 print "Reading: ",sec 96 skipIt=False 97 if config.has_option(sec,"skip"): 98 skipIt=config.getboolean(sec,"skip") 99 if skipIt: 100 print "Skipping case ....." 101 continue 102 sol=config.get(sec,"solver") 103 cas=config.get(sec,"case") 104 pre=eval(config.get(sec,"prepare")) 105 preCon=[] 106 if config.has_option(sec,"preControlDict"): 107 preCon=eval(config.get(sec,"preControlDict")) 108 con=eval(config.get(sec,"controlDict")) 109 bas=config.getfloat(sec,"baseline") 110 wei=config.getfloat(sec,"weight") 111 add=[] 112 if config.has_option(sec,"additional"): 113 add=eval(config.get(sec,"additional")) 114 print "Adding: ", add 115 util=[] 116 if config.has_option(sec,"utilities"): 117 util=eval(config.get(sec,"utilities")) 118 print "Utilities: ", util 119 nr=99999 120 if config.has_option(sec,"nr"): 121 nr=eval(config.get(sec,"nr")) 122 sp=None 123 if config.has_option(sec,"blockSplit"): 124 sp=eval(config.get(sec,"blockSplit")) 125 toRm=[] 126 if config.has_option(sec,"filesToRemove"): 127 toRm=eval(config.get(sec,"filesToRemove")) 128 setInit=[] 129 if config.has_option(sec,"setInitial"): 130 setInit=eval(config.get(sec,"setInitial")) 131 132 parallelOK=False 133 if config.has_option(sec,"parallelOK"): 134 parallelOK=config.getboolean(sec,"parallelOK") 135 136 deMet=["metis"] 137 if config.has_option(sec,"decomposition"): 138 deMet=config.get(sec,"decomposition").split() 139 140 if deMet[0]=="metis": 141 pass 142 elif deMet[0]=="simple": 143 if len(deMet)<2: 144 deMet.append(0) 145 else: 146 deMet[1]=int(deMet[1]) 147 else: 148 print "Unimplemented decomposition method",deMet[0],"switching to metis" 149 deMet=["metis"] 150 151 if isParallel==False or parallelOK==True: 152 if path.exists(path.join(casesDirectory,sol,cas)): 153 benchCases.append( (nr,sec,sol,cas,pre,con,preCon,bas,wei,add,util,sp,toRm,setInit,deMet) ) 154 else: 155 print "Skipping",sec,"because directory",path.join(casesDirectory,sol,cas),"could not be found" 156 else: 157 print "Skipping",sec,"because not parallel" 158 159 benchCases.sort() 160 161 parallelString="" 162 if isParallel: 163 parallelString=".cpus="+str(nrCpus) 164 165 resultFile=open("Benchmark."+benchName+"."+uname()[1]+parallelString+".results","w") 166 167 totalSpeedup=0 168 minSpeedup=None 169 maxSpeedup=None 170 totalWeight =0 171 runsOK=0 172 currentEstimate = 1. 173 174 print "\nStart Benching\n" 175 csvFile=open("Benchmark."+benchName+"."+uname()[1]+parallelString+".csv","w") 176 csvHeaders=["description","solver","case","caseDir","base", 177 "benchmark","machine","arch","cpus","os","version", 178 "wallclocktime","cputime","cputimeuser","cputimesystem","maxmemory","cpuusage","speedup"] 179 writer=csv.DictWriter(csvFile,csvHeaders) 180 181 # write the headers to the file 182 result={} 183 for h in csvHeaders: 184 result[h]=h 185 writer.writerow(result) 186 csvFile.flush() 187 188 for nr,description,solver,case,prepare,control,preControl,base,weight,additional,utilities,split,toRemove,setInit,decomposition in benchCases: 189 # control.append( ("endTime",-2000) ) 190 print "Running Benchmark: ",description 191 print "Solver: ",solver 192 print "Case: ",case 193 caseName=solver+"_"+case+"_"+benchName+"."+uname()[1]+".case" 194 print "Short name: ",caseName 195 caseDir=caseName+".runDir" 196 197 result={} 198 result["description"]=description 199 result["solver"]=solver 200 result["case"]=case 201 result["caseDir"]=caseDir 202 result["base"]=base 203 204 result["benchmark"]=benchName 205 result["machine"]=uname()[1] 206 result["arch"]=uname()[4] 207 if lam==None: 208 result["cpus"]=1 209 else: 210 result["cpus"]=lam.cpuNr() 211 result["os"]=uname()[0] 212 result["version"]=uname()[2] 213 214 workDir=path.realpath(path.curdir) 215 216 orig=SolutionDirectory(path.join(casesDirectory,solver,case),archive=None) 217 for a in additional+utilities: 218 orig.addToClone(a) 219 orig.cloneCase(path.join(workDir,caseDir)) 220 221 run=BasicRunner(silent=True,argv=[solver,workDir,caseDir],logname="BenchRunning",lam=lam) 222 runDir=run.getSolutionDirectory() 223 controlFile=ParameterFile(runDir.controlDict()) 224 225 for name,value in preControl: 226 print "Setting parameter",name,"to",value,"in controlDict" 227 controlFile.replaceParameter(name,value) 228 229 for rm in toRemove: 230 fn=path.join(caseDir,rm) 231 print "Removing file",fn 232 execute("rm -f "+fn) 233 234 for field,bc,val in setInit: 235 print "Setting",field,"on",bc,"to",val 236 SolutionFile(runDir.initialDir(),field).replaceBoundary(bc,val) 237 238 oldDeltaT=controlFile.replaceParameter("deltaT",0) 239 240 for u in utilities: 241 print "Building utility ",u 242 execute("wmake 2>&1 >%s %s" % (path.join(caseDir,"BenchCompile."+u),path.join(caseDir,u))) 243 244 print "Preparing the case: " 245 if lam!=None: 246 prepare=prepare+[("decomposePar","")] 247 if decomposition[0]=="metis": 248 lam.writeMetis(SolutionDirectory(path.join(workDir,caseDir))) 249 elif decomposition[0]=="simple": 250 lam.writeSimple(SolutionDirectory(path.join(workDir,caseDir)),decomposition[1]) 251 252 if split: 253 print "Splitting the mesh:",split 254 bm=BlockMesh(runDir.blockMesh()) 255 bm.refineMesh(split) 256 257 for pre,post in prepare: 258 print "Doing ",pre," ...." 259 post=post.replace("%case%",caseDir) 260 args=string.split("%s %s %s %s" % (pre,workDir,caseDir,post)) 261 util=BasicRunner(silent=True,argv=args,logname="BenchPrepare_"+pre) 262 util.start() 263 264 controlFile.replaceParameter("deltaT",oldDeltaT) 265 266 # control.append(("endTime",-1000)) 267 for name,value in control: 268 print "Setting parameter",name,"to",value,"in controlDict" 269 controlFile.replaceParameter(name,value) 270 271 print "Starting at ",asctime(localtime(time())) 272 print " Baseline is %f, estimated speedup %f -> estimated end at %s " % (base,currentEstimate,asctime(localtime(time()+base/currentEstimate))) 273 print "Running the case ...." 274 run.start() 275 276 speedup=None 277 cpuUsage=0 278 speedupOut=-1 279 280 try: 281 speedup=base/run.run.wallTime() 282 cpuUsage=100.*run.run.cpuTime()/run.run.wallTime() 283 except ZeroDivisionError: 284 print "Division by Zero: ",run.run.wallTime() 285 286 if not run.runOK(): 287 print "\nWARNING!!!!" 288 print "Run had a problem, not using the results. Check the log\n" 289 speedup=None 290 291 if speedup!=None: 292 speedupOut=speedup 293 294 totalSpeedup+=speedup*weight 295 totalWeight +=weight 296 runsOK+=1 297 if maxSpeedup==None: 298 maxSpeedup=speedup 299 elif speedup>maxSpeedup: 300 maxSpeedup=speedup 301 if minSpeedup==None: 302 minSpeedup=speedup 303 elif speedup<minSpeedup: 304 minSpeedup=speedup 305 306 print "Wall clock: ",run.run.wallTime() 307 print "Speedup: ",speedup," (Baseline: ",base,")" 308 print "CPU Time: ",run.run.cpuTime() 309 print "CPU Time User: ",run.run.cpuUserTime() 310 print "CPU Time System: ",run.run.cpuSystemTime() 311 print "Memory: ",run.run.usedMemory() 312 print "CPU Usage: %6.2f%%" % (cpuUsage) 313 314 result["wallclocktime"]=run.run.wallTime() 315 result["cputime"]=run.run.cpuTime() 316 result["cputimeuser"]=run.run.cpuUserTime() 317 result["cputimesystem"]=run.run.cpuSystemTime() 318 result["maxmemory"]=run.run.usedMemory() 319 result["cpuusage"]=cpuUsage 320 result["speedup"]=speedup 321 322 writer.writerow(result) 323 csvFile.flush() 324 325 resultFile.write("Case %s WallTime %g CPUTime %g UserTime %g SystemTime %g Memory %g MB Speedup %g\n" %(caseName,run.run.wallTime(),run.run.cpuTime(),run.run.cpuUserTime(),run.run.cpuSystemTime(),run.run.usedMemory(),speedupOut)) 326 327 resultFile.flush() 328 329 if speedup!=None: 330 currentEstimate=totalSpeedup/totalWeight 331 332 if self.opts.removeCases: 333 print "Clearing case", 334 if speedup==None: 335 print "not ... because it failed" 336 else: 337 print "completely" 338 execute("rm -rf "+caseDir) 339 340 print 341 print 342 343 csvFile.close() 344 345 if lam!=None: 346 lam.stop() 347 348 print "Total Speedup: ",currentEstimate," ( ",totalSpeedup," / ",totalWeight, " ) Range: [",minSpeedup,",",maxSpeedup,"]" 349 350 print runsOK,"of",len(benchCases),"ran OK" 351 352 resultFile.write("Total Speedup: %g\n" % (currentEstimate)) 353 if minSpeedup and maxSpeedup: 354 resultFile.write("Range: [ %g , %g ]\n" % (minSpeedup,maxSpeedup)) 355 356 resultFile.close()
357