00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
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
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", )
00030 cpDirFilter = ( )
00031
00032 TimeSizeNumOfEvents = -9999
00033 IgProfNumOfEvents = -9999
00034 CallgrindNumOfEvents = -9999
00035 MemcheckNumOfEvents = -9999
00036
00037 DirName=(
00038 "TimeSize",
00039 "IgProf",
00040 "IgProf_Perf",
00041 "IgProf_Mem",
00042 "Callgrind",
00043 "Memcheck",
00044
00045 "PU_TimeSize",
00046 "PU_IgProf",
00047 "PU_IgProf_Perf",
00048 "PU_IgProf_Mem",
00049 "PU_Callgrind",
00050 "PU_Memcheck"
00051 )
00052
00053 Steps=set(Step+ProductionSteps+["GEN,FASTSIM","GEN,FASTSIM_PILEUP"])
00054 print Steps
00055
00056
00057
00058
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
00080
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
00087
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
00201
00202 def main():
00203 global TimeSizeNumOfEvents,IgProfNumOfEvents,CallgrindNumOfEvents,MemcheckNumOfEvents
00204
00205
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
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
00231 print_header()
00232
00233
00234
00235 print "\n Getting Environment variables..."
00236 (LocalPath, ShowTagsResult) = get_environ()
00237
00238
00239 (options,args) = optionparse()
00240
00241
00242 print "\n Determining locations for input and staging..."
00243 (drive,path,remote,stage,port,repdir,prevrev,igprof_remotedir) = getStageRepDirs(options,args)
00244
00245
00246 print "\n Getting the number of events for each test..."
00247
00248 cmsPerfSuiteLogfile="%s/cmsPerfSuite.log"%repdir
00249
00250 if os.path.exists(cmsPerfSuiteLogfile):
00251 try:
00252 (TimeSizeNumOfEvents,IgProfNumOfEvents,CallgrindNumOfEvents,MemcheckNumOfEvents)=getNumOfEventsFromLog(cmsPerfSuiteLogfile)
00253
00254 (CMSSW_arch,CMSSW_version)=getArchVersionFromLog(cmsPerfSuiteLogfile)
00255
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
00263 (ExecutionDate,LogFiles,date,cmsScimarkResults,cmsScimarkDir) = scanReportArea(repdir)
00264 print "cmsScimarkResults are %s"%cmsScimarkResults
00265 print "\n Copy report files to staging directory..."
00266
00267 _copyReportsToStaging(repdir,LogFiles,cmsScimarkDir,stage)
00268
00269 print "\n Creating log file..."
00270
00271 _createLogFile("%s/ProductionLog.txt" % stage,date,repdir,ShowTagsResult)
00272
00273
00274 for dirname in os.listdir(repdir):
00275 if "IgProf" in dirname:
00276 print "\n Handling IgProf reports..."
00277
00278 stageIgProfReports(igprof_remotedir,CMSSW_arch,CMSSW_version)
00279
00280 print "\n Creating HTML files..."
00281
00282 createWebReports(stage,repdir,ExecutionDate,LogFiles,cmsScimarkResults,date,prevrev)
00283
00284 print "\n Copy profiling logs to staging directory..."
00285
00286 getDirnameDirs(repdir,stage)
00287
00288
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
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
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
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
00359 )
00360
00361 parser.add_option(
00362 '-v',
00363 '--verbose',
00364 action="store_true",
00365 dest='verbose',
00366 help='output more information',
00367
00368 )
00369
00370 parser.add_option(
00371 '--simul',
00372 action="store_true",
00373 dest='simulation',
00374 help='Use the default simulation location',
00375
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',
00408
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
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
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
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
00459
00460
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
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]
00528 else:
00529 defaultlocal = True
00530 uri = DEF_LOCAL
00531
00532
00533
00534
00535
00536
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
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
00578
00579
00580 StagingArea=""
00581 localExists = os.path.exists("%s/%s" % (CMSSW_WORK,CMSSW_VERSION))
00582
00583 if remote:
00584
00585
00586 TMP_DIR=tmp.mkdtemp(prefix="/build/%s" % PROG_NAME)
00587 StagingArea = TMP_DIR
00588
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
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
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
00621
00622
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
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
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
00659
00660
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
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
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
00799 if stepreg.search(xstr) and x_idx == -1:
00800 bestx_idx = i
00801 if stepreg.search(ystr) and y_idx == -1:
00802 besty_idx = i
00803
00804 if Step[i] == xstr and x_idx == -1:
00805 x_idx = i
00806 if Step[i] == ystr and y_idx == -1:
00807 y_idx = i
00808 if not ( x_idx == -1 or y_idx == -1):
00809 break
00810
00811
00812 if x_idx == -1:
00813 x_idx = bestx_idx
00814 if y_idx == -1:
00815 y_idx = besty_idx
00816
00817
00818 if x_idx == -1:
00819 x_idx = sndbst_x
00820 if y_idx == -1:
00821 y_idx = sndbst_y
00822
00823
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
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
00857
00858 ProfileTemplate=os.path.join(repdir, "%s_%s" % (CurrentCandle,CurDir), "*_%s_%s*" % (step,CurrentProfile),Profiler)
00859
00860
00861 ProfileTemplateLowCaps=os.path.join(repdir, "%s_%s" % (CurrentCandle,CurDir), "*_%s_%s*" % (step.lower(),CurrentProfile),Profiler)
00862 ProfileReportLink = glob.glob(ProfileTemplate)
00863
00864
00865
00866
00867
00868
00869 if len(ProfileReportLink) > 0:
00870
00871 if not reduce(lambda x,y: x or y,map(lambda x: CurrentCandle in x,ProfileReportLink)):
00872 ProfileReportLink = glob.glob(ProfileTemplateLowCaps)
00873 else:
00874 ProfileReportLink = glob.glob(ProfileTemplateLowCaps)
00875 ProfileReportLink = map(lambda x: _stripbase(repdir,x),ProfileReportLink)
00876
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
00884 if CurrentProfile == "memcheck_valgrind":
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
00890 EndOfJobProfileLink=filter(lambda x: "IgProfMemTotal.res" in x or "IgProfMemLive.res" in x, ProfileLinks)[0]
00891
00892 ProfileLinks.remove(EndOfJobProfileLink)
00893
00894 ProfileLinks.sort(key=lambda x: int(x.split(".")[-2]))
00895
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
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
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
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
00916 INDEX.write("</table>")
00917 INDEX.write("</li>")
00918
00919
00920
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
00939 "TimingReport",
00940 "TimeReport",
00941 "SimpleMemReport",
00942 "EdmSize",
00943 "IgProfperf",
00944 "IgProfMemTotal",
00945 "IgProfMemLive",
00946 "IgProfMemAnalyse",
00947 "valgrind",
00948 "memcheck_valgrind"
00949 )
00950 IgProfMemAnalyseOut=(
00951 "doBeginJob_output.html",
00952 "doEvent_output.html",
00953 "mem_live.html",
00954 "mem_total.html"
00955 )
00956 memcheck_valgrindOut=(
00957 "beginjob.html",
00958 "edproduce.html",
00959 "esproduce.html"
00960 )
00961 OutputHtml={
00962 Profile[0] : "*TimingReport.html",
00963 Profile[1] : "TimeReport.html",
00964 Profile[2] : "*.html",
00965 Profile[3] : "objects_pp.html",
00966 Profile[4] : "overall.html",
00967 Profile[5] : "overall.html",
00968 Profile[6] : "overall.html",
00969 Profile[7] : "doBeginJob_output.html",
00970 Profile[8] : "overall.html",
00971 Profile[9] : "beginjob.html"
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
00998
00999 if CurDir == DirName[0] or CurDir == DirName[6]:
01000 profs = Profile[0:4]
01001 elif CurDir == DirName[1] or CurDir == DirName[7]:
01002 profs = Profile[4:8]
01003 elif CurDir == DirName[2] or CurDir == DirName[8]:
01004 profs =[Profile[4]]
01005 elif CurDir == DirName[3] or CurDir == DirName[9]:
01006 profs =Profile[5:8]
01007 elif CurDir == DirName[4] or CurDir == DirName[10]:
01008 profs = [Profile[8]]
01009 elif CurDir == DirName[5] or CurDir == DirName[11]:
01010 profs = [Profile[9]]
01011
01012
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
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
01139 for step in Steps:
01140
01141
01142 ProfileReportLink = _getProfileReportLink(repdir,CurrentCandle,
01143 CurDir,
01144 step,
01145 CurrentProfile,
01146 OutputHtml[CurrentProfile])
01147
01148
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
01155
01156 if (PrintedOnce==False):
01157
01158
01159
01160 CAND.write("<p><strong>%s</strong></p>\n" % CurDir)
01161 CAND.write("<ul>\n")
01162 PrintedOnce=True
01163
01164
01165
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 :
01179
01180 IgProfDumpsTable(CAND,ProfileReportLink,step)
01181
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 :
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
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 :
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:
01218 _writeReportLink(CAND,prolink,CurrentProfile,step,NumOfEvents[CurDir])
01219
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","Δ"]
01311 elif mode == 2 or mode == 3:
01312 colspan = cols
01313 innercol = 1
01314 else:
01315 labels = ["t1" ,"t2" ,"Δ"]
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)
01364 else:
01365 INDEX.write("%6.2f" % dat)
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
01380
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
01397
01398 if ":" in remotedir:
01399 (host,dir)=remotedir.split(":")
01400 mkdir_cmd="ssh %s (mkdir %s;mkdir %s/%s)"%(host,dir,dir,arch)
01401 else:
01402 mkdir_cmd="mkdir %s;mkdir %s/%s"%(remotedir,remotedir,arch)
01403
01404
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
01413
01414
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
01421
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
01429 if ":" in remotedir:
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
01441
01442
01443
01444
01445
01446
01447 def createWebReports(WebArea,repdir,ExecutionDate,LogFiles,cmsScimarkResults,date,prevrev):
01448
01449
01450
01451 Candle = Candles
01452
01453 CmsDriverCandle = CandFname
01454
01455
01456
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
01471
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
01502 elif fsizereg.search(NewFileLine):
01503
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
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
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 Δ in (k/M/G) bytes.",
01649 "Filesizes",1)
01650 except IOError, detail:
01651 print detail
01652 except OSError, detail:
01653 print detail
01654
01655 elif cpureg.search(NewFileLine):
01656
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
01722 else:
01723
01724
01725
01726
01727
01728
01729 cpu_time_tab = populateFromTupleRoot("cpu_time_tuple",repdir,"timing-regress.root",pureg)
01730
01731
01732
01733
01734
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 Δ 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
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
01766 cmssci = os.path.basename(cmssci)
01767 relativelink=os.path.join(localdir,cmssci)
01768
01769 INDEX.write("<a href=\"%s\"> %s </a>" % (relativelink,cmssci))
01770 INDEX.write("<br />\n")
01771
01772
01773 elif dirbreg.search(NewFileLine):
01774
01775
01776
01777
01778
01779
01780
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
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
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":
01822
01823 os.symlink("%s/%s"%("..",file),"%s/DirectoryBrowsing/%s" % (WebArea,file))
01824
01825
01826
01827
01828 def syncToRemoteLoc(stage,drive,path,port):
01829 stage = addtrailingslash(stage)
01830 cmd = "rsync -avz"
01831
01832
01833
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
01847 def delTmpDir():
01848 if os.path.exists(TMP_DIR) and IS_TMP:
01849 os.system("rm -Rf " + TMP_DIR)
01850
01851
01852
01853
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
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)
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
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()