CMS 3D CMS Logo

/data/refman/pasoursint/CMSSW_5_2_9/src/Validation/Performance/scripts/cmsPerfPublish.py

Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 #G.Benelli Jan 22 2007, J. Nicolson 12 Aug 2008
00003 #A little script to move Simulation Performance Suite
00004 #relevant html and log files into our public area
00005 #/afs/cern.ch/cms/sdt/web/performance/simulation/
00006 #Set here the standard number of events (could become an option... or could be read from the log...)
00007 
00008 ###############################
00009 #
00010 # Warning!!! We should use copytree() instead of our self defined copytree4
00011 #            However, copytree does not use ignore patterns (for filtering files)
00012 #            before python v2.6, when we upgrade to python 2.6 we should use this
00013 #            functionality.
00014 import tempfile as tmp
00015 import optparse as opt
00016 import cmsPerfRegress as cpr
00017 import re, os, sys, time, glob, socket, fnmatch
00018 from shutil import copy2, copystat
00019 from stat   import *
00020 from cmsPerfCommons import CandFname, Step, ProductionSteps, Candles
00021 import ROOT
00022 #Switching from os.popen4 to subprocess.Popen for Python 2.6 (340_pre5 onwards):
00023 import subprocess
00024 
00025 PROG_NAME  = os.path.basename(sys.argv[0])
00026 DEF_RELVAL = "/afs/cern.ch/cms/sdt/web/performance/RelVal"
00027 DEF_SIMUL  = "/afs/cern.ch/cms/sdt/web/performance/simulation"
00028 TMP_DIR    = ""
00029 cpFileFilter = ( "*.root", ) # Unix pattern matching not regex
00030 cpDirFilter  = (           ) # Unix pattern matching not regex
00031 
00032 TimeSizeNumOfEvents = -9999
00033 IgProfNumOfEvents   = -9999
00034 CallgrindNumOfEvents = -9999
00035 MemcheckNumOfEvents = -9999
00036 
00037 DirName=( #These need to match the candle directory names ending (depending on the type of profiling)
00038           "TimeSize",
00039           "IgProf",
00040           "IgProf_Perf",
00041           "IgProf_Mem",
00042           "Callgrind",
00043           "Memcheck",
00044           #Adding the extra PU directories:
00045           "PU_TimeSize",
00046           "PU_IgProf",
00047           "PU_IgProf_Perf",
00048           "PU_IgProf_Mem",
00049           "PU_Callgrind",
00050           "PU_Memcheck"
00051           )
00052 #Defining Steps as a union of Step and ProductionSteps:
00053 Steps=set(Step+ProductionSteps+["GEN,FASTSIM","GEN,FASTSIM_PILEUP"]) #Adding GEN,FASTSIM too by hand.
00054 print Steps
00055 
00056 ##################
00057 #
00058 # Small functions
00059 #
00060 
00061 class ReldirExcept(Exception):
00062     "Relative directory could not be determined"
00063 
00064 def fail(errstr=""):
00065     print errstr
00066     delTmpDir()
00067     sys.exit()
00068 
00069 def addtrailingslash(adir):
00070     trail = re.compile("/$")
00071     if os.path.isdir(adir) and not trail.search(adir):
00072         adir = adir + "/" 
00073     return adir
00074 
00075 def getDate():
00076     return time.ctime()
00077 
00078 def getcmdBasic(cmd):
00079     #Obsolete popen4-> subprocess.Popen
00080     #return os.popen4(cmd)[1].read().strip()
00081     return subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read().strip()
00082 
00083 def getcmd(command):
00084     if _debug > 2:
00085         print command
00086     #Obsolete popen4-> subprocess.Popen
00087     #return os.popen4(command)[1].read().strip()
00088     return subprocess.Popen(command,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT).stdout.read().strip()
00089 
00090 def prettySize(size):
00091     nega = size < 0
00092     if nega:
00093         size = -size
00094     suffixes = [("B",2**10), ("k",2**20), ("M",2**30), ("G",2**40), ("T",2**50)]
00095     for suf, lim in suffixes:
00096         if size > lim:
00097             continue
00098         else:
00099             if nega:
00100                 return "-" + round(size/float(lim/2**10),2).__str__() + suf
00101             else:
00102                 return round(size/float(lim/2**10),2).__str__()+suf                
00103 
00104 class Row(object):
00105 
00106     def __init__(self,table):
00107         self.table   = table
00108         self.coldata = {}
00109         
00110     def __str__(self):
00111         return str(self.coldata)
00112     
00113     def addEntry(self,colname,value):
00114         self.table._newCol(colname)
00115         self.coldata[colname] = value
00116 
00117     def getRowDict(self):
00118         return self.coldata
00119 
00120 class Table(object):
00121     
00122     def __init__(self):
00123         self.colNames = []
00124         self.keys     = [None]
00125         self.rows     = {None: self.colNames}
00126 
00127     def __str__(self):
00128         out = self.keys
00129         out += "\n" + self.rows
00130         return out
00131 
00132     def _newCol(self,name):
00133         if name in self.colNames:
00134             pass
00135         else:
00136             self.colNames.append(name)
00137 
00138     def getCols(self):
00139         return self.colNames
00140 
00141     def newRow(self,name):
00142         if name in self.rows.keys():
00143             pass
00144         else:
00145             self.keys.append(name)
00146             self.rows[name] = Row(self)
00147             
00148         return self.rows[name]
00149 
00150     def getTable(self,mode=0):
00151         name = "Total"
00152         
00153         for key in self.keys:
00154             if  key == None:
00155                 pass
00156             else:
00157                 total1 = 0
00158                 total2 = 0                
00159                 rowobj  = self.rows[key]
00160                 rowdict = rowobj.getRowDict()
00161                 for col in self.colNames:
00162                     if col == None:
00163                         pass
00164                     elif rowdict.has_key(col) and not col == name:
00165                         if mode == 1:
00166                             total1 += rowdict[col]
00167                         else:
00168                             (step_tot1, step_tot2) = rowdict[col]
00169                             total1 += step_tot1
00170                             total2 += step_tot2
00171                 if mode == 1:
00172                     rowobj.addEntry(name,total1)                    
00173                 else:
00174                     rowobj.addEntry(name,(total1,total2))
00175                 
00176         return (self.keys, self.rows)
00177 
00178     def addRow(self,row,name):
00179         if name in self.rows.keys():
00180             pass
00181         else:
00182             self.keys.append(name)
00183             self.rows[name] = row
00184             
00185     def transpose(self):
00186         transp = Table()
00187         for col in self.colnames:
00188             rowobj = transp.newRow(col)
00189             for key in self.keys:
00190                 if key == None:
00191                     pass
00192                 else:
00193                     row_dict = self.rows[key].getRowDict()
00194                     if row_dict.has_key(key):
00195                         rowobj.addEntry(key,row_dict[col])
00196         return transp
00197 
00198 ######################
00199 #
00200 # Main 
00201 #
00202 def main():
00203     global TimeSizeNumOfEvents,IgProfNumOfEvents,CallgrindNumOfEvents,MemcheckNumOfEvents
00204     #Bad design... why is this function defined here?
00205     #Either no function, or define somewhere else.
00206     def _copyReportsToStaging(repdir,LogFiles,cmsScimarkDir,stage):
00207         """Use function syscp to copy LogFiles and cmsScimarkDir over to staging area"""
00208         if _verbose:
00209             print "Copying the logfiles to %s/." % stage
00210             print "Copying the cmsScimark2 results to the %s/." % stage  
00211 
00212         syscp(LogFiles     , stage + "/")
00213         syscp(cmsScimarkDir, stage + "/")
00214 
00215     #Same comment as above about the opportunity of this function definition here.
00216     def _createLogFile(LogFile,date,LocalPath,ShowTagsResult):
00217         """Creating a small logfile with basic publication script running information (never used really by other scripts in the suite)."""
00218         try:
00219             LOG = open(LogFile,"w")
00220             if _verbose:
00221                 print "Writing Production Host, Location, Release and Tags information in %s" % LogFile 
00222             LOG.write("These performance tests were executed on host %s and published on %s" % (HOST,date))
00223             LOG.write("They were run in %s" % LocalPath)
00224             LOG.write("Results of showtags -r in the local release:\n%s" % ShowTagsResult)
00225             LOG.close()
00226         except IOError, detail:
00227             print "WARNING: Can't create log file"            
00228             print detail
00229 
00230     # Print Program header
00231     print_header()
00232 
00233     # Get environment variables
00234     #FIXME: should check into this and make sure the proper variables for the tests being published are read from logfile (case of deprecated releases...)
00235     print "\n Getting Environment variables..."
00236     (LocalPath, ShowTagsResult) = get_environ()
00237 
00238     # Parse options
00239     (options,args) = optionparse()
00240 
00241     # Determine program parameters and input/staging locations
00242     print "\n Determining locations for input and staging..."
00243     (drive,path,remote,stage,port,repdir,prevrev,igprof_remotedir) = getStageRepDirs(options,args)
00244 
00245     #Get the number of events for each test from logfile:
00246     print "\n Getting the number of events for each test..."
00247     #Let's do a quick implementation of something that looks at the logfile:
00248     cmsPerfSuiteLogfile="%s/cmsPerfSuite.log"%repdir
00249 
00250     if os.path.exists(cmsPerfSuiteLogfile):
00251         try:
00252             (TimeSizeNumOfEvents,IgProfNumOfEvents,CallgrindNumOfEvents,MemcheckNumOfEvents)=getNumOfEventsFromLog(cmsPerfSuiteLogfile)
00253             #Get the CMSSW version and SCRAM architecture from log (need these for the IgProf new publishing with igprof-navigator)
00254             (CMSSW_arch,CMSSW_version)=getArchVersionFromLog(cmsPerfSuiteLogfile)
00255             #For now keep the dangerous default? Better set it to a negative number...
00256         except:
00257             print "There was an issue in reading out the number of events for the various tests or the architecture/CMSSW version using the standard logfile %s"%cmsPerfSuiteLogFile
00258             print "Check that the format was not changed: this scripts relies on the initial perfsuite arguments to be dumped in the logfile one per line!"
00259             print "For now taking the default values for all tests (0)!"
00260 
00261     print "\n Scan report directory..."
00262     # Retrieve some directories and information about them
00263     (ExecutionDate,LogFiles,date,cmsScimarkResults,cmsScimarkDir) = scanReportArea(repdir)
00264     print "cmsScimarkResults are %s"%cmsScimarkResults
00265     print "\n Copy report files to staging directory..."
00266     # Copy reports to staging area 
00267     _copyReportsToStaging(repdir,LogFiles,cmsScimarkDir,stage)
00268 
00269     print "\n Creating log file..."
00270     # Produce a small logfile with basic info on the Production area
00271     _createLogFile("%s/ProductionLog.txt" % stage,date,repdir,ShowTagsResult)
00272 
00273     #Check if there are IgProf tests:
00274     for dirname in os.listdir(repdir):
00275         if "IgProf" in dirname:
00276             print "\n Handling IgProf reports..."
00277             # add a function to handle the IgProf reports
00278             stageIgProfReports(igprof_remotedir,CMSSW_arch,CMSSW_version)
00279     
00280     print "\n Creating HTML files..."
00281     # create HTML files
00282     createWebReports(stage,repdir,ExecutionDate,LogFiles,cmsScimarkResults,date,prevrev)
00283 
00284     print "\n Copy profiling logs to staging directory..."
00285     # Copy over profiling logs...
00286     getDirnameDirs(repdir,stage)
00287 
00288     # Send files to remote location
00289     if remote:
00290         print "\n Uploading web report to remote location..."
00291         syncToRemoteLoc(stage,drive,path,port)
00292         print "\n Finished uploading! Now removing staging directory..."
00293         delTmpDir()
00294 
00295     print "\n Finished!!!"
00296 
00297 ##########################
00298 #
00299 # Get require environment variables
00300 #
00301 def get_environ():
00302     global CMSSW_VERSION, CMSSW_RELEASE_BASE, CMSSW_BASE, HOST, USER, BASE_PERFORMANCE, CMSSW_WORK
00303     global DEF_RELVAL, DEF_SIMUL
00304     
00305     try:
00306         CMSSW_VERSION=os.environ['CMSSW_VERSION']
00307         CMSSW_RELEASE_BASE=os.environ['CMSSW_RELEASE_BASE']
00308         CMSSW_BASE=os.environ['CMSSW_BASE']
00309         HOST=os.environ['HOST']
00310         USER=os.environ['USER']
00311         CMSSW_WORK = os.path.join(CMSSW_BASE,"work/Results")
00312     except KeyError, detail:
00313         fail("ERROR: Could not retrieve some necessary environment variables. Have you ran scramv1 runtime -csh yet?. Details: %s" % detail)
00314 
00315     LocalPath=getcmdBasic("pwd")
00316     ShowTagsResult=getcmdBasic("showtags -r")
00317 
00318     #Adding a check for a local version of the packages
00319     PerformancePkg="%s/src/Validation/Performance"        % CMSSW_BASE
00320     if (os.path.exists(PerformancePkg)):
00321         BASE_PERFORMANCE=PerformancePkg
00322         print "**Using LOCAL version of Validation/Performance instead of the RELEASE version**"
00323     else:
00324         BASE_PERFORMANCE="%s/src/Validation/Performance"  % CMSSW_RELEASE_BASE
00325 
00326     return (LocalPath,ShowTagsResult)
00327 
00328 ###############
00329 #Option parser
00330 #
00331 def optionparse():
00332     global PROG_NAME, _debug, _dryrun, _verbose
00333 
00334     parser = opt.OptionParser(usage=("""%s [HOST:]DEST_PATH [Options]
00335 
00336     Arguments:
00337         [HOST:]DEST_PATH - This is where the report should be published, you can specify a local path or a directory on a remote machine (HOST is optional)
00338 
00339     Examples:  
00340        Publish report to default local directory
00341         ./%s 
00342        Publish report to \"/some/local/dir\"
00343         ./%s /some/local/dir
00344        Publish report to \"/some/other/dir\" remote host \"hal.cern.ch\" 
00345         ./%s hal.cern.ch:/some/other/dir
00346        Publish report to default relval location (this could be remote or local depending on the hardcoded default)
00347         ./%s --relval"""
00348       % ( PROG_NAME, PROG_NAME, PROG_NAME, PROG_NAME, PROG_NAME)))
00349     
00350     devel  = opt.OptionGroup(parser, "Developer Options",
00351                                      "Caution: use these options at your own risk."
00352                                      "It is believed that some of them bite.\n")
00353     parser.add_option(
00354         '--relval',
00355         action="store_true",
00356         dest='relval',
00357         help='Use the default RelVal location',
00358         #metavar='<STEPS>',
00359         )
00360 
00361     parser.add_option(
00362         '-v',
00363         '--verbose',
00364         action="store_true",
00365         dest='verbose',
00366         help='output more information',
00367         #metavar='<STEPS>',
00368         )    
00369 
00370     parser.add_option(
00371         '--simul',
00372         action="store_true",
00373         dest='simulation',
00374         help='Use the default simulation location',
00375         #metavar='<STEPS>',
00376         )
00377 
00378     parser.add_option(
00379         '--prev',
00380         type="string",
00381         dest='previousrev',
00382         help='The override the name of the previous release. Default is the string obtain from the identification file REGRESSION.<prevrel>.vs.<newrel>',
00383         metavar='<NAME>',
00384         default="",
00385         )    
00386 
00387     parser.add_option(
00388         '--input',
00389         type="string",
00390         dest='repdir',
00391         help='The location of the report files to be published',
00392         metavar='<DIR>'
00393         )
00394 
00395     parser.add_option(
00396         '-p',
00397         '--port',
00398         type='int',
00399         dest='port',
00400         help='Use a particular port number to rsync material to a remote server',
00401         metavar='<PORT>'
00402         )
00403     parser.add_option(
00404         '--igprof',
00405         type='string',
00406         dest='ig_remotedir',
00407         default='IgProfData', #Reverting to local default publication for now#'/afs/cern.ch/cms/sdt/web/qa/igprof-testbed/data', #For now going straight into AFS... later implement security via local disk on cmsperfvm and cron job there:
00408         #default='cmsperfvm:/data/projects/conf/PerfSuiteDB/IgProfData', #This should not change often! In this virtual machine a cron job will run to move stuff to AFS.
00409         help='Specify an AFS or host:mydir remote directory instead of default one',
00410         metavar='<IGPROF REMOTE DIRECTORY>'
00411         )
00412     
00413     devel.add_option(
00414         '-d',
00415         '--debug',
00416         type='int',
00417         dest='debug',
00418         help='Show debug output',
00419         #metavar='DEBUG',
00420         )
00421 
00422     devel.add_option(
00423         '--dry-run',
00424         action="store_true",
00425         dest='dryrun',
00426         help='Do not send files to remote server, but run everything else',
00427         #metavar='DEBUG',
00428         )
00429 
00430     repdirdef = os.getcwd()
00431     parser.set_defaults(debug=0,simulation=False,relval=False,port=873,pretend=False,repdir=repdirdef,verbose=False)
00432     parser.add_option_group(devel)
00433 
00434     (options, args) = parser.parse_args()
00435 
00436     _debug   = options.debug
00437     _dryrun  = options.dryrun
00438     _verbose = options.verbose
00439 
00440     numofargs = len(args) 
00441 
00442     if (options.simulation and options.relval) or ((options.simulation or options.relval) and numofargs >= 1):
00443         parser.error("You can not specify simulation and relval together. Neither can you specify simulation or relval AND a path")
00444         sys.exit()
00445 
00446     return (options, args)
00447 
00448 
00449 #A function to get the number of events for each test from the logfile:
00450 def getNumOfEventsFromLog(logfile):
00451     '''A very fragile function to get the Number of events for each test by parsing the logfile of the Suite. This relies on the fact that nobody will turn off the print out of the options in the cmsPerfSuite.py output... ARGH!'''
00452     log=open(logfile,"r")
00453     TimeSizeEvents=0
00454     IgProfEvents=0
00455     CallgrindEvents=0
00456     MemcheckEvents=0
00457     for line in log:
00458         #FIXME:
00459         #For robustness could read this from the Launching the X tests (.....) with N events each and keep that format decent for parsing.
00460         #One more place where XML would seem a better choice to extract information (Timing of the performance suite in general is also, but publishing and harvesting some other info as well).
00461         if 'TimeSizeEvents' in line and not TimeSizeEvents:
00462             lineitems=line.split()
00463             TimeSizeEvents=lineitems[lineitems.index('TimeSizeEvents')+1]
00464         if 'IgProfEvents' in line and not IgProfEvents:
00465             lineitems=line.split()
00466             IgProfEvents=lineitems[lineitems.index('IgProfEvents')+1]
00467         if 'CallgrindEvents' in line and not CallgrindEvents:
00468             lineitems=line.split()
00469             CallgrindEvents=lineitems[lineitems.index('CallgrindEvents')+1]
00470         if 'MemcheckEvents' in line and not MemcheckEvents:
00471             lineitems=line.split()
00472             MemcheckEvents=lineitems[lineitems.index('MemcheckEvents')+1]
00473     return (TimeSizeEvents,IgProfEvents,CallgrindEvents,MemcheckEvents)
00474 
00475 def getArchVersionFromLog(logfile):
00476     '''Another very fragile function to get the architecture and the CMSSW version parsing the logfile...'''
00477     log=open(logfile,"r")
00478     arch=re.compile("^Current Architecture is")
00479     version=re.compile("^Current CMSSW version is")
00480     CMSSW_arch="UNKNOWN_ARCH"
00481     CMSSW_version="UNKNOWN_VERSION"
00482     for line in log:
00483         if arch.search(line):
00484             CMSSW_arch=line.split()[3]
00485         if version.search(line):
00486             CMSSW_version=line.split()[4]
00487     return(CMSSW_arch,CMSSW_version)
00488 
00489 
00490 #####################
00491 #
00492 # Determine locations of staging and report dirs 
00493 #
00494 def getStageRepDirs(options,args):
00495     global TMP_DIR, IS_TMP, DEF_LOCAL, CMSSW_VERSION
00496     DEF_LOCAL = CMSSW_WORK
00497     numofargs = len(args)
00498 
00499     repdir = os.path.abspath(options.repdir)
00500     repdir = addtrailingslash(repdir)
00501 
00502     if not os.path.exists(repdir):
00503         fail("ERROR: The specified report directory %s to retrieve report information from does not exist, exiting" % repdir)
00504 
00505     previousrev = options.previousrev
00506     if previousrev == "":
00507         regressfiles = glob.glob("%s/REGRESSION.*.vs.*" % repdir)
00508         if not len(regressfiles) == 0:
00509             regressID   = regressfiles[0]
00510             base        = os.path.basename(regressID)
00511             split       = base.split(".")
00512             previousrev = split[1]
00513             currentrel  = split[3]
00514             print "Regression Identification file exists, renaming report title for regression report. Old ver: %s" % previousrev
00515         else:
00516             print "No regression ID file exists and previous release name was not specified. Producing normal report."
00517     else:
00518         print "Previous release name was specified, renaming report title for regression report. Old ver %s" % previousrev
00519     
00520     uri = ""
00521     defaultlocal = False
00522     if options.simulation:
00523         uri = DEF_SIMUL
00524     elif options.relval:
00525         uri = DEF_RELVAL
00526     elif numofargs >= 1:
00527         uri = args[0] # Add directory CMSSW_VERSION later in temp! Not now, otherwise we get into a mess if this is a remote dir
00528     else:
00529         defaultlocal = True
00530         uri = DEF_LOCAL
00531 
00532     ####
00533     #
00534     # Determine if location is remote
00535     #
00536     # Try not to re-arrange we don't want to assume that default locations are not remote
00537     #
00538     ####
00539 
00540     drive = ""
00541     path = ""
00542     if ":" in uri:
00543         drive, path = uri.split(":",1)
00544     else:
00545         path = uri
00546         
00547     if drive == "":
00548         path = os.path.abspath(path)
00549     remote = not drive == ""
00550 
00551     if remote:
00552         unResolved = True
00553         try:
00554             socket.getaddrinfo(drive,53)
00555             unResolved = False
00556         except socket.gaierror:
00557             unResolved = True
00558 
00559         # try see if it's an ipaddress
00560         if unResolved:
00561             try:
00562                 socket.gethostbyaddr(drive)
00563                 unResolved = False
00564             except socket.gaierror:
00565                 unResolved = True
00566             if unResolved:
00567                 print "ERROR: Can not determine your hostname or ipv{4,6} address %s" % drive
00568                 if not (_dryrun or _test):
00569                     fail("exiting...")
00570 
00571     if (not remote) and (not options.port == 873) :
00572         print "WARNING: Can not use a port if not performing a remote copy, ignoring"
00573     port = options.port
00574 
00575     ###
00576     #
00577     # Determine Staging Area
00578     #
00579 
00580     StagingArea=""
00581     localExists = os.path.exists("%s/%s" % (CMSSW_WORK,CMSSW_VERSION))
00582     
00583     if remote:
00584         #Cannot use this since the /tmp is limited to 2GB on lxbuild machines!
00585         #TMP_DIR=tmp.mkdtemp(prefix="/tmp/%s" % PROG_NAME)
00586         TMP_DIR=tmp.mkdtemp(prefix="/build/%s" % PROG_NAME)
00587         StagingArea = TMP_DIR
00588     #Local but dir already exists
00589     elif defaultlocal and localExists:
00590         TMP_DIR=tmp.mkdtemp(prefix="%s/%s" % (CMSSW_WORK,CMSSW_VERSION))
00591         StagingArea = TMP_DIR
00592         print "WARNING: %s already exists, creating a temporary staging area %s" % (CMSSW_WORK,TMP_DIR)
00593     #Local cases
00594     elif defaultlocal:
00595         StagingArea = CMSSW_WORK
00596         try:
00597             os.mkdir(os.path.join(CMSSW_BASE,"work"))
00598             os.mkdir(os.path.join(CMSSW_BASE,"work","Results"))
00599         except OSError:
00600             pass
00601         print "**User did not specify location of results, staging in default %s**" % StagingArea 
00602     else:
00603         print "**User chose to publish results in a local directory**" 
00604         StagingArea = path
00605         if not os.path.exists(path):
00606             try:
00607                 os.mkdir("%s" % path)
00608             except OSError, detail:
00609                 if   detail.errno == 13:
00610                     fail("ERROR: Failed to create staging area %s because permission was denied " % StagingArea)
00611                 elif detail.errno == 17:
00612                     #If the directory already exists just carry on
00613                     pass
00614                 else:
00615                     fail("ERROR: There was some problem (%s) when creating the staging directory" % detail)            
00616 
00617     IS_TMP = not TMP_DIR == ""
00618     ######
00619     #
00620     # create Version dir
00621     # This is why when we create a Tmp dir we get the version(tmpname)/version
00622     # structure. We should remove this if we don't want it but i dont think it matters
00623     StagingArea="%s/%s" % (StagingArea,CMSSW_VERSION)
00624     try:
00625         os.mkdir("%s" % StagingArea)
00626     except OSError, detail:
00627         if   detail.errno == 13:
00628             fail("ERROR: Failed to create staging area %s because permission was denied " % StagingArea)
00629         elif detail.errno == 17:
00630             #If the directory already exists just carry on
00631             pass
00632         else:
00633             fail("ERROR: There was some problem (%s) when creating the staging directory" % detail)
00634     
00635     return (drive,path,remote,StagingArea,port,repdir,previousrev,options.ig_remotedir)
00636 
00637 ####################
00638 #
00639 # Scan report area for required things
00640 #
00641 def scanReportArea(repdir):
00642     """Scans the working directory for cms*.logs (cmsPerfSuite.log and cmsScimark*.log, and cmsScimark results.
00643     It returns Execution date (completion), current date, list of logfiles and cmsScimark results"""
00644     date=getDate()
00645     LogFiles  = glob.glob(repdir + "cms*.log")
00646     if _verbose:
00647         print "Found the following log files:"
00648         print LogFiles
00649 
00650     cmsScimarkDir = glob.glob(repdir + "cmsScimarkResults_*")
00651     if _verbose:
00652         print "Found the following cmsScimark2 results directories:"
00653         print cmsScimarkDir
00654 
00655     cmsScimarkResults = []
00656     for adir in cmsScimarkDir:
00657         htmlfiles = glob.glob(adir + "/*.html")
00658         #FIXME:
00659         #Really unnecessary use of map in my opinion
00660         #Could do with cmsScimarkResults.extend(htmlfiles)
00661         map(cmsScimarkResults.append,htmlfiles)
00662 
00663     ExecutionDateLast = ""
00664     ExecutionDate = ""
00665     ExecutionDateSec=0
00666     cmsreg = re.compile("^cmsPerfSuite")
00667     for logf in LogFiles:
00668         if cmsreg.search(logf):
00669             ExecutionDateLastSec = os.stat(logf)[ST_CTIME]
00670             ExecutionDateLast    = os.stat(logf)[ST_MTIME]
00671             if _verbose:
00672                 print "Execution (completion) date for %s was: %s" % (logf,ExecutionDateLast)
00673             if (ExecutionDateLastSec > ExecutionDateSec):
00674                 ExecutionDateSec = ExecutionDateLastSec
00675                 ExecutionDate    = ExecutionDateLast
00676                 
00677     if ExecutionDate == "":
00678         ExecutionDate = ExecutionDateLast
00679 
00680     return (ExecutionDate,LogFiles,date,cmsScimarkResults,cmsScimarkDir)
00681 
00682 def createRegressHTML(reghtml,repdir,outd,CurrentCandle,htmNames):
00683     RegressTmplHTML="%s/doc/regress.html" % (BASE_PERFORMANCE)
00684     candnreg  = re.compile("CandleName")
00685     candhreg  = re.compile("CandlesHere")
00686     try:
00687         REGR = open(reghtml,"w")
00688         for line in open(RegressTmplHTML):
00689             if candhreg.search(line):
00690                 html = "<table>"
00691                 
00692                 for x in htmNames:
00693                     abspath = os.path.join(repdir,outd)
00694                     if os.path.exists(abspath):
00695                         html += "<tr><td><a href=\"./%s/%s\"><img src=\"./%s/%s\" /></a></td></tr>\n" % (outd,x,outd,x)
00696                     else:
00697                         html += "<tr><td> %s does not exist probably because the log file for the previous release was missing</td></tr>" % (abspath)
00698                 html += "</table>"
00699                 REGR.write(html)
00700             elif candnreg.search(line):
00701                 REGR.write(CurrentCandle)
00702             else:
00703                 REGR.write(line)
00704     except IOError, detail:
00705         print "ERROR: Could not write regression html %s because %s" % (os.path.basename(reghtml),detail)                
00706 
00707 def getOutputNames(base,reportName):
00708     logreg   = re.compile("(.*)\.log$")
00709     matches  = logreg.search(reportName)
00710     logdir   = logreg.sub(matches.groups()[0],reportName)
00711     outd     = os.path.join(base,logdir)
00712     nologext = matches.groups()[0]
00713     return (nologext,outd)
00714 
00715 def rootfile_cmp(x,y):
00716     (fname,x) = x
00717     (fname,y) = y
00718     x = os.path.basename(x)
00719     y = os.path.basename(y)
00720     stepreg = re.compile("%s_(..*)\.root" % fname)
00721     if stepreg.search(x):
00722         x = stepreg.search(x).groups()[0]
00723     if stepreg.search(y):
00724         y = stepreg.search(y).groups()[0]
00725     return step_cmp(x,y)
00726 
00727 def dirname_cmp(x,y):
00728     (candle,prof,x) = x
00729     (candle,prof,y) = y
00730     x = os.path.basename(x)
00731     y = os.path.basename(y)
00732     stepreg = re.compile("%s_(..*)_%s" % (candle,prof))
00733     if stepreg.search(x):
00734         x = stepreg.search(x).groups()[0]
00735     if stepreg.search(y):
00736         y = stepreg.search(y).groups()[0]
00737     return step_cmp(x,y)
00738 
00739 def reg_dirname_cmp(x,y):
00740     (candle,prof,x) = x
00741     (candle,prof,y) = y
00742     x = os.path.basename(x)
00743     y = os.path.basename(y)
00744     stepreg = re.compile("%s_(..*)_%s_regression" % (candle,prof))
00745     if stepreg.search(x):
00746         x = stepreg.search(x).groups()[0]
00747     if stepreg.search(y):
00748         y = stepreg.search(y).groups()[0]
00749     return step_cmp(x,y)
00750 
00751 def logrep_cmp(x,y):
00752     (fname,x) = x
00753     (fname,y) = y    
00754     x = os.path.basename(x)
00755     y = os.path.basename(y)
00756     stepreg = re.compile("%s_(..*)_TimingReport.log" % fname)
00757     if stepreg.search(x):
00758         x = stepreg.search(x).groups()[0]
00759     if stepreg.search(y):
00760         y = stepreg.search(y).groups()[0]
00761     return step_cmp(x,y)
00762 
00763 def timerep_cmp(x,y):
00764     (fname,x) = x
00765     (fname,y) = y        
00766     x = os.path.basename(x)
00767     y = os.path.basename(y)
00768     stepreg = re.compile("%s_(..*)_TimingReport" % fname)
00769     if stepreg.search(x):
00770         x = stepreg.search(x).groups()[0]
00771     if stepreg.search(y):
00772         y = stepreg.search(y).groups()[0]
00773     return step_cmp(x,y)
00774 
00775 def step_cmp(x,y):
00776     xstr = x
00777     ystr = y
00778     x_idx = -1
00779     y_idx = -1
00780     bestx_idx = -1
00781     besty_idx = -1
00782     sndbst_x = -1
00783     sndbst_y = -1
00784     last_x = -1
00785     last_y = -1        
00786     for i in range(len(Step)):
00787         stepreg = re.compile("^%s.*" % Step[i])
00788         # fallback
00789         if Step[i] in xstr and sndbst_x == -1:         
00790             last_x = i
00791         if Step[i] in ystr and sndbst_y == -1:                     
00792             last_y = i        
00793         # second best
00794         if xstr in Step[i] and bestx_idx == -1:         
00795             sndbst_x = i
00796         if ystr in Step[i] and besty_idx == -1:                     
00797             sndbst_y = i
00798         # next best
00799         if stepreg.search(xstr) and x_idx == -1: 
00800             bestx_idx = i # If an exact match has not been found but something similar has, set x best index
00801         if stepreg.search(ystr) and y_idx == -1:
00802             besty_idx = i # If an exact match has not been found but something similar has, set y best index
00803         # actual
00804         if Step[i] == xstr and x_idx == -1:
00805             x_idx = i     # if an exact match has been found then set x index
00806         if Step[i] == ystr and y_idx == -1:
00807             y_idx = i     # if an exact match has been found then set y index
00808         if not ( x_idx == -1 or y_idx == -1):
00809             break         # if an exact match has been found for both, stop
00810 
00811     # use best match if we still can't find indices
00812     if x_idx == -1:
00813         x_idx = bestx_idx
00814     if y_idx == -1:
00815         y_idx = besty_idx
00816 
00817     # use second best if we still can't find indices
00818     if x_idx == -1:
00819         x_idx = sndbst_x
00820     if y_idx == -1:
00821         y_idx = sndbst_y
00822 
00823     # use fallback if we still can't find indices
00824     if x_idx == -1:
00825         x_idx = last_x
00826     if y_idx == -1:
00827         y_idx = last_y
00828 
00829     if x_idx == -1 or y_idx == -1:
00830         print "WARNING: No valid step names could be found in the logfiles or root filenames being sorted: x: %s y: %s." % (xstr,ystr)
00831         print "x", x_idx, "y", y_idx
00832 
00833     if x_idx < y_idx:
00834         return -1
00835     elif x_idx == y_idx:
00836         return 0
00837     elif y_idx < x_idx:
00838         return 1
00839         
00840 
00841 ######################
00842 #
00843 # Create HTML pages for candles
00844 
00845 def createCandlHTML(tmplfile,candlHTML,CurrentCandle,WebArea,repdir,ExecutionDate,LogFiles,cmsScimarkResults,date,prevrev):
00846     global TimeSizeNumOfEvents,IgProfNumOfEvents,CallgrindNumOfEvents,MemcheckNumOfEvents
00847     def _stripbase(base, astr):
00848         basereg = re.compile("^%s/?(.*)" % base)
00849         out = astr
00850         found = basereg.search(astr)
00851         if found:
00852             out = found.groups()[0]
00853         return out
00854     
00855     def _getProfileReportLink(repdir,CurrentCandle,CurDir,step,CurrentProfile,Profiler):
00856         #FIXME:
00857         #Pileup now has it own directory... should add it in the DirName dictionary at the beginning?
00858         ProfileTemplate=os.path.join(repdir, "%s_%s" % (CurrentCandle,CurDir), "*_%s_%s*" % (step,CurrentProfile),Profiler)
00859         #print ProfileTemplate
00860         #There was the issue of SIM vs sim (same for DIGI) between the previous RelVal based performance suite and the current.
00861         ProfileTemplateLowCaps=os.path.join(repdir, "%s_%s" % (CurrentCandle,CurDir), "*_%s_%s*" % (step.lower(),CurrentProfile),Profiler)        
00862         ProfileReportLink = glob.glob(ProfileTemplate)
00863         #Filter out the Pile up directories when step does not contain Pile up
00864         #if not ('PILEUP' in step):
00865         #    print "NPNPNPNP BEFORE %s"%ProfileReportLink
00866         #    ProfileReportLink=filter(lambda x: "PU" not in x,ProfileReportLink)
00867         #    print "NPNPNPNP %s"%ProfileReportLink
00868         #print ProfileReportLink
00869         if len(ProfileReportLink) > 0:
00870             #print ProfileReportLink
00871             if not reduce(lambda x,y: x or y,map(lambda x: CurrentCandle in x,ProfileReportLink)):# match with caps try low caps
00872                 ProfileReportLink = glob.glob(ProfileTemplateLowCaps)
00873         else:
00874             ProfileReportLink = glob.glob(ProfileTemplateLowCaps)
00875         ProfileReportLink = map(lambda x: _stripbase(repdir,x),ProfileReportLink)
00876         #print ProfileReportLink
00877         return ProfileReportLink
00878 
00879     def _writeReportLink(INDEX,ProfileReportLink,CurrentProfile,step,NumOfEvents,Profiler=""):
00880         if Profiler == "":
00881             INDEX.write("<li><a href=\"%s\">%s %s (%s events)</a></li>\n" % (ProfileReportLink,CurrentProfile,step,NumOfEvents))
00882         else:
00883             #FIXME: need to fix this: why do we have the number of Memcheck events hardcoded? 
00884             if CurrentProfile == "memcheck_valgrind":#FIXME:quick and dirty hack to report we have changed memcheck to 5 events now...
00885                 INDEX.write("<li><a href=\"%s\">%s %s %s (%s events)</a></li>\n" % (ProfileReportLink,CurrentProfile,Profiler,step,"5"))
00886             else:
00887                 INDEX.write("<li><a href=\"%s\">%s %s %s (%s events)</a></li>\n" % (ProfileReportLink,CurrentProfile,Profiler,step,NumOfEvents))
00888     def IgProfDumpsTable(INDEX,ProfileLinks,step):
00889         #See if the end of job profiles IgProfMemTotal.res or IgProfMemLive.res are in the list as they should:
00890         EndOfJobProfileLink=filter(lambda x: "IgProfMemTotal.res" in x or "IgProfMemLive.res" in x, ProfileLinks)[0] #Assume only one of the two is there, as it should.
00891         #Remove it from the list so we can order it:
00892         ProfileLinks.remove(EndOfJobProfileLink)
00893         #Sort the list in numerical order:
00894         ProfileLinks.sort(key=lambda x: int(x.split(".")[-2]))
00895         #Prepare regexp to find and replace MemTotal with MemLive for .gz links
00896         IgProfMemLive_regexp=re.compile("IgProfMemLive")
00897         if IgProfMemLive_regexp.search(EndOfJobProfileLink):
00898             MemProfile="IgProf MEM LIVE"
00899         else:
00900             MemProfile="IgProf MEM TOTAL"
00901         #Prepare the table header:
00902         INDEX.write("<li>%s"%MemProfile)
00903         INDEX.write("<table><tr><td>Profile after event</td><td>Total Memory Size (bytes)</td><td>Total Calls (number)</td><td>Link to gzipped IgProf profile</td></tr>")
00904         for link in ProfileLinks:
00905             #Build and check the link to the .gz profile that is always called IgProfMemTotal also for MemLive:
00906             gzProfile=os.path.join(link.split("/")[-3],link.split("/")[-1])[:-3]+"gz"
00907             if IgProfMemLive_regexp.search(gzProfile):
00908                 gzProfile=IgProfMemLive_regexp.sub(r"IgProfMemTotal",gzProfile)
00909             INDEX.write("<tr><td>%s</td><td>%s</td><td>%s</td><td><a href=%s>%s</a></td></tr>"%(link.split(".")[-2],open(link,"r").readlines()[6].split()[1],open(link,"r").readlines()[6].split()[2],gzProfile,os.path.basename(gzProfile)))
00910         #Put in the end of job one by hand:
00911         gzEndOfJobProfileLink=os.path.join(EndOfJobProfileLink.split("/")[-3],EndOfJobProfileLink.split("/")[-1])[:-3]+"gz"
00912         if IgProfMemLive_regexp.search(gzEndOfJobProfileLink):
00913             gzEndOfJobProfileLink=IgProfMemLive_regexp.sub(r"IgProfMemTotal",gzEndOfJobProfileLink)
00914         INDEX.write("<tr><td>%s</td><td>%s</td><td>%s</td><td><a href=%s>%s</a></td></tr>"%("End of job",open(EndOfJobProfileLink,"r").readlines()[6].split()[1],open(EndOfJobProfileLink,"r").readlines()[6].split()[2],gzEndOfJobProfileLink,os.path.basename(gzEndOfJobProfileLink)))
00915         #Closing the table and the list item tags
00916         INDEX.write("</table>")
00917         INDEX.write("</li>")
00918     #FIXME:
00919     #These numbers are used in the index.html they are not automatically matched to the actual
00920     #ones (one should automate this, by looking into the cmsCreateSimPerfTestPyRelVal.log logfile)    
00921                             
00922     NumOfEvents={
00923                 DirName[0] : TimeSizeNumOfEvents,
00924                 DirName[1] : IgProfNumOfEvents,
00925                 DirName[2] : IgProfNumOfEvents,
00926                 DirName[3] : IgProfNumOfEvents,
00927                 DirName[4] : CallgrindNumOfEvents,
00928                 DirName[5] : MemcheckNumOfEvents,
00929                 DirName[6] : TimeSizeNumOfEvents,
00930                 DirName[7] : IgProfNumOfEvents,
00931                 DirName[8] : IgProfNumOfEvents,
00932                 DirName[9] : IgProfNumOfEvents,
00933                 DirName[10] : CallgrindNumOfEvents,
00934                 DirName[11] : MemcheckNumOfEvents
00935                 }
00936 
00937     Profile=(
00938         #These need to match the profile directory names ending within the candle directories
00939               "TimingReport",
00940               "TimeReport",
00941               "SimpleMemReport",
00942               "EdmSize",
00943               "IgProfperf",
00944               "IgProfMemTotal",
00945               "IgProfMemLive",
00946               "IgProfMemAnalyse",
00947               "valgrind",
00948               "memcheck_valgrind"
00949                )
00950     IgProfMemAnalyseOut=( #This is the special case of IgProfMemAnalyse
00951                           "doBeginJob_output.html",
00952                           "doEvent_output.html",
00953                           "mem_live.html",
00954                           "mem_total.html" 
00955                           )
00956     memcheck_valgrindOut=( #This is the special case of Valgrind MemCheck (published via Giovanni's script)
00957                            "beginjob.html",
00958                            "edproduce.html",
00959                            "esproduce.html"
00960                            )
00961     OutputHtml={ #These are the filenames to be linked in the candle html page for each profile
00962                  Profile[0] : "*TimingReport.html", #The wildcard spares the need to know the candle name
00963                  Profile[1] : "TimeReport.html", #This is always the same (for all candles)
00964                  Profile[2] : "*.html", #This is supposed to be *SimpleMemoryCheck.html, but there is a bug in cmsRelvalreport.py and it is called TimingReport.html!
00965                  Profile[3] : "objects_pp.html", #This is one of 4 objects_*.html files, it's indifferent which one to pick, just need consistency
00966                  Profile[4] : "overall.html", #This is always the same (for all candles)
00967                  Profile[5] : "overall.html", #This is always the same (for all candles)
00968                  Profile[6] : "overall.html", #This is always the same (for all candles)
00969                  Profile[7] : "doBeginJob_output.html", #This is complicated... there are 3 html to link... (see IgProf MemAnalyse below)
00970                  Profile[8] : "overall.html", #This is always the same (for all candles)
00971                  Profile[9] : "beginjob.html" #This is complicated there are 3 html to link here too... (see Valgrind MemCheck below)
00972                  }
00973 
00974 
00975     candnreg  = re.compile("CandleName")
00976     candhreg  = re.compile("CandlesHere")
00977     try:
00978         CAND = open(candlHTML,"w")
00979         for line in open(tmplfile):
00980             if candhreg.search(line):
00981                 CAND.write('<div id="content">')                
00982                 CAND.write("<h2>")
00983                 CAND.write(CurrentCandle)
00984                 CAND.write("</h2>\n")
00985 
00986                 if _verbose:
00987                     print "Producing candles html: ", CurrentCandle
00988                 
00989                 for CurDir in DirName:
00990 
00991                     LocalPath = os.path.join(repdir,"%s_%s" % (CurrentCandle,CurDir))
00992                     LocalDirname = os.path.basename(LocalPath)
00993 
00994                     if not prevrev == "":
00995 
00996                         profs = []
00997                         #FIXME!
00998                         #Check what this was used for.. it now has different DirName list since we added IgProf_Perf and IgProf_Mem on top of IgProf alone (still there)
00999                         if   CurDir == DirName[0] or CurDir == DirName[6]: #TimeSize tests (with and without PU)
01000                             profs = Profile[0:4]
01001                         elif CurDir == DirName[1] or CurDir == DirName[7]: #IgProf tests (with and without PU)
01002                             profs = Profile[4:8]
01003                         elif CurDir == DirName[2] or CurDir == DirName[8]: #IgProf Perf tests (with and without PU)
01004                             profs =[Profile[4]] #Keeping format to a list...
01005                         elif CurDir == DirName[3] or CurDir == DirName[9]: #IgProf Mem tests (with and without PU)
01006                             profs =Profile[5:8] #Keeping format to a list...  
01007                         elif CurDir == DirName[4] or CurDir == DirName[10]: #Callgrind tests (with and without PU)
01008                             profs = [Profile[8]] #Keeping format to a list...
01009                         elif CurDir == DirName[5] or CurDir == DirName[11]: #Memcheck tests (with and without PU)
01010                             profs = [Profile[9]] #Keeping format to a list...
01011                         #This could be optimized, but for now just comment the code:
01012                         #This for cycle takes care of the case in which there are regression reports to link to the html:
01013                         for prof in profs:
01014                             if _verbose:
01015                                 print "Scanning for profile information for: ", prof
01016                                 
01017                             printed = False
01018                             fullprof = (CurrentCandle,prof)
01019                             outd     = ""
01020                             nologext = ""                            
01021                             if prof == "TimingReport":
01022                                 timeReports = glob.glob(os.path.join(LocalPath,"%s_*_%s.log" % (CandFname[CurrentCandle],prof)))
01023                                 if len(timeReports) > 0:
01024                                     if not printed:
01025                                         CAND.write("<p><strong>%s %s</strong></p>\n" % (prof,"Regression Analysis"))                                        
01026                                         printed = True
01027                                     for log in timeReports:
01028                                         reportName = os.path.basename(log)
01029                                         (nologext, outd) = getOutputNames(LocalDirname,reportName) 
01030                                         CAND.write("<h4>%s</h4>\n" % reportName)
01031                                         htmNames   = ["changes.gif"]
01032                                         otherNames = ["graphs.gif" , "histos.gif"] 
01033                                         regressHTML= "%s-regress.html" % nologext
01034                                         pathsExist = reduce (lambda x,y: x or y,map(os.path.exists,map(lambda x: os.path.join(repdir,outd,x),otherNames)))
01035                                         html = ""
01036                                         if pathsExist:
01037                                             html = "<p>Performance graphs and histograms superimposed for %s are <a href=\"%s\">here</a></p>\n" % (reportName,regressHTML)
01038                                         else:
01039                                             html = "<p>No change in performance graph available</p>\n"
01040                                         regressHTML="%s/%s" % (WebArea,regressHTML)
01041 
01042                                         for x in htmNames:
01043                                             abspath = os.path.join(repdir,outd,x)
01044                                             if os.path.exists(abspath):
01045                                                 html += "<p><a href=\"./%s/%s\"><img src=\"./%s/%s\" /></a></p>\n" % (outd,x,outd,x)
01046                                             else:
01047                                                 html += "<p>%s does not exist probably because the log file for the previous release was missing</p>" % (abspath)
01048 
01049                                         createRegressHTML(regressHTML,repdir,outd,CurrentCandle,otherNames)
01050                                         CAND.write(html)
01051                                         CAND.write("\n</tr></table>")                                
01052 
01053 
01054                             elif prof == "SimpleMemReport":
01055                                 simMemReports = glob.glob(os.path.join(LocalPath,"%s_*_%s" % (CandFname[CurrentCandle],prof)))
01056                                 simMemReports = map(lambda x: (CandFname[CurrentCandle],prof,x), simMemReports )
01057                                 simMemReports.sort(cmp=dirname_cmp)
01058                                 simMemReports = map(lambda x: x[2], simMemReports )
01059                                 if len(simMemReports) > 0:
01060                                     if not printed:
01061                                         CAND.write("<p><strong>%s %s</strong></p>\n" % (prof,"Regression Analysis"))
01062                                         printed = True                                    
01063                                     for adir in simMemReports:
01064                                         reportName = os.path.basename(adir)
01065                                         CAND.write("<h4>%s</h4>\n" % reportName)
01066                                         htmNames   = ["vsize_change.gif", "rss_change.gif"]
01067                                         otherNames = ["vsize_graphs.gif","rss_graphs.gif"]
01068                                         nologext = reportName
01069                                         outd     = reportName
01070                                         regressHTML= "%s-regress.html" % nologext
01071                                         pathsExist = reduce (lambda x,y: x or y,map(os.path.exists,map(lambda x: os.path.join(repdir,LocalDirname,outd,x),otherNames)))
01072                                         html = ""
01073                                         if pathsExist:
01074                                             html = "<p>Superimposed memory performance graphs for %s are <a href=\"%s\">here</a></p>\n" % (reportName,regressHTML)
01075                                         else:
01076                                             html = "<p>No change in performance graph available</p>\n"
01077                                         regressHTML="%s/%s" % (WebArea,regressHTML)
01078 
01079                                         for x in htmNames:
01080                                             abspath = os.path.join(repdir,LocalDirname,outd,x)
01081                                             if os.path.exists(abspath):
01082                                                 html += "<p><a href=\"./%s/%s/%s\"><img src=\"./%s/%s/%s\" /></a></p>\n" % (LocalDirname,outd,x,LocalDirname,outd,x)
01083                                             else:
01084                                                 html += "<p>%s does not exist probably because the log file for the previous release was missing</p>" % (abspath)
01085 
01086                                         createRegressHTML(regressHTML,repdir,"%s/%s" % (LocalDirname,outd),CurrentCandle,otherNames)
01087                                         CAND.write(html)
01088                                         CAND.write("\n</tr></table>")   
01089 
01090                             elif prof == "EdmSize" or prof == "IgProfMemTotal" or prof == "IgProfMemLive" or prof== "IgProfperf" or prof == "Callgrind":
01091                                 regresPath = os.path.join(LocalPath,"%s_*_%s_regression" % (CandFname[CurrentCandle],prof))
01092                                 regresses  = glob.glob(regresPath)
01093                                 stepreg = re.compile("%s_([^_]*(_PILEUP)?)_%s_regression" % (CandFname[CurrentCandle],prof))
01094                                 if len(regresses) > 0:
01095                                     if not printed:
01096                                         CAND.write("<p><strong>%s %s</strong></p>\n" % (prof,"Regression Analysis"))                                        
01097                                         printed = True
01098                                     regresses = map(lambda x: (CandFname[CurrentCandle],prof,x),regresses)                                        
01099                                     regresses.sort(cmp=reg_dirname_cmp)                                    
01100                                     regresses = map(lambda x: x[2],regresses)
01101                                     for rep in regresses:
01102                                         base  = os.path.basename(rep)
01103                                         found = stepreg.search(base)
01104                                         step = "Unknown-step"
01105                                         if found:
01106                                             step = found.groups()[0]
01107                                         htmlpage = ""
01108                                         if prof == "IgProfMemLive" or prof == "IgProfMemTotal" or prof== "IgProfperf" or prof == "Callgrind":
01109                                             htmlpage = "overall.html"
01110                                         else:
01111                                             htmlpage = "objects_pp.html"
01112                                         CAND.write("<a href=\"%s/%s/%s\">%s %s regression report</a><br/>\n" % (LocalDirname,base,htmlpage,prof,step))
01113                     #Here we go back to the "non-regression" reports listing
01114                     CandleLogFiles = []
01115                     if os.path.exists(LocalPath):
01116                         thedir = os.listdir(LocalPath)
01117                         CandleLogFiles = filter(lambda x: (x.endswith(".log") or x.endswith("EdmSize")) and not os.path.isdir(x) and os.path.exists(x), map(lambda x: os.path.abspath(os.path.join(LocalPath,x)),thedir))                    
01118 
01119                     if (len(CandleLogFiles)>0):
01120                         
01121                         syscp(CandleLogFiles,WebArea + "/")
01122                         base = os.path.basename(LocalPath)
01123                         lfileshtml = ""
01124                      
01125                         for cand in CandleLogFiles:
01126                             cand = os.path.basename(cand)
01127                             if _verbose:
01128                                 print "Found %s in %s\n" % (cand,LocalPath)
01129                                 
01130                             if not "EdmSize" in cand:
01131                                 lfileshtml += "<a href=\"./%s/%s\">%s </a><br/>" % (base,cand,cand)
01132                                     
01133                         CAND.write("<p><strong>Logfiles for %s</strong></p>\n" % CurDir)    
01134                         CAND.write(lfileshtml)
01135 
01136                     PrintedOnce = False
01137                     for CurrentProfile in Profile:
01138                         #print Steps
01139                         for step in Steps: #Using Steps here that is Step+ProductionSteps!
01140                             #print step
01141                             #print "DEBUG:%s,%s,%s,%s,%s,%s"%(repdir,CurrentCandle,CurDir,step,CurrentProfile,OutputHtml[CurrentProfile])
01142                             ProfileReportLink = _getProfileReportLink(repdir,CurrentCandle,
01143                                                                      CurDir,
01144                                                                      step,
01145                                                                      CurrentProfile,
01146                                                                      OutputHtml[CurrentProfile])
01147                             #if ProfileReportLink:
01148                             #    print ProfileReportLink
01149                             isProfinLink = False
01150                             if len (ProfileReportLink) > 0:
01151                                 isProfinLink = reduce(lambda x,y: x or y,map(lambda x: CurrentProfile in x,ProfileReportLink))
01152 
01153                             if isProfinLink:
01154                                 #It could also not be there
01155 
01156                                 if (PrintedOnce==False): 
01157                                     #Making sure it's printed only once per directory (TimeSize, IgProf, Valgrind) each can have multiple profiles
01158 
01159                                     #This is the "title" of a series of profiles, (TimeSize, IgProf, Valgrind)
01160                                     CAND.write("<p><strong>%s</strong></p>\n" % CurDir)
01161                                     CAND.write("<ul>\n")
01162                                     PrintedOnce=True
01163                                 
01164                                 #Special cases first (IgProf MemAnalyse and Valgrind MemCheck)
01165                                 #Add among the special cases any IgProfMem (5,6,7) since now we added the dumping:
01166                                 if (CurrentProfile == Profile[5] or CurrentProfile == Profile[6]):
01167                                     for prolink in ProfileReportLink:
01168                                         _writeReportLink(CAND,prolink,CurrentProfile,step,NumOfEvents[CurDir])
01169                                     for igprofmem in ["*IgProfMemTotal*.res","*IgProfMemLive*.res"]:
01170                                         ProfileReportLink = _getProfileReportLink(repdir,CurrentCandle,
01171                                                                                  CurDir,
01172                                                                                  step,
01173                                                                                  CurrentProfile,
01174                                                                                  igprofmem)
01175                                         isProfinLink = False
01176                                         if len (ProfileReportLink) > 0:
01177                                             isProfinLink = reduce(lambda x,y: x or y,map(lambda x: CurrentProfile in x,ProfileReportLink))                                        
01178                                         if isProfinLink :#It could also not be there
01179                                             #for prolink in ProfileReportLink:
01180                                             IgProfDumpsTable(CAND,ProfileReportLink,step)
01181                                             #    _writeReportLink(CAND,prolink,CurrentProfile,step,NumOfEvents[CurDir],Profiler=os.path.basename(prolink))
01182                                     
01183                                 elif (CurrentProfile == Profile[7]):
01184                                     for igprof in IgProfMemAnalyseOut:
01185                                         ProfileReportLink = _getProfileReportLink(repdir,CurrentCandle,
01186                                                                                  CurDir,
01187                                                                                  step,
01188                                                                                  CurrentProfile,
01189                                                                                  igprof)
01190                                         isProfinLink = False
01191                                         if len (ProfileReportLink) > 0:
01192                                             isProfinLink = reduce(lambda x,y: x or y,map(lambda x: CurrentProfile in x,ProfileReportLink))                                        
01193                                         if isProfinLink :#It could also not be there
01194                                             for prolink in ProfileReportLink:
01195                                                 _writeReportLink(CAND,prolink,CurrentProfile,step,NumOfEvents[CurDir],Profiler=igprof)
01196 
01197 
01198                                 elif (CurrentProfile == Profile[9]):
01199 
01200                                     for memprof in memcheck_valgrindOut:
01201                                         #print memprof
01202                                         ProfileReportLink = _getProfileReportLink(repdir,CurrentCandle,
01203                                                                                   CurDir,
01204                                                                                   step,
01205                                                                                   CurrentProfile,
01206                                                                                   memprof
01207                                                                                   )
01208                                         isProfinLink = False
01209                                         if len (ProfileReportLink) > 0:
01210                                             isProfinLink = reduce(lambda x,y: x or y,map(lambda x: CurrentProfile in x,ProfileReportLink))                                        
01211                                         if isProfinLink :#It could also not be there                                        
01212                                             for prolink in ProfileReportLink:
01213                                                 _writeReportLink(CAND,prolink,CurrentProfile,step,NumOfEvents[CurDir],Profiler=memprof)
01214 
01215                                 else:
01216                                     for prolink in ProfileReportLink:
01217                                         if "regression" not in prolink: #To avoid duplication of links to regression reports!
01218                                             _writeReportLink(CAND,prolink,CurrentProfile,step,NumOfEvents[CurDir])
01219                                             #print "Step is %s, CurrentProfile is %s and ProfileReportLink is %s and prolink is %s"%(step,CurrentProfile,ProfileReportLink,prolink)
01220 
01221 
01222                     if PrintedOnce:
01223                         CAND.write("</ul>\n")
01224                     PrintedOnce=False
01225 
01226                 CAND.write("<hr />")
01227                 CAND.write("<br />\n")
01228                 CAND.write("</div>\n")
01229             elif candnreg.search(line):
01230                 CAND.write(CurrentCandle)
01231             else:
01232                 CAND.write(line)
01233 
01234         CAND.close()
01235     except IOError, detail:
01236         print "ERROR: Could not write candle html %s because %s" % (os.path.basename(candlHTML),detail)
01237 
01238 
01239 def populateFromTupleRoot(tupname,repdir,rootfile,pureg):
01240     table = Table()
01241     for cand in Candles:
01242         fname = CandFname[cand]
01243         globpath = os.path.join(repdir,"%s_TimeSize" % cand,"%s_*_TimingReport" % fname)
01244         stepDirs = glob.glob(globpath)
01245         stepDirs = map(lambda x: (fname,x), stepDirs)
01246         stepDirs.sort(cmp=timerep_cmp)
01247         stepDirs = map(lambda x: x[1], stepDirs)
01248         stepreg = re.compile("%s_(.*)_TimingReport" % fname)
01249         createNewRow = True
01250         curRow = None
01251         createPURow = True
01252         puRow = None
01253         for stepdir in stepDirs:
01254             base  = os.path.basename(stepdir)
01255             found = stepreg.search(base)
01256             step  = "Unknown-step"
01257             if found:
01258                 step = found.groups()[0]
01259             realstep  = "Unknown-step"
01260             if "PILEUP" in step:
01261                 found = pureg.search(step)
01262                 if found:
01263                     realstep = found.groups()[0]
01264                 if createPURow:
01265                     createPURow = False
01266                     puRow = Row(table)                
01267             rootf = os.path.join(stepdir,rootfile)
01268 
01269             if os.path.exists(rootf):
01270                 f = ROOT.TFile(rootf)
01271 
01272                 cpu_time_tree = ROOT.TTree()
01273                 f.GetObject("cpu_time_tuple;1",cpu_time_tree)
01274                 if cpu_time_tree:
01275                     if cpu_time_tree.InheritsFrom("TTree"):
01276                         data1 = None
01277                         data2 = None
01278                         for t in cpu_time_tree:
01279                             data1 = t.total1
01280                             data2 = t.total2
01281                         if data1 and data2:
01282                             if createNewRow:
01283                                 createNewRow = False
01284                                 curRow = table.newRow(cand)
01285                             data_tuple = (data1,data2)
01286 
01287                             if "PILEUP" in step:
01288                                 puRow.addEntry(realstep,data_tuple)
01289                             else:
01290                                 if createNewRow:
01291                                     createNewRow = False
01292                                     curRow = table.newRow(cand)
01293 
01294                                 curRow.addEntry(step,data_tuple)
01295                 f.Close()
01296         if puRow == None:
01297             pass
01298         else:
01299             table.addRow(puRow,"%s PILEUP" %cand)                
01300     return table
01301                 
01302 
01303 def createHTMLtab(INDEX,table_dict,ordered_keys,header,caption,name,mode=0):
01304     cols     = len(ordered_keys)
01305     totcols  = (cols * 3) + 1
01306     innercol = 3
01307     colspan  = totcols - 1
01308     labels   = []
01309     if mode == 1:
01310         labels = ["fs1","fs2","&#x0394;"]
01311     elif mode == 2 or mode == 3:
01312         colspan = cols
01313         innercol = 1
01314     else:
01315         labels = ["t1" ,"t2" ,"&#x0394;"]
01316 
01317 
01318     INDEX.write("<h3>%s</h3>\n" % header)
01319     INDEX.write("<table>\n")
01320     INDEX.write("<caption>%s</caption>\n" % caption)
01321     INDEX.write("<thead><tr><th></th><th colspan=\"%s\" scope=\"colgroup\">%s</th></tr></thead>" % (colspan,name)) 
01322     INDEX.write("<tbody>\n")
01323     for key in ordered_keys:
01324         INDEX.write("<tr>")
01325         if key == None:
01326             INDEX.write("<th></th>")
01327         else:
01328             INDEX.write("<td scope=\"row\">")
01329             INDEX.write(key)
01330             INDEX.write("</td>")
01331         for col in table_dict[None]:
01332             if key == None:
01333                 INDEX.write("<th colspan=\"%s\" scope=\"col\">" % innercol)
01334                 INDEX.write(col)
01335                 INDEX.write("</th>")                            
01336             else:
01337                 rowdict = table_dict[key].getRowDict()
01338                 if rowdict.has_key(col):
01339                     if mode == 2:
01340                         dat = prettySize(rowdict[col])
01341                         INDEX.write("<td>")
01342                         INDEX.write("%s" % dat)
01343                         INDEX.write("</td>")
01344                         
01345                     elif mode == 3:
01346                         dat = rowdict[col]
01347                         INDEX.write("<td>")
01348                         INDEX.write("%6.2f" % dat)
01349                         INDEX.write("</td>")                        
01350                     else:
01351                         (data1, data2) = rowdict[col]
01352                         diff = data2 - data1
01353 
01354                         if mode == 1:
01355                             diff  = prettySize(diff)
01356                             data1 = prettySize(data1)
01357                             data2 = prettySize(data2)
01358                         
01359                         seq = [ data1, data2, diff ]
01360                         for dat in seq:
01361                             INDEX.write("<td id=\"data\">")
01362                             if mode == 1:
01363                                 INDEX.write("%s" % dat) # %s if                            
01364                             else:
01365                                 INDEX.write("%6.2f" % dat) # %s if                            
01366 
01367                             INDEX.write("</td>")
01368                 else:
01369                     if mode == 2 or mode == 3:
01370                         INDEX.write("<td>")                                    
01371                         INDEX.write("N/A")
01372                         INDEX.write("</td>")                         
01373                     else:
01374                         for i in range(3):
01375                             INDEX.write("<td>")                                    
01376                             INDEX.write("N/A")
01377                             INDEX.write("</td>") 
01378         INDEX.write("</tr>\n")
01379         # write an additional row if this row is the header row
01380         # we need to describe the sub columns
01381         if not (mode == 2 or mode == 3 ):
01382             if key == None:
01383                 INDEX.write("<tr>")
01384                 INDEX.write("<th>Candles</th>")
01385                 for col in table_dict[None]:
01386                     INDEX.write("<th>%s</th>" % labels[0])
01387                     INDEX.write("<th>%s</th>" % labels[1])
01388                     INDEX.write("<th>%s</th>" % labels[2])
01389                 INDEX.write("</tr>\n")
01390     INDEX.write("</tbody></table>\n")
01391 
01392     INDEX.write("<br />")    
01393 
01394 def stageIgProfReports(remotedir,arch,version):
01395     '''Publish all IgProf files into one remote directory (new naming convention). Can publish to AFS location or to a local directory on a remote (virtual) machine.'''
01396     #FIXME: can eliminate this part if using tar pipes... was done with rsynch in mind
01397     #Compose command to create remote dir:
01398     if ":" in remotedir: #Remote host local directory case
01399         (host,dir)=remotedir.split(":")
01400         mkdir_cmd="ssh %s (mkdir %s;mkdir %s/%s)"%(host,dir,dir,arch)
01401     else: #AFS or local case
01402         mkdir_cmd="mkdir %s;mkdir %s/%s"%(remotedir,remotedir,arch)
01403 
01404     #Create remote dir:
01405     try:
01406         print mkdir_cmd
01407         os.system(mkdir_cmd)
01408         print "Successfully created publication directory"
01409     except:
01410         print "Issues with publication directory existence/creation!"
01411         
01412     #Copy files over to remote dir
01413     #replacing rsync with tar pipes since it can hang on AFS (Andreas' experience):
01414     #rsync_cmd="rsync -avz *_IgProf_*/*.sql3 %s/%s/%s"%(remotedir,arch,version)
01415     if ":" in remotedir:
01416         tarpipe_cmd='tar cf - *_IgProf_*/*.sql3 | ssh %s "cd %s/%s; mkdir %s; cd %s; tar xf -; mv *_IgProf_*/*.sql3 .; rmdir *_IgProf_*"'%(host,dir,arch,version,version)
01417     else:
01418         tarpipe_cmd='tar cf - *_IgProf_*/*.sql3 | (cd %s/%s; mkdir %s; cd %s; tar xf -; mv *_IgProf_*/*.sql3 .; rmdir *_IgProf_*)'%(remotedir,arch,version,version)
01419     try:
01420     #    print rsync_cmd
01421     #    os.system(rsync_cmd)
01422         print tarpipe_cmd
01423         os.system(tarpipe_cmd)
01424         print "Successfully copied IgProf reports to %s"%remotedir
01425     except:
01426         print "Issues with rsyncing to the remote directory %s!"%remotedir
01427 
01428     #Make sure permissions are set for group to be able to write:
01429     if ":" in remotedir: #Remote host local directory case
01430         chmod_cmd="ssh %s chmod -R 775 %s/%s"%(host,dir,arch)
01431     else:
01432         chmod_cmd="chmod -R 775 %s/%s"%(remotedir,arch)
01433     try:
01434         print chmod_cmd
01435         os.system(chmod_cmd)
01436         print "Successfully set permissions for IgProf reports directory %s"%remotedir
01437     except:
01438         print "(Potential) issues with chmoding the remote directory %s!"%remotedir
01439     
01440     return #Later, report here something like the web link to the reports in igprof-navigator...
01441 
01442 
01443 #####################
01444 #
01445 # Create web report index and create  HTML file for each candle
01446 #
01447 def createWebReports(WebArea,repdir,ExecutionDate,LogFiles,cmsScimarkResults,date,prevrev):
01448 
01449     #Some nomenclature
01450 
01451     Candle = Candles #These need to match the directory names in the work area
01452 
01453     CmsDriverCandle = CandFname #{ #These need to match the cmsDriver.py output filenames
01454 
01455 
01456     #Produce a "small" index.html file to navigate the html reports/logs etc
01457     IndexFile="%s/index.html" % WebArea
01458     TemplateHtml="%s/doc/index.html" % BASE_PERFORMANCE
01459 
01460     cmsverreg = re.compile("CMSSW_VERSION")
01461     hostreg   = re.compile("HOST")
01462     lpathreg  = re.compile("LocalPath")
01463     fsizereg  = re.compile("FSizeTable")        
01464     cpureg    = re.compile("CPUTable")    
01465     proddreg  = re.compile("ProductionDate")
01466     logfreg   = re.compile("LogfileLinks")
01467     dirbreg   = re.compile("DirectoryBrowsing")
01468     pubdreg   = re.compile("PublicationDate")
01469     candhreg  = re.compile("CandlesHere")
01470     #Loop line by line to build our index.html based on the template one
01471     #Copy the perf_style.css file from Validation/Performance/doc
01472 
01473     CandlTmpltHTML="%s/doc/candle.html" % BASE_PERFORMANCE
01474     if _verbose:
01475         print "Copying %s/doc/perf_style.css style file to %s/." % (BASE_PERFORMANCE,WebArea)    
01476         print "Template used: %s" % TemplateHtml
01477 
01478     syscp((BASE_PERFORMANCE + "/doc/perf_style.css"),WebArea + "/.")
01479     pureg = re.compile("(.*)_PILEUP")    
01480     try:
01481         INDEX = open(IndexFile,"w") 
01482         for NewFileLine in open(TemplateHtml) :
01483             if cmsverreg.search(NewFileLine):
01484                 if prevrev == "":
01485                     INDEX.write("Performance Reports for %s\n" % CMSSW_VERSION)
01486                 else:
01487                     globpath = os.path.join(repdir,"REGRESSION.%s.vs.*" % (prevrev))
01488                     globs = glob.glob(globpath)
01489                     if len(globs) < 1:
01490                         pass
01491                     else:
01492                         latestreg = re.compile("REGRESSION.%s.vs.(.*)" % prevrev)
01493                         found = latestreg.search(os.path.basename(globs[0]))
01494                         if found:
01495                             latestrel = found.groups()[0]
01496                             INDEX.write("Performance Reports with regression: %s VS %s\n" % (prevrev,latestrel))                                                        
01497                         else:
01498                             INDEX.write("Performance Reports with regression: %s VS %s\n" % (prevrev,CMSSW_VERSION))                            
01499             elif hostreg.search(NewFileLine):
01500                 INDEX.write(HOST + "\n")
01501             #File Size Summary Table
01502             elif fsizereg.search(NewFileLine):
01503                 #Case of NO-REGRESSION:
01504                 if prevrev == "":
01505                     fsize_tab = Table()
01506 
01507                     for cand in Candles:
01508                         fname = CandFname[cand]
01509                         globpath  = os.path.join(repdir,"%s*_TimeSize" % cand,"%s_*.root" % fname)
01510                         rootfiles = glob.glob(globpath)
01511                         rootfiles = map(lambda x: (fname,x), rootfiles)
01512                         rootfiles.sort(cmp=rootfile_cmp)
01513                         rootfiles = map(lambda x: x[1], rootfiles)
01514                         stepreg = re.compile("%s_(.*).root" % fname)
01515                         createNewRow = True
01516                         curRow = None
01517                         createPURow = True
01518                         puRow = None                        
01519                         for rootf in rootfiles:
01520                             base  = os.path.basename(rootf)
01521                             found = stepreg.search(base)
01522                             step  = "Unknown-step"
01523                             if found:
01524                                 step = found.groups()[0]
01525                             realstep  = "Unknown-step"
01526                             if "PILEUP" in step:
01527                                 found = pureg.search(step)
01528                                 if found:
01529                                     realstep = found.groups()[0]
01530                                 if createPURow:
01531                                     createPURow = False
01532                                     puRow = Row(fsize_tab)
01533                             try:
01534                                 statinfo = os.stat(rootf)
01535                                 fsize    = statinfo.st_size
01536                                 if createNewRow:
01537                                     createNewRow = False
01538                                     curRow = fsize_tab.newRow(cand)
01539                                     
01540                                 if "PILEUP" in step:
01541                                     puRow.addEntry(realstep,fsize)
01542                                 else:
01543                                     if createNewRow:
01544                                         createNewRow = False
01545                                         curRow = fsize_tab.newRow(cand)
01546                                         
01547                                     curRow.addEntry(step,fsize)       
01548                             except IOError, detail:
01549                                 print detail
01550                             except OSError, detail:
01551                                 print detail
01552                         if puRow == None:
01553                             pass
01554                         else:
01555                             fsize_tab.addRow(puRow,"%s PILEUP" %cand)                                                                    
01556                     (ordered_keys,table_dict) = fsize_tab.getTable(1)
01557                     cols = len(ordered_keys)
01558                     
01559                     if len(table_dict) > 1 and cols > 0:
01560                         createHTMLtab(INDEX,table_dict,ordered_keys,
01561                                       "Release ROOT file sizes",
01562                                       "Table showing current release ROOT filesizes in (k/M/G) bytes.",
01563                                       "Filesizes",2)   
01564                 #Case of REGRESSION vs previous release:
01565                 else:
01566                     try:
01567                         globpath = os.path.join(repdir,"REGRESSION.%s.vs.*" % (prevrev))
01568                         globs = glob.glob(globpath)
01569                         if len(globs) < 1:
01570                             raise IOError(2,globpath,"File does not exist","File does not exist")
01571                         idfile  = open(globs[0])
01572                         oldpath = ""
01573                         for line in idfile:
01574                             oldpath = line
01575                         oldpath = oldpath.strip()
01576                         #print "##########TABLE DEBUG :oldpath is %s"%oldpath
01577                         fsize_tab = Table()
01578 
01579                         for cand in Candles:
01580                             fname = CandFname[cand]
01581                             globpath  = os.path.join(repdir,"%s*_TimeSize" % cand,"%s_*.root" % fname)
01582                             rootfiles = glob.glob(globpath)
01583                             rootfiles = map(lambda x: (fname,x), rootfiles)
01584                             rootfiles.sort(cmp=rootfile_cmp)
01585                             rootfiles = map(lambda x: x[1], rootfiles)
01586                             stepreg = re.compile("%s_(.*).root" % fname)
01587                             createNewRow = True
01588                             curRow = None
01589                             createPURow = True
01590                             puRow = None                            
01591                             for rootf in rootfiles:
01592                                 base  = os.path.basename(rootf)
01593                                 found = stepreg.search(base)
01594                                 step  = "Unknown-step"
01595                                 if found:
01596                                     step = found.groups()[0]
01597                                     
01598                                 realstep  = "Unknown-step"
01599                                 if "PILEUP" in step:
01600                                     found = pureg.search(step)
01601                                     if found:
01602                                         realstep = found.groups()[0]
01603                                     if createPURow:
01604                                         createPURow = False
01605                                         puRow = Row(fsize_tab)
01606                                 try:
01607                                     statinfo = os.stat(rootf)
01608                                     fsize2   = statinfo.st_size
01609                                     oldfile  = os.path.join(oldpath,"%s_TimeSize" % cand,base)
01610                                     if "PILEUP" in step:
01611                                         oldfile  = os.path.join(oldpath,"%s_PU_TimeSize" % cand,base)
01612                                     fsize1   = 0
01613 
01614                                     if os.path.exists(oldfile):
01615                                         statinfo = os.stat(oldfile)
01616                                         fsize1   = statinfo.st_size
01617                                     else:
01618                                         print "######DID NOT FIND Previous file (needed for the filesize table): %s"%oldfile
01619                                             
01620                                     if createNewRow:
01621                                         createNewRow = False
01622                                         curRow = fsize_tab.newRow(cand)
01623 
01624                                     data_tuple = (fsize1,fsize2)
01625                                     if "PILEUP" in step:
01626                                         puRow.addEntry(realstep,data_tuple)
01627                                     else:
01628                                         if createNewRow:
01629                                             createNewRow = False
01630                                             curRow = fsize_tab.newRow(cand)
01631 
01632                                         curRow.addEntry(step,data_tuple)
01633                                 except IOError, detail:
01634                                     print detail
01635                                 except OSError, detail:
01636                                     print detail
01637                             if puRow == None:
01638                                 pass
01639                             else:
01640                                 fsize_tab.addRow(puRow,"%s PILEUP" %cand)                                    
01641                                     
01642                         (ordered_keys,table_dict) = fsize_tab.getTable()
01643                         cols = len(ordered_keys)
01644                     
01645                         if len(table_dict) > 1 and cols > 0:
01646                             createHTMLtab(INDEX,table_dict,ordered_keys,
01647                                           "Release ROOT file sizes",
01648                                           "Table showing previous release ROOT filesizes, fs1, latest sizes, fs2, and the difference between them &#x0394; in (k/M/G) bytes.",
01649                                           "Filesizes",1)
01650                     except IOError, detail:
01651                         print detail
01652                     except OSError, detail:
01653                         print detail
01654             #CPU Time Summary Table    
01655             elif cpureg.search(NewFileLine):
01656                 #Case of NO REGRESSION
01657                 if prevrev == "":
01658                     time_tab = Table()
01659 
01660                     for cand in Candles:
01661                         fname = CandFname[cand]
01662                         globpath  = os.path.join(repdir,"%s*_TimeSize" % cand,"%s_*_TimingReport.log" % fname)
01663                         logfiles = glob.glob(globpath)
01664                         logfiles = map(lambda x: (fname,x), logfiles)
01665                         logfiles.sort(cmp=logrep_cmp)                        
01666                         logfiles = map(lambda x: x[1], logfiles)
01667 
01668                         stepreg = re.compile("%s_(.*)_TimingReport.log" % fname)
01669                         createNewRow = True
01670                         curRow = None
01671                         createPURow = True
01672                         puRow = None
01673                         for log in logfiles:
01674                             base  = os.path.basename(log)
01675                             found = stepreg.search(base)
01676                             step  = "Unknown-step"
01677                             if found:
01678                                 step = found.groups()[0]
01679 
01680                             realstep  = "Unknown-step"
01681                             if "PILEUP" in step:
01682                                 found = pureg.search(step)
01683                                 if found:
01684                                     realstep = found.groups()[0]
01685                                 if createPURow:
01686                                     createPURow = False
01687                                     puRow = Row(time_tab)
01688                                 
01689                             data = cpr.getTimingLogData(log)
01690                             mean = 0
01691                             i    = 0
01692                             for evtnum, time in data:
01693                                 mean += time
01694                                 i += 1
01695                             try:
01696                                 mean = mean / float(i)
01697                             except ZeroDivisionError, detail:
01698                                 print "WARNING: Could not calculate mean CPU time from log because no events could be parsed", log
01699 
01700                             if "PILEUP" in step:
01701                                 puRow.addEntry(realstep,mean)
01702                             else:
01703                                 if createNewRow:
01704                                     createNewRow = False
01705                                     curRow = time_tab.newRow(cand)
01706 
01707                                 curRow.addEntry(step,mean)                                
01708                         if puRow == None:
01709                             pass
01710                         else:
01711                             time_tab.addRow(puRow,"%s PILEUP" %cand)
01712 
01713                     (ordered_keys,table_dict) = time_tab.getTable(1)
01714                     cols = len(ordered_keys)
01715                     
01716                     if len(table_dict) > 1 and cols > 0:
01717                         createHTMLtab(INDEX,table_dict,ordered_keys,
01718                                       "Release CPU times",
01719                                       "Table showing current release CPU times in secs.",
01720                                       "CPU Times (s)",3)
01721                 #Case of REGRESSION (CPU Time Summary Table)
01722                 else:
01723 
01724 
01725                     ####
01726                     #
01727                     # Create the table data structure
01728                     #
01729                     cpu_time_tab =  populateFromTupleRoot("cpu_time_tuple",repdir,"timing-regress.root",pureg)
01730                     
01731 
01732                     ###########
01733                     #
01734                     # Create HTML table from table data structure
01735                     #
01736 
01737                     (ordered_keys,table_dict) = cpu_time_tab.getTable()
01738 
01739                     cols = len(ordered_keys)
01740                     if len(table_dict) > 1 and cols > 0:
01741                         createHTMLtab(INDEX,table_dict,ordered_keys,
01742                                       "Release CPU times",
01743                                       "Table showing previous release CPU times, t1, latest times, t2, and the difference between them &#x0394; in secs.",
01744                                       "CPU Times (s)")
01745 
01746                         
01747                     
01748             elif lpathreg.search(NewFileLine):
01749                 INDEX.write(repdir + "\n")
01750             elif proddreg.search(NewFileLine):
01751                 INDEX.write(ExecutionDate + "\n")
01752             elif logfreg.search(NewFileLine):
01753                 INDEX.write("<br />\n")
01754                 for log in LogFiles:
01755                     log = os.path.basename(log)
01756                     if _verbose:
01757                         print "linking log file %s" % log
01758                     INDEX.write("<a href=\"./%s\"> %s </a>" % (log,log))
01759                     INDEX.write("<br />\n")
01760                 #Add the cmsScimark results here:
01761                 INDEX.write("Results for cmsScimark2 benchmark (running on the other cores) available at:\n")
01762                 for cmssci in cmsScimarkResults:
01763                     scimarkdirs=cmssci.split("/")
01764                     localdir=scimarkdirs[-2]
01765                     #print localdir
01766                     cmssci = os.path.basename(cmssci)
01767                     relativelink=os.path.join(localdir,cmssci)
01768                     #print relativelink
01769                     INDEX.write("<a href=\"%s\"> %s </a>" % (relativelink,cmssci))
01770                     INDEX.write("<br />\n")
01771 
01772 
01773             elif dirbreg.search(NewFileLine):
01774                 #Create a subdirectory DirectoryBrowsing to circumvent the fact the dir is not browsable if there is an index.html in it.
01775                 #Bug! This does not work since it points to index.html automatically!
01776                 #os.symlink("./","%s/DirectoryBrowsing" % WebArea)
01777                 #Actually all the following is done later...
01778                 #Create a physical directory first
01779                 #os.mkdir("%s/DirectoryBrowsing" % WebArea)
01780                 #Then will populate it with symbolic links(once they have been copied there!) from all WebArea files, except index.html, see down towards the end!
01781                 INDEX.write("Click <a href=\"./DirectoryBrowsing/\">here</a> to browse the directory containing all results (except the root files)\n")
01782 
01783             elif pubdreg.search(NewFileLine):
01784                 INDEX.write(date + "\n")
01785             elif candhreg.search(NewFileLine):
01786                 for acandle in Candle:
01787                     globpath = os.path.join(repdir,"%s_*" % acandle)
01788                     globs = glob.glob(globpath)
01789                     if len(globs) > 0:
01790                         candlHTML = "%s.html" % acandle
01791                         INDEX.write("<a href=\"./%s\"> %s </a>" % (candlHTML,acandle))
01792                         INDEX.write("<br />\n")
01793                     
01794                         candlHTML=os.path.join(WebArea,candlHTML)
01795                         createCandlHTML(CandlTmpltHTML,candlHTML,acandle,WebArea,repdir,ExecutionDate,LogFiles,cmsScimarkResults,date,prevrev)
01796             else:
01797                 INDEX.write(NewFileLine)
01798 
01799         #End of while loop on template html file
01800         INDEX.close()
01801     except IOError, detail:
01802         print "Error: Could not create index Html file for some reason, check position. Details : %s" % detail
01803 
01804 ########################
01805 #
01806 # Grab dirs that end in strings defined in DirName
01807 #
01808 def getDirnameDirs(repdir,WebArea):
01809     Dir = os.listdir(repdir)
01810     def _containsDirName(elem):
01811         return reduce(lambda x,y: x or y,map(lambda x: x in elem, DirName))
01812     def _print4Lambda(elem,WebArea):
01813         if _verbose:
01814             print "Copying %s to %s\n" %  (elem,WebArea)
01815 
01816     dirstocp = filter(lambda x: _containsDirName(x),map(lambda x: repdir + x,Dir))
01817     map(lambda x: _print4Lambda(x,WebArea),dirstocp)
01818     syscp(dirstocp,WebArea + "/")
01819     os.mkdir("%s/DirectoryBrowsing" % WebArea)
01820     for file in os.listdir(WebArea):
01821         if file != "index.html": #Potential maintenance issue if the index.html changes name to something the server automatically displays when pointing to the directory...
01822             #Use relative path ".." instead of WebArea to avoid problems when copying stuff to a remote server!
01823             os.symlink("%s/%s"%("..",file),"%s/DirectoryBrowsing/%s" % (WebArea,file))
01824 
01825 #######################
01826 #
01827 # Upload stage to remote location
01828 def syncToRemoteLoc(stage,drive,path,port):
01829     stage = addtrailingslash(stage)
01830     cmd = "rsync -avz"
01831     # We must, MUST, do os.path.normpath otherwise rsync will dump the files in the directory
01832     # we specify on the remote server, rather than creating the CMS_VERSION directory
01833     #--rsh=\"ssh -l relval\" 
01834     args = "--port=%s %s %s:%s" % (port,os.path.normpath(stage),drive,path)
01835     retval = -1
01836     if _dryrun:
01837         print              cmd + " --dry-run " + args 
01838         retval = os.system(cmd + " --dry-run " + args )
01839     else:
01840         print cmd+" "+args
01841         retval = os.system(cmd + " " + args)
01842     return retval
01843 
01844 ################
01845 # 
01846 # Delete tmp dir if we used it
01847 def delTmpDir():
01848     if os.path.exists(TMP_DIR) and IS_TMP:
01849         os.system("rm -Rf " + TMP_DIR)
01850 
01851 #####################
01852 #
01853 # Some functions used for copying
01854 
01855 def getRelativeDir(parent,child,keepTop=True):
01856     def _walkpath(path):
01857         dirs = []
01858         while True:
01859             head , tail = os.path.split(path)
01860             if tail == "":
01861                 break
01862             dirs.append(tail)
01863             path = head
01864         for i in range(len(dirs)-1,-1,-1):
01865             adir = dirs[i]
01866             yield adir
01867         return
01868     pwalk = _walkpath(parent)
01869     n = 0
01870     try:
01871         while True:
01872             pwalk.next()
01873             n += 1
01874     except StopIteration:
01875         pass
01876 
01877     if keepTop:
01878         n = n - 1
01879 
01880     cwalk = _walkpath(child)
01881     try:
01882         #prewalk
01883         for x in range(n):
01884             cwalk.next()
01885     except StopIteration:
01886         print "ERROR: Unable to determine relative dir"
01887         raise ReldirExcept
01888 
01889     relpath = ""
01890     try:
01891         while True:
01892             relpath=os.path.join(relpath,cwalk.next())
01893     except StopIteration:
01894         pass
01895     return relpath
01896 
01897 def docopy(src,dest):
01898     try:
01899         copy2(src,dest)
01900     except OSError, detail:
01901         print "WARNING: Could not copy %s to %s because %s" % (src,dest,detail)        
01902     except IOError, detail:
01903         print "WARNING: Could not copy %s to %s because %s" % (src,dest,detail)
01904     else:
01905         if _verbose:
01906             print "Copied %s to %s" % (src,dest)
01907 
01908 def copytree4(src,dest,keepTop=True):
01909     def _getNewLocation(source,child,dst,keepTop=keepTop):
01910         place = getRelativeDir(source,child,keepTop=keepTop)
01911         return os.path.join(dst,place)
01912     def _copyFilter(source,dst,curdir,fsnodes,filter,dirs=False):
01913         for node in fsnodes:
01914             dontFilter = True
01915             filterExist = not len(filter) == 0
01916             if filterExist:
01917                 dontFilter = not reduce(lambda x,y: x or y,map(lambda x: fnmatch.fnmatch(node,x),filter))
01918             if dontFilter:
01919                 node = os.path.join(curdir,node) # convert to absolute path
01920                 try:
01921                     newnode = _getNewLocation(source,node,dst)
01922                     if dirs:
01923                         os.mkdir(newnode)                
01924                     else:
01925                         copy2(node,newnode)
01926                 except IOError, detail:
01927                     print "WARNING: Could not copy %s to %s because %s" % (node,newnode,detail)
01928                 except OSError, detail:
01929                     print "WARNING: Could not copy %s to %s because %s" % (src,dest,detail)                    
01930                 except ReldirExcept:
01931                     print "WARNING: Could not determine new location for source %s into destination %s" % (source,dst)
01932                 else:
01933                     if len(filter) > 0:
01934                         try:
01935                             match = fnmatch.fnmatch(node,filter[0])
01936                             assert not match
01937                         except AssertionError, detail:
01938                             print node, filter[0], match
01939                             raise RuntimeError
01940                     if _verbose:
01941                         if "root" in node:                            
01942                             print "Filter %s Copied %s to %s" % (dontFilter,node,newnode)
01943                             print "fnmatch %s" % fnmatch.fnmatch(node,cpFileFilter[0]) 
01944                     
01945     gen  = os.walk(src)
01946     try:
01947         newloc = _getNewLocation(src,src,dest)
01948 
01949         os.mkdir(newloc)
01950         try:
01951             while True:
01952                 step   = gen.next()
01953                 curdir = step[0]
01954                 dirs   = step[1]
01955                 files  = step[2]
01956 
01957                 _copyFilter(src,dest,curdir,dirs,cpDirFilter,dirs=True)
01958                 _copyFilter(src,dest,curdir,files,cpFileFilter)
01959 
01960         except StopIteration:
01961             pass        
01962     except IOError, detail:
01963         print "WARNING: Could not copy %s to %s because %s" % (src,dest,detail)
01964     except OSError, detail:
01965         print "WARNING: Could not copy %s to %s because %s" % (src,dest,detail)        
01966     except ReldirExcept:
01967         print "WARNING: Could not determine the new location for source %s into destination %s" % (src,dest)
01968         
01969 def syscp(srcs,dest):
01970     if type(srcs) == type(""):
01971         if os.path.exists(srcs):
01972             if os.path.isdir(srcs):
01973                 copytree4(srcs,dest)
01974             else:
01975                 docopy(srcs,dest)
01976         else:
01977             print "ERROR: file to be copied %s does not exist" % foo            
01978     else:
01979         for src in srcs:
01980             if os.path.exists(src):
01981                 if os.path.isdir(src):
01982                 #copy tree
01983                     copytree4(src,dest)
01984                 else:
01985                     docopy(src,dest)
01986             else:
01987                 print "ERROR: file to be copied %s does not exist" % foo
01988             
01989 def print_header():
01990     print "%s\n" % PROG_NAME
01991 
01992 if __name__ == "__main__":
01993     main()