00001
00002
00003 r'''
00004 cmsRelvalreport.py: a script to run performance tests and produce reports in a automated way.
00005 '''
00006
00007 import glob,re
00008
00009
00010
00011 PR3_BASE='/afs/cern.ch/user/d/dpiparo/w0/perfreport3installation/'
00012 PR3=PR3_BASE+'/bin/perfreport'
00013 PERFREPORT3_PATH=PR3_BASE+'/share/perfreport'
00014
00015 PR3_PRODUCER_PLUGIN='/afs/cern.ch/user/d/dpiparo/w0/pr3/perfreport/plugins/cmssw_by_producer/libcmssw_by_producer.so'
00016
00017
00018 PR2_BASE='/afs/cern.ch/user/g/gbenelli/public/PerfReport2/2.0.1/'
00019 PR2='%s' %(PR2_BASE+'/bin/perfreport')
00020 PERFREPORT2_PATH=PR2_BASE+'/share/perfreport'
00021
00022 import os
00023 cmssw_base=os.environ["CMSSW_BASE"]
00024 cmssw_release_base=os.environ["CMSSW_RELEASE_BASE"]
00025 pyrelvallocal=cmssw_base+"/src/Configuration/PyReleaseValidation"
00026
00027 if os.path.exists(pyrelvallocal):
00028 RELEASE='CMSSW_BASE'
00029 print "Using LOCAL version of Configuration/PyReleaseValidation instead of the RELEASE version"
00030 elif not os.path.exists(pyrelvallocal):
00031 RELEASE='CMSSW_RELEASE_BASE'
00032
00033
00034
00035
00036 VMPARSER='valgrindMemcheckParser.pl'
00037
00038
00039
00040 VMPARSERSTYLE='%s/src/Utilities/ReleaseScripts/data/valgrindMemcheckParser.css' %os.environ['CMSSW_RELEASE_BASE']
00041
00042
00043
00044 IGPROFANALYS='cmsIgProf_Analysis.py'
00045
00046
00047
00048 TIMEREPORTPARSER='cmsTimeReport.pl'
00049
00050
00051
00052 SIMPLEMEMPARSER='cmsSimplememchecker_parser.py'
00053
00054
00055
00056 TIMINGPARSER='cmsTiming_parser.py'
00057
00058
00059 MAKESKIMDRIVERDIR='%s/src/Configuration/EventContent/test' %os.environ[RELEASE]
00060 MAKESKIMDRIVER='%s/makeSkimDriver.py'%MAKESKIMDRIVERDIR
00061
00062
00063
00064
00065
00066 VFCE_LIB='/afs/cern.ch/user/m/moserro/public/vgfcelib'
00067 PERL5_LIB='/afs/cern.ch/user/d/dpiparo/w0/PERLlibs/5.8.0'
00068
00069
00070
00071
00072 STDOUTPROFILERS=['Memcheck_Valgrind',
00073 'Timereport_Parser',
00074 'Timing_Parser',
00075 'SimpleMem_Parser']
00076
00077 PROFILERS=['ValgrindFCE',
00078 'IgProf_perf',
00079 'IgProf_mem',
00080 'Edm_Size']+STDOUTPROFILERS
00081
00082
00083
00084 EXECUTABLE='cmsRun'
00085
00086
00087 EXEC=True
00088 DEBUG=True
00089
00090
00091 IgProfCounters={'IgProfPerf':['PERF_TICKS'],
00092 'IgProfMem':['MEM_TOTAL','MEM_LIVE','MEM_MAX']
00093 }
00094 IgProfProfiles={'PERF_TICKS':'IgProfPerf',
00095 'MEM_TOTAL':'IgProfMem',
00096 'MEM_LIVE':'IgProfMem',
00097 'MEM_MAX':'IgProfMem'
00098 }
00099 import time
00100 import optparse
00101 import sys
00102
00103
00104
00105 def red(string):
00106 return '%s%s%s' %('\033[1;31m',string,'\033[1;0m')
00107 def green(string):
00108 return '%s%s%s' %('\033[1;32m',string,'\033[1;0m')
00109 def yellow(string):
00110 return '%s%s%s' %('\033[1;33m',string,'\033[1;0m')
00111
00112
00113 def clean_name(name):
00114 '''
00115 Trivially removes an underscore if present as last char of a string
00116 '''
00117 i=-1
00118 is_dirty=True
00119 while(is_dirty):
00120 if name[i]=='_':
00121 name=name[:-1]
00122 else:
00123 return name
00124 i-=1
00125
00126
00127
00128 def execute(command):
00129 '''
00130 It executes command if the EXEC switch is True.
00131 Catches exitcodes different from 0.
00132 '''
00133 logger('%s %s ' %(green('[execute]'),command))
00134 if EXEC:
00135 exit_code=os.system(command)
00136 if exit_code!=0:
00137 logger(red('*** Seems like "%s" encountered problems.' %command))
00138 return exit_code
00139 else:
00140 return 0
00141
00142
00143
00144 def logger(message,level=0):
00145 '''
00146 level=0 output, level 1 debug.
00147 '''
00148 message='%s %s' %(yellow('[RelValreport]'),message)
00149
00150 sys.stdout.flush()
00151
00152 if level==0:
00153 print message
00154 if level==1 and DEBUG:
00155 print message
00156
00157 sys.stdout.flush()
00158
00159
00160
00161 class Candles_file:
00162 '''
00163 Class to read the trivial ASCII file containing the candles
00164 '''
00165 def __init__(self, filename):
00166
00167 self.commands_profilers_meta_list=[]
00168
00169 candlesfile=open(filename,'r')
00170
00171 if filename[-3:]=='xml':
00172 command=''
00173 profiler=''
00174 meta=''
00175 db_meta=''
00176 reuse=False
00177
00178 from xml.dom import minidom
00179
00180
00181 xmldoc = minidom.parse(filename)
00182
00183
00184 candles_list = xmldoc.getElementsByTagName('candle')
00185
00186
00187 candles_dict_list=[]
00188
00189 for candle in candles_list:
00190 info_dict={}
00191 for child in candle.childNodes:
00192 if not child.__dict__.has_key('nodeName'):
00193
00194 continue
00195
00196 tag_name=child.tagName
00197
00198 data=child.firstChild.data
00199
00200
00201 info_dict[tag_name]=data
00202
00203 candles_dict_list.append(info_dict)
00204
00205
00206
00207 for candle_dict in candles_dict_list:
00208
00209 command=candle_dict['command']
00210 profiler=candle_dict['profiler']
00211 meta=candle_dict['meta']
00212
00213 try:
00214 db_meta=candle_dict['db_meta']
00215 except:
00216 db_meta=None
00217 try:
00218 reuse=candle_dict['reuse']
00219 except:
00220 reuse=False
00221
00222 self.commands_profilers_meta_list.append([command,profiler,meta,reuse,db_meta])
00223
00224
00225 else:
00226 for candle in candlesfile.readlines():
00227
00228 if candle[0]!='#' and candle.strip(' \n\t')!='':
00229 if candle[-1]=='\n':
00230 candle=candle[:-1]
00231 splitted_candle=candle.split('@@@')
00232
00233
00234 command=splitted_candle[0]
00235 profiler=splitted_candle[1].strip(' \t')
00236 meta=splitted_candle[2].strip(' \t')
00237 info=[command,profiler,meta]
00238
00239
00240
00241 len_splitted_candle=len(splitted_candle)
00242 reuse=False
00243 if len_splitted_candle>3:
00244
00245 if 'reuse' in splitted_candle[3]:
00246 reuse=True
00247 info.append(reuse)
00248 else:
00249 info.append(reuse)
00250
00251
00252 if len_splitted_candle>4 or (len_splitted_candle>3 and not reuse):
00253 cmssw_scram_version_string=splitted_candle[-1].strip(' \t')
00254 info.append(cmssw_scram_version_string)
00255 else:
00256 info.append(None)
00257
00258
00259 self.commands_profilers_meta_list.append(info)
00260
00261
00262
00263 def get_commands_profilers_meta_list(self):
00264 return self.commands_profilers_meta_list
00265
00266
00267
00268 class Profile:
00269 '''
00270 Class that represents the procedure of performance report creation
00271 '''
00272 def __init__(self,command,profiler,profile_name):
00273 self.command=command
00274 self.profile_name=profile_name
00275 self.profiler=profiler
00276
00277
00278
00279 def make_profile(self):
00280 '''
00281 Launch the right function according to the profiler name.
00282 '''
00283 if self.profiler=='ValgrindFCE':
00284 return self._profile_valgrindfce()
00285 elif self.profiler.find('IgProf')!=-1:
00286 return self._profile_igprof()
00287 elif self.profiler.find('Edm_Size')!=-1:
00288 return self._profile_edmsize()
00289 elif self.profiler=='Memcheck_Valgrind':
00290 return self._profile_Memcheck_Valgrind()
00291 elif self.profiler=='Timereport_Parser':
00292 return self._profile_Timereport_Parser()
00293 elif self.profiler=='Timing_Parser':
00294 return self._profile_Timing_Parser()
00295 elif self.profiler=='SimpleMem_Parser':
00296 return self._profile_SimpleMem_Parser()
00297 elif self.profiler=='':
00298 return self._profile_None()
00299 elif self.profiler=='None':
00300 return self._profile_None()
00301 else:
00302 raise('No %s profiler found!' %self.profiler)
00303
00304 def _profile_valgrindfce(self):
00305 '''
00306 Valgrind profile launcher.
00307 '''
00308
00309 os.environ["VALGRIND_LIB"]=VFCE_LIB
00310
00311 profiler_line=''
00312 valgrind_options= 'time valgrind '+\
00313 '--tool=callgrind '+\
00314 '--fce=%s ' %(self.profile_name)
00315
00316
00317 if EXECUTABLE=='cmsRun' and self.command.find('cmsDriver.py')!=-1:
00318 profiler_line='%s --prefix "%s"' %(self.command,valgrind_options)
00319
00320 else:
00321 profiler_line='%s %s' %(valgrind_options,self.command)
00322
00323
00324 return execute(profiler_line)
00325
00326
00327 def _profile_igprof(self):
00328 '''
00329 IgProf profiler launcher.
00330 '''
00331 profiler_line=''
00332
00333 igprof_options='igprof -d -t %s ' \
00334 %EXECUTABLE
00335
00336
00337 if self.profiler=='IgProf_perf':
00338 igprof_options+='-pp '
00339 elif self.profiler=='IgProf_mem':
00340 igprof_options+='-mp '
00341 else:
00342 raise ('Unknown IgProf flavour: %s !'%self.profiler)
00343 igprof_options+='-z -o %s' %(self.profile_name)
00344
00345
00346 if EXECUTABLE=='cmsRun' and self.command.find('cmsDriver.py')!=-1:
00347 profiler_line='%s --prefix "%s"' %(self.command,igprof_options)
00348 else:
00349 profiler_line='%s %s' %(igprof_options, self.command)
00350
00351 return execute(profiler_line)
00352
00353
00354
00355 def _profile_edmsize(self):
00356 '''
00357 Launch edm size profiler
00358 '''
00359
00360 input_rootfile=self.command
00361
00362
00363 if '.' in self.profiler:
00364
00365 clean_profiler_name,options=self.profiler.split('.')
00366 content,nevts=options.split(',')
00367 outfilename='%s_%s.root'%(os.path.basename(self.command)[:-6],content)
00368 oldpypath=os.environ['PYTHONPATH']
00369 os.environ['PYTHONPATH']+=':%s' %MAKESKIMDRIVERDIR
00370 execute('%s -i %s -o %s --outputcommands %s -n %s' %(MAKESKIMDRIVER,
00371 self.command,
00372 outfilename,
00373 content,
00374 nevts))
00375 os.environ['PYTHONPATH']=oldpypath
00376
00377 self.command=outfilename
00378 self.profiler=clean_profiler_name
00379
00380
00381 profiler_line='edmEventSize -o %s -d %s'\
00382 %(self.profile_name,self.command)
00383
00384 return execute(profiler_line)
00385
00386
00387
00388 def _profile_Memcheck_Valgrind(self):
00389 '''
00390 Valgrind Memcheck profile launcher
00391 '''
00392 profiler_line=''
00393
00394
00395
00396
00397
00398
00399 valgrind_options='time valgrind --tool=memcheck `cmsvgsupp` '+\
00400 '--num-callers=20 '+\
00401 '--xml=yes '+\
00402 '--xml-file=%s.xml '%self.profile_name.replace(",","-")[:-4]
00403
00404
00405 if EXECUTABLE=='cmsRun' and self.command.find('cmsDriver.py')!=-1:
00406
00407
00408 profiler_line='%s --prefix "%s" >& %s' %(self.command,valgrind_options,self.profile_name)
00409
00410 else:
00411 profiler_line='%s %s >& %s' %(valgrind_options,self.command,self.profile_name)
00412
00413 return execute(profiler_line)
00414
00415
00416 def _profile_Timereport_Parser(self):
00417 return self._save_output()
00418
00419
00420
00421 def _profile_SimpleMem_Parser(self):
00422 return self._save_output()
00423
00424
00425
00426 def _profile_Timing_Parser(self):
00427 return self._save_output()
00428
00429
00430
00431 def _save_output(self):
00432 '''
00433 Save the output of cmsRun on a file!
00434 '''
00435
00436
00437
00438
00439
00440 profiler_line='%s >& %s' %(self.command,self.profile_name)
00441 return execute(profiler_line)
00442
00443
00444
00445 def _profile_None(self):
00446 '''
00447 Just Run the command!
00448 '''
00449 return execute(self.command)
00450
00451
00452
00453 def make_report(self,
00454 fill_db=False,
00455 db_name=None,
00456 tmp_dir=None,
00457 outdir=None,
00458 IgProf_option=None,
00459 metastring=None):
00460 '''
00461 Make a performance report with CMSSW scripts for CMSSW internal profiling (Timing/SimpleMemoryCheck) and Memcheck, PR2 for edmEventSize and Callgrind (NOTE PR2 is not supported anymore and is not currently in the CMSSW external, running froma privat AFS!), igprof-analyse for all IgProf profiling.
00462 '''
00463
00464 if outdir==None or outdir==self.profile_name:
00465 outdir=self.profile_name+'_outdir'
00466
00467
00468 if not os.path.exists(outdir) and not fill_db and not IgProf_option:
00469
00470 execute('mkdir %s' %outdir)
00471
00472 if fill_db:
00473 db_option='-a'
00474 if not os.path.exists(db_name):
00475 db_option='-A'
00476
00477
00478 tmp_switch=''
00479 if tmp_dir!='':
00480 execute('mkdir %s' %tmp_dir)
00481 tmp_switch=' -t %s' %tmp_dir
00482
00483
00484
00485
00486
00487
00488 if self.profiler=='ValgrindFCE':
00489 perfreport_command=''
00490
00491 if not fill_db:
00492 os.environ["PERFREPORT_PATH"]='%s/' %PERFREPORT2_PATH
00493 perfreport_command='%s %s -ff -i %s -o %s' %(PR2,
00494 tmp_switch,
00495 self.profile_name,
00496 outdir)
00497 else:
00498 os.environ["PERFREPORT_PATH"]='%s/' %PERFREPORT3_PATH
00499 perfreport_command='%s %s -n5000 -u%s -ff -m \'scram_cmssw_version_string,%s\' -i %s %s -o %s' \
00500 %(PR3,
00501 tmp_switch,
00502 PR3_PRODUCER_PLUGIN,
00503 metastring,
00504 self.profile_name,
00505 db_option,
00506 db_name)
00507 return execute(perfreport_command)
00508
00509
00510
00511
00512 if self.profiler.find('IgProf')!=-1:
00513
00514 if not 'ANALYSE' in IgProf_option:
00515
00516
00517
00518 NumberOfEvents=self.command.split()[3]
00519 sqlite_outputfile=self.profile_name.split(".")[0].replace(IgProfProfiles[IgProf_option[0]],IgProf_option[0])+'___'+NumberOfEvents+'_EndOfJob.sql3'
00520 logger("Executing the report of the IgProf end of job profile")
00521 exit=execute('igprof-analyse --sqlite -d -v -g -r %s %s | sqlite3 %s'%(IgProf_option[0],self.profile_name,sqlite_outputfile))
00522 return exit
00523
00524
00525
00526
00527
00528
00529 else:
00530
00531
00532 IgProfCounter=IgProf_option[1]
00533
00534 logger("Looking for IgProf intermediate event profile dumps")
00535
00536 IgProfDumps=glob.glob("IgProf.*.gz")
00537
00538
00539 if not IgProfDumps:
00540 localFiles=os.listdir('.')
00541 IgProfDumpProfilesPrevious=re.compile(r"\w+.\d+.gz")
00542 IgProfDumps=filter(lambda x: IgProfDumpProfilesPrevious.search(x),localFiles)
00543
00544 if IgProfDumps:
00545 IgProfDumps.sort()
00546 logger("Found the following IgProf intermediate event profile dumps:")
00547 logger(IgProfDumps)
00548 FirstDumpEvent=9999999
00549 LastDumpEvent=0
00550 exit=0
00551 for dump in IgProfDumps:
00552 if "___" in dump:
00553 DumpEvent=dump.split(".")[0].split("___")[-1]
00554 else:
00555 DumpEvent=dump.split(".")[1]
00556
00557 DumpedProfileName=self.profile_name[:-3]+"___"+DumpEvent+".gz"
00558 if dump.startswith("IgProf"):
00559 execute('mv %s %s'%(dump,DumpedProfileName))
00560
00561 if int(DumpEvent) < FirstDumpEvent:
00562 FirstDumpEvent = int(DumpEvent)
00563 if int(DumpEvent) > LastDumpEvent:
00564 LastDumpEvent = int(DumpEvent)
00565
00566
00567
00568
00569
00570 logger("Executing the igprof-analyse analysis saving into igprof-navigator browseable SQLite3 format")
00571
00572
00573
00574
00575
00576
00577
00578
00579 exit=exit+execute('%s -c%s -i%s -t%s' %(IGPROFANALYS,IgProfCounter,DumpedProfileName,"SQLite3"))
00580
00581
00582
00583
00584
00585
00586 FirstDumpProfile=self.profile_name[:-3]+"___"+str(FirstDumpEvent)+".gz"
00587 LastDumpProfile=self.profile_name[:-3]+"___"+str(LastDumpEvent)+".gz"
00588
00589
00590 if len(IgProfDumps)>1:
00591 logger("Executing the igprof-analyse regression between the first IgProf profile dump and the last one")
00592
00593
00594
00595 exit=exit+execute('%s -c%s -i%s -r%s' %(IGPROFANALYS,IgProfCounter,LastDumpProfile,FirstDumpProfile))
00596 else:
00597 logger("CANNOT execute any regressions: not enough IgProf intermediate event profile dumps!")
00598
00599 logger("Executing the igprof-analyse analysis merging the results by library via regexp and saving the result in igprof-navigator browseable SQLite3 format")
00600
00601
00602
00603 exit=exit+execute('%s -c%s -i%s --library' %(IGPROFANALYS,IgProfCounter,LastDumpProfile))
00604
00605 else:
00606 logger("No IgProf intermediate event profile dumps found!")
00607 exit=0
00608
00609 return exit
00610
00611
00612
00613
00614
00615 if 'Edm_Size' in self.profiler:
00616 perfreport_command=''
00617 if not fill_db:
00618 os.environ["PERFREPORT_PATH"]='%s/' \
00619 %PERFREPORT2_PATH
00620 perfreport_command='%s %s -fe -i %s -o %s' \
00621 %(PR2,
00622 tmp_switch,
00623 self.profile_name,
00624 outdir)
00625 else:
00626 os.environ["PERFREPORT_PATH"]='%s/' \
00627 %PERFREPORT3_PATH
00628 perfreport_command='%s %s -n5000 -u%s -fe -i %s -a -o %s' \
00629 %(PR3,
00630 tmp_switch,
00631 PR3_PRODUCER_PLUGIN,
00632 self.profile_name,
00633 db_name)
00634
00635 return execute(perfreport_command)
00636
00637
00638 if tmp_dir!='':
00639 execute('rm -r %s' %tmp_dir)
00640
00641
00642
00643
00644 if self.profiler=='Memcheck_Valgrind':
00645
00646 os.environ['PERL5LIB']=PERL5_LIB
00647 report_coordinates=(VMPARSER,self.profile_name,outdir)
00648
00649 copyStyleFile='cp -pR %s %s'%(VMPARSERSTYLE,outdir)
00650 execute(copyStyleFile)
00651 report_commands=('%s --preset +prod,-prod1 %s > %s/edproduce.html'\
00652 %report_coordinates,
00653 '%s --preset +prod1 %s > %s/esproduce.html'\
00654 %report_coordinates,
00655 '%s -t beginJob %s > %s/beginjob.html'\
00656 %report_coordinates)
00657 exit=0
00658 for command in report_commands:
00659 exit= exit + execute(command)
00660 return exit
00661
00662
00663
00664
00665 if self.profiler=='Timereport_Parser':
00666 return execute('%s %s %s' %(TIMEREPORTPARSER,self.profile_name,outdir))
00667
00668
00669
00670
00671
00672 if self.profiler=='Timing_Parser':
00673 return execute('%s -i %s -o %s' %(TIMINGPARSER,self.profile_name,outdir))
00674
00675
00676
00677
00678
00679
00680 if self.profiler=='SimpleMem_Parser':
00681 return execute('%s -i %s -o %s' %(SIMPLEMEMPARSER,self.profile_name,outdir))
00682
00683
00684
00685
00686
00687 if self.profiler=='' or self.profiler=='None':
00688 return 0
00689
00690
00691
00692 def principal(options):
00693 '''
00694 Here the objects of the Profile class are istantiated.
00695 '''
00696
00697 exitCodeSum=0
00698
00699
00700 commands_profilers_meta_list=[]
00701
00702
00703 if options.infile=='':
00704 logger('Single command found...')
00705 commands_profilers_meta_list.append([options.command,'','',False,''])
00706
00707
00708 else:
00709 logger('List of commands found. Processing %s ...' %options.infile)
00710
00711
00712 candles_file = Candles_file(options.infile)
00713
00714 commands_profilers_meta_list=candles_file.get_commands_profilers_meta_list()
00715
00716
00717 logger('Iterating through commands of executables to profile ...')
00718
00719
00720 len_commands_profilers_meta_list=len(commands_profilers_meta_list)
00721
00722 commands_counter=1
00723 precedent_profile_name=''
00724 precedent_reuseprofile=False
00725 for command,profiler_opt,meta,reuseprofile,db_metastring in commands_profilers_meta_list:
00726
00727 exit_code=0
00728
00729 logger('Processing command %d/%d' \
00730 %(commands_counter,len_commands_profilers_meta_list))
00731 logger('Process started on %s' %time.asctime())
00732
00733
00734
00735 profile_name=''
00736 profiler=''
00737 reportdir=options.output
00738 IgProf_counter=options.IgProf_counter
00739
00740
00741 if options.infile!='':
00742
00743 reportdir='%s_%s' %(meta,options.output)
00744 reportdir=clean_name(reportdir)
00745
00746 profile_name=clean_name('%s_%s'%(meta,options.profile_name))
00747
00748
00749
00750 if profiler_opt.find('.')!=-1 and profiler_opt.find('IgProf')!=-1:
00751 profiler_opt_split=profiler_opt.split('.')
00752 profiler=profiler_opt_split[0]
00753 IgProf_counter=profiler_opt_split[1:]
00754 if profile_name[-3:]!='.gz':
00755 profile_name+='.gz'
00756
00757
00758 elif profiler_opt in STDOUTPROFILERS:
00759
00760 if profile_name[:-4]!='.log':
00761 profile_name+='.log'
00762 profiler=profiler_opt
00763
00764
00765 else:
00766 profiler=profiler_opt
00767
00768 if precedent_reuseprofile:
00769 profile_name=precedent_profile_name
00770 if reuseprofile:
00771 precedent_profile_name=profile_name
00772
00773
00774
00775 else:
00776 profile_name=options.profile_name
00777 reportdir=options.output
00778 profiler=options.profiler
00779
00780
00781
00782
00783 if precedent_profile_name!='':
00784 if os.path.exists(precedent_profile_name):
00785 logger('Reusing precedent profile: %s ...' %precedent_profile_name)
00786 if profile_name!=precedent_profile_name:
00787 logger('Copying the old profile to the new name %s ...' %profile_name)
00788 execute('cp %s %s' %(precedent_profile_name, profile_name))
00789
00790 performance_profile=Profile(command,
00791 profiler,
00792 profile_name)
00793
00794
00795 if options.profile:
00796 if reuseprofile:
00797 logger('Saving profile name to reuse it ...')
00798 precedent_profile_name=profile_name
00799 else:
00800 precedent_profile_name=''
00801
00802 if not precedent_reuseprofile:
00803 logger('Creating profile for command %d using %s ...' \
00804 %(commands_counter,profiler))
00805 exit_code=performance_profile.make_profile()
00806 print exit_code
00807 logger('The exit code was %s'%exit_code)
00808 exitCodeSum=exitCodeSum+exit_code
00809 logger('The exit code sum is %s'%exitCodeSum)
00810
00811
00812
00813 if options.report:
00814 if exit_code!=0:
00815 logger('Halting report creation procedure: unexpected exit code %s from %s ...' \
00816 %(exit_code,profiler))
00817 else:
00818 logger('Creating report for command %d using %s ...' \
00819 %(commands_counter,profiler))
00820
00821
00822 if options.db:
00823 exit_code=performance_profile.make_report(fill_db=True,
00824 db_name=options.output,
00825 metastring=db_metastring,
00826 tmp_dir=options.pr_temp,
00827 IgProf_option=IgProf_counter)
00828 exitCodeSum=exitCodeSum+exit_code
00829 else:
00830 exit_code=performance_profile.make_report(outdir=reportdir,
00831 tmp_dir=options.pr_temp,
00832 IgProf_option=IgProf_counter)
00833 exitCodeSum=exitCodeSum+exit_code
00834
00835 commands_counter+=1
00836 precedent_reuseprofile=reuseprofile
00837 if not precedent_reuseprofile:
00838 precedent_profile_name=''
00839
00840 logger('Process ended on %s\n' %time.asctime())
00841
00842 logger('Procedure finished on %s' %time.asctime())
00843 logger("Exit code sum is %s"%exitCodeSum)
00844 return exitCodeSum
00845
00846
00847
00848 if __name__=="__main__":
00849
00850 usage='\n'+\
00851 '----------------------------------------------------------------------------\n'+\
00852 ' RelValreport: a tool for automation of benchmarking and report generation. \n'+\
00853 '----------------------------------------------------------------------------\n\n'+\
00854 'relvalreport.py <options>\n'+\
00855 'relvalreport.py -i candles_150.txt -R -P -n 150.out -o 150_report\n'+\
00856 ' - Executes the candles contained in the file candles_150.txt, create\n'+\
00857 ' profiles, specified by -n, and reports, specified by -o.\n\n'+\
00858 'Candles file grammar:\n'+\
00859 'A candle is specified by the syntax:\n'+\
00860 'executable_name @@@ profiler_name @@@ meta\n'+\
00861 ' - executable_name: the name of the executable to benchmark.\n'+\
00862 ' - profiler_name: the name of the profiler to use. The available are: %s.\n' %str(PROFILERS)+\
00863 ' In case you want to use IgProf_mem or IgProf_perf, the counter (MEM_TOTAL,PERF_TICKS...)\n'+\
00864 ' must be added with a ".": IgProf_mem.MEM_TOTAL.\n'+\
00865 ' - meta: metastring that is used to change the name of the names specified in the command line\n'+\
00866 ' in case of batch execution.'+\
00867 'An example of candle file:\n\n'+\
00868 ' ># My list of candles:\n'+\
00869 ' >\n'+\
00870 ' >cmsDriver.py MU- -sSIM -e10_20 @@@ IgProf_perf.PERF_TICKS @@@ QCD_sim_IgProfperf\n'+\
00871 ' >cmsDriver.py MU- -sRECO -e10_20 @@@ ValgrindFCE @@@ QCD_reco_Valgrind\n'+\
00872 ' >cmsRun mycfg.cfg @@@ IgProf_mem.MEM_TOTAL @@@ Mycfg\n'
00873
00874
00875
00876 parser = optparse.OptionParser(usage)
00877
00878 parser.add_option('-p', '--profiler',
00879 help='Profilers are: %s' %str(PROFILERS) ,
00880 default='',
00881 dest='profiler')
00882
00883 parser.add_option('-c', '--command',
00884 help='Command to profile. If specified the infile is ignored.' ,
00885 default='',
00886 dest='command')
00887
00888 parser.add_option('-t',
00889 help='The temp directory to store the PR service files. Default is PR_TEMP Ignored if PR is not used.',
00890 default='',
00891 dest='pr_temp')
00892
00893
00894
00895 parser.add_option('--db',
00896 help='EXPERIMENTAL: Write results on the db.',
00897 action='store_true',
00898 default=False,
00899 dest='db')
00900
00901 parser.add_option('-R','--Report',
00902 help='Create a static html report. If db switch is on this is ignored.',
00903 action='store_true',
00904 default=False,
00905 dest='report')
00906
00907 parser.add_option('-P','--Profile',
00908 help='Create a profile for the selected profiler.',
00909 action='store_true',
00910 default=False,
00911 dest='profile')
00912
00913
00914
00915 parser.add_option('-n', '--profile_name',
00916 help='Profile name' ,
00917 default='',
00918 dest='profile_name')
00919
00920 parser.add_option('-o', '--output',
00921 help='Outdir for the html report or db filename.' ,
00922 default='',
00923 dest='output')
00924
00925
00926
00927 parser.add_option('-i', '--infile',
00928 help='Name of the ASCII file containing the commands to profile.' ,
00929 default='',
00930 dest='infile')
00931
00932
00933
00934 parser.add_option('-y',
00935 help='Specify the IgProf counter or the CMSSW. '+\
00936 'If a profiler different from '+\
00937 'IgProf is selected this is ignored.' ,
00938 default=None,
00939 dest='IgProf_counter')
00940
00941 parser.add_option('--executable',
00942 help='Specify executable to monitor if different from cmsRun. '+\
00943 'Only valid for IgProf.',
00944 default='',
00945 dest='executable')
00946
00947
00948 parser.add_option('--noexec',
00949 help='Do not exec commands, just display them!',
00950 action='store_true',
00951 default=False,
00952 dest='noexec')
00953
00954 (options,args) = parser.parse_args()
00955
00956
00957 if options.infile=='' and options.command=='' and not (options.report and not options.profile):
00958 raise('Specify at least one command to profile!')
00959 if options.profile_name=='' and options.infile=='':
00960 raise('Specify a profile name!')
00961 if not options.db and options.output=='' and options.infile=='':
00962 raise('Specify a db name or an output dir for the static report!')
00963
00964 if not options.profile:
00965 if not os.path.exists(options.profile_name) and options.infile=='':
00966 raise('Profile %s does not exist!' %options.profile_name)
00967 logger("WARNING: No profile will be generated. An existing one will be processed!")
00968
00969 if options.command!='' and options.infile!='':
00970 raise('-c and -i options cannot coexist!')
00971
00972 if options.profiler=='Memcheck_Valgrind' and not os.path.exists(VMPARSER):
00973 raise('Couldn\'t find Valgrind Memcheck Parser Script! Please install it from Utilities/ReleaseScripts.')
00974
00975 if options.executable!='':
00976 globals()['EXECUTABLE']=options.executable
00977
00978 if options.noexec:
00979 globals()['EXEC']=False
00980
00981 logger('Procedure started on %s' %time.asctime())
00982
00983 if options.infile == '':
00984 logger('Script options:')
00985 for key,val in options.__dict__.items():
00986 if val!='':
00987 logger ('\t\t|- %s = %s' %(key, str(val)))
00988 logger ('\t\t|')
00989 exit=principal(options)
00990 logger("Exit code received from principal is: %s"%exit)
00991
00992 if exit:
00993 exit=1
00994 sys.exit(exit)
00995