CMS 3D CMS Logo

Public Member Functions | Public Attributes | Private Member Functions

cmsRelvalreport::Profile Class Reference

List of all members.

Public Member Functions

def __init__
def make_profile
def make_report

Public Attributes

 command
 profile_name
 profiler

Private Member Functions

def _profile_edmsize
def _profile_igprof
def _profile_Memcheck_Valgrind
def _profile_None
def _profile_SimpleMem_Parser
def _profile_Timereport_Parser
def _profile_Timing_Parser
def _profile_valgrindfce
def _save_output

Detailed Description

Class that represents the procedure of performance report creation

Definition at line 269 of file cmsRelvalreport.py.


Constructor & Destructor Documentation

def cmsRelvalreport::Profile::__init__ (   self,
  command,
  profiler,
  profile_name 
)

Definition at line 273 of file cmsRelvalreport.py.

00274                                                     :
00275         self.command=command
00276         self.profile_name=profile_name
00277         self.profiler=profiler
    

Member Function Documentation

def cmsRelvalreport::Profile::_profile_edmsize (   self) [private]
Launch edm size profiler

Definition at line 356 of file cmsRelvalreport.py.

00357                               :
00358         '''
00359         Launch edm size profiler
00360         '''
00361         # In this case we replace the name to be clear
00362         input_rootfile=self.command
00363         
00364         # Skim the content if requested!
00365         if '.' in self.profiler:
00366             
00367             clean_profiler_name,options=self.profiler.split('.')
00368             content,nevts=options.split(',')
00369             outfilename='%s_%s.root'%(os.path.basename(self.command)[:-6],content)
00370             oldpypath=os.environ['PYTHONPATH']
00371             os.environ['PYTHONPATH']+=':%s' %MAKESKIMDRIVERDIR
00372             execute('%s -i %s -o %s --outputcommands %s -n %s' %(MAKESKIMDRIVER,
00373                                                                  self.command,
00374                                                                  outfilename,
00375                                                                  content,
00376                                                                  nevts)) 
00377             os.environ['PYTHONPATH']=oldpypath
00378             #execute('rm %s' %outfilename)
00379             self.command=outfilename
00380             self.profiler=clean_profiler_name
00381                                                                                                         
00382         
00383         profiler_line='edmEventSize -o %s -d %s'\
00384                             %(self.profile_name,self.command)
00385         
00386         return execute(profiler_line)
   
def cmsRelvalreport::Profile::_profile_igprof (   self) [private]
IgProf profiler launcher.

Definition at line 328 of file cmsRelvalreport.py.

00328                              : 
00329         '''
00330         IgProf profiler launcher.
00331         '''
00332         profiler_line=''
00333         
00334         igprof_options='igprof -d -t %s ' \
00335                     %EXECUTABLE # IgProf profile not general only for CMSRUN!
00336         
00337         # To handle Igprof memory and performance profiler in one function
00338         if self.profiler=='IgProf_perf':
00339             igprof_options+='-pp '
00340         elif self.profiler=='IgProf_mem':
00341             igprof_options+='-mp '
00342         else:
00343             raise ('Unknown IgProf flavour: %s !'%self.profiler)
00344         igprof_options+='-z -o %s' %(self.profile_name)
00345         
00346         # If we are using cmsDriver we should use the prefix switch 
00347         if EXECUTABLE=='cmsRun' and self.command.find('cmsDriver.py')!=-1:
00348             profiler_line='%s --prefix "%s"' %(self.command,igprof_options) 
00349         else:
00350             profiler_line='%s %s' %(igprof_options, self.command)  
00351             
00352         return execute(profiler_line)
00353     
def cmsRelvalreport::Profile::_profile_Memcheck_Valgrind (   self) [private]
Valgrind Memcheck profile launcher

Definition at line 389 of file cmsRelvalreport.py.

00390                                         :
00391         '''
00392         Valgrind Memcheck profile launcher
00393         '''
00394         profiler_line=''
00395         #Adding cms suppression of useless messages (cmsvgsupp)
00396         #Removing leak-checking (done with igprof)
00397         #'--leak-check=no '+\ (no is the default)
00398         #'--show-reachable=yes '+\
00399         #'--track-fds=yes '
00400         #Adding xml logging
00401         xmlFileName = self.profile_name.replace(",","-")[:-4] + ".xml"
00402         valgrind_options='time valgrind --track-origins=yes '+\
00403                                '--tool=memcheck `cmsvgsupp` '+\
00404                                '--num-callers=20 '+\
00405                                '--xml=yes '+\
00406                                '--xml-file=%s '%xmlFileName
00407         
00408         # If we are using cmsDriver we should use the prefix switch        
00409         if EXECUTABLE=='cmsRun' and self.command.find('cmsDriver.py')!=-1:
00410             #Replacing 2>&1 |tee with >& in the shell command to preserve the return code significance:
00411             # using tee return would be 0 even if the command failed before the pipe:
00412             profiler_line='%s --prefix "%s" >& %s' %(self.command,valgrind_options,self.profile_name)
00413                             
00414         else:                          
00415             profiler_line='%s %s >& %s' %(valgrind_options,self.command,self.profile_name)
00416                         #'--trace-children=yes '+\
00417         exec_status = execute(profiler_line)
00418 
00419         # compact the xml by removing the Leak_* errors
00420         if not exec_status:
00421             newFileName = xmlFileName.replace('valgrind.xml', 'vlgd.xml')
00422             compactCmd = 'xsltproc --output %s %s/test/filterOutValgrindLeakErrors.xsl %s' %(newFileName, valperf, xmlFileName)
00423             execute(compactCmd)
00424         
        return exec_status
def cmsRelvalreport::Profile::_profile_None (   self) [private]
Just Run the command!

Definition at line 456 of file cmsRelvalreport.py.

00457                            :
00458         '''
00459         Just Run the command!
00460         '''
00461         return execute(self.command)
    
def cmsRelvalreport::Profile::_profile_SimpleMem_Parser (   self) [private]

Definition at line 432 of file cmsRelvalreport.py.

00433                                        :
00434         return self._save_output()

def cmsRelvalreport::Profile::_profile_Timereport_Parser (   self) [private]

Definition at line 427 of file cmsRelvalreport.py.

00428                                         :
00429         return self._save_output()
        
def cmsRelvalreport::Profile::_profile_Timing_Parser (   self) [private]

Definition at line 437 of file cmsRelvalreport.py.

00438                                     :
00439         return self._save_output()     
    
def cmsRelvalreport::Profile::_profile_valgrindfce (   self) [private]
Valgrind profile launcher.

Definition at line 305 of file cmsRelvalreport.py.

00306                                   :
00307         '''
00308         Valgrind profile launcher.
00309         '''
00310         # ValgrindFCE needs a special library to run
00311         os.environ["VALGRIND_LIB"]=VFCE_LIB
00312         
00313         profiler_line=''
00314         valgrind_options= 'time valgrind '+\
00315                           '--tool=callgrind '+\
00316                           '--fce=%s ' %(self.profile_name)
00317         
00318         # If we are using cmsDriver we should use the prefix switch        
00319         if EXECUTABLE=='cmsRun' and self.command.find('cmsDriver.py')!=-1:
00320             profiler_line='%s --prefix "%s"' %(self.command,valgrind_options)
00321                             
00322         else:                          
00323             profiler_line='%s %s' %(valgrind_options,self.command)
00324                         #'--trace-children=yes '+\
00325         
00326         return execute(profiler_line)
    
def cmsRelvalreport::Profile::_save_output (   self) [private]
Save the output of cmsRun on a file!

Definition at line 442 of file cmsRelvalreport.py.

00443                           :
00444         '''
00445         Save the output of cmsRun on a file!
00446         '''               
00447 #         # a first maquillage about the profilename:
00448 #         if self.profile_name[-4:]!='.log':
00449 #             self.profile_name+='.log'
00450         #Replacing 2>&1 |tee with >& in the shell command to preserve the return code significance:
00451         # using tee return would be 0 even if the command failed before the pipe:
00452         profiler_line='%s  >& %s' %(self.command,self.profile_name)
00453         return execute(profiler_line)    

def cmsRelvalreport::Profile::make_profile (   self)
Launch the right function according to the profiler name.

Definition at line 280 of file cmsRelvalreport.py.

00281                           :
00282         '''
00283         Launch the right function according to the profiler name.
00284         '''  
00285         if self.profiler=='ValgrindFCE':
00286             return self._profile_valgrindfce()
00287         elif self.profiler.find('IgProf')!=-1:
00288             return self._profile_igprof()    
00289         elif self.profiler.find('Edm_Size')!=-1:
00290             return self._profile_edmsize()
00291         elif self.profiler=='Memcheck_Valgrind':
00292             return self._profile_Memcheck_Valgrind()
00293         elif self.profiler=='Timereport_Parser':
00294             return self._profile_Timereport_Parser()
00295         elif self.profiler=='Timing_Parser':
00296             return self._profile_Timing_Parser()        
00297         elif self.profiler=='SimpleMem_Parser':
00298             return self._profile_SimpleMem_Parser()
00299         elif self.profiler=='':
00300             return self._profile_None()
00301         elif self.profiler=='None': #adding this for the case of candle ASCII file non-profiling commands
00302             return self._profile_None()
00303         else:
            raise('No %s profiler found!' %self.profiler)
def cmsRelvalreport::Profile::make_report (   self,
  fill_db = False,
  db_name = None,
  tmp_dir = None,
  outdir = None,
  IgProf_option = None,
  metastring = None 
)
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.

Definition at line 464 of file cmsRelvalreport.py.

00471                                     :
00472         '''
00473         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.
00474         '''
00475 
00476         if outdir==None or outdir==self.profile_name:
00477             outdir=self.profile_name+'_outdir'
00478             
00479         #Create the directory where the report will be stored:
00480         if not os.path.exists(outdir) and not fill_db and not IgProf_option:
00481             #Added an IgProf condition to avoid the creation of a directory that we will not need anymore, since we will put all info in the filenames
00482             execute('mkdir %s' %outdir)
00483         
00484         if fill_db:
00485             db_option='-a'
00486             if not os.path.exists(db_name):
00487                 db_option='-A'
00488         
00489         # temp in the local dir for PR
00490         tmp_switch=''    
00491         if tmp_dir!='':
00492             execute('mkdir %s' %tmp_dir)
00493             tmp_switch=' -t %s' %tmp_dir
00494 
00495         #Handle the various profilers:
00496         
00497         ##################################################################### 
00498         
00499         # Profiler is ValgrindFCE:
00500         if self.profiler=='ValgrindFCE':
00501             perfreport_command=''
00502             # Switch for filling the db
00503             if not fill_db:
00504                 os.environ["PERFREPORT_PATH"]='%s/' %PERFREPORT2_PATH
00505                 perfreport_command='%s %s -ff -i %s -o %s' %(PR2,
00506                                                              tmp_switch,
00507                                                              self.profile_name,
00508                                                              outdir)
00509             else:
00510                 os.environ["PERFREPORT_PATH"]='%s/' %PERFREPORT3_PATH
00511                 perfreport_command='%s %s -n5000 -u%s  -ff  -m \'scram_cmssw_version_string,%s\' -i %s %s -o %s' \
00512                                                     %(PR3,
00513                                                       tmp_switch,
00514                                                       PR3_PRODUCER_PLUGIN,
00515                                                       metastring,
00516                                                       self.profile_name,
00517                                                       db_option,
00518                                                       db_name)
00519             return execute(perfreport_command)
00520         
00521         #####################################################################            
00522             
00523         # Profiler is IgProf:
00524         if self.profiler.find('IgProf')!=-1:
00525             #First the case of IgProf PERF and MEM reporting:
00526             if not 'ANALYSE' in IgProf_option:
00527                 #Switch to the use of igprof-analyse instead of PerfReport!
00528                 #Will use the ANALYSE case for regressions between early event dumps and late event dumps of the profiles
00529                 #Following Andreas suggestion, add the number of events for the EndOfJob report
00530                 NumberOfEvents=self.command.split()[3] #FIXME: this is quite hardcoded... but should be stable...
00531                 sqlite_outputfile=self.profile_name.split(".")[0].replace(IgProfProfiles[IgProf_option[0]],IgProf_option[0])+'___'+NumberOfEvents+'_EndOfJob.sql3'
00532                 logger("Executing the report of the IgProf end of job profile")
00533                 exit=execute('igprof-analyse --sqlite -d -v -g -r %s %s | sqlite3 %s'%(IgProf_option[0],self.profile_name,sqlite_outputfile)) 
00534                 return exit
00535             #Then the "ANALYSE" case that we want to use to add to the same directories (Perf, MemTotal, MemLive)
00536             #also some other analyses and in particular:
00537             #1-the first 7 lines of the ASCII analysis of the IgProf profile dumps (total of the counters)
00538             #2-the dump at different event numbers,
00539             #3-the diff between the first and last dump,
00540             #4-the counters grouped by library using regexp at the last dump:
00541             else: #We use IgProf Analysis
00542                 #Set the IgProfCounter from the ANALYSE.MEM_TOT style IgProf_option
00543                 #print IgProf_option
00544                 IgProfCounter=IgProf_option[1]
00545                 #Add here the handling of the new IgProf.N.gz files so that they will get preserved and not overwritten:
00546                 logger("Looking for IgProf intermediate event profile dumps")
00547                 #Check if there are IgProf.N.gz dump files:
00548                 IgProfDumps=glob.glob("IgProf.*.gz")
00549                 #in case there are none check if they have already been mv'd to another name to avoid overwriting
00550                 #(MEM_LIVE usually re-uses MEM_TOTAL, so the IgProf.N.gz files will already have a MemTotal name...)
00551                 if not IgProfDumps:
00552                     localFiles=os.listdir('.')
00553                     IgProfDumpProfilesPrevious=re.compile(r"\w+.\d+.gz")
00554                     IgProfDumps=filter(lambda x: IgProfDumpProfilesPrevious.search(x),localFiles)
00555                 #Now if there are dumps execute the following analyses:
00556                 if IgProfDumps:
00557                     IgProfDumps.sort()
00558                     logger("Found the following IgProf intermediate event profile dumps:")
00559                     logger(IgProfDumps)
00560                     FirstDumpEvent=9999999
00561                     LastDumpEvent=0
00562                     exit=0
00563                     for dump in IgProfDumps:
00564                         if "___" in dump:
00565                             DumpEvent=dump.split(".")[0].split("___")[-1]
00566                         else:
00567                             DumpEvent=dump.split(".")[1]
00568                         #New naming convention using ___ as separator
00569                         DumpedProfileName=self.profile_name[:-3]+"___"+DumpEvent+".gz"
00570                         if dump.startswith("IgProf"):
00571                             execute('mv %s %s'%(dump,DumpedProfileName))
00572                         #Keep a tab of the first and last dump event for the diff analysis
00573                         if int(DumpEvent) < FirstDumpEvent:
00574                             FirstDumpEvent = int(DumpEvent)
00575                         if int(DumpEvent) > LastDumpEvent:
00576                             LastDumpEvent = int(DumpEvent)
00577                         #Eliminating the ASCII analysis to get the totals, Giulio will provide this information in igprof-navigator with a special query
00578                         #First type of analysis: dump first 7 lines of ASCII analysis:
00579                         #logger("Executing the igprof-analyse analysis to dump the ASCII 7 lines output with the totals for the IgProf counter")
00580                         #exit=execute('%s -o%s -i%s -t%s' %(IGPROFANALYS,outdir,DumpedProfileName,"ASCII"))
00581                         #Second type of analysis: dump the report in sqlite format to be ready to be browsed with igprof-navigator
00582                         logger("Executing the igprof-analyse analysis saving into igprof-navigator browseable SQLite3 format")
00583                         #exit=exit+execute('%s -o%s -i%s -t%s' %(IGPROFANALYS,outdir,DumpedProfileName,"SQLite3"))
00584                         #Execute all types of analyses available with the current profile (using the dictionary IgProfProfile):
00585                         #To avoid this we should use a further input in SimulationCandles.txt IgProfMem.ANALYSE.MEM_TOTAL maybe the cleanest solution.
00586                         #for IgProfile in IgProfCounters.keys():
00587                         #    if DumpedProfileName.find(IgProfile)>0:
00588                         #        for counter in IgProfCounters[IgProfile]:
00589                         #Check that the file does not exist:
00590                         #if not os.path.exists(DumpedProfileName.split(".")[0].replace(IgProfProfiles[counter],counter)+".sql3"):
00591                         exit=exit+execute('%s -c%s -i%s -t%s' %(IGPROFANALYS,IgProfCounter,DumpedProfileName,"SQLite3"))
00592                                     #else:
00593                                     #    print "File %s already exists will not process profile"%DumpedProfileName.split(".")[0].replace(IgProfProfiles[counter],counter)+".sql3"
00594                     #FIXME:
00595                     #Issue with multiple profiles in the same dir: assuming Perf and Mem will always be in separate dirs
00596                     #Potential ssue with multiple steps?
00597                     #Adapting to new igprof naming scheme:
00598                     FirstDumpProfile=self.profile_name[:-3]+"___"+str(FirstDumpEvent)+".gz"
00599                     LastDumpProfile=self.profile_name[:-3]+"___"+str(LastDumpEvent)+".gz"
00600                     #Third type of analysis: execute the diff analysis:
00601                     #Check there are at least 2 IgProf intermediate event dump profiles to do a regression!
00602                     if len(IgProfDumps)>1:
00603                         logger("Executing the igprof-analyse regression between the first IgProf profile dump and the last one")
00604                         #for IgProfile in IgProfCounters.keys():
00605                         #    if DumpedProfileName.find(IgProfile)>0:
00606                         #        IgProfCounter=IgProfCounters[IgProfile]
00607                         exit=exit+execute('%s -c%s -i%s -r%s' %(IGPROFANALYS,IgProfCounter,LastDumpProfile,FirstDumpProfile))
00608                     else:
00609                         logger("CANNOT execute any regressions: not enough IgProf intermediate event profile dumps!")
00610                     #Fourth type of analysis: execute the grouped by library igprof-analyse:
00611                     logger("Executing the igprof-analyse analysis merging the results by library via regexp and saving the result in igprof-navigator browseable SQLite3 format")
00612                     #for IgProfile in IgProfCounters.keys():
00613                     #        if DumpedProfileName.find(IgProfile)>0:
00614                     #            IgProfCounter=IgProfCounters[IgProfile]
00615                     exit=exit+execute('%s -c%s -i%s --library' %(IGPROFANALYS,IgProfCounter,LastDumpProfile))
00616                 #If they are not there at all (no dumps)
00617                 else:
00618                     logger("No IgProf intermediate event profile dumps found!")
00619                     exit=0
00620                 
00621                 return exit
00622                 
00623 
00624         #####################################################################                     
00625             
00626         # Profiler is EdmSize:        
00627         if 'Edm_Size' in self.profiler:
00628             perfreport_command=''
00629             if not fill_db:
00630                 os.environ["PERFREPORT_PATH"]='%s/' \
00631                                             %PERFREPORT2_PATH
00632                 perfreport_command='%s %s -fe -i %s -o %s' \
00633                                             %(PR2,
00634                                               tmp_switch,
00635                                               self.profile_name,
00636                                               outdir)
00637             else:
00638                 os.environ["PERFREPORT_PATH"]='%s/' \
00639                                             %PERFREPORT3_PATH
00640                 perfreport_command='%s %s -n5000 -u%s -fe -i %s -a -o %s' \
00641                                             %(PR3,
00642                                               tmp_switch,
00643                                               PR3_PRODUCER_PLUGIN,
00644                                               self.profile_name,
00645                                               db_name)             
00646 
00647             return execute(perfreport_command)    
00648 
00649         #FIXME: probably need to move this somewhere else now that we use return statements
00650         if tmp_dir!='':
00651             execute('rm -r %s' %tmp_dir)
00652             
00653         #####################################################################    
00654                             
00655         # Profiler is Valgrind Memcheck
00656         if self.profiler=='Memcheck_Valgrind':
00657             # Three pages will be produced:
00658             os.environ['PERL5LIB']=PERL5_LIB
00659             report_coordinates=(VMPARSER,self.profile_name,outdir)
00660             # Copy the Valgrind Memcheck parser style file in the outdir
00661             copyStyleFile='cp -pR %s %s'%(VMPARSERSTYLE,outdir)
00662             execute(copyStyleFile)
00663             report_commands=('%s --preset +prod,-prod1 %s > %s/edproduce.html'\
00664                                 %report_coordinates,
00665                              '%s --preset +prod1 %s > %s/esproduce.html'\
00666                                 %report_coordinates,
00667                              '%s -t beginJob %s > %s/beginjob.html'\
00668                                 %report_coordinates)
00669             exit=0
00670             for command in report_commands:
00671                 exit= exit + execute(command)      
00672             return exit
00673         #####################################################################                
00674                 
00675         # Profiler is TimeReport parser
00676         
00677         if self.profiler=='Timereport_Parser':
00678             return execute('%s %s %s' %(TIMEREPORTPARSER,self.profile_name,outdir))
00679 
00680         #####################################################################
00681         
00682         # Profiler is Timing Parser            
00683         
00684         if self.profiler=='Timing_Parser':
00685             return execute('%s -i %s -o %s' %(TIMINGPARSER,self.profile_name,outdir))
00686         
00687                     
00688         #####################################################################
00689         
00690         # Profiler is Simple memory parser
00691         
00692         if self.profiler=='SimpleMem_Parser':
00693             return execute('%s -i %s -o %s' %(SIMPLEMEMPARSER,self.profile_name,outdir))
00694             
00695         #####################################################################
00696         
00697         # no profiler
00698             
00699         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).
00700             return 0         #Used to be pass, but we need a return 0 to handle exit code properly!         
                                                                

Member Data Documentation

Definition at line 273 of file cmsRelvalreport.py.

Definition at line 273 of file cmsRelvalreport.py.

Definition at line 273 of file cmsRelvalreport.py.