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