CMS 3D CMS Logo

cmsRelvalreport.py

Go to the documentation of this file.
00001 #! /usr/bin/env python
00002 
00003 r'''
00004 Relvalreport_v2: a script to run performance tests and produce reports in a automated way.
00005 '''
00006 
00007 
00008 # Configuration parameters:#############################################################
00009 
00010 # Perfreport 3 and 2 coordinates:
00011 PR3_BASE='/afs/cern.ch/user/d/dpiparo/w0/perfreport3installation/'
00012 PR3=PR3_BASE+'/bin/perfreport'# executable
00013 PERFREPORT3_PATH=PR3_BASE+'/share/perfreport' #path to xmls
00014 #PR3_PRODUCER_PLUGIN=PR3_BASE+'/lib/libcmssw_by_producer.so' #plugin for fpage
00015 PR3_PRODUCER_PLUGIN='/afs/cern.ch/user/d/dpiparo/w0/pr3/perfreport/plugins/cmssw_by_producer/libcmssw_by_producer.so'
00016 
00017 #PR2_BASE='/afs/cern.ch/user/d/dpiparo/w0/perfreport2.1installation/'
00018 PR2_BASE='/afs/cern.ch/user/g/gbenelli/public/PerfReport2/2.0.1/'
00019 PR2='%s' %(PR2_BASE+'/bin/perfreport')# executable
00020 PERFREPORT2_PATH=PR2_BASE+'/share/perfreport' #path to xmls
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 #Set the path depending on the presence of a locally checked out version of PyReleaseValidation
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 #Eliminating the full paths to all the scripts used they are assumed to be in the release by default, being in the scripts/ directory of their package    
00034 # Valgrind Memcheck Parser coordinates:
00035 #VMPARSER='%s/src/Utilities/ReleaseScripts/scripts/valgrindMemcheckParser.pl' %os.environ['CMSSW_RELEASE_BASE']#This has to always point to 'CMSSW_RELEASE_BASE'
00036 VMPARSER='valgrindMemcheckParser.pl'
00037 
00038 #Not a script... need to keep the full path to the release
00039 # Valgrind Memcheck Parser output style file coordinates:
00040 VMPARSERSTYLE='%s/src/Utilities/ReleaseScripts/data/valgrindMemcheckParser.css' %os.environ['CMSSW_RELEASE_BASE']#This has to always point to 'CMSSW_RELEASE_BASE'
00041 
00042 # IgProf_Analysis coordinates:
00043 #IGPROFANALYS='%s/src/Validation/Performance/scripts/cmsIgProf_Analysis.py'%os.environ[RELEASE]
00044 IGPROFANALYS='cmsIgProf_Analysis.py'
00045 
00046 # Timereport parser
00047 #TIMEREPORTPARSER='%s/src/Validation/Performance/scripts/cmsTimeReport.pl'%os.environ[RELEASE]
00048 TIMEREPORTPARSER='cmsTimeReport.pl'
00049 
00050 # Simple memory parser
00051 #SIMPLEMEMPARSER='%s/src/Validation/Performance/scripts/cmsSimplememchecker_parser.py' %os.environ[RELEASE]
00052 SIMPLEMEMPARSER='cmsSimplememchecker_parser.py'
00053 
00054 # Timing Parser
00055 #TIMINGPARSER='%s/src/Validation/Performance/scripts/cmsTiming_parser.py' %os.environ[RELEASE]
00056 TIMINGPARSER='cmsTiming_parser.py'
00057 
00058 # makeSkimDriver
00059 MAKESKIMDRIVERDIR='%s/src/Configuration/EventContent/test' %os.environ[RELEASE]
00060 MAKESKIMDRIVER='%s/makeSkimDriver.py'%MAKESKIMDRIVERDIR
00061 
00062 ########################################################################################
00063 
00064 
00065 # Library to include to run valgrind fce
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 # the profilers that use the stout of the app..
00072 STDOUTPROFILERS=['Memcheck_Valgrind',
00073                  'Timereport_Parser',
00074                  'Timing_Parser',
00075                  'SimpleMem_Parser']
00076 # Profilers list
00077 PROFILERS=['ValgrindFCE',
00078            'IgProf_perf',
00079            'IgProf_mem',
00080            'Edm_Size']+STDOUTPROFILERS
00081                             
00082 
00083 # name of the executable to benchmark. It can be different from cmsRun in future           
00084 EXECUTABLE='cmsRun'
00085 
00086 # Command execution and debug switches
00087 EXEC=True
00088 DEBUG=True
00089  
00090 import time   
00091 import optparse 
00092 import sys
00093 
00094 
00095 #######################################################################
00096 def red(string):
00097     return '%s%s%s' %('\033[1;31m',string,'\033[1;0m')    
00098 def green(string):
00099     return '%s%s%s' %('\033[1;32m',string,'\033[1;0m') 
00100 def yellow(string):
00101     return '%s%s%s' %('\033[1;33m',string,'\033[1;0m')     
00102 #######################################################################
00103 
00104 def clean_name(name):
00105     '''
00106     Trivially removes an underscore if present as last char of a string
00107     '''
00108     i=-1
00109     is_dirty=True
00110     while(is_dirty):
00111         if name[i]=='_':
00112             name=name[:-1]
00113         else:
00114             return name
00115         i-=1
00116 
00117 #######################################################################
00118 
00119 def execute(command):
00120         '''
00121         It executes command if the EXEC switch is True. 
00122         Catches exitcodes different from 0.
00123         '''
00124         logger('%s %s ' %(green('[execute]'),command))
00125         if EXEC:
00126             exit_code=os.system(command)
00127             if exit_code!=0:
00128                 logger(red('*** Seems like "%s" encountered problems.' %command))
00129             return exit_code
00130         else:
00131             return 0
00132             
00133 #######################################################################            
00134             
00135 def logger(message,level=0):
00136     '''
00137     level=0 output, level 1 debug.
00138     '''                  
00139     message='%s %s' %(yellow('[RelValreport]'),message)
00140     
00141     sys.stdout.flush()
00142     
00143     if level==0:
00144         print message
00145     if level==1 and DEBUG:
00146         print message    
00147     
00148     sys.stdout.flush()
00149 
00150 #######################################################################
00151 
00152 class Candles_file:
00153     '''
00154     Class to read the trivial ASCCI file containing the candles
00155     '''
00156     def __init__(self, filename):
00157         
00158         self.commands_profilers_meta_list=[]    
00159     
00160         candlesfile=open(filename,'r')
00161         
00162         if filename[-3:]=='xml':
00163             command=''
00164             profiler=''
00165             meta=''
00166             db_meta=''
00167             reuse=False    
00168             
00169             from xml.dom import minidom
00170             
00171             # parse the config
00172             xmldoc = minidom.parse(filename)
00173             
00174             # get the candles
00175             candles_list = xmldoc.getElementsByTagName('candle')
00176             
00177             # a list of dictionaries to store the info
00178             candles_dict_list=[]
00179             
00180             for candle in candles_list:
00181                 info_dict={}
00182                 for child in candle.childNodes:# iteration over candle node children
00183                     if not child.__dict__.has_key('nodeName'):# if just a text node skip!
00184                         #print 'CONTINUE!'
00185                         continue
00186                     # We pick the info from the node
00187                     tag_name=child.tagName
00188                     #print 'Manipulating a %s ...'%tag_name
00189                     data=child.firstChild.data
00190                     #print 'Found the data: %s !' %data
00191                     # and we put it in the dictionary
00192                     info_dict[tag_name]=data
00193                 # to store it in a list
00194                 candles_dict_list.append(info_dict)
00195             
00196             # and now process what was parsed
00197                         
00198             for candle_dict in candles_dict_list:
00199                 # compulsory params!!
00200                 command=candle_dict['command']
00201                 profiler=candle_dict['profiler']
00202                 meta=candle_dict['meta']
00203                 # other params
00204                 try:
00205                     db_meta=candle_dict['db_meta']
00206                 except:
00207                     db_meta=None
00208                 try:
00209                     reuse=candle_dict['reuse']
00210                 except:
00211                     reuse=False    
00212                             
00213                 self.commands_profilers_meta_list.append([command,profiler,meta,reuse,db_meta])
00214         
00215         # The file is a plain ASCII
00216         else:
00217             for candle in candlesfile.readlines():
00218                 # Some parsing of the file
00219                 if candle[0]!='#' and candle.strip(' \n\t')!='': # if not a comment or an empty line
00220                     if candle[-1]=='\n': #remove trail \n if it's there
00221                         candle=candle[:-1] 
00222                     splitted_candle=candle.split('@@@') #separate
00223                     
00224                     # compulsory fields
00225                     command=splitted_candle[0]
00226                     profiler=splitted_candle[1].strip(' \t')
00227                     meta=splitted_candle[2].strip(' \t')        
00228                     info=[command,profiler,meta]
00229                     
00230                     # FIXME: AN .ini or xml config??
00231                     # do we have something more?
00232                     len_splitted_candle=len(splitted_candle)
00233                     reuse=False
00234                     if len_splitted_candle>3:
00235                         # is it a reuse statement?
00236                         if 'reuse' in splitted_candle[3]:
00237                             reuse=True
00238                         info.append(reuse)
00239                     else:
00240                         info.append(reuse)               
00241                     
00242                     # we have one more field or we hadn't a reuse in the last one    
00243                     if len_splitted_candle>4 or (len_splitted_candle>3 and not reuse):
00244                         cmssw_scram_version_string=splitted_candle[-1].strip(' \t')
00245                         info.append(cmssw_scram_version_string)
00246                     else:
00247                         info.append(None)
00248     
00249                         
00250                     self.commands_profilers_meta_list.append(info)
00251                     
00252     #----------------------------------------------------------------------
00253         
00254     def get_commands_profilers_meta_list(self):
00255         return self.commands_profilers_meta_list
00256             
00257 #######################################################################
00258 
00259 class Profile:
00260     '''
00261     Class that represents the procedure of performance report creation
00262     '''
00263     def __init__(self,command,profiler,profile_name):
00264         self.command=command
00265         self.profile_name=profile_name
00266         self.profiler=profiler
00267     
00268     #------------------------------------------------------------------
00269     # edit here if more profilers added
00270     def make_profile(self):
00271         '''
00272         Launch the right function according to the profiler name.
00273         '''  
00274         if self.profiler=='ValgrindFCE':
00275             return self._profile_valgrindfce()
00276         elif self.profiler.find('IgProf')!=-1:
00277             return self._profile_igprof()    
00278         elif self.profiler.find('Edm_Size')!=-1:
00279             return self._profile_edmsize()
00280         elif self.profiler=='Memcheck_Valgrind':
00281             return self._profile_Memcheck_Valgrind()
00282         elif self.profiler=='Timereport_Parser':
00283             return self._profile_Timereport_Parser()
00284         elif self.profiler=='Timing_Parser':
00285             return self._profile_Timing_Parser()        
00286         elif self.profiler=='SimpleMem_Parser':
00287             return self._profile_SimpleMem_Parser()
00288         elif self.profiler=='':
00289             return self._profile_None()
00290         elif self.profiler=='None': #adding this for the case of candle ASCII file non-profiling commands
00291             return self._profile_None()
00292         else:
00293             raise('No %s profiler found!' %self.profiler)
00294     #------------------------------------------------------------------
00295     def _profile_valgrindfce(self):
00296         '''
00297         Valgrind profile launcher.
00298         '''
00299         # ValgrindFCE needs a special library to run
00300         os.environ["VALGRIND_LIB"]=VFCE_LIB
00301         
00302         profiler_line=''
00303         valgrind_options= 'time valgrind '+\
00304                           '--tool=callgrind '+\
00305                           '--fce=%s ' %(self.profile_name)
00306         
00307         # If we are using cmsDriver we should use the prefix switch        
00308         if EXECUTABLE=='cmsRun' and self.command.find('cmsDriver.py')!=-1:
00309             profiler_line='%s --prefix "%s"' %(self.command,valgrind_options)
00310                             
00311         else:                          
00312             profiler_line='%s %s' %(valgrind_options,self.command)
00313                         #'--trace-children=yes '+\
00314         
00315         return execute(profiler_line)
00316     
00317     #------------------------------------------------------------------
00318     def _profile_igprof(self): 
00319         '''
00320         IgProf profiler launcher.
00321         '''
00322         profiler_line=''
00323         
00324         igprof_options='igprof -d -t %s ' \
00325                     %EXECUTABLE # IgProf profile not general only for CMSRUN!
00326         
00327         # To handle Igprof memory and performance profiler in one function
00328         if self.profiler=='IgProf_perf':
00329             igprof_options+='-pp '
00330         elif self.profiler=='IgProf_mem':
00331             igprof_options+='-mp '
00332         else:
00333             raise ('Unknown IgProf flavour: %s !'%self.profiler)
00334         
00335         igprof_options+='-z -o %s' %(self.profile_name)
00336         
00337         # If we are using cmsDriver we should use the prefix switch 
00338         if EXECUTABLE=='cmsRun' and self.command.find('cmsDriver.py')!=-1:
00339             profiler_line='%s --prefix "%s"' %(self.command,igprof_options) 
00340         else:
00341             profiler_line='%s %s' %(igprof_options, self.command)  
00342             
00343         return execute(profiler_line)
00344     
00345     #------------------------------------------------------------------
00346     
00347     def _profile_edmsize(self):
00348         '''
00349         Launch edm size profiler
00350         '''
00351         # In this case we replace the name to be clear
00352         input_rootfile=self.command
00353         
00354         # Skim the content if requested!
00355         if '.' in self.profiler:
00356             
00357             clean_profiler_name,options=self.profiler.split('.')
00358             content,nevts=options.split(',')
00359             outfilename='%s_%s.root'%(os.path.basename(self.command)[:-6],content)
00360             oldpypath=os.environ['PYTHONPATH']
00361             os.environ['PYTHONPATH']+=':%s' %MAKESKIMDRIVERDIR
00362             execute('%s -i %s -o %s --outputcommands %s -n %s' %(MAKESKIMDRIVER,
00363                                                                  self.command,
00364                                                                  outfilename,
00365                                                                  content,
00366                                                                  nevts)) 
00367             os.environ['PYTHONPATH']=oldpypath
00368             #execute('rm %s' %outfilename)
00369             self.command=outfilename
00370             self.profiler=clean_profiler_name
00371                                                                                                         
00372         
00373         profiler_line='edmEventSize -o %s -d %s'\
00374                             %(self.profile_name,self.command)
00375         
00376         return execute(profiler_line)
00377    
00378    #------------------------------------------------------------------
00379    
00380     def _profile_Memcheck_Valgrind(self):
00381         '''
00382         Valgrind Memcheck profile launcher
00383         '''
00384         profiler_line=''
00385         valgrind_options='time valgrind --tool=memcheck '+\
00386                                '--leak-check=yes '+\
00387                                '--show-reachable=yes '+\
00388                                '--num-callers=20 '+\
00389                                '--track-fds=yes '
00390         
00391         # If we are using cmsDriver we should use the prefix switch        
00392         if EXECUTABLE=='cmsRun' and self.command.find('cmsDriver.py')!=-1:
00393             #Replacing 2>&1 |tee with >& in the shell command to preserve the return code significance:
00394             # using tee return would be 0 even if the command failed before the pipe:
00395             profiler_line='%s --prefix "%s" >& %s' %(self.command,valgrind_options,self.profile_name)
00396                             
00397         else:                          
00398             profiler_line='%s %s >& %s' %(valgrind_options,self.command,self.profile_name)
00399                         #'--trace-children=yes '+\
00400         return execute(profiler_line)
00401     #-------------------------------------------------------------------
00402     
00403     def _profile_Timereport_Parser(self):
00404         return self._save_output()
00405         
00406     #-------------------------------------------------------------------
00407     
00408     def _profile_SimpleMem_Parser(self):
00409         return self._save_output()
00410 
00411     #-------------------------------------------------------------------
00412     
00413     def _profile_Timing_Parser(self):
00414         return self._save_output()     
00415     
00416     #-------------------------------------------------------------------
00417         
00418     def _save_output(self):
00419         '''
00420         Save the output of cmsRun on a file!
00421         '''               
00422 #         # a first maquillage about the profilename:
00423 #         if self.profile_name[-4:]!='.log':
00424 #             self.profile_name+='.log'
00425         #Replacing 2>&1 |tee with >& in the shell command to preserve the return code significance:
00426         # using tee return would be 0 even if the command failed before the pipe:
00427         profiler_line='%s  >& %s' %(self.command,self.profile_name)
00428         return execute(profiler_line)    
00429 
00430     #-------------------------------------------------------------------                    
00431     
00432     def _profile_None(self):
00433         '''
00434         Just Run the command!
00435         '''
00436         return execute(self.command)
00437     
00438     #-------------------------------------------------------------------
00439     
00440     def make_report(self,
00441                     fill_db=False,
00442                     db_name=None,
00443                     tmp_dir=None,
00444                     outdir=None,
00445                     IgProf_option=None,
00446                     metastring=None):
00447         '''
00448         Make a performance report with perfreport 3 or 2. PR2 will be no longer supported in future.
00449         '''
00450 
00451         
00452         if outdir==None or outdir==self.profile_name:
00453             outdir=self.profile_name+'_outdir'            
00454                   
00455         if not os.path.exists(outdir) and not fill_db:
00456             execute('mkdir %s' %outdir)
00457         
00458         if fill_db:
00459             db_option='-a'
00460             if not os.path.exists(db_name):
00461                 db_option='-A'
00462         
00463         # temp in the local dir for PR
00464         tmp_switch=''    
00465         if tmp_dir!='':
00466             execute('mkdir %s' %tmp_dir)
00467             tmp_switch=' -t %s' %tmp_dir
00468         
00469         # Profiler is ValgrindFCE:
00470         if self.profiler=='ValgrindFCE':
00471             perfreport_command=''
00472             # Switch for filling the db
00473             if not fill_db:
00474                 os.environ["PERFREPORT_PATH"]='%s/' %PERFREPORT2_PATH
00475                 perfreport_command='%s %s -ff -i %s -o %s' %(PR2,
00476                                                              tmp_switch,
00477                                                              self.profile_name,
00478                                                              outdir)
00479             else:
00480                 os.environ["PERFREPORT_PATH"]='%s/' %PERFREPORT3_PATH
00481                 perfreport_command='%s %s -n5000 -u%s  -ff  -m \'scram_cmssw_version_string,%s\' -i %s %s -o %s' \
00482                                                     %(PR3,
00483                                                       tmp_switch,
00484                                                       PR3_PRODUCER_PLUGIN,
00485                                                       metastring,
00486                                                       self.profile_name,
00487                                                       db_option,
00488                                                       db_name)
00489             return execute(perfreport_command)
00490         
00491         #####################################################################            
00492             
00493         # Profiler is IgProf:
00494         if self.profiler.find('IgProf')!=-1:
00495             if IgProf_option!='ANALYSE':
00496                 uncompressed_profile_name=self.profile_name[:-3]+'_uncompressed'
00497                 execute('gzip -d -c %s > %s' %(self.profile_name,uncompressed_profile_name))
00498                 perfreport_command=''
00499                 # Switch for filling the db
00500                 if not fill_db:
00501                     os.environ["PERFREPORT_PATH"]='%s/' %PERFREPORT2_PATH
00502                     perfreport_command='%s %s -fi -y %s -i %s -o %s' \
00503                                     %(PR2,
00504                                       tmp_switch,
00505                                       IgProf_option,
00506                                       uncompressed_profile_name,
00507                                       outdir)
00508                 else:
00509                     os.environ["PERFREPORT_PATH"]='%s/' %PERFREPORT3_PATH
00510                     perfreport_command='%s %s -n5000 -u%s  -fi -m \'scram_cmssw_version_string,%s\' -y %s -i %s %s -o %s' \
00511                                     %(PR3,
00512                                       tmp_switch,
00513                                       PR3_PRODUCER_PLUGIN,
00514                                       metastring,
00515                                       IgProf_option,
00516                                       uncompressed_profile_name,
00517                                       db_option,db_name)            
00518                 
00519                 exit=execute(perfreport_command)
00520                 execute('rm  %s' %uncompressed_profile_name)
00521                 return exit
00522             else: #We use IgProf Analisys
00523                 return execute('%s -o%s -i%s' %(IGPROFANALYS,outdir,self.profile_name))
00524                 
00525 
00526         #####################################################################                     
00527             
00528         # Profiler is EdmSize:        
00529         if 'Edm_Size' in self.profiler:
00530             perfreport_command=''
00531             if not fill_db:
00532                 os.environ["PERFREPORT_PATH"]='%s/' \
00533                                             %PERFREPORT2_PATH
00534                 perfreport_command='%s %s -fe -i %s -o %s' \
00535                                             %(PR2,
00536                                               tmp_switch,
00537                                               self.profile_name,
00538                                               outdir)
00539             else:
00540                 os.environ["PERFREPORT_PATH"]='%s/' \
00541                                             %PERFREPORT3_PATH
00542                 perfreport_command='%s %s -n5000 -u%s -fe -i %s -a -o %s' \
00543                                             %(PR3,
00544                                               tmp_switch,
00545                                               PR3_PRODUCER_PLUGIN,
00546                                               self.profile_name,
00547                                               db_name)             
00548 
00549             return execute(perfreport_command)    
00550 
00551         #FIXME: probably need to move this somewhere else now that we use return statements
00552         if tmp_dir!='':
00553             execute('rm -r %s' %tmp_dir)
00554             
00555         #####################################################################    
00556                             
00557         # Profiler is Valgrind Memcheck
00558         if self.profiler=='Memcheck_Valgrind':
00559             # Three pages will be produced:
00560             os.environ['PERL5LIB']=PERL5_LIB
00561             report_coordinates=(VMPARSER,self.profile_name,outdir)
00562             # Copy the Valgrind Memcheck parser style file in the outdir
00563             copyStyleFile='cp -pR %s %s'%(VMPARSERSTYLE,outdir)
00564             execute(copyStyleFile)
00565             report_commands=('%s --preset +prod,-prod1 %s > %s/edproduce.html'\
00566                                 %report_coordinates,
00567                              '%s --preset +prod1 %s > %s/esproduce.html'\
00568                                 %report_coordinates,
00569                              '%s -t beginJob %s > %s/beginjob.html'\
00570                                 %report_coordinates)
00571             exit=0
00572             for command in report_commands:
00573                 exit= exit + execute(command)      
00574             return exit
00575         #####################################################################                
00576                 
00577         # Profiler is TimeReport parser
00578         
00579         if self.profiler=='Timereport_Parser':
00580             return execute('%s %s %s' %(TIMEREPORTPARSER,self.profile_name,outdir))
00581 
00582         #####################################################################
00583         
00584         # Profiler is Timing Parser            
00585         
00586         if self.profiler=='Timing_Parser':
00587             return execute('%s -i %s -o %s' %(TIMINGPARSER,self.profile_name,outdir))
00588         
00589                     
00590         #####################################################################
00591         
00592         # Profiler is Simple memory parser
00593         
00594         if self.profiler=='SimpleMem_Parser':
00595             return execute('%s -i %s -o %s' %(SIMPLEMEMPARSER,self.profile_name,outdir))
00596             
00597         #####################################################################
00598         
00599         # no profiler
00600             
00601         if self.profiler=='' or self.profiler=='None': #Need to catch the None case, since otherwise we get no return code (crash for pre-requisite step running).
00602             return 0         #Used to be pass, but we need a return 0 to handle exit code properly!         
00603                                                                 
00604 #############################################################################################
00605 
00606 def principal(options):
00607     '''
00608     Here the objects of the Profile class are istantiated.
00609     '''
00610     #Add a global exit code variable, that is the sum of all exit codes, to return it at the end:
00611     exitCodeSum=0
00612     # Build a list of commands for programs to benchmark.
00613     # It will be only one if -c option is selected
00614     commands_profilers_meta_list=[]
00615     
00616     # We have only one
00617     if options.infile=='':
00618         logger('Single command found...')
00619         commands_profilers_meta_list.append([options.command,'','',False,''])
00620     
00621     # We have more: we parse the list of candles    
00622     else:
00623         logger('List of commands found. Processing %s ...' %options.infile)
00624         
00625         # an objects that represents the cndles file:
00626         candles_file = Candles_file(options.infile)
00627         
00628         commands_profilers_meta_list=candles_file.get_commands_profilers_meta_list()
00629        
00630         
00631     logger('Iterating through commands of executables to profile ...')
00632     
00633     # Cycle through the commands
00634     len_commands_profilers_meta_list=len(commands_profilers_meta_list)    
00635     
00636     commands_counter=1
00637     precedent_profile_name=''
00638     precedent_reuseprofile=False
00639     for command,profiler_opt,meta,reuseprofile,db_metastring in commands_profilers_meta_list:
00640                   
00641         exit_code=0
00642         
00643         logger('Processing command %d/%d' \
00644                     %(commands_counter,len_commands_profilers_meta_list))
00645         logger('Process started on %s' %time.asctime())
00646         
00647         # for multiple directories and outputs let's put the meta
00648         # just before the output profile and the outputdir
00649         profile_name=''
00650         profiler=''
00651         reportdir=options.output
00652         IgProf_counter=options.IgProf_counter
00653            
00654         
00655         if options.infile!='': # we have a list of commands
00656 
00657             reportdir='%s_%s' %(meta,options.output)
00658             reportdir=clean_name(reportdir)                        
00659          
00660             profile_name=clean_name('%s_%s'%(meta,options.profile_name))
00661                     
00662             # profiler is igprof: we need to disentangle the profiler and the counter
00663             if profiler_opt.find('.')!=-1 and \
00664                profiler_opt.find('IgProf')!=-1:
00665                 profiler_opt_split=profiler_opt.split('.')
00666                 profiler,IgProf_counter=profiler_opt_split
00667                 if profile_name[-3:]!='.gz':
00668                     profile_name+='.gz'
00669                     
00670             elif profiler_opt.find('MEM_TOTAL')!=-1 or\
00671                  profiler_opt.find('MEM_LIVE')!=-1 or\
00672                  profiler_opt.find('MEM_PEAK')!=-1: 
00673                 profiler='IgProf_mem'
00674                 IgProf_counter=profiler_opt
00675 
00676 
00677                 if profile_name[-3:]!='.gz':
00678                     profile_name+='.gz'
00679             
00680             # Profiler is Timereport_Parser
00681             elif profiler_opt in STDOUTPROFILERS:
00682                 # a first maquillage about the profilename:
00683                 if profile_name[:-4]!='.log':
00684                     profile_name+='.log'
00685                 profiler=profiler_opt
00686                         
00687             # profiler is not igprof
00688             else:
00689                 profiler=profiler_opt
00690             
00691             if precedent_reuseprofile:
00692                 profile_name=precedent_profile_name
00693             if reuseprofile:
00694                 precedent_profile_name=profile_name 
00695 
00696                                 
00697                         
00698         else: # we have a single command: easy job!
00699             profile_name=options.profile_name
00700             reportdir=options.output
00701             profiler=options.profiler
00702 
00703         
00704         
00705         # istantiate a Profile object    
00706         if precedent_profile_name!='':
00707             if os.path.exists(precedent_profile_name):
00708                 logger('Reusing precedent profile: %s ...' %precedent_profile_name)
00709                 logger('Copying the old profile to the new name %s ...' %profile_name)
00710                 execute('cp %s %s' %(precedent_profile_name, profile_name))
00711                 
00712         performance_profile=Profile(command,
00713                                     profiler,
00714                                     profile_name)   
00715 
00716         # make profile if needed
00717         if options.profile:                                         
00718             if reuseprofile:
00719                 logger('Saving profile name to reuse it ...')
00720                 precedent_profile_name=profile_name
00721             else:
00722                 precedent_profile_name=''                                
00723             
00724             if not precedent_reuseprofile:
00725                 logger('Creating profile for command %d using %s ...' \
00726                                                 %(commands_counter,profiler))     
00727                 exit_code=performance_profile.make_profile()
00728                 print exit_code
00729                 logger('The exit code was %s'%exit_code)
00730                 exitCodeSum=exitCodeSum+exit_code #Add all exit codes into the global exitCodeSum in order to return it on cmsRelvareport.py exit.
00731                 logger('The exit code sum is %s'%exitCodeSum)
00732             
00733         
00734         # make report if needed   
00735         if options.report:
00736             if exit_code!=0:
00737                 logger('Halting report creation procedure: unexpected exit code %s from %s ...' \
00738                                             %(exit_code,profiler))
00739             else:   
00740                 logger('Creating report for command %d using %s ...' \
00741                                                 %(commands_counter,profiler))     
00742                                                
00743                 # Write into the db instead of producing html if this is the case:
00744                 if options.db:
00745                     exit_code=performance_profile.make_report(fill_db=True,
00746                                                     db_name=options.output,
00747                                                     metastring=db_metastring,
00748                                                     tmp_dir=options.pr_temp,
00749                                                     IgProf_option=IgProf_counter)
00750                     exitCodeSum=exitCodeSum+exit_code #this is to also check that the reporting works... a little more ambitious testing... could do without for release integration
00751                 else:
00752                     exit_code=performance_profile.make_report(outdir=reportdir,
00753                                                     tmp_dir=options.pr_temp,
00754                                                     IgProf_option=IgProf_counter)
00755                     exitCodeSum=exitCodeSum+exit_code #this is to also check that the reporting works... a little more ambitious testing... could do without for release integration
00756                     
00757         commands_counter+=1                                                
00758         precedent_reuseprofile=reuseprofile
00759         if not precedent_reuseprofile:
00760             precedent_profile_name=''
00761         
00762         logger('Process ended on %s\n' %time.asctime())
00763     
00764     logger('Procedure finished on %s' %time.asctime())
00765     logger("Exit code sum is %s"%exitCodeSum)
00766     return exitCodeSum
00767 
00768 ###################################################################################################    
00769         
00770 if __name__=="__main__":
00771 
00772     usage='\n'+\
00773           '----------------------------------------------------------------------------\n'+\
00774           ' RelValreport: a tool for automation of benchmarking and report generation. \n'+\
00775           '----------------------------------------------------------------------------\n\n'+\
00776           'relvalreport.py <options>\n'+\
00777           'relvalreport.py -i candles_150.txt -R -P -n 150.out -o 150_report\n'+\
00778           ' - Executes the candles contained in the file candles_150.txt, create\n'+\
00779           '   profiles, specified by -n, and reports, specified by -o.\n\n'+\
00780           'Candles file grammar:\n'+\
00781           'A candle is specified by the syntax:\n'+\
00782           'executable_name @@@ profiler_name @@@ meta\n'+\
00783           ' - executable_name: the name of the executable to benchmark.\n'+\
00784           ' - profiler_name: the name of the profiler to use. The available are: %s.\n' %str(PROFILERS)+\
00785           '   In case you want to use IgProf_mem or IgProf_perf, the counter (MEM_TOTAL,PERF_TICKS...)\n'+\
00786           '   must be added with a ".": IgProf_mem.MEM_TOTAL.\n'+\
00787           ' - meta: metastring that is used to change the name of the names specified in the command line\n'+\
00788           '   in case of batch execution.'+\
00789           'An example of candle file:\n\n'+\
00790           '  ># My list of candles:\n'+\
00791           '  >\n'+\
00792           '  >cmsDriver.py MU- -sSIM  -e10_20 @@@ IgProf_perf.PERF_TICKS @@@ QCD_sim_IgProfperf\n'+\
00793           '  >cmsDriver.py MU- -sRECO -e10_20 @@@ ValgrindFCE            @@@ QCD_reco_Valgrind\n'+\
00794           '  >cmsRun mycfg.cfg                @@@ IgProf_mem.MEM_TOTAL   @@@ Mycfg\n'
00795              
00796              
00797 
00798     parser = optparse.OptionParser(usage)
00799 
00800     parser.add_option('-p', '--profiler',
00801                       help='Profilers are: %s' %str(PROFILERS) ,
00802                       default='',
00803                       dest='profiler')
00804                                             
00805     parser.add_option('-c', '--command',
00806                       help='Command to profile. If specified the infile is ignored.' ,
00807                       default='',
00808                       dest='command') 
00809                       
00810     parser.add_option('-t',
00811                       help='The temp directory to store the PR service files. Default is PR_TEMP Ignored if PR is not used.',
00812                       default='',
00813                       dest='pr_temp')
00814     
00815     #Flags                      
00816                       
00817     parser.add_option('--db',
00818                       help='EXPERIMENTAL: Write results on the db.',
00819                       action='store_true',
00820                       default=False,
00821                       dest='db')               
00822 
00823     parser.add_option('-R','--Report',
00824                       help='Create a static html report. If db switch is on this is ignored.',
00825                       action='store_true',
00826                       default=False,
00827                       dest='report')                      
00828     
00829     parser.add_option('-P','--Profile',
00830                       help='Create a profile for the selected profiler.',
00831                       action='store_true',
00832                       default=False,
00833                       dest='profile')                        
00834     
00835     # Output location for profile and report                      
00836     
00837     parser.add_option('-n', '--profile_name',
00838                       help='Profile name' ,
00839                       default='',
00840                       dest='profile_name') 
00841                                                                                                                             
00842     parser.add_option('-o', '--output',
00843                       help='Outdir for the html report or db filename.' ,
00844                       default='',
00845                       dest='output')
00846                       
00847     #Batch functionality                       
00848                                                
00849     parser.add_option('-i', '--infile',
00850                       help='Name of the ASCII file containing the commands to profile.' ,
00851                       default='',
00852                       dest='infile')    
00853     
00854     # ig prof options
00855 
00856     parser.add_option('-y', 
00857                       help='Specify the IgProf counter or the CMSSW. '+\
00858                            'If a profiler different from '+\
00859                            'IgProf is selected this is ignored.' ,
00860                       default='PERF_TICKS',
00861                       dest='IgProf_counter')                        
00862                       
00863     parser.add_option('--executable',
00864                       help='Specify executable to monitor if different from cmsRun. '+\
00865                            'Only valid for IgProf.',
00866                       default='',
00867                       dest='executable')                               
00868               
00869     # Debug options
00870     parser.add_option('--noexec',
00871                       help='Do not exec commands, just display them!',
00872                       action='store_true',
00873                       default=False,
00874                       dest='noexec')   
00875                                         
00876     (options,args) = parser.parse_args()
00877     
00878     # FAULT CONTROLS
00879     if options.infile=='' and options.command=='' and not (options.report and not options.profile):
00880         raise('Specify at least one command to profile!')
00881     if options.profile_name=='' and options.infile=='':
00882         raise('Specify a profile name!')
00883     if not options.db and options.output=='' and options.infile=='':
00884         raise('Specify a db name or an output dir for the static report!')
00885     
00886     if not options.profile:
00887         if not os.path.exists(options.profile_name) and options.infile=='':
00888             raise('Profile %s does not exist!' %options.profile_name)
00889         logger("WARNING: No profile will be generated. An existing one will be processed!")
00890     
00891     if options.command!='' and options.infile!='':
00892         raise('-c and -i options cannot coexist!')    
00893     
00894     if options.profiler=='Memcheck_Valgrind' and not os.path.exists(VMPARSER):
00895         raise('Couldn\'t find Valgrind Memcheck Parser Script! Please install it from Utilities/ReleaseScripts.')
00896             
00897     if options.executable!='':
00898         globals()['EXECUTABLE']=options.executable
00899     
00900     if options.noexec:
00901         globals()['EXEC']=False
00902         
00903     logger('Procedure started on %s' %time.asctime())                               
00904     
00905     if options.infile == '':
00906         logger('Script options:')
00907         for key,val in options.__dict__.items():
00908             if val!='':
00909                 logger ('\t\t|- %s = %s' %(key, str(val)))
00910                 logger ('\t\t|')
00911     exit=principal(options)
00912     logger("Exit code received from principal is: %s"%exit)
00913     #Mind you! exit codes in Linux are all 0 if they are even! We can easily make the code 1
00914     if exit: #This is different than 0 only if there have been at least one non-zero exit(return) code in the cmsRelvalreport.py
00915         exit=1
00916     sys.exit(exit)
00917                 

Generated on Tue Jun 9 17:49:26 2009 for CMSSW by  doxygen 1.5.4