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

Source Code for Module PyFoam.Applications.Benchmark

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