diff --git a/Control/PerformanceMonitoring/PerfMonAna/CMakeLists.txt b/Control/PerformanceMonitoring/PerfMonAna/CMakeLists.txt index cd6c384f07969c5793da4d1b121d6b5b597a7197..034fdd28c6ac46df39f3172c301286c8e2216647 100644 --- a/Control/PerformanceMonitoring/PerfMonAna/CMakeLists.txt +++ b/Control/PerformanceMonitoring/PerfMonAna/CMakeLists.txt @@ -6,11 +6,16 @@ atlas_subdir( PerfMonAna ) # External dependencies: find_package( pandas ) find_package( sqlalchemy ) +# These need to be added to Externals first, then enabled +# However, the fact that they're missing is not an immediate +# Showstopper... +#find_package( matplotlib ) +#find_package( numpy ) find_package( ROOT COMPONENTS Core PyROOT Tree MathCore Hist RIO pthread ) # Install files from the package: -atlas_install_python_modules( python/*.py ) -atlas_install_scripts( bin/*.py ) +atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) +atlas_install_scripts( bin/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) # Aliases: atlas_add_alias( perfgrind "perfgrind.py" ) diff --git a/Control/PerformanceMonitoring/PerfMonAna/bin/perf-dpmon.py b/Control/PerformanceMonitoring/PerfMonAna/bin/perf-dpmon.py index 112d40a56886d4e8787a8e794ee23ebb7a9ff1c3..6c3685fe1f96c98e6d39ae35ea410ca6086024bf 100755 --- a/Control/PerformanceMonitoring/PerfMonAna/bin/perf-dpmon.py +++ b/Control/PerformanceMonitoring/PerfMonAna/bin/perf-dpmon.py @@ -1,6 +1,6 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration # @file: perf-dpmon.py # @purpose: analyze the output of PerfMon::StorePayloadMon to display the # DataProxies' payload sizes @@ -13,38 +13,31 @@ __doc__ = "analyze the output of PerfMon::StorePayloadMon to display the Dat import os, glob import sys -import traceback def ana(fname, n_consumers): - import numpy as np - import matplotlib.pyplot as plt - DpLoad_dtype = np.dtype([('b0','int32'), ('b1','int32'), ('delta','int32'), - ('clid','|S40'),('sg','|S40')]) - import imp mod_name = 'perf_dpmon_data_%s' % ( os.path.splitext(os.path.basename(fname))[0], ) mod_file = open(fname) mod = imp.load_module(mod_name, mod_file, fname, ('', '', imp.PY_SOURCE)) - #execfile(fname) dp_mon_data = getattr(mod, 'data') nevts = len(dp_mon_data) - for ievt in xrange(nevts): + for ievt in range(nevts): data = dp_mon_data[ievt] store= data[-1] - print "::: evt=%4i: %10d -> %10d -- delta= %10d (= %10.3f kb)" % ( - ievt, store[0], store[1], store[2], store[2]/1024.) + print( "::: evt=%4i: %10d -> %10d -- delta= %10d (= %10.3f kb)" % ( + ievt, store[0], store[1], store[2], store[2]/1024.) ) top_consumers = [ d for d in data[:-1] ] - top_consumers.sort(cmp=lambda x,y: cmp(x[2], y[2])) - print "::: top-consumers: (%s/%s)" % (n_consumers,len(top_consumers)) + top_consumers = sorted(top_consumers, key=lambda x: x[2]) + print( "::: top-consumers: (%s/%s)" % (n_consumers,len(top_consumers)) ) for c in top_consumers[:n_consumers]: - print "%4s %10d -> %10d -- delta= %10d (= %10.3f kb) [%s#%s]" % ( + print( "%4s %10d -> %10d -- delta= %10d (= %10.3f kb) [%s#%s]" % ( '', c[0], c[1], c[2], c[2]/1024., c[3], c[4], - ) + ) ) del dp_mon_data del mod @@ -71,7 +64,7 @@ def main(): (options, args) = parser.parse_args() - if isinstance(options.input_files, basestring): + if isinstance(options.input_files, str): options.input_files = [ options.input_files ] for arg in args: @@ -85,23 +78,23 @@ def main(): input_files += f if len(input_files) == 0: - print "ERROR: invalid input files (do they exist ?)" - print "ERROR: got: %r" % options.input_files + print( "ERROR: invalid input files (do they exist ?)" ) + print( "ERROR: got: %r" % options.input_files ) return 1 all_good = True for fname in input_files: try: - print ":"*80 - print "::: analyzing: [%s]..." % (fname,) + print( ":"*80 ) + print( "::: analyzing: [%s]..." % (fname,) ) ana(fname, options.n_consumers) - print "::: analyzing: [%s]... [done]" % (fname,) - print "" - except Exception, err: - print "ERROR: caught:\n%s" % (err,) + print( "::: analyzing: [%s]... [done]" % (fname,) ) + print( "" ) + except Exception as err: + print( "ERROR: caught:\n%s" % (err,) ) all_good = False - print "::: bye." + print( "::: bye." ) if all_good: return 0 return 1 diff --git a/Control/PerformanceMonitoring/PerfMonAna/bin/perfgrind.py b/Control/PerformanceMonitoring/PerfMonAna/bin/perfgrind.py index 5bd35e4950f5d76bb946b742a4dab5c2c70a7df0..e1a19d8a54ebc6654d52b9ed00a272826e169976 100755 --- a/Control/PerformanceMonitoring/PerfMonAna/bin/perfgrind.py +++ b/Control/PerformanceMonitoring/PerfMonAna/bin/perfgrind.py @@ -1,6 +1,6 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration # @file PerfMonAna/bin/perfgrind.py # @purpose a little script to convert a pmon.gz file into a kcachegrind one # @date December 2009 @@ -10,7 +10,6 @@ __doc__ = "a little script to convert a pmon.gz file into a kcachegrind one" __author__ = "Sebastien Binet" ### imports ------------------------------------------------------------------- -import os import sys import argparse diff --git a/Control/PerformanceMonitoring/PerfMonAna/bin/perfmon.py b/Control/PerformanceMonitoring/PerfMonAna/bin/perfmon.py index 05ad464624a61feb4ffa707fec073c3aadd38aae..63f9305f6b9721b313d0ead7c9f9bfdf6dd237d1 100755 --- a/Control/PerformanceMonitoring/PerfMonAna/bin/perfmon.py +++ b/Control/PerformanceMonitoring/PerfMonAna/bin/perfmon.py @@ -1,6 +1,6 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration # @file: perfmon.py # @purpose: launch the performance monitoring analysis script # @author: Sebastien Binet <binet@.cern.ch> @@ -42,7 +42,7 @@ def main(): help = "comma-separated list of analyzers to be run during perfmon "\ "processing (eg: cpu,mem,io)" ) - + p( "-l", "--labels", dest = "dsLabels", @@ -97,8 +97,8 @@ def main(): print ("ERROR: you need to give an output file name !") parser.print_help() return ExitCodes.ERROR - - if type(options.inputFiles) == type(""): + + if isinstance(options.inputFiles, str): options.inputFiles = [ options.inputFiles ] for arg in args: @@ -106,14 +106,14 @@ def main(): options.inputFiles += [ arg ] from PerfMonAna.PyRootLib import importRoot - ROOT = importRoot( batch = options.rootBatch ) + ROOT = importRoot( batch = options.rootBatch ) # noqa: F841 inputFiles = [] for f in options.inputFiles: f = glob.glob(os.path.expandvars(os.path.expanduser(f))) f.sort() inputFiles += f - + ## we want to preserve the potential order of files ## => don't use a set inputFileNames = [] @@ -126,17 +126,17 @@ def main(): print ("ERROR: got: %r" % options.inputFiles) #parser.print_help() return ExitCodes.ERROR - + if options.outFileName is None: outFileName = os.path.basename(inputFileNames[0]) options.outFileName = outFileName.replace(".pmon.gz", ".perfmon.root") - + outFileName = os.path.expandvars(os.path.expanduser(options.outFileName)) ## massage the supposedly comma-separated list of dataset labels dsLabels = None - if type(options.dsLabels) == type(""): + if isinstance(options.dsLabels, str): options.dsLabels = options.dsLabels.strip() if options.dsLabels.count(",") > 0: dsLabels = options.dsLabels.split(",") @@ -149,7 +149,7 @@ def main(): analyzers = options.analyzers.split(",") else: analyzers = ( options.analyzers, ) - + ## loads and install the user filtering function from PerfMonAna.UserFct import loadFilterFct loadFilterFct(options.selectionUri) @@ -167,7 +167,7 @@ def main(): traceback.print_exc( file = sys.stdout ) sc = ExitCodes.ERROR pass - + return sc @@ -176,11 +176,11 @@ if __name__ == "__main__": print (":"*80) print ("::: perfmon analysis script :::") print ("") - + sc = main() - + print ("") print ("::: bye") print (":"*80) sys.exit( sc ) - + diff --git a/Control/PerformanceMonitoring/PerfMonAna/bin/perfmonmt-plotter.py b/Control/PerformanceMonitoring/PerfMonAna/bin/perfmonmt-plotter.py old mode 100644 new mode 100755 index 6585790a5fcf7f9880e1bbbb5c868e69bd32528f..f1df6823bb3708a28172bb0caec02436c5a0ea8c --- a/Control/PerformanceMonitoring/PerfMonAna/bin/perfmonmt-plotter.py +++ b/Control/PerformanceMonitoring/PerfMonAna/bin/perfmonmt-plotter.py @@ -1,13 +1,12 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 + # Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration # @author: Hasan Ozturk <haozturk@cern.ch> - __author__ = "Hasan Ozturk <haozturk@cern.ch" __doc__ = "A python module which parses the PerfMonMTSvc results and makes plots" - import json import matplotlib @@ -96,7 +95,7 @@ def plotSnapshotLevel(snapshotData, plotname): stepNames, dCPUVals, dWallVals, dVmemVals, dRssVals, dPssVals, dSwapVals = [],[],[],[],[],[],[] for step in ['Finalize', 'Execute', 'Initialize', 'Configure']: meas = snapshotData[step] - + # Show in seconds dCPU = meas["dCPU"] * 0.001 dWall = meas["dWall"] * 0.001 @@ -106,7 +105,7 @@ def plotSnapshotLevel(snapshotData, plotname): dRss = meas["dRss"] * 0.001 dPss = meas["dPss"] * 0.001 dSwap = meas["dSwap"] * 0.001 - + stepNames.append(step) dCPUVals.append(dCPU) dWallVals.append(dWall) @@ -162,7 +161,7 @@ def plotSnapshotLevel(snapshotData, plotname): "ylabelFontSize": 40, "legendFontSize": 30 } - + plotBarChart(timeMonParams) plotBarChart(memMonParams) @@ -176,7 +175,7 @@ def plotSnapshotLevel(snapshotData, plotname): def plotComponentLevel(componentLevelData, compCountPerPlot): - + timeMonFig = plt.figure(figsize=(35,105)) memMonFig = plt.figure(figsize=(35,105)) @@ -292,7 +291,7 @@ def plotEventLevel(eventLevelData): timeMonParams = { "ax": timeMonAx, - "yVals": timeMonVals, + "yVals": timeMonVals, "xVals": eventVals, # Maybe x ticks? "xlabel": "Events", "ylabel": "Time [sec]", @@ -317,7 +316,7 @@ def plotEventLevel(eventLevelData): memMonFig.set_tight_layout(True) memMonFig.savefig("Event_Level_Memory") - + def main(): ''' Main function for producing plots from PerfMonMT JSON file.''' diff --git a/Control/PerformanceMonitoring/PerfMonAna/bin/perfmonmt-printer.py b/Control/PerformanceMonitoring/PerfMonAna/bin/perfmonmt-printer.py index 507fbaf6c16ae399520209a58d10ca9a2ab82f4a..b9e645a363cd68ee6cb4a5483cd61b20b5907ba1 100755 --- a/Control/PerformanceMonitoring/PerfMonAna/bin/perfmonmt-printer.py +++ b/Control/PerformanceMonitoring/PerfMonAna/bin/perfmonmt-printer.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python +#!/usr/bin/env python3 # Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration diff --git a/Control/PerformanceMonitoring/PerfMonAna/bin/perfrtt.py b/Control/PerformanceMonitoring/PerfMonAna/bin/perfrtt.py deleted file mode 100755 index a0b5973bd3bb089c5f9a1def0c82ac8b3840ae8a..0000000000000000000000000000000000000000 --- a/Control/PerformanceMonitoring/PerfMonAna/bin/perfrtt.py +++ /dev/null @@ -1,205 +0,0 @@ -#!/usr/bin/env python - -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration -# @file: perfrtt.py -# @purpose: thin layer on top of @c perfmon.py for RTT harvesting -# @author: Sebastien Binet <binet@.cern.ch> -# $Id: perfrtt.py,v 1.1 2007-07-18 23:02:25 binet Exp $ - -__author__ = "Sebastien Binet" -__version__ = "$Revision: 1.1 $" -__doc__ = "thin layer on top of @c perfmon.py for RTT harvesting" - -import os -import sys -import traceback -import glob - -def importRoot( batch = True ): - import sys - _oldArgs = sys.argv - if batch: sys.argv = sys.argv[:1] + ['-b'] + sys.argv[1:] - import ROOT - sys.argv = _oldArgs - del _oldArgs - return ROOT - -class Rtt: - Home = "/afs/cern.ch/atlas/project/RTT" - Nightlies = [ 'bugfix', 'val', 'mig0', 'dev' ] - Builds = [ '10', '11', '12', '13' ] - Platforms = [ 'slc3', 'slc4' ] - - class Release( object ): - """A simple modeling of an Athena release (nightly,release,platform,...) - """ - def __init__(self, id): - object.__init__(self) - - self.name = None - self.platform = None - self._parseId(id) - return - - def _parseId(self, id): - id = [ i.lower() for i in id.split(',') ] - print id - name = None - relName = [] - archName = [] - isStable = False - for i in id: - if 'rel' in i: - relName.append(i) - elif i in Rtt.Nightlies: - relName.append(i) - elif i.replace('.','').isdigit(): # 13.0.20 -> 13020' - isStable = True - name = i - else: - archName.append(i) - - if len(relName) == 0: - assert(isStable) - self.name = name - else: - self.name = [ i for i in relName if i not in Rtt.Nightlies ]+\ - [ i for i in relName if i in Rtt.Nightlies ] - - - if len(archName) == 0: - archName.append('opt') - self.platform = '-'.join(archName) - - print "name:",self.name - print "arch:",self.platform - return - - def isNightly(self): - return True - - def isStable(self): - return not self.isNightly() - - def _id(self): - if self.isNightly(): return self.name - else: return [self.name] - - def root(self): - return [ Rtt.Home, 'Results' ] + self._id() - - def cmtconfig(self): - return "i686-slc4-gcc34-"+self.platform - - pass # class RttRelease - - pass # class Rtt - -def rttPath( rel, pkgName = 'RecExRecoTest' ): - root = os.sep.join( - rel.root() + ['build', rel.cmtconfig(), 'offline', pkgName,'*'] - ) - rtt = [f for f in glob.glob(root) \ - if os.path.isdir(f) and os.path.basename(f) != "AthenaATN" ] - assert(len(rtt)==1) - return rtt[0] - -def main(): - """main entry point""" - sc = 0 - from optparse import OptionParser - parser = OptionParser( usage = "usage: %prog [options]" ) -## parser.add_option( -## "-f", -## "--file", -## dest = "chkFileName", -## help = "path to the performance monitoring file to analyze" -## ) -## parser.add_option( -## "-r", -## "--ref", -## dest = "refFileName", -## default = "", -## help = "path to the (reference) performance monitoring file (if any)" -## ) - -## parser.add_option( -## "-o", -## "--out", -## dest = "outFileName", -## default = "", -## help = "path to the output file which will contain analyzed performance monitoring data/infos" -## ) - - parser.add_option( - "--no-batch", - action = "store_false", - dest = "rootBatch", - default = False, - help = "Switch to tell ROOT to load graphics libraries" - ) - - parser.add_option( - "-b", - "--batch", - action = "store_true", - dest = "rootBatch", - default = True, - help = "Switch to tell ROOT _NOT_ to load graphics libraries" - ) - - (options, args) = parser.parse_args() - -## if len(args) > 0 and args[0][0] != "-": -## options.chkFileName = args[0] -## pass - -## if len(args) > 1 and args[1][0] != "-": -## options.refFileName = args[1] -## pass - -## if len(args) > 2 and args[2][0] != "-": -## options.outFileName = args[2] -## pass - -## ROOT = importRoot( batch = options.rootBatch ) - -## from PerfMonAna.PerfMonProcessing import ExitCodes -## if options.chkFileName == None: -## str(parser.print_help() or "ERROR: no help to print !!") -## return ExitCodes.ERROR - - rel = Rtt.Release( "rel_2,opt,val" ) - rtt= rttPath(rel) - print rtt - print os.listdir(rtt) -## chkFileName = os.path.expandvars(os.path.expanduser(options.chkFileName)) -## refFileName = os.path.expandvars(os.path.expanduser(options.refFileName)) -## outFileName = os.path.expandvars(os.path.expanduser(options.outFileName)) - -## try: -## from PerfMonAna import PerfMonProcessing as pm -## ana = pm.AnaMgr( chkFileName, refFileName, outFileName ) -## sc = ana.run() -## except Exception, err: -## print "::: Caught:",err -## traceback.print_exc( file = sys.stdout ) -## sc = ExitCodes.ERROR -## pass - - return sc - - - -if __name__ == "__main__": - print ":"*80 - print "::: perfRTT analysis script :::" - print "" - - sc = main() - - print "" - print "::: bye" - print ":"*80 - sys.exit( sc ) - diff --git a/Control/PerformanceMonitoring/PerfMonAna/bin/pmonsd.py b/Control/PerformanceMonitoring/PerfMonAna/bin/pmonsd.py index 22bfec7510080bc45535e4c8cbd53fb7aca881f3..aa56e2ec6616fd2cd52bf492812c5e903bdded94 100755 --- a/Control/PerformanceMonitoring/PerfMonAna/bin/pmonsd.py +++ b/Control/PerformanceMonitoring/PerfMonAna/bin/pmonsd.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration __doc__ ='Script for parsing and basic analysis of Semi-Detailed PerfMon (PMonSD) output. More info at https://twiki.cern.ch/twiki/bin/viewauth/Atlas/PerfMonSD' @@ -9,31 +9,31 @@ import sys def _usage(ec=0): import os appname=os.path.basename(sys.argv[0]) - print "Usage, one of the following:" - print - print "1) List most significant performance differences in PMonSD outputs:" - print " <EXPERIMENTAL FEATURE>" - print " %s --diff INFILE1 INFILE2"%appname - print - print "2) Parse PMonSD text output and create pickle file:" - print " %s --parse INFILE [--output=OUTFILE[.psd[.gz]]]"%appname - print - print "3) Print content in ASCII format:" - print " %s --print INFILE"%appname - print - print "4) Print content as a raw python dictionary:" - print " %s --print-raw INFILE [KEYS]"%appname - print - print "INFILE : can be a logfile, a PerfMon tar-ball with PMonSD info inside, or a pickle file" - print " produced earlier from one of those by this script. Infiles can be gzipped if" - print " they have the .gz extension. PerfMon tar-balls must have .pmon.gz extension," - print " and Pickle files must have a .psd or .psd.gz extension." - print "OUTFILE : File for storing parsed information in python pickle format." - print "KEYS : Specify a list of keys to \"dive into\" the extracted dictionary" - print - print "Note that if you prefer to work entirely in python, you can access all of the above" - print "functionality through the module PerfMonComps.PMonSD and the functions therein:" - print "PMonSD.parse(infile,outfile=None), PMonSD.print_ascii(infile) and PMonSD.diff(infile1,infile2)." + print( "Usage, one of the following:" ) + print( ) + print( "1) List most significant performance differences in PMonSD outputs:" ) + print( " <EXPERIMENTAL FEATURE>" ) + print( " %s --diff INFILE1 INFILE2"%appname ) + print( ) + print( "2) Parse PMonSD text output and create pickle file:" ) + print( " %s --parse INFILE [--output=OUTFILE[.psd[.gz]]]"%appname ) + print( ) + print( "3) Print content in ASCII format:" ) + print( " %s --print INFILE"%appname ) + print( ) + print( "4) Print content as a raw python dictionary:" ) + print( " %s --print-raw INFILE [KEYS]"%appname ) + print( ) + print( "INFILE : can be a logfile, a PerfMon tar-ball with PMonSD info inside, or a pickle file" ) + print( " produced earlier from one of those by this script. Infiles can be gzipped if" ) + print( " they have the .gz extension. PerfMon tar-balls must have .pmon.gz extension," ) + print( " and Pickle files must have a .psd or .psd.gz extension." ) + print( "OUTFILE : File for storing parsed information in python pickle format." ) + print( "KEYS : Specify a list of keys to \"dive into\" the extracted dictionary" ) + print( ) + print( "Note that if you prefer to work entirely in python, you can access all of the above" ) + print( "functionality through the module PerfMonComps.PMonSD and the functions therein:" ) + print( "PMonSD.parse(infile,outfile=None), PMonSD.print_ascii(infile) and PMonSD.diff(infile1,infile2)." ) sys.exit(ec) def main(args): @@ -47,12 +47,14 @@ def main(args): #Differences in the two files is not a failure. return 0 elif n in [2,3] and args[0]=='--parse': - if n==3: outfile=args[2] - else: outfile=args[1] + if n==3: + outfile=args[2] + else: + outfile=args[1] PerfMonComps.PMonSD.parse(args[1],outfile) return 0 elif n==2 and args[0]=='--print': - if PerfMonComps.PMonSD.print_ascii(args[1])==False:#todo: actually return false in case of problems + if not PerfMonComps.PMonSD.print_ascii(args[1]):#todo: actually return false in case of problems return 1 return 0 elif n>=2 and args[0]=='--print-raw': @@ -63,33 +65,33 @@ def main(args): #list index keys[0]=int(keys[0]) if keys[0]>=len(d): - print "ERROR: Index out of range: %i (Only found %i PMonSD summaries in input)"%(keys[0],len(d)) + print( "ERROR: Index out of range: %i (Only found %i PMonSD summaries in input)"%(keys[0],len(d)) ) return 1 d=d[int(keys[0])] keys=keys[1:] elif len(d)>1: - print "Parsed list of length %i. Specify index (0,1,...) to pick out specific dictionary"%len(d) + print( "Parsed list of length %i. Specify index (0,1,...) to pick out specific dictionary"%len(d) ) return 0 elif len(d)==1: d=d[0] else: - print "Did not parse any PMonSD info" + print( "Did not parse any PMonSD info" ) return 1 #Dive in, according to keys (all strings we assume): while keys: k=keys.pop(0) if not type(d)==dict: - print "ERROR: Can't dive further into dictionary. Remaining objects are:" - print ' '+str(d) + print( "ERROR: Can't dive further into dictionary. Remaining objects are:" ) + print( ' '+str(d) ) return 1 - if not k in d.keys(): - print "ERROR: Invalid key '%s'. Valid keys are:" - print ' '+str(d.keys()) + if k not in d.keys(): + print( "ERROR: Invalid key '%s'. Valid keys are:" ) + print( ' '+str(d.keys()) ) return 1 d=d[k] - print d + print( d ) if type(d)==dict: - print "Next keys: %s"%str(d.keys()) + print( "Next keys: %s"%str(d.keys()) ) return 0 elif n in [2,3] and args[0]=='--validate': #hidden feature to use by validation scripts. @@ -97,12 +99,12 @@ def main(args): #file is a pickle with result of previous parsings. #a) Test that we didn't change results from parsing: if n==3: - if PerfMonComps.PMonSD._validate_identical(args[1],args[2])!=True: - print 'ERROR: Detected differences in information loaded from %s and %s'%(args[1],args[2]) + if not PerfMonComps.PMonSD._validate_identical(args[1],args[2]): + print( 'ERROR: Detected differences in information loaded from %s and %s'%(args[1],args[2]) ) return 1 #b) Test that we can reproduce the output with the deparsing ability: - if PerfMonComps.PMonSD._validate_deparsing(args[1])!=True: - print 'ERROR: Errors detected in deparsing of %s'%args[1] + if not PerfMonComps.PMonSD._validate_deparsing(args[1]): + print( 'ERROR: Errors detected in deparsing of %s'%args[1] ) return 1 return 0 _usage(1) diff --git a/Control/PerformanceMonitoring/PerfMonAna/bin/pmontree.py b/Control/PerformanceMonitoring/PerfMonAna/bin/pmontree.py index 66eeb52fb0eacbc3d56cc543affaf199cdc3d9c2..bf1e8f938cafafa73e6ac5c1d289f7e898743428 100755 --- a/Control/PerformanceMonitoring/PerfMonAna/bin/pmontree.py +++ b/Control/PerformanceMonitoring/PerfMonAna/bin/pmontree.py @@ -1,6 +1,6 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration __author__ = "Frank Winklmeier" __version__ = "$Revision: 270227 $" @@ -9,7 +9,6 @@ __doc__ = "Script to create dependency tree of perfmon stats" import sys import operator import re -import tarfile import PerfMonComps.PerfMonSerializer as pmon_ser @@ -63,14 +62,15 @@ class ResUser(Resource): indent = (' '*level*(not opt.flat)) s = '\n' + indent + self._node() - for d in self.dep: s += d._show(level+1, showFct) + for d in self.dep: + s += d._show(level+1, showFct) return s def calcSelf(self, children=None): self.dvmem_self = self.dvmem def show(self, showFct=None): - print self._show(0, showFct), + print( self._show(0, showFct), ) def _node(self): return self.name @@ -80,13 +80,15 @@ class ResUser(Resource): """ # Mark dependents for deletion for d in self.dep: - if purgeFct(d): d.name = None + if purgeFct(d): + d.name = None # Recursively call children - for d in self.dep: d.purge(purgeFct) + for d in self.dep: + d.purge(purgeFct) # Remove from list - self.dep = [ d for d in self.dep if d.name!=None ] + self.dep = [ d for d in self.dep if d.name is not None ] class Comp(ResUser): """Component (Algorithm, Tool, Service, etc.) @@ -155,10 +157,12 @@ def getResUser(f, resTree, steps=['ini'], current=None): parent = current for line in f: - if line.startswith(('#','/io/')): continue + if line.startswith(('#','/io/')): + continue step,name,idx = sliceCompIdx(line) - if step not in steps: continue + if step not in steps: + continue # startAud if idx==0: @@ -182,7 +186,7 @@ def getResUser(f, resTree, steps=['ini'], current=None): # stopAud if idx==1: if name != current.name: - raise RuntimeError, "stop for %s within scope of %s" % (name, current.name) + raise RuntimeError( "stop for %s within scope of %s" % (name, current.name) ) else: current.set(line, idx) current.wrapup() @@ -190,48 +194,60 @@ def getResUser(f, resTree, steps=['ini'], current=None): if step=='cbk': offset = current.name.split(']+')[1] i = current.name.find('[') - if i>0: current.name = '%s{+%s}' % (current.name[:i],offset) + if i>0: + current.name = '%s{+%s}' % (current.name[:i],offset) if parent is None: current=None continue - else: return + else: + return def readEvents(f): """Read components for evt slice """ - reEvent = re.compile('AthenaEventLoopMgr\s*INFO\s*===>>> done processing event.*') + reEvent = re.compile(r'AthenaEventLoopMgr\s*INFO\s*===>>> done processing event.*') evt = None comps = [] # [ {name : [Comp]} ] for line in f: m = reEvent.match(line) if m: - if evt: evt+=1 - else: evt=0 + if evt: + evt+=1 + else: + evt=0 comps.append({}) - if evt is None: continue - + if evt is None: + continue + + ''' + ## FIX ME : This bit needs to be checked + ## It's not obvious what reAud is inteded to be... m = reAud.match(line) - if m and m.group('slice')!='evt': continue + if m and m.group('slice')!='evt': + continue if m and m.group('action')=='start': comp = Comp(m.group('comp')) comp.set(m, 0) - if not comp.name in comps[evt]: comps[evt][comp.name] = [] + if comp.name not in comps[evt]: + comps[evt][comp.name] = [] comps[evt][comp.name].append(comp) if m and m.group('action')=='stop': comp = comps[evt][comp.name][-1] comp.set(m, 1) comp.wrapup() + ''' return comps def resAvg(res): """Calculate average of list of resources""" - if len(res)==0: return None + if len(res)==0: + return None a = Comp(res[0].name) a.step = res[0].step for r in res: @@ -250,7 +266,8 @@ def calcEventAvg(comps, sliceObj=slice(None)): tmp = {} # { comp: [] } for evt in comps[sliceObj]: for comp in evt.keys(): - if not comp in tmp: tmp[comp] = [] + if comp not in tmp: + tmp[comp] = [] tmp[comp] += evt[comp] avg = [] @@ -267,8 +284,10 @@ def getCompList(resTree, resList): Call with resList = []. """ for r in resTree: - if isinstance(r, ResUser): resList.append(r) - for d in r.dep: getCompList([d], resList) + if isinstance(r, ResUser): + resList.append(r) + for d in r.dep: + getCompList([d], resList) return resList[:] @@ -279,11 +298,12 @@ def diff(table, opt, attrgetter=operator.attrgetter('dvmem')): for i,t in enumerate(table): for comp in t: label = comp.symbol + ' ' + comp.name - if not label in tmp: tmp[label] = [0]*len(table) + if label not in tmp: + tmp[label] = [0]*len(table) tmp[label][i] = attrgetter(comp) # Convert to list - if opt.min!=None: + if opt.min is not None: limit = opt.min + 0.00001 cmpTable = [ [k]+v for k,v in tmp.iteritems() if abs(v[1]-v[0])>limit ] else: @@ -292,12 +312,12 @@ def diff(table, opt, attrgetter=operator.attrgetter('dvmem')): if opt.diff and len(table)==2: cmpTable.sort( lambda x,y : (int(x[2]-x[1])-int(y[2]-y[1])), reverse=True ) for c in cmpTable: - print "%-60s %10.0f %10.0f %10.0f" % (c[0],c[1],c[2],c[2]-c[1]) + print( "%-60s %10.0f %10.0f %10.0f" % (c[0],c[1],c[2],c[2]-c[1]) ) else: cmpTable.sort( lambda x,y : int(x[1]-y[1]), reverse=True) for c in cmpTable: - print "%-60s" % c[0], - print "%10.0f "*(len(c)-1) % tuple(c[1:]) + print( "%-60s" % c[0], ) + print( "%10.0f "*(len(c)-1) % tuple(c[1:]) ) return @@ -308,8 +328,8 @@ def printTable(compList, opt): avgmalloc = c.dmalloc*1024/c.nmalloc else: avgmalloc = 0 - print "%-60s %10.0f %10.0f %10.0f %10.0f" %\ - (c.name,c.dvmem,c.dmalloc,c.nmalloc,avgmalloc) + print( "%-60s %10.0f %10.0f %10.0f %10.0f" %\ + (c.name,c.dvmem,c.dmalloc,c.nmalloc,avgmalloc) ) def main(): import argparse @@ -348,7 +368,7 @@ def main(): return 1 if opt.diff and len(opt.files)!=2: - print "Can only calculate difference if two files are given" + print( "Can only calculate difference if two files are given" ) return 1 slices = [opt.slice] @@ -368,26 +388,29 @@ def main(): # Read files resTreeList = [] for f in opt.files: - l = [] + z = [] fstream = pmon_ser.extract_pmon_files(f)['data'] - getResUser(fstream, l, slices) + getResUser(fstream, z, slices) del fstream - resTreeList.append(l[:]) + resTreeList.append(z[:]) # Calculate self-VMem - if not opt.libself: children = [SharedLib] - else: children = None - for r in resTreeList[-1]: r.calcSelf(children) + if not opt.libself: + children = [SharedLib] + else: + children = None + for r in resTreeList[-1]: + r.calcSelf(children) # Diff if len(opt.files)>1: - print '#'*80 + print( '#'*80 ) for i,f in enumerate(opt.files): - print "# [%d] %s" % (i+1,f) + print( "# [%d] %s" % (i+1,f) ) if opt.diff: - print "# [3] difference [2]-[1]" - print '#'*80 + print( "# [3] difference [2]-[1]" ) + print( '#'*80 ) table = [ getCompList(t,[]) for t in resTreeList ] if opt.self: @@ -399,12 +422,16 @@ def main(): # Only one file resTree = resTreeList[0] - if opt.min!=None: + if opt.min is not None: # Use VMem or self-VMem for filtering - vmem = lambda c : c.dvmem_self if (opt.self==True and hasattr(c,'dvmem_self')) else c.dvmem - for r in resTree: r.show(lambda c: vmem(c)>opt.min) + def vmem( c ): + result = c.dvmem_self if (opt.self is True and hasattr(c,'dvmem_self')) else c.dvmem + return result + for r in resTree: + r.show(lambda c: vmem(c)>opt.min) else: - for r in resTree: r.show() + for r in resTree: + r.show() return 0 @@ -412,9 +439,11 @@ def main(): if __name__ == "__main__": try: sys.exit(main()) - except IOError, e: + except IOError as e: (code, msg) = e - if (code==32): pass # ignore broken pipe exception - else: raise e + if (code==32): + pass # ignore broken pipe exception + else: + raise e except KeyboardInterrupt: sys.exit(1) diff --git a/Control/PerformanceMonitoring/PerfMonAna/python/Analyzer.py b/Control/PerformanceMonitoring/PerfMonAna/python/Analyzer.py index e50c95346b64249904c1fd4beff1d35d4367a1fa..fc2ff754944164fdbb6610f3aa98592d72ec8543 100755 --- a/Control/PerformanceMonitoring/PerfMonAna/python/Analyzer.py +++ b/Control/PerformanceMonitoring/PerfMonAna/python/Analyzer.py @@ -1,4 +1,4 @@ -# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration # @file: Analyzer.py # @purpose: a set of classes to analyze data from a perfmon tuple @@ -15,7 +15,6 @@ __version__ = "$Revision: 1.15 $" __doc__ = "A set of classes to analyze data from a perfmon tuple." import logging -import os from PerfMonAna.PyRootLib import importRoot @@ -37,7 +36,8 @@ def getAnalyzer(monVarName, monName): klass_path = monName[0].split('.') m = __import__('.'.join(klass_path[:-1]), fromlist=klass_path[-1:]) Klass = getattr(m, klass_path[-1]) - if len(monName)==2: monName = monName[1] + if len(monName)==2: + monName = monName[1] else: raise RuntimeError('unknown analyzer [monVarName=%r, monName=%r]' %\ (monVarName, monName)) @@ -96,7 +96,8 @@ def mon_project(tree, monInfos, id, varexp, selection="", opt="", hEvol = ROOT.TH1F(id, "%s;%s;%s" % (monInfos[0], monInfos[1], monInfos[2]), n, v2[0]-binWide/2., v2[n-1]+binWide/2.) _fill = hEvol.Fill - for i in xrange(n): _fill(v2[i], v1[i]) + for i in range(n): + _fill(v2[i], v1[i]) return (hEvol,hDistrib) def make_stack( canvas, pad_nbr, title, drawopt="nostack" ): @@ -112,48 +113,49 @@ def make_stack( canvas, pad_nbr, title, drawopt="nostack" ): def make_canvas(name, title, items, shape=None): ROOT = importRoot() nItems = len(items) - if shape is None: shape=(1,nItems) + if shape is None: + shape=(1,nItems) c = ROOT.gROOT.FindObject(name) #DR if c is None: - if not c: + if not c: drawOpt = "" c = ROOT.TCanvas(name, title) - setattr(c, '_stacks', [make_stack(c,i,title) for i in xrange(nItems)]) + setattr(c, '_stacks', [make_stack(c,i,title) for i in range(nItems)]) setattr(c, '_shape', shape) def _plot(self): return #DR if self._shape is None: return - if not self._shape : return - for ipad in xrange(self._shape[0]*self._shape[1]): - pad = self.cd(ipad+1) + if not self._shape : + return + for ipad in range(self._shape[0]*self._shape[1]): stack = self._stacks[ipad] print ("-->",ipad,self.GetName(),stack.GetName()) stack.Draw("nostack") - for gr in stack._graphs: gr.Draw("SAME") + for gr in stack._graphs: + gr.Draw("SAME") return setattr(c, '_plot', _plot) - if nItems>=1: c.Divide(shape[0], shape[1]) - elif nItems==0: return c + if nItems>=1: + c.Divide(shape[0], shape[1]) + elif nItems==0: + return c else: drawOpt = " SAME" if nItems>=1: for i,o in enumerate(items): - pad = c.cd(i+1); pad.SetGrid() - stack = c._stacks[i] + pad = c.cd(i+1) + pad.SetGrid() drawOpt = o[1]+drawOpt o = o[0] if isinstance(o, ROOT.TGraph): - o.GetHistogram().Draw(drawOpt); + o.GetHistogram().Draw(drawOpt) o.Draw(drawOpt) -## stack._graphs.append(o) -## stack.Add(o.GetHistogram(), drawOpt) else: -## stack.Add(o, drawOpt) o.Draw(drawOpt) #c._plot(c) return c - + class Analyzer(object): """ The base object for analyzing data from a perfmon tuple @@ -163,14 +165,14 @@ class Analyzer(object): object.__init__(self) self.msg = logging.getLogger( "Analyzer" ) self.msg.setLevel( logging.INFO ) - + self.name = name self.typeName = typeName self.nEntries = None self.minEvt = None self.maxEvt = None - + self.histos = { } return @@ -182,7 +184,7 @@ class Analyzer(object): self.bookHistos( monComp ) return - + def run(self, monComp): if self.visit( monComp ): @@ -191,15 +193,9 @@ class Analyzer(object): self.fitHistos ( monComp ) return -## def __bookHistos(self): -## return - -## def __fillHistos(self): -## return - def fitHistos(self, monComp): return - + ## class NoopAnalyzer(Analyzer): diff --git a/Control/PerformanceMonitoring/PerfMonAna/python/App.py b/Control/PerformanceMonitoring/PerfMonAna/python/App.py index fd8dcd5d5ccbec90e07f0f768ee53d67eb01e9bc..46c170b9743db6e10c1871c053b8ed7c33a59f1e 100644 --- a/Control/PerformanceMonitoring/PerfMonAna/python/App.py +++ b/Control/PerformanceMonitoring/PerfMonAna/python/App.py @@ -19,46 +19,36 @@ __doc__ = "A set of classes and utilities to post-process/analyze a (set of) import sys import os import logging -from array import array import numpy import six -#import pyximport -#pyximport.install(pyimport=True) -#from pyximport import pyxbuild -#pyxbuild.DEBUG = 0 - import tempfile mplconfig_dir = tempfile.mkdtemp(prefix='matplotlib-%s-' % os.getpid()) os.environ['MPLCONFIGDIR'] = mplconfig_dir import atexit def del_mplconfig_dir(): - #print ("... removing [%s] ..." % mplconfig_dir) import os if os.system('/bin/rm -rf %s' % mplconfig_dir): - print ("** could not remove temporary $MPLCONFIGDIR ** (sc=%s)" % (sc,)) + print ("** could not remove temporary $MPLCONFIGDIR **") return atexit.register(del_mplconfig_dir) #print ("===>",os.environ['MPLCONFIGDIR']) import matplotlib -if not 'matplotlib.backends' in sys.modules: +if 'matplotlib.backends' not in sys.modules: matplotlib.use('pdf') import matplotlib.pyplot as pyplot _rc = pyplot.rcParams _rc['legend.fontsize'] = 'medium' _rc['axes.titlesize'] = 'medium' -#_rc['text.fontsize'] = 'smaller' _rc['xtick.labelsize'] = 'small' _rc['ytick.labelsize'] = 'small' _rc['font.size'] = 7.0 -#_rc['figure.autolayout'] = True _rc['figure.dpi'] = 100 _rc['figure.subplot.bottom'] = 0.05 _rc['figure.subplot.hspace'] = 0.3 _rc['figure.subplot.right'] = 0.95 -#_rc['figure.subplot.left'] = 0.05 _rc['figure.subplot.top'] = 0.95 _rc['figure.subplot.wspace'] = 0.3 @@ -71,7 +61,7 @@ pyplot.legend = my_legend import pylab pylab.legend = my_legend del my_legend - + from .DataLoader import DataLoader __do_monitoring = False @@ -102,13 +92,17 @@ def _installLogger( lvl = logging.INFO ): logging.getLogger('').addHandler(logger) ## pre-defining some loggers with default logging-level - log = logging.getLogger("AppMgr"); log.setLevel( lvl ) + log = logging.getLogger("AppMgr") + log.setLevel( lvl ) for i in range(10): - log = logging.getLogger("AnaMgr-" + str(i).zfill(3)); + log = logging.getLogger("AnaMgr-" + str(i).zfill(3)) log.setLevel( lvl ) - log = logging.getLogger("Ana-chk"); log.setLevel( logging.ERROR ) - log = logging.getLogger("Ana-ref"); log.setLevel( logging.ERROR ) - log = logging.getLogger("Analyzer"); log.setLevel( logging.ERROR ) + log = logging.getLogger("Ana-chk") + log.setLevel( logging.ERROR ) + log = logging.getLogger("Ana-ref") + log.setLevel( logging.ERROR ) + log = logging.getLogger("Analyzer") + log.setLevel( logging.ERROR ) return ## install the logger at py-module import and clean-up @@ -159,14 +153,16 @@ class AppMgr(object): if fitSlice is None: self._fitSlice = '1:' - elif not ':' in fitSlice: + elif ':' not in fitSlice: bins = self.anaMgrs[0].bins nbins = len(bins[1:]) - try: fitSlice = float(fitSlice) - except ValueError: raise + try: + fitSlice = float(fitSlice) + except ValueError: + raise if fitSlice <= 0. or fitSlice > 1.: raise ValueError ( - "You have to give a fitSlice in (0.,1.] (got: %r)" % + "You have to give a fitSlice in (0.,1.] (got: %r)" % fitSlice) # get the last x percent of the total range, _ratio = (1.- float(fitSlice))*nbins @@ -179,7 +175,8 @@ class AppMgr(object): self._fitSlice += "95" elif nbins > 120 : self._fitSlice = "105:" - else: self._fitSlice = fitSlice + else: + self._fitSlice = fitSlice self.msg.info( "fit slice: [%s]", self._fitSlice ) self.analyzers = analyzers self.msg.info( "Scheduled analyzers: %r", self.analyzers ) @@ -190,7 +187,6 @@ class AppMgr(object): """ main entry point to run the post-processing of a perfmon job """ - msg=self.msg self.msg.info( "running app..." ) ## check everybody has the same bins for i in range(len(self.anaMgrs)): @@ -204,7 +200,7 @@ class AppMgr(object): self.msg.warning( " [%s] : %r", self.anaMgrs[j].name, self.anaMgrs[j].bins ) - + self.msg.info( "nbr of datasets: %i", len(DataSetMgr.instances.keys()) ) from . import Analyzer self.msg.info( "running analyzers..." ) @@ -232,10 +228,10 @@ class AppMgr(object): self.__writeRootFile() self.__writeAsciiFile() self.__writePdfFile() - + self.msg.info( "running app... [DONE]" ) return ExitCodes.SUCCESS - + def __filter(self, monComp): """hook for the user to filter out some MonitoredComponent""" ## user filtering fct @@ -251,12 +247,13 @@ class AppMgr(object): outFile = ROOT.fopen( outName, 'RECREATE' ) for dsName in DataSetMgr.names(): outFile.cd( "/" ) - outFile.mkdir( dsName ); outFile.cd( dsName ); + outFile.mkdir( dsName ) + outFile.cd( dsName ) for m in MonitoredComponent.instances.values(): - if (not m.name.startswith('PerfMonSlice') and + if (not m.name.startswith('PerfMonSlice') and not self.__filter(m)): continue - if not dsName in m.data: + if dsName not in m.data: continue for h in m.data[dsName]['histos'].values(): @@ -269,15 +266,17 @@ class AppMgr(object): outName ) self.msg.debug( "create ROOT file... [DONE]" ) return - + def __writePdfFile(self): figs = [] for k in [ 'ini', '1st', 'evt', 'fin', 'io' ]: if 'fig' in self.summary.sum[k]: f = self.summary.sum[k]['fig'] - if type(f) == type([]): figs.extend(f) - else: figs += [ f ] + if isinstance(f, list): + figs.extend(f) + else: + figs += [ f ] jobSlice = MonitoredComponent.instances['PerfMonSlice'] for k in [ 'cpu', 'mem', 'io' ]: fig = 'evt/%s' % k @@ -289,10 +288,13 @@ class AppMgr(object): for m in MonitoredComponent.instances.values(): if not self.__filter(m): continue - if m.type in ('alg','algtool','svc'): algFigs += m.figs.values() - elif m.type == 'io' : ioFigs += m.figs.values() - else: continue - + if m.type in ('alg','algtool','svc'): + algFigs += m.figs.values() + elif m.type == 'io': + ioFigs += m.figs.values() + else: + continue + figs += algFigs figs += ioFigs @@ -310,7 +312,7 @@ class AppMgr(object): def __writeAsciiFile(self): """Fill an ASCII with the summary data in a 'nice' format """ - outName = self.outputFile+".summary.txt" + outName = self.outputFile+".summary.txt" o = open( outName, 'w' ) _txt = self.summary.txt print (":"*80, file=o) @@ -318,18 +320,18 @@ class AppMgr(object): for i in ( 'ini','1st','evt','fin'): print ("=== [%s - %s] ===" % (i,c), file=o) for j in ( 'mem', 'cpu', 'allocs', ): - for l in _txt[i][j][c]: - print (l, file=o) + for z in _txt[i][j][c]: + print (z, file=o) print (":"*80, file=o) print ("="*80, file=o) o.close() - + if os.path.exists( outName ): self.msg.info( " --> (%10.3f kB) [%s]", os.stat(outName).st_size / 1024., outName ) return - + class AnaMgr(object): """ The main class to analyze the content of a perfmon tuple @@ -364,24 +366,20 @@ class AnaMgr(object): data['meta']['iocontainers'] ) storeNames = [ k for k in six.iterkeys(data['data']) if k != 'meta' ] compNames = [ c for c in compNames ] - + _monitor('4') dataSetName = self.name - ## print (">>>",len(compNames),len(data.keys())) - _data_keys = list(data.keys()) for compName in compNames: - ## print (":::::::::",compName) monComp = MonitoredComponent(compName, dataSetName) monData = monComp.data[dataSetName] for storeName in storeNames: - ## print ("--",storeName) try: monData[storeName] = data['data'][storeName][compName] except KeyError: monData[storeName] = None if storeName == 'io' and compName == 'PerfMonSlice': monData[storeName] = data['data']['io']['PerfMonSliceIo'] - + pass self.bins = numpy.arange(len(data['data']['evt']['PerfMonSlice'])) _monitor('5') @@ -390,7 +388,7 @@ class AnaMgr(object): _comps = list(data['meta']['components' ].keys()) _ioconts = data['meta']['iocontainers'] for monComp in MonitoredComponent.instances.values(): - if monComp.type != None: + if monComp.type is not None: continue monName = monComp.name if monName in _comps: @@ -400,18 +398,20 @@ class AnaMgr(object): ## FIXME: not there yet... ## monComp.domain = domain(_compsDb[monName]['class'], ## _compsDb[monName]['module']) - elif monName in _ioconts : monComp.type = 'io' - else : monComp.type = 'usr' + elif monName in _ioconts: + monComp.type = 'io' + else: + monComp.type = 'usr' pass _monitor('6') ## push the data into the according dataset dataSet = DataSetMgr(dataSetName, data) dataSet.bins = self.bins - + self.msg.debug( "Loading perfmon data... [OK]" ) return - + class MonitoredComponent(object): """ An object modelling a (Gaudi) component which has been monitored with the @@ -426,9 +426,12 @@ class MonitoredComponent(object): 'type' : None } def __new__(cls, *p, **kw): - if len(p) > 0: kw['name'] = p[0] - if len(p) > 1: kw['dataSetName'] = p[1] - if len(p) > 2: kw['data'] = p[2] + if len(p) > 0: + kw['name'] = p[0] + if len(p) > 1: + kw['dataSetName'] = p[1] + if len(p) > 2: + kw['data'] = p[2] # already created... if kw['name'] in cls.instances.keys(): @@ -440,12 +443,12 @@ class MonitoredComponent(object): for k in cls.__slots__.keys(): setattr(obj, k, cls.__slots__[k]) - + # update repository of instances cls.instances[kw['name']] = obj - + return obj - + def __init__(self, name, dataSetName): object.__init__(self) @@ -453,10 +456,10 @@ class MonitoredComponent(object): if not self.data: self.data = {} - + if not self.figs: self.figs = {} - + if dataSetName not in self.data: self.data[dataSetName] = {} @@ -476,7 +479,7 @@ class MonitoredComponent(object): for storeName,store in ds.items(): monKeys += [ k.split("/")[0] for k in store.keys() ] return [ k for k in set(monKeys) ] - + class DataSetMgr(object): """Borg-class (python-singleton) to hold the different 'dataset' """ @@ -489,9 +492,12 @@ class DataSetMgr(object): } def __new__(cls, *args, **kw): - if len(args) > 0: kw['name' ] = args[0] - if len(args) > 1: kw['data' ] = args[1] - if len(args) > 2: kw['label'] = args[2] + if len(args) > 0: + kw['name' ] = args[0] + if len(args) > 1: + kw['data' ] = args[1] + if len(args) > 2: + kw['label'] = args[2] # already created ? if kw['name'] in cls.instances.keys(): @@ -506,17 +512,17 @@ class DataSetMgr(object): # update repository of instances cls.instances[kw['name']] = obj - + return obj - + @staticmethod def labels( keys = None ): - if keys == None: + if keys is None: keys = list(DataSetMgr.instances.keys()) keys.sort() return [DataSetMgr.instances[k].label for k in keys] - + @staticmethod def names(): keys = list(DataSetMgr.instances.keys()) @@ -529,22 +535,25 @@ class DataSetMgr(object): # skip indigo... color = iter(list(pylab.cm.colors.cnames.keys())[1:]) return color - + def __init__(self, name, data, label=None): object.__init__(self) self.name = name - if not self.data: self.data = data - if not self.bins: self.bins = [] + if not self.data: + self.data = data + if not self.bins: + self.bins = [] + + if not self.label: + self.label = name - if not self.label: self.label = name - - if label == None: + if label is None: self.label = self.name - + return - - + + class PdfMgr(object): """Borg-class (python-singleton) to hold different Pdf files, containing multiple figures @@ -556,8 +565,10 @@ class PdfMgr(object): } def __new__(cls, *args, **kw): - if len(args) > 0: kw['name'] = args[0] - if len(args) > 1: kw['figs'] = args[1] + if len(args) > 0: + kw['name'] = args[0] + if len(args) > 1: + kw['figs'] = args[1] # already created ? if kw['name'] in cls.instances.keys(): @@ -572,10 +583,10 @@ class PdfMgr(object): # update repository of instances cls.instances[kw['name']] = obj - + return obj - - + + def __init__(self, name, figs = None): object.__init__(self) @@ -585,11 +596,8 @@ class PdfMgr(object): def save(self, pdfFileName, figs, orientation='portrait'): from matplotlib.backends.backend_pdf import PdfPages - - tmpFiles = [] + import os - os_close = os.close - from tempfile import mkstemp _monitor('7') if os.path.exists( pdfFileName ): os.remove( pdfFileName ) @@ -597,13 +605,14 @@ class PdfMgr(object): for idx,fig in enumerate(figs): out.savefig(fig) ## closing canvas to recover some memory - fig.clear(); del fig + fig.clear() + del fig figs[idx] = None - + _monitor('8') out.close() return - + """ def legend(*args, **kwargs): diff --git a/Control/PerformanceMonitoring/PerfMonAna/python/CpuAnalyzer.py b/Control/PerformanceMonitoring/PerfMonAna/python/CpuAnalyzer.py index 51f1a2ddd76c2f7a6191b80d4763c91a39c62b76..fc0c320b79d974944df7f3876ee3d581f001c18a 100755 --- a/Control/PerformanceMonitoring/PerfMonAna/python/CpuAnalyzer.py +++ b/Control/PerformanceMonitoring/PerfMonAna/python/CpuAnalyzer.py @@ -1,4 +1,4 @@ -# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration # @file: CpuAnalyzer.py # @purpose: a set of classes to analyze (CPU) data from a perfmon tuple @@ -12,12 +12,11 @@ __author__ = 'Sebastien Binet' __version__ = "$Revision: 1.19 $" __doc__ = "A set of classes to analyze (CPU) data from a perfmon tuple." -import os import logging -import numpy,pylab +import numpy import matplotlib.pyplot as plt from .PyRootLib import importRoot -from .Analyzer import Analyzer,bookAvgHist,mon_project,make_canvas +from .Analyzer import Analyzer,bookAvgHist from .Constants import Units class CpuAnalyzer( Analyzer ): @@ -26,7 +25,7 @@ class CpuAnalyzer( Analyzer ): the initialize and finalize steps (on a per-algorithm basis) and the execute step (on a per-event and per-algorithm basis). """ - + def __init__(self, name): Analyzer.__init__(self, name, 'cpu') self.msg = logging.getLogger( "Cpu-%s" % name ) @@ -34,15 +33,16 @@ class CpuAnalyzer( Analyzer ): return def visit(self, monComp): - if not monComp.type in ['alg','user']: + if monComp.type not in ['alg','user']: self.msg.debug( " skipping %s [%s]",monComp.name,monComp.type ) return False return True - + def bookHistos(self, monComp): ROOT = importRoot() #Analyzer.__bookHistos(self) - from .PyRootLib import setupRootStyle; setupRootStyle(); + from .PyRootLib import setupRootStyle + setupRootStyle() from .App import DataSetMgr for dataSetName in monComp.data.keys(): @@ -53,7 +53,7 @@ class CpuAnalyzer( Analyzer ): ## print ":::",dataSetName,minEvt,maxEvt,nEntries histos = monComp.data[dataSetName]['histos'] - + monCompName = monComp.name.replace( "/", "#" ) hId = 'cpu_%s.%s' % (monCompName, dataSetName) hName = 'cpu_%s' % dataSetName @@ -68,35 +68,29 @@ class CpuAnalyzer( Analyzer ): from .App import DataSetMgr self.msg.debug("filling histograms...") - + # short-hands msg = self.msg # milliseconds ms = Units.ms - monName = monComp.name dsNames = DataSetMgr.names() yMin = [] yMax = [] allGood = True - - figs = monComp.figs for dsName in dsNames: if dsName not in monComp.data: continue data = monComp.data[dsName] - ## print "..",dsName,data.keys() - if not 'evt' in data: + if 'evt' not in data: continue data = data['evt'] if data is None: continue - - ## print "..",dsName,data.keys() - - if not 'cpu' in data.dtype.names: + + if 'cpu' not in data.dtype.names: allGood = False msg.debug('component [%s] has empty cpu/user infos for ' 'dataset [%s]', @@ -116,18 +110,18 @@ class CpuAnalyzer( Analyzer ): if len(yMin) == 0 and len(yMax) == 0: msg.debug("Component [%s] has no 'evt' level data", monComp.name) return - + yMin = min(yMin) yMax = max(yMax) - + for dsName in dsNames: if dsName not in monComp: continue data = monComp.data[dsName] - if not 'evt' in data: + if 'evt' not in data: continue bins = DataSetMgr.instances[dsName].bins - if not 'evt/cpu' in monComp.figs: + if 'evt/cpu' not in monComp.figs: monComp.figs['evt/cpu'] = plt.figure() monComp.figs['evt/cpu'].add_subplot(211).hold(True) monComp.figs['evt/cpu'].add_subplot(212).hold(True) @@ -135,14 +129,12 @@ class CpuAnalyzer( Analyzer ): ax = fig.axes[0] cpu = data['evt']['cpu'] cpu_c = cpu['cpu'] - cpu_u = cpu['user'] - cpu_s = cpu['sys'] binMax = len(cpu_c[self.minEvt:len(bins)]) - pl = ax.plot(bins[self.minEvt:binMax], - cpu_c[self.minEvt:binMax,2]*ms, - linestyle = 'steps', - label = dsName) + ax.plot(bins[self.minEvt:binMax], + cpu_c[self.minEvt:binMax,2]*ms, + linestyle = 'steps', + label = dsName) ax.grid(True) ax.set_title ( "CPU time [%s]" % monComp.name ) ax.set_ylabel( 'CPU time [ms]' ) @@ -161,7 +153,7 @@ class CpuAnalyzer( Analyzer ): ax.set_xlabel( 'CPU time [ms]' ) ax.set_ylim( (ax.get_ylim()[0], ax.get_ylim()[1]*1.1) ) - + h = data['histos']['cpu_%s' % dsName] hAvg = bookAvgHist(h, cpu_c[:,2] * ms) data['histos'][h.GetName()] = hAvg @@ -173,7 +165,7 @@ class CpuAnalyzer( Analyzer ): hAvg.Fill( cpuTime ) pass # loop over datasets - + for ax in monComp.figs['evt/cpu'].axes: ax.legend( DataSetMgr.labels( dsNames ), loc='best' ) @@ -185,8 +177,8 @@ class CpuAnalyzer( Analyzer ): ROOT = importRoot(batch=True) RootFct = ROOT.TF1 dummyCanvas = ROOT.TCanvas( 'dummyFitCanvas' ) - - histos = [ h for h in self.histos.values() + + histos = [ h for h in self.histos.values() if hasattr(h, 'tag') and h.tag == 'summary' and \ not h.GetName().startswith("cfg.") ] @@ -196,7 +188,7 @@ class CpuAnalyzer( Analyzer ): xMax = x.GetXmax() name = h.GetName() - modelFct = prl.Polynom( degree = 1 ) + prl.Polynom( degree = 1 ) fct = RootFct( 'fitFct_%s' % name, "pol1", xMin, xMax ) ## Q: quiet ## R: Use the range specified in the function range @@ -210,27 +202,8 @@ class CpuAnalyzer( Analyzer ): ( name, fitRes, fct.GetChisquare(), fct.GetNDF() ) self.msg.info( msg ) pass - - # FIXME: not yet for prod! -## histos = [ h for h in self.histos.values() -## if h.GetName().count("avg_") > 0 ] - -## for h in histos: -## x = h.GetXaxis() -## xMin, xMax = x.GetXmin(), x.GetXmax() -## name = h.GetName() -## fct = RootFct( "fitFct_%s" % name, "gaus", xMin, xMax ) -## fct.SetParameter( 1, h.GetMaximum() ) -## h.Fit(fct, "QOR") -## nPars = fct.GetNpar() -## self.msg.info( "[%-50s] %s", name, "\t".join( -## "p[%i] = %12.3f ms " % (i, fct.GetParameter(i)) \ -## for i in range(nPars) ) -## ) - -## pass - + del dummyCanvas return - + pass # class CpuAnalyzer diff --git a/Control/PerformanceMonitoring/PerfMonAna/python/DataLoader.py b/Control/PerformanceMonitoring/PerfMonAna/python/DataLoader.py index 64e916beff8aa304710e5d79d48394c997f51cf8..78c4195d8148bc1e5195c8c2ca0432fd6456e787 100644 --- a/Control/PerformanceMonitoring/PerfMonAna/python/DataLoader.py +++ b/Control/PerformanceMonitoring/PerfMonAna/python/DataLoader.py @@ -1,32 +1,29 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration # @file: PerfMonAna/python/DataLoader.py # @purpose: handles various data formats and loads data from these files # @author: Sebastien Binet <binet@cern.ch> -import shelve,os,tempfile,glob,atexit,shutil -import cppyy +import shelve,os class DataFormatHandler(object): pass # class DataFormatHandler class DataHdlr_v000000(object): def __init__(self, fileName): - import cppyy object.__init__(self) self._fileName = fileName self._outFileName = None def cnv(self): return - + pass # class DataHdlr_v000000 class DataHdlr_v000100(object): """Data handler for pure python format. v00.01.00 """ def __init__(self, fileName, scratchDir): - import cppyy object.__init__(self) self._fileName = fileName self._tmpdir = scratchDir @@ -35,7 +32,7 @@ class DataHdlr_v000100(object): def cnv(self): data = {} - import tempfile,os,glob + import tempfile,os import gzip import shutil @@ -49,6 +46,7 @@ class DataHdlr_v000100(object): if self._fileName.endswith('.gz'): f = gzip.GzipFile(fileobj=f) f.seek(0) + tmpFileName = 'foo.bar' tmpFile = open(tmpFileName, 'w') shutil.copyfileobj(f, tmpFile) f.close() @@ -69,69 +67,24 @@ class DataHdlr_v000100(object): 'components' : _data['meta://components'], 'iocontainers' : _data['meta://iocontainers'], } - compNames = set(_data['components'].keys() + - _data['iocontainers']) - from PyRootLib import importRoot - ROOT = importRoot() - root = ROOT.fopen( - os.path.join([tmpdir,self._fileName+".root"]), - "recreate" - ) - -## dataSetName = self.name -## ## print ">>>",len(compNames),len(data.keys()) -## _data_keys = data.keys() -## for compName in compNames: -## ## print ":::::::::",compName -## monComp = MonitoredComponent(compName, dataSetName) -## monData = monComp.data[dataSetName] -## for storeName in storeNames: -## ## print compName,storeName -## if not monData.has_key(storeName): -## monData[storeName] = {} -## compNameHdr1 = compName + '://' + storeName -## compNameHdr2 = compName + ':///' + storeName -## for k in _data_keys: -## if k.startswith( compNameHdr1 ) or \ -## k.startswith( compNameHdr2 ): -## monKey = k[k.find(storeName+'/')+len(storeName)+1:] -## monData[storeName][monKey] = numpy.array(data[k]) -## if storeName == 'evt' and monData[storeName].has_key('evtNbr'): -## self.bins = monData[storeName]['evtNbr'] -## pass -## pass -## _monitor('5') - -## _compsDb = data['meta://components' ] -## _comps = data['meta://components' ].keys() -## _ioconts = data['meta://iocontainers'] -## for monComp in MonitoredComponent.instances.values(): -## if monComp.type != None: -## continue -## monName = monComp.name -## if monName in _comps : monComp.type = _compsDb[monName] -## elif monName in _ioconts : monComp.type = 'io' -## else : monComp.type = 'usr' -## pass - - finally: os.chdir(wkdir) + finally: + os.chdir(wkdir) return data - + pass # class DataHdlr_v000100 class DataHdlr_v000200(object): """Data handler for mixed ROOT/TTree-python format. v00.02.00 """ def __init__(self, fileName, scratchDir): - import cppyy object.__init__(self) self._fileName = fileName self._tmpdir = scratchDir def cnv(self): data = {} - import tempfile,os,glob + import os,glob origdir = os.getcwd() tmpdir = self._tmpdir try: @@ -148,21 +101,21 @@ class DataHdlr_v000200(object): else: db = shelve.open(fname) data['meta'] = {} - for k in db.iterkeys(): data['meta'][k] = db[k] + for k in db.iterkeys(): + data['meta'][k] = db[k] db.close() - -## print "version:",data['meta']['version_id'] from PyRootLib import importRoot ROOT = importRoot() root = ROOT.fopen(glob.glob("*.root")[0], "read") - for k in ('ini','evt','fin'): data[k] = root.Get("perfmon/%s"%k) + for k in ('ini','evt','fin'): + data[k] = root.Get("perfmon/%s"%k) data['meta']['rootFile'] = root finally: os.chdir(origdir) - + return data - + pass # class DataHdlr_v000200 @@ -177,6 +130,6 @@ class DataLoader(object): infos, data = pmon_ser.pmon_load(self.fileName) return {'meta':infos, 'data':data} - + pass # class DataLoader diff --git a/Control/PerformanceMonitoring/PerfMonAna/python/IoAnalyzer.py b/Control/PerformanceMonitoring/PerfMonAna/python/IoAnalyzer.py index 705d06329ab7f487fe7ab67998dbdaac18279c81..79e029d79fd66797efe9e9b535c64fd680e6245d 100755 --- a/Control/PerformanceMonitoring/PerfMonAna/python/IoAnalyzer.py +++ b/Control/PerformanceMonitoring/PerfMonAna/python/IoAnalyzer.py @@ -1,4 +1,4 @@ -# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration # @file: IoAnalyzer.py # @purpose: a set of classes to analyze (I/O) data from a perfmon tuple @@ -34,11 +34,11 @@ class IoAnalyzer( Analyzer ): return def visit(self, monComp): - if not monComp.type in ['io']:#'cfg']: + if monComp.type not in ['io']:#'cfg']: self.msg.debug( " skipping %s [%s]",monComp.name,monComp.type ) return False return True - + def bookHistos(self, monComp): ROOT = importRoot() #Analyzer.__bookHistos(self) @@ -94,8 +94,10 @@ class IoAnalyzer( Analyzer ): ms = Units.ms dsNames = DataSetMgr.names() - yMinRead = []; yMaxRead = [] - yMinWrite = []; yMaxWrite = [] + yMinRead = [] + yMaxRead = [] + yMinWrite = [] + yMaxWrite = [] for dsName in dsNames: if dsName not in monComp.data: continue @@ -117,7 +119,7 @@ class IoAnalyzer( Analyzer ): yMaxRead = max(yMaxRead) yMinWrite = min(yMinWrite) yMaxWrite = max(yMaxWrite) - + for dsName in dsNames: if dsName not in monComp.data: continue @@ -136,11 +138,11 @@ class IoAnalyzer( Analyzer ): fig = monComp.figs['evt/io'] ax = fig.axes[0] _iy = self.minEvt + len(bins[self.minEvt:]) - pl = ax.plot( bins[self.minEvt:], - data['evt']['io/cpu/r'][self.minEvt:_iy] * ms, - linestyle = 'steps', - label = dsName ) - + ax.plot( bins[self.minEvt:], + data['evt']['io/cpu/r'][self.minEvt:_iy] * ms, + linestyle = 'steps', + label = dsName ) + ax.grid( True ) ax.set_title ( "[%s]" % monComp.name ) ax.set_ylabel( '(R) CPU time [ms]' ) @@ -160,15 +162,15 @@ class IoAnalyzer( Analyzer ): ax.set_xlabel( '(R) CPU time [ms]' ) ax.set_ylim( (ax.get_ylim()[0], ax.get_ylim()[1]*1.1) ) - + ## write fig = monComp.figs['evt/io'] ax = fig.axes[2] _iy = self.minEvt + len(bins[self.minEvt:]) - pl = ax.plot( bins[self.minEvt:], - data['evt']['io/cpu/w'][self.minEvt:_iy] * ms, - linestyle = 'steps', - label = dsName ) + ax.plot( bins[self.minEvt:], + data['evt']['io/cpu/w'][self.minEvt:_iy] * ms, + linestyle = 'steps', + label = dsName ) ax.grid( True ) ax.set_title ( "[%s]" % monComp.name ) ax.set_ylabel( '(W) CPU time [ms]' ) @@ -233,10 +235,10 @@ class IoAnalyzer( Analyzer ): fig = monComp.figs['evt/rio'] ax = fig.axes[0] _iy = self.minEvt + len(bins[self.minEvt:]) - pl = ax.plot( bins[self.minEvt:], - data['evt']['io/cpu/rr'][self.minEvt:_iy] * ms, - linestyle = 'steps', - label = dsName ) + ax.plot( bins[self.minEvt:], + data['evt']['io/cpu/rr'][self.minEvt:_iy] * ms, + linestyle = 'steps', + label = dsName ) ax.set_title ( "[%s]" % monComp.name ) ax.set_ylabel( '(RR) CPU time [ms]' ) ax.set_xlabel( 'Event number' ) @@ -259,22 +261,23 @@ class IoAnalyzer( Analyzer ): ratios = [] for idx,num in enumerate(data['evt']['io/cpu/rr'][self.minEvt:_iy]): den = data['evt']['io/cpu/r'][idx] - if den == 0.: r = 0 - else : r = num/den*100. + if den == 0.: + r = 0 + else: + r = num/den*100. ratios.append(r) -## print "%3i %8.3f %8.3f %8.3f" % (idx,num,den,r) - + ratios = numpy.array(ratios) yMinRatio = min(ratios) yMaxRatio = max(ratios) - + ## pure ROOT read over T/P read fig = monComp.figs['evt/rio'] ax = fig.axes[2] - pl = ax.plot( bins[self.minEvt:], - ratios, - linestyle = 'steps', - label = dsName ) + ax.plot( bins[self.minEvt:], + ratios, + linestyle = 'steps', + label = dsName ) ax.set_title ( "[%s]" % monComp.name ) ax.set_ylabel( 'Pure-ROOT over Full read CPU time (%)' ) ax.set_xlabel( 'Event number' ) diff --git a/Control/PerformanceMonitoring/PerfMonAna/python/MemAnalyzer.py b/Control/PerformanceMonitoring/PerfMonAna/python/MemAnalyzer.py index ed435879a6c5caa77e67fed328d0d0f34a0b6e63..dca9fd6180763f73d4308a25a77bc0426fd1e246 100755 --- a/Control/PerformanceMonitoring/PerfMonAna/python/MemAnalyzer.py +++ b/Control/PerformanceMonitoring/PerfMonAna/python/MemAnalyzer.py @@ -13,12 +13,12 @@ __version__ = "$Revision: 1.21 $" __doc__ = "A set of classes to analyze (Mem) data from a perfmon tuple." import logging -import numpy, pylab +import numpy import matplotlib.pyplot as plt from .PyRootLib import importRoot -from .Analyzer import Analyzer, bookAvgHist, mon_project, make_canvas +from .Analyzer import Analyzer, bookAvgHist from .Constants import Units - + class MemAnalyzer( Analyzer ): """analyzer working on memory related quantities. It reads the perfmon tuple and extracts virtual memory and resident set size memory consumptions @@ -36,17 +36,16 @@ class MemAnalyzer( Analyzer ): return def visit(self, monComp): - if not monComp.type in ['alg','user']: + if monComp.type not in ['alg','user']: self.msg.debug( " skipping %s [%s]",monComp.name,monComp.type ) return False - + return True - + def bookHistos(self, monComp): ROOT = importRoot() - from .PyRootLib import setupRootStyle; setupRootStyle(); - - #Analyzer.__bookHistos(self) + from .PyRootLib import setupRootStyle + setupRootStyle() from .App import DataSetMgr for dataSetName in monComp.data.keys(): @@ -82,46 +81,40 @@ class MemAnalyzer( Analyzer ): return def fillHistos(self, monComp): - + from .App import DataSetMgr self.msg.debug("filling histograms...") # short-hands msg = self.msg - - # convert page-size into MB - Mb = Units.Mb + # convert page-size into kB kb = Units.kb - monName = monComp.name dsNames = DataSetMgr.names() ymin = {'vmem':[], 'malloc':[]} ymax = {'vmem':[], 'malloc':[]} allGood = True - + for dsName in dsNames: - if not dsName in monComp.data: + if dsName not in monComp.data: continue - #print "---",dsName,monComp.name data = monComp.data[dsName] - if not 'evt' in data: + if 'evt' not in data: continue data = data['evt'] if data is None: ## print "---",dsName,monComp.name,"data['evt'] is None" continue - if not 'mem' in data.dtype.names: + if 'mem' not in data.dtype.names: allGood = False msg.debug('component [%s] has empty mem infos for ' 'dataset [%s]', monComp.name, dsName) - ## print "--->",dsName,monComp.name,data.dtype.names continue - ## print "+++",dsName,monComp.name mem = data['mem'] dvmem = mem['vmem'][:,2] ymin['vmem'].append(dvmem[self.minEvt:].min()*kb) @@ -142,28 +135,28 @@ class MemAnalyzer( Analyzer ): self.msg.debug("Component [%s] has no 'evt' level data", monComp.name) return - + for k in ymin.keys(): ymin[k] = min(ymin[k]) ymax[k] = max(ymax[k]) pass - + for dsName in dsNames: - if not dsName in monComp.data: + if dsName not in monComp.data: continue data = monComp.data[dsName] - if not 'evt' in data: + if 'evt' not in data: continue data = data['evt'] if data is None: continue - - if not 'mem' in data.dtype.names: + + if 'mem' not in data.dtype.names: continue bins = DataSetMgr.instances[dsName].bins - if not 'evt/mem' in monComp.figs: + if 'evt/mem' not in monComp.figs: monComp.figs['evt/mem'] = plt.figure() monComp.figs['evt/mem'].add_subplot(221).hold( True ) monComp.figs['evt/mem'].add_subplot(222).hold( True ) @@ -174,21 +167,21 @@ class MemAnalyzer( Analyzer ): mem = data['mem'] dvmem = mem['vmem'][:,2] dmall = mem['mall'][:,2] - + ## VMem ax = fig.axes[0] binMax = len(dvmem[self.minEvt:len(bins)]) - pl = ax.plot(bins[self.minEvt:binMax], - dvmem[self.minEvt:binMax] * kb, - linestyle = 'steps', - label = dsName) + ax.plot(bins[self.minEvt:binMax], + dvmem[self.minEvt:binMax] * kb, + linestyle = 'steps', + label = dsName) ax.grid(True) ax.set_title ('Delta V-Mem\n[%s]' % monComp.name) ax.set_ylabel('Delta V-Mem [kb]') ax.set_xlabel('Event number') ax.set_ylim((ax.get_ylim()[0]*0.9, ax.get_ylim()[1]*1.1)) - + h,b = numpy.histogram( dvmem[self.minEvt:binMax] * kb, bins = 20, @@ -204,17 +197,17 @@ class MemAnalyzer( Analyzer ): ## Malloc ax = fig.axes[1] - pl = ax.plot(bins[self.minEvt:binMax], - dmall[self.minEvt:binMax] * kb, - linestyle = 'steps', - label = dsName) + ax.plot(bins[self.minEvt:binMax], + dmall[self.minEvt:binMax] * kb, + linestyle = 'steps', + label = dsName) ax.grid(True) ax.set_title ('Delta Malloc\n[%s]' % monComp.name) ax.set_ylabel('Delta Malloc [kb]') ax.set_xlabel('Event number') ax.set_ylim((ax.get_ylim()[0]*0.9, ax.get_ylim()[1]*1.1)) - + h,b = numpy.histogram( dmall[self.minEvt:binMax] * kb, bins = 20, @@ -254,8 +247,6 @@ class MemAnalyzer( Analyzer ): return def fitHistos(self, monComp): - # convert page-size into MB - Mb = Units.Mb # convert page-size into kB kb = Units.kb @@ -263,12 +254,12 @@ class MemAnalyzer( Analyzer ): ROOT = importRoot() RootFct = ROOT.TF1 dummyCanvas = ROOT.TCanvas( 'dummyFitCanvas' ) - - histos = [ h for h in self.histos.values() + + histos = [ h for h in self.histos.values() if hasattr(h, 'tag') and h.tag == 'summary' and \ not h.GetName().startswith("cfg.") ] - + for h in histos: x = h.GetXaxis() xMin = x.GetXmin() @@ -279,7 +270,7 @@ class MemAnalyzer( Analyzer ): # could make sense for mem-leak... xMin = xMin + ( xMax-xMin) / 2. - modelFct = prl.Polynom( degree = 1 ) + prl.Polynom( degree = 1 ) fct = RootFct( 'fitFct_%s' % name, "pol1", xMin, xMax ) ## Q: quiet ## R: Use the range specified in the function range @@ -294,7 +285,7 @@ class MemAnalyzer( Analyzer ): self.msg.info( msg ) pass del dummyCanvas - + return - + pass # class MemAnalyzer diff --git a/Control/PerformanceMonitoring/PerfMonAna/python/PyRootLib.py b/Control/PerformanceMonitoring/PerfMonAna/python/PyRootLib.py index 3efeb8834144104188631459a3acaa2fc0137b4f..29523c85fc94a4b637254af0fa939768d97a0a8a 100755 --- a/Control/PerformanceMonitoring/PerfMonAna/python/PyRootLib.py +++ b/Control/PerformanceMonitoring/PerfMonAna/python/PyRootLib.py @@ -23,7 +23,7 @@ def importRoot( batch = True ): if 'DISPLAY' in os.environ: x_display = os.environ['DISPLAY'] del os.environ['DISPLAY'] - + ## few customizations ROOT.gErrorIgnoreLevel = ROOT.kError if ROOT.gROOT.GetVersionInt() >= 51800: @@ -38,7 +38,7 @@ def importRoot( batch = True ): ROOT.kMyRed = ROOT.kRed ROOT.kMyGreen = ROOT.kGreen+100 ROOT.kDarkGreen = ROOT.kGreen +100 - + ## if batch: if x_display: @@ -63,7 +63,7 @@ def importRoot( batch = True ): def fopen(*args): global _root_files f = ROOT.TFile.Open(*args) - if not f in _root_files: + if f not in _root_files: _root_files.append(f) return f ROOT.fopen = fopen @@ -73,7 +73,7 @@ ROOT = importRoot() def setupRootStyle(): """Somehow beautify the ugly default ROOT display style""" - + style = ROOT.gROOT.GetStyle( "Plain" ) # no borders, white color @@ -91,14 +91,14 @@ def setupRootStyle(): style.SetTitleOffset(1.1) style.SetTitleSize(0.035,"Y") style.SetTitleOffset(1.1,"Y") - + # canvas stuff style.SetCanvasBorderSize(0) style.SetCanvasDefH( 800) style.SetCanvasDefW(1000) style.SetFrameBorderMode(0) style.SetFrameBorderSize(0) - + style.SetStatX(0.95) style.SetStatY(0.9) style.SetStatW(0.18) @@ -119,7 +119,7 @@ def setupRootStyle(): style.SetPalette(1) #style.SetOptStat(111111) style.SetOptStat(0) - + ROOT.gROOT.SetStyle( "Plain" ) ROOT.gROOT.ForceStyle() @@ -144,7 +144,7 @@ class Polynom: self.n = degree def __call__(self, x, par): return sum( (x[0]**i) + par[i] for i in range(self.n+1) ) - + class OptionStyle: """ Struct to hold options (color/width/style) for a TStyle-like object @@ -175,12 +175,14 @@ class Style(object): self.line = lineOptions self.marker = markerOptions self.fillStyle = fillStyle - - if self.line == None: self.line = OptionStyle() - if self.marker == None: self.marker = OptionStyle() + + if self.line is None: + self.line = OptionStyle() + if self.marker is None: + self.marker = OptionStyle() return def getLine(self): return self.line def getMarker(self): return self.marker - + diff --git a/Control/PerformanceMonitoring/PerfMonAna/python/Rtt.py b/Control/PerformanceMonitoring/PerfMonAna/python/Rtt.py deleted file mode 100644 index f1de91a7f9f8776941997b4f8b8df1acdd4b7577..0000000000000000000000000000000000000000 --- a/Control/PerformanceMonitoring/PerfMonAna/python/Rtt.py +++ /dev/null @@ -1,192 +0,0 @@ -# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration - -# @file: PerfMonAna/python/Rtt.py -# @purpose: a set of classes to interact with RTT -# @author: Sebastien Binet <binet@cern.ch> -# $Id: Rtt.py,v 1.2 2007-07-19 18:27:49 binet Exp $ - -from __future__ import print_function - -""" a set of classes to interact with RTT -""" -# -# -__author__ = 'Sebastien Binet' -__version__ = "$Revision: 1.2 $" -__doc__ = "a set of classes to interact with RTT" - -import os, sys - -class RttHelper: - """A set of helpers to deal with RTT XML summary files""" - - @staticmethod - def getText(nodeList): - return "".join( [ node.data for node in nodeList.childNodes \ - if node.nodeType == node.TEXT_NODE ] ) - - @staticmethod - def val(path, element): - paths = path.split('/') - curGenEls = [element] - for p in paths: - nextGenEls = [] - if p == 'text()': - texts = [] - [texts.extend(RttHelper.getText(e)) for e in curGenEls] - text = reduce(lambda x,y:x+y, texts,'') - return text - else: - [nextGenEls.extend(e.childNodes) for e in curGenEls] - nextGenEls = [n for n in nextGenEls if n.nodeName == p] - curGenEls = nextGenEls - return curGenEls.strip() - - @staticmethod - def makeDict(node): - elements = [ elem for elem in node.childNodes \ - if elem.nodeType == elem.ELEMENT_NODE ] - d = { } - for elem in elements: - d[elem.tagName.strip()] = RttHelper.val('text()', elem) - return d - -class Rtt(object): - Home = "/afs/cern.ch/atlas/project/RTT" - Nightlies = [ 'bugfix', 'val', 'mig0', 'dev' ] - Builds = [ '10', '11', '12', '13' ] - Platforms = [ 'slc3', 'slc4' ] - - RelNbrKey = "rel_nbr" - RelTypeKey = "rel_type" - PlatformKey = "platform" - - RelNbr = "%("+RelNbrKey+")s" - RelType = "%("+RelTypeKey+")s" - Platform = "%("+PlatformKey+")s" - - - # template to generate a path to results - path = os.path.join( Home, "Results", RelNbr, RelType, "build", - Platform, "offline" ) - -class RttDb(object): - """A naive repository of RTT test packages""" - - def __init__(self): - object.__init__(self) - - self.dbName = os.path.expanduser( - os.path.join( "~", ".perfrtt", "rttPkgs.db" ) - ) - - self.updatePkgDb() - - def updatePkgDb(self): - - if not os.path.exists( os.path.dirname(self.dbName) ): - os.mkdir( os.path.dirname(self.dbName) ) - return self.createPkgDb() - - if not os.path.exists( self.dbName ): - return self.createPkgDb() - - rootXml = os.path.join( Rtt.Home, 'Results', 'page1.xml' ) - - # compare last modification of our repository and the - # master RTT file from which that repository was built - if os.path.getmtime( self.dbName ) < os.path.getmtime( rootXml ): - return self.createPkgDb() - - return - - def createPkgDb(self): - if not os.path.exists( os.path.dirname(self.dbName) ): - os.mkdir( os.path.dirname(self.dbName) ) - - val = RttHelper.val - - # get list of releases, nightlies... - rootXml = open( os.path.join( Rtt.Home, 'Results', 'page1.xml' ), 'r' ) - import xml.dom.minidom as Xml - dom = Xml.parse(rootXml) - rootXml.close() - - releases = [] - for rel in dom.getElementsByTagName('overview'): - relDb = { - 'name' : val('releaseName/text()', rel).strip(), - 'type' : val('originalBranch/text()', rel).strip(), - 'nbr' : val('release/text()', rel).strip(), - 'results' : val('resReleaseDir/text()', rel).strip(), - 'platform': val('targetCMTCONFIG/text()',rel).strip(), - } - ## we want 'bugfix/rel_2' instead of 'rel_2/bugfix' - ## so it better meshes with the Athena AFS install naming scheme - if relDb['name'].count('/') > 0: - relDb['name'] = relDb['name'].split('/') - relDb['name'].reverse() - relDb['name'] = "/".join( relDb['name'] ) - - releases.append( relDb ) - - pkgs = set() - jobDb = {} - idDups = {} - releases.sort( lambda x,y: cmp(x['name'],y['name']) ) - for r in releases: - print ("%10s" % r['type'],"%10s" % r['nbr'],"\t\t",r['name'],) - print (r['platform']) -## if r['type'] != 'bugfix': -## continue - sumFileName = os.path.join(r['results'], 'RTTSummary.xml') - summary = Xml.parse( open(sumFileName, 'r') ) - for pkgNode in summary.getElementsByTagName('package'): - pkgName = val( 'packageName/text()', pkgNode ).strip() - pkgs.add( pkgName ) - for m in pkgNode.getElementsByTagName('minder'): - pkg = { - 'pkgName' : pkgName, - 'jobId' : int(val('jobID/text()', m).strip()), - 'idName' : val('identifiedName/text()', m).strip(), - 'results' : val('resultsPath/text()', m).strip(), - 'jobName' : val('jobName/text()', m).strip(), - 'docStr' : val('jobDocString/text()', m).strip(), - 'status' : val('status/text()', m).strip(), - } - res = pkg['results'] - res = res.replace( "/%s/" % r['nbr'], - "/"+Rtt.RelNbr+"/" ) - res = res.replace( "/%s/" % r['type'], - "/"+Rtt.RelType+"/" ) - res = res.replace( "/%s/" % r['platform'], - "/"+Rtt.Platform+"/" ) - pkg['path'] = res - jobId = pkg['jobId'] - if res.count(Rtt.RelType) <= 0: - continue - - if jobDb.has_key(jobId): - o = jobDb[jobId] - if o['idName'] != pkg['idName']: - if not idDups.has_key(jobId): - idDups[jobId] = [] - if pkg['results'] not in idDups[jobId]: - idDups[jobId] += [pkg['results']] - if o['results'] not in idDups[jobId]: - idDups[jobId] += [o['results']] - else: - jobDb[jobId] = pkg - - print ("pkgs:",len(pkgs)) - for id in idDups.keys(): - print (">>> warning...",id) - idDups[id].sort() - for r in idDups[id]: - print (" ",r) - print ("dups: %i/%i" % (len(idDups.keys()), len(jobDb.keys()))) - return - - pass # RttDb - - diff --git a/Control/PerformanceMonitoring/PerfMonAna/python/SkelAnalyzer.py b/Control/PerformanceMonitoring/PerfMonAna/python/SkelAnalyzer.py deleted file mode 100755 index c993d53f6fd3e93506c9b02edbaccb31c89e37bc..0000000000000000000000000000000000000000 --- a/Control/PerformanceMonitoring/PerfMonAna/python/SkelAnalyzer.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - -# @file: SkelAnalyzer.py -# @purpose: a set of classes to analyze (Skel) data from a perfmon tuple -# @author: Sebastien Binet <binet@cern.ch> - -""" A set of classes to analyze (Skel) data from a perfmon tuple -""" -# -# -__author__ = 'Sebastien Binet' -__version__ = "$Revision: 1.3 $" -__doc__ = "A set of classes to analyze (Skel) data from a perfmon tuple." - -import logging -from PerfMonAna.PyRootLib import importRoot -from PerfMonAna.Data import Data -from PerfMonAna.Analyzer import Analyzer - -class SkelAnalyzer( Analyzer ): - - typeName = 'Skel' - - def __init__(self, name, fileName): - Analyzer.__init__(self, name, fileName, '<none>') - return - - def bookHistos(self): - ROOT = importRoot() - #Analyzer.__bookHistos(self) - - meta = self.meta.skel - - nJobOpts = meta.cfg().size()+1 - return - - def fillHistos(self): - - self.msg.debug("filling histograms...") - - self.msg.debug("filling histograms... [DONE]") - return - - pass # class SkelAnalyzer diff --git a/Control/PerformanceMonitoring/PerfMonAna/python/SummaryCreator.py b/Control/PerformanceMonitoring/PerfMonAna/python/SummaryCreator.py index d794223364cf4ad5dd76c6b83c918bdbbb005ab4..c4f118992956a78580750a38c7702dbfa62055fe 100644 --- a/Control/PerformanceMonitoring/PerfMonAna/python/SummaryCreator.py +++ b/Control/PerformanceMonitoring/PerfMonAna/python/SummaryCreator.py @@ -1,4 +1,4 @@ -# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration # @file: SummaryCreator.py # @purpose: a set of classes to create a summary from a perfmon tuple @@ -12,12 +12,11 @@ __author__ = 'Sebastien Binet' __version__ = "$Revision: 1.20 $" __doc__ = "a set of classes to create a summary from a perfmon tuple" -import logging,os +import logging import numpy import numpy.lib.polynomial import matplotlib.pyplot as plt -from .Analyzer import Analyzer, bookAvgHist,mon_project,project,make_canvas -from .PyRootLib import importRoot +from .Analyzer import bookAvgHist,project from .Constants import Units def array_mean(a): @@ -39,8 +38,10 @@ class SummaryCreator(object): } self._fitSlice = [] for i in fitSlice.split(":"): - try: self._fitSlice += [ int(i) ] - except ValueError: self._fitSlice += [ None ] + try: + self._fitSlice += [ int(i) ] + except ValueError: + self._fitSlice += [ None ] # text format of the summary self.txt = {} for i in ( 'ini','1st','evt','fin'): @@ -50,7 +51,7 @@ class SummaryCreator(object): 'slice' : [], 'comps' : [], } - + # maximal number of top-XXX consumers to display self.max = 20 @@ -62,9 +63,10 @@ class SummaryCreator(object): from .PyRootLib import importRoot ROOT = importRoot(batch=True) - from .PyRootLib import setupRootStyle; setupRootStyle() + from .PyRootLib import setupRootStyle + setupRootStyle() c = ROOT.TCanvas('c_default') - + for m in [ self.processIni, self.processFirstEvt, self.processEvt, @@ -85,7 +87,7 @@ class SummaryCreator(object): begSlice = 0, endSlice = 1 ) return - + def processFirstEvt(self, dataSetMgr, monCompMgr): ## get top-20 consumers @@ -96,40 +98,39 @@ class SummaryCreator(object): begSlice = 0, endSlice = 1 ) return - + def processEvt(self, dataSetMgr, monCompMgr): from .App import DataSetMgr from .PyRootLib import importRoot ROOT = importRoot(batch=True) - + ## RootFct = ROOT.TF1 ## dummyCanvas = ROOT.TCanvas("dummyFitCanvas") ## import PyRootLib as prl - + ## self.sum['evt']['histos'] = [] ## self.sum['evt']['fig'] = [] - + ## short-hand ms = Units.ms kb = Units.kb Mb = Units.Mb - Mb2Kb = 1000. - msg = self.msg - + ## get top-20 consumers dsNames = DataSetMgr.names() - color = DataSetMgr.colorIter() _txt = self.txt['evt'] monComp = monCompMgr['PerfMonSlice'] - yMinCpu = []; yMaxCpu = [] - yMinIo = []; yMaxIo = [] + yMinCpu = [] + yMaxCpu = [] + yMinIo = [] + yMaxIo = [] for dsName in dsNames: data = monComp.data[dsName] histos = data['histos'] = {} - if not 'evt' in data: + if 'evt' not in data: continue data = data['evt'] if data is None: @@ -144,7 +145,7 @@ class SummaryCreator(object): dcpu_s= cpu_s[:,2] dcpu_r= cpu_r[:,2] dcpu_c= cpu_c[:,2] - + mem = data['mem'] vmem = mem['vmem'] dvmem = vmem[:,2] @@ -155,7 +156,7 @@ class SummaryCreator(object): nallocs = mem['nmall'][:,2] nfrees = mem['nfree'][:,2] - + yMinCpu.append(dcpu_c[self.minEvt:].min() * ms) yMaxCpu.append(dcpu_c[self.minEvt:].max() * ms) @@ -164,9 +165,6 @@ class SummaryCreator(object): yMinIo.append(io_c[self.minEvt:].min() * ms) yMaxIo.append(io_c[self.minEvt:].max() * ms) -## data['mem/vmem/d'] = data['mem/vmem/1'] - data['mem/vmem/0'] -## data['mem/rss/d' ] = data['mem/rss/1' ] - data['mem/rss/0' ] - ## fill-in some data for ASCII summary if dsName == '000': _txt['cpu']['slice'] += [ @@ -192,12 +190,12 @@ class SummaryCreator(object): nfrees[self.minEvt:].mean(), ), ] - + ## book ROOT histos nEntries = len(dataSetMgr[dsName].bins)-1 minEvt = dataSetMgr[dsName].bins[self.minEvt] maxEvt = dataSetMgr[dsName].bins[-1] - + hId = 'cpu_%s.%s' % (monComp.name, dsName) hName = 'cpu_%s' % dsName histos[hName] = ROOT.TH1F( @@ -242,7 +240,7 @@ class SummaryCreator(object): nEntries, minEvt, maxEvt ) pass - + yMinIo = min(yMinIo) yMaxIo = max(yMaxIo) yMinCpu = min(yMinCpu) @@ -250,11 +248,11 @@ class SummaryCreator(object): def markForLegend(p): setattr(p, '_markedForLegend', True) def isMarked(p): return hasattr(p, '_markedForLegend') - + memLeak = [] for dsName in dsNames: - if not 'evt' in monComp.data[dsName]: + if 'evt' not in monComp.data[dsName]: continue data = monComp.data[dsName] @@ -262,11 +260,11 @@ class SummaryCreator(object): cpu = data['evt']['cpu'] cpu_c = cpu['cpu'] dcpu_c= cpu_c[:,2] - + ## CPU bins = dataSetMgr[dsName].bins xbins= bins[self.minEvt:] - if not 'evt/cpu' in monComp.figs: + if 'evt/cpu' not in monComp.figs: monComp.figs['evt/cpu'] = plt.figure() monComp.figs['evt/cpu'].add_subplot(211) monComp.figs['evt/cpu'].add_subplot(212) @@ -285,7 +283,7 @@ class SummaryCreator(object): ax.set_ylim((ax.get_ylim()[0]*0.9, ax.get_ylim()[1]*1.1)) markForLegend(pl[0]) - + h,b = numpy.histogram( dcpu_c[self.minEvt:] * ms, bins = 20, @@ -306,14 +304,14 @@ class SummaryCreator(object): cpuTime = dcpu_c[i] * ms h.Fill( float(bins[i]), cpuTime ) hAvg.Fill( cpuTime ) - + ## Mem mem = data['evt']['mem'] vmem = mem['vmem'] dvmem = vmem[:,2] dmall = mem['mall'][:,2] - - if not 'evt/mem' in monComp.figs: + + if 'evt/mem' not in monComp.figs: monComp.figs['evt/mem'] = plt.figure() monComp.figs['evt/mem'].add_subplot(311) monComp.figs['evt/mem'].add_subplot(312) @@ -368,7 +366,7 @@ class SummaryCreator(object): ax.get_ylim()[1]*1.1) ) ax.grid( True ) markForLegend( pl[0] ) - + ax = fig.axes[2] pl = ax.plot( xbins, dmall[self.minEvt:] * Mb, @@ -380,7 +378,7 @@ class SummaryCreator(object): ax.get_ylim()[1]*1.1) ) ax.grid( True ) markForLegend( pl[0] ) - + h = data['histos']['vmem_%s' % dsName] hAvg = bookAvgHist(h, mem['vmem'][:,1] * Mb) @@ -399,7 +397,7 @@ class SummaryCreator(object): hAvg.Fill( rss ) ## I/O - if not 'evt/io' in monComp.figs: + if 'evt/io' not in monComp.figs: monComp.figs['evt/io'] = plt.figure() monComp.figs['evt/io'].add_subplot(211) monComp.figs['evt/io'].add_subplot(212) @@ -441,7 +439,7 @@ class SummaryCreator(object): cpuTime = io_c[i] * ms h.Fill( float(bins[i]), cpuTime ) hAvg.Fill( cpuTime ) - + pass # loop over data sets ## handle mem-leak text @@ -458,9 +456,10 @@ class SummaryCreator(object): transform = ax.transAxes ) for figName,fig in monComp.figs.items(): loc = 'best' - if figName == 'evt/mem': loc = 'lower right' + if figName == 'evt/mem': + loc = 'lower right' for ax in fig.axes: - objs = [ l for l in ax.lines if isMarked(l) ] + objs = [ z for z in ax.lines if isMarked(z) ] ax.legend( objs, DataSetMgr.labels(), #loc='lower right' #loc='best' @@ -476,7 +475,7 @@ class SummaryCreator(object): begSlice = self.minEvt, endSlice = None ) return - + def processFin(self, dataSetMgr, monCompMgr): self._top_consumers( @@ -488,28 +487,26 @@ class SummaryCreator(object): endSlice = None ) return - + def processIo(self, dataSetMgr, monCompMgr): - from .App import DataSetMgr ## short-hand ms = Units.ms - kb = Units.kb - Mb = Units.Mb dsNames = dataSetMgr.keys() dsNames.sort() monComps = [ ] - cppTypes = {}; + cppTypes = {} for monComp in monCompMgr.values(): if monComp.type != 'io': continue - + monCompKeys = monComp.data.keys() monCompKeys.sort() - if monCompKeys != dsNames: continue + if monCompKeys != dsNames: + continue monComps.append( monComp ) cppTypes[monComp.name.split("#")[0]] = {} @@ -527,36 +524,41 @@ class SummaryCreator(object): not k.startswith( "meta://outputPoolFiles/" ): continue n,i = k.split( "PoolFiles/" ) - if n.startswith( "meta://input" ): f = inputFiles - elif n.startswith( "meta://output"): f = outputFiles - else: continue + if n.startswith( "meta://input" ): + f = inputFiles + elif n.startswith( "meta://output"): + f = outputFiles + else: + continue try: f[dsName][int(i)]= d[k] - except KeyError: f[dsName] = {}; f[dsName][int(i)]= d[k] + except KeyError: + f[dsName] = {} + f[dsName][int(i)]= d[k] def _findFolders( files, pattern, dsName ): d = {} cppType = pattern[0] sgKey = pattern[1] - if files.has_key(dsName): + if dsName in files: for file in files[dsName].values(): -## print ":"*80,"-->file" for f in file['data']: n = f['name'] pat = n.startswith( cppType+"_" ) and \ n.endswith ( "_"+sgKey ) -# pat = n.endswith ( "_"+sgKey ) -# pat = n.count( sgKey ) > 0 if pat: size = f['diskSize'] / float( f['nEntries'] ) - try: d[n] += size - except KeyError: d[n] = size -## print "\t-%5s" % str(pat),n + try: + d[n] += size + except KeyError: + d[n] = size keys = d.keys() if len(keys) > 1: raise RuntimeError ("len(d) > 1: %r" % d) - if len(keys) == 0: return [] - else: return [ d.items()[0] ] + if len(keys) == 0: + return [] + else: + return [ d.items()[0] ] ## helper function def io_proj(data, varexp): @@ -570,12 +572,9 @@ class SummaryCreator(object): for monComp in monComps: monName = monComp.name cppType, sgKey = monComp.name.split("#") -## print "---- %-30s %-30s ----" % (cppType,sgKey) - #print "monComp:",monComp.name,cppType,sgKey - #tp_pattern = re.compile( r'%s_.*?%s' % ( cppType, sgKey ) ) tp_pattern = ( cppType, sgKey ) for dsName in dsNames: - if not cppTypes[cppType].has_key( dsName ): + if dsNames not in cppTypes[cppType]: cppTypes[cppType][dsName] = {} data = monComp.data[dsName]['evt'] @@ -586,9 +585,6 @@ class SummaryCreator(object): ior = ( ior, io_proj(data, varexp=monName+".r.user") * ms ) iorr= ( iorr, io_proj(data, varexp=monName+".rr.user") * ms ) iow = ( iow, io_proj(data, varexp=monName+".w.user") * ms ) -## print "\tio-r ",ior -## print "\tio-rr",iorr -## print "\tio-w ",iow if ior[0] > 0.: d = { 'size' : _findFolders( inputFiles, tp_pattern, dsName ), @@ -597,7 +593,8 @@ class SummaryCreator(object): } monComp.data[dsName]['io/in'] = d if len(d['size']) > 0: - try: io_in = cppTypes[cppType][dsName]['io/in'] + try: + io_in = cppTypes[cppType][dsName]['io/in'] except KeyError: cppTypes[cppType][dsName]['io/in'] = { 'size' : [], 'r' : [], 'rr' : [] @@ -613,7 +610,8 @@ class SummaryCreator(object): } monComp.data[dsName]['io/out']= d if len(d['size']) > 0: - try: io_out = cppTypes[cppType][dsName]['io/out'] + try: + io_out = cppTypes[cppType][dsName]['io/out'] except KeyError: cppTypes[cppType][dsName]['io/out'] = { 'size' : [], 'w' : [] @@ -621,14 +619,8 @@ class SummaryCreator(object): io_out = cppTypes[cppType][dsName]['io/out'] io_out['size'] += [ d['size'][0][1] ] io_out['w' ] += [ iow ] -## try: -## print "in: ",monComp.data['000']['io/in'] -## except KeyError: print "<none>";pass -## try: -## print "out:",monComp.data['000']['io/out'] -## except KeyError: print "<none>";pass pass - + self.sum['io']['fig'] = [] def _createFig( ioKey, speedKey, cppTypes, dsNames, figTitle ): @@ -640,7 +632,7 @@ class SummaryCreator(object): from .App import DataSetMgr color = DataSetMgr.colorIter() - + # to hold 'cpu' for each dataSet axes = [ [], [], [] ] @@ -650,7 +642,7 @@ class SummaryCreator(object): names[dsName] = [] for cppType in cppTypes.keys(): store = cppTypes[cppType][dsName] - if not store.has_key(ioKey): + if ioKey not in store: continue store = store[ioKey] if len(store['size']) <= 0: @@ -691,8 +683,8 @@ class SummaryCreator(object): } ) table = numpy.array( table, dtype = descr ) nData = len(table) -## print speedKey,nData,names - if nData == 0: return None + if nData == 0: + return None table.sort( order=('size',) ) @@ -722,7 +714,7 @@ class SummaryCreator(object): ax.set_yticks( pos + 0.5 ) ax.set_yticklabels( labels, fontsize =6, horizontalalignment = 'right' ) - + # display 'user' part only data = table[speedKey+'/user'] pos = numpy.arange(nData) @@ -746,7 +738,7 @@ class SummaryCreator(object): color = 'g', label = dsName, lw = lw ) - + ## -- Speed ax = fig.axes[1] @@ -767,7 +759,7 @@ class SummaryCreator(object): ax.set_yticks( pos + 0.5 ) ax.set_yticklabels( labels, fontsize =6, horizontalalignment = 'right' ) - + # display 'user' part only data = table[speedKey+'/user'] data = table['speed'] @@ -800,7 +792,7 @@ class SummaryCreator(object): ax.set_yticks( pos + 0.5 ) ax.set_yticklabels( labels, fontsize =6, horizontalalignment = 'right' ) - + # display 'user' part only data = table[speedKey+'/userFreq'] pos = numpy.arange(nData) @@ -820,18 +812,16 @@ class SummaryCreator(object): fig = _createFig( 'io/in', 'r', cppTypes, dsNames, figTitle = '[P->T] transformations' ) - if fig: self.sum['io']['fig'] += [ fig ] + if fig: + self.sum['io']['fig'] += [ fig ] -## fig = _createFig( 'io/in', 'rr', cppTypes, dsNames, -## figTitle = '[P->T] transformations (ROOT part)' ) -## if fig: self.sum['io']['fig'] += [ fig ] - fig = _createFig( 'io/out', 'w', cppTypes, dsNames, figTitle = '[T->P] transformations' ) - if fig: self.sum['io']['fig'] += [ fig ] + if fig: + self.sum['io']['fig'] += [ fig ] return - + def _top_consumers(self, dataSetMgr, monCompMgr, compTypes, title, storeName, @@ -845,16 +835,16 @@ class SummaryCreator(object): kb = Units.kb Mb = Units.Mb msg = self.msg - + dsNames = list(dataSetMgr.keys()) dsNames.sort() monComps = [ ] for monComp in monCompMgr.values(): - if not monComp.type in compTypes: + if monComp.type not in compTypes: continue - + monCompKeys = list(monComp.data.keys()) monCompKeys.sort() if monCompKeys != dsNames: @@ -863,9 +853,9 @@ class SummaryCreator(object): if monComp.name in ('AthMasterSeq', 'AthAlgSeq',): continue monComps.append(monComp) - + if len(monComps) == 0: - msg.debug("Could not find any monitored component for" + msg.debug("Could not find any monitored component for" " _top_consumers_ analysis !") return @@ -880,7 +870,7 @@ class SummaryCreator(object): # to hold 'cpu' for each dataSet axes = [ [], [], [], [] ] - + color = DataSetMgr.colorIter() timings = {} @@ -892,16 +882,10 @@ class SummaryCreator(object): timings[dsName] = [] for monComp in _monComps: - if not storeName in monComp.data[dsName]: + if storeName not in monComp.data[dsName]: continue - usrKey = 'cpu/user' - sysKey = 'cpu/sys' - realKey= 'cpu/real' - vm0Key = 'mem/vmem/0' - vm1Key = 'mem/vmem/1' - malKey = 'mem/malloc/d' - + store = monComp.data[dsName][storeName] if store is None: ## if storeName == 'evt': @@ -917,13 +901,13 @@ class SummaryCreator(object): cpu_s = cpu['sys'][:,2] cpu_c = cpu['cpu'][:,2] cpu_r = cpu['real'][:,2] - + mem = store['mem'] vmem= mem['vmem'] mall= mem['mall'] dvmem = vmem[:,2] dmall = mall[:,2] - + monComps.append(monComp) timings[dsName].append(monComp.name) table.append( @@ -952,7 +936,7 @@ class SummaryCreator(object): table[-1] = tuple(new_value) msg.warn(" +%s", table[-1]) pass - + pass # loop over components descr = numpy.dtype( { @@ -965,7 +949,7 @@ class SummaryCreator(object): } ) try: table = numpy.array( table, dtype = descr ) - + nData = min( self.max, len([ m for m in monComps if m.type in compTypes ]) @@ -977,7 +961,7 @@ class SummaryCreator(object): title, storeName, sliceName, begSlice, endSlice) nData = 0 continue - + if nData == 0: _warn = msg.warning _warn("in top_consumers: no data to plot for [%s]!", title) @@ -985,7 +969,7 @@ class SummaryCreator(object): _warn("dsname=[%s] storename=[%s]", dsName, storeName) _warn("no component found with type %s", compTypes) continue - + # linewidth for horizontal bars lw = 0.01 names = timings[dsName] @@ -1013,7 +997,7 @@ class SummaryCreator(object): ax.set_yticklabels( labels, fontsize = 6, horizontalalignment = 'right' ) - + # display 'user' part only data = table['cpu/user'][-nData:] pos = numpy.arange(nData) @@ -1036,9 +1020,10 @@ class SummaryCreator(object): _c += [ "[cpu/sys] %10.3f %10.3f (ms) | %s" % _i ] - else: self.msg.error( "%s contains weird data !!",_i[-1] ) + else: + self.msg.error( "%s contains weird data !!",_i[-1] ) _c.reverse() - + ## real-time table.sort( order=('cpu/real',) ) labels = [ names[i] for i in table['name'][-nData:] ] @@ -1092,7 +1077,8 @@ class SummaryCreator(object): [ names[i] for i in table['name'] ] ): if not numpy.isnan(_i[0]): _c += [ "dVmem|dMalloc %10.3f %10.3f kB | %s" % _i ] - else: self.msg.error( "%s contains weird data !!",_i[-1] ) + else: + self.msg.error( "%s contains weird data !!",_i[-1] ) _c.reverse() ## malloc @@ -1129,13 +1115,14 @@ class SummaryCreator(object): [ names[i] for i in table['name'] ] ): if not numpy.isnan(_i[0]): _c += [ "alloc|free %10i %10i | %s" % _i ] - else: self.msg.error( "%s contains weird data !!",_i[-1] ) + else: + self.msg.error( "%s contains weird data !!",_i[-1] ) _c.reverse() pass # loop over data sets if nData != 0: - + for ix, ax in zip(axes, fig.axes): ax.legend(ix[::nData], DataSetMgr.labels(), loc='lower right') else: @@ -1144,7 +1131,7 @@ class SummaryCreator(object): ## dsName, monComp.name, storeName) ## return pass - + m = monCompMgr['PerfMonSlice'] d = m.data['000'][storeName] cpu = "%-20s [%10.3f ms %10.3f ms\t real= %10.3f ms ]" % ( @@ -1157,7 +1144,7 @@ class SummaryCreator(object): dvmem = d['mem']['vmem'][:,2] drss = d['mem']['rss'][:,2] dmall = d['mem']['mall'][:,2] - + mem = "%-20s [%10.3f MB -> %10.3f MB\t delta= %10.3f kB ]\n" \ "%-20s [%10.3f MB -> %10.3f MB\t delta= %10.3f kB ]\n" \ "%-20s [%10.3f MB -> %10.3f MB\t delta= %10.3f kB ]\n" \ @@ -1187,5 +1174,5 @@ class SummaryCreator(object): _txt['cpu']['slice'] += [ cpu ] _txt['mem']['slice'] += [ mem ] - + return diff --git a/Control/PerformanceMonitoring/PerfMonAna/python/UserFct.py b/Control/PerformanceMonitoring/PerfMonAna/python/UserFct.py index b2cdeb10db1265c88e4801d6908f164c2fd68f1f..1bb4bfe2d3adab066c5f85c6063c9aa51e188bd5 100644 --- a/Control/PerformanceMonitoring/PerfMonAna/python/UserFct.py +++ b/Control/PerformanceMonitoring/PerfMonAna/python/UserFct.py @@ -1,4 +1,4 @@ -# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration # @file: UserFct.py # @purpose: classes to allow users to specialize (and load) filtering functions @@ -21,7 +21,7 @@ class PluginFct: class FilterFct: __sharedState = { ## default selector: selects everything - PluginFct.Name : lambda x: x != None + PluginFct.Name : lambda x: x is not None } def __init__(self): @@ -32,7 +32,7 @@ class FilterFct: def setFilter(self, fct): self.__sharedState[PluginFct.Name] = fct - + def loadFilterFct( uri ): """Load and inspect a 'URI'-like resource. If this URI looks like a file, then it will be loaded and inspected for any function whose name is @@ -61,6 +61,6 @@ def loadFilterFct( uri ): def userFct (m): return eval (uri) filterFct.setFilter( userFct ) - + return filterFct - + diff --git a/Control/PerformanceMonitoring/PerfMonAna/python/root_pickle.py b/Control/PerformanceMonitoring/PerfMonAna/python/root_pickle.py index 5444844e0e107c3d1cef351f6b2b52bc5480d2af..5cf9e3c37c59cd7b0df54146cab7f9fe39c1e2f9 100755 --- a/Control/PerformanceMonitoring/PerfMonAna/python/root_pickle.py +++ b/Control/PerformanceMonitoring/PerfMonAna/python/root_pickle.py @@ -1,4 +1,4 @@ -# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration # # $Id: root_pickle.py,v 1.1 2007-07-22 01:51:43 binet Exp $ @@ -156,7 +156,7 @@ Root objects. """Clears the pickler's internal memo.""" self.__pickle.memo.clear() return - + def _persistent_id (self, o): @@ -169,7 +169,7 @@ Root objects. pid = "%s;%d" % (k.GetName(), k.GetCycle()) return pid return - + _compat_hooks = None @@ -182,11 +182,11 @@ class Root_Proxy: self.__o = None return def __getattr__ (self, a): - if self.__o == None: + if self.__o is None: self.__o = self.__f.Get (self.__pid) return getattr (self.__o, a) def __obj (self): - if self.__o == None: + if self.__o is None: self.__o = self.__f.Get (self.__pid) return self.__o class Unpickler: @@ -211,7 +211,8 @@ FILE should be a Root TFile. def load (self): """Read a pickled object representation from the open file.""" o = None - if _compat_hooks: save = _compat_hooks[0]() + if _compat_hooks: + save = _compat_hooks[0]() try: self.__n += 1 s = self.__file.Get ('_pickle;%d' % self.__n) @@ -219,9 +220,10 @@ FILE should be a Root TFile. o = self.__unpickle.load() self.__io.reopen () finally: - if _compat_hooks: save = _compat_hooks[1](save) + if _compat_hooks: + save = _compat_hooks[1](save) return o - + def _persistent_load (self, pid): if self.__use_proxy: o = Root_Proxy (self.__file, pid) @@ -253,7 +255,7 @@ FILE should be a Root TFile. setattr (mod, name, Dummy) return Dummy return - + def compat_hooks (hooks): @@ -262,7 +264,7 @@ If this is set, then hooks[0] is called before loading, and hooks[1] is called after loading. hooks[1] is called with the return value of hooks[0] as an argument. This is useful for backwards compatibility in some situations.""" - _compat_hooks = hooks + _compat_hooks = hooks # noqa: F841 return diff --git a/Control/PerformanceMonitoring/PerfMonEvent/python/__init__.py b/Control/PerformanceMonitoring/PerfMonEvent/python/__init__.py deleted file mode 100755 index 0f21b42a6739d2259c4edacf72a26e59c647ace3..0000000000000000000000000000000000000000 --- a/Control/PerformanceMonitoring/PerfMonEvent/python/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - -## hook for the PerfMonEvent py-module - -def setup(): - """bring in the extension module""" - import os - __path__.append( os.path.join( __path__[0], os.environ[ 'CMTCONFIG' ] ) ) - import DataStore - return -setup() -del setup diff --git a/Control/PerformanceMonitoring/PerfMonGPerfTools/CMakeLists.txt b/Control/PerformanceMonitoring/PerfMonGPerfTools/CMakeLists.txt index 4a1e58b1c1f8b55d3df509a3c9c3e1e1cfd92615..cc532c76b37137bda55a2b4216b5e444f6c51dc1 100644 --- a/Control/PerformanceMonitoring/PerfMonGPerfTools/CMakeLists.txt +++ b/Control/PerformanceMonitoring/PerfMonGPerfTools/CMakeLists.txt @@ -5,6 +5,7 @@ atlas_subdir( PerfMonGPerfTools ) # External dependencies: find_package( gperftools COMPONENTS profiler ) +find_package( pprof ) # Component(s) in the package: atlas_add_component( PerfMonGPerfTools @@ -14,6 +15,5 @@ atlas_add_component( PerfMonGPerfTools LINK_LIBRARIES ${GPERFTOOLS_LIBRARIES} GaudiKernel AthenaBaseComps AthenaKernel ) # Install files from the package: -atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) -atlas_install_joboptions( share/*.py ) +atlas_install_joboptions( share/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) atlas_install_scripts( scripts/*.py scripts/gathena ) diff --git a/Control/PerformanceMonitoring/PerfMonGPerfTools/python/Utils.py b/Control/PerformanceMonitoring/PerfMonGPerfTools/python/Utils.py deleted file mode 100644 index 6d8eb92c83fb9047d12a7b37dc32f2832b62761e..0000000000000000000000000000000000000000 --- a/Control/PerformanceMonitoring/PerfMonGPerfTools/python/Utils.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration - -# $Id: Utils.py 491963 2012-03-30 14:53:13Z krasznaa $ -# -# Python utility functions used in multiple scripts. -# - -## -# @short Function finding AtlasGPerfTools/cmt/setup.sh -# -# The script needs to source the setup script of the GPerfTools glue package -# internally. This function finds the location of the script in the filesystem -# that should be used. -# -# @returns The full path of the setup script to be used -# -def locateSetupScript(): - - # Set up a logger object: - from AthenaCommon.Logging import logging - logger = logging.getLogger( "locateSetupScript" ) - - # Locate the AtlasGPerfTools package using CMT: - import subprocess - process = subprocess.Popen( [ "cmt", "show", "versions", - "External/AtlasGPerfTools" ], - stdout = subprocess.PIPE, - stderr = subprocess.PIPE ) - ( result, errors ) = process.communicate() - - # Check that the CMT command was successful: - if len( errors ): - logger.error( "Couldn't execute cmt show versions command" ) - return "" - - # Select the first result: - first_version = result.split( '\n' )[ 0 ] - logger.verbose( "Preferred AtlasGPerfTools version: " + first_version ) - - # The line should look like this: - # [package name] [package version] [path] - package_info = first_version.split( ' ' ) - if len( package_info ) != 3: - logger.error( "Couldn't interpret: " + first_version ) - return "" - - # Now, construct the path: - path = package_info[ 2 ] + "/" + package_info[ 0 ] + "/cmt/setup.sh" - logger.debug( "Setup script found under: " + path ) - - return path diff --git a/Control/PerformanceMonitoring/PerfMonGPerfTools/scripts/aprof.py b/Control/PerformanceMonitoring/PerfMonGPerfTools/scripts/aprof.py index eb11a59063afd67d28b83975d0d0d72ba1e0a451..6812f1671367745b560bdb8124d755774599a0c8 100755 --- a/Control/PerformanceMonitoring/PerfMonGPerfTools/scripts/aprof.py +++ b/Control/PerformanceMonitoring/PerfMonGPerfTools/scripts/aprof.py @@ -1,6 +1,6 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -# Copyright (C) 2002-2017 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration # # $Id: aprof.py 783179 2016-11-09 11:13:54Z limosani $ # @@ -77,19 +77,9 @@ def makePdf( input_file, output_file ): from AthenaCommon.Logging import logging logger = logging.getLogger( "makePdf" ) - import os - # CMAKE - if os.environ.get( 'CMTPATH', '' ) == '': - commandprefix = "" - else: - # CMT - # Locate the setup script: - from PerfMonGPerfTools.Utils import locateSetupScript - script = locateSetupScript() - # Construct and run the command: import os - command = "source " + script + " && pprof --pdf --nodecount=200 --nodefraction=0.001 " \ + command = "pprof --pdf --nodecount=200 --nodefraction=0.001 " \ "--edgefraction=0.0002 `which python` " + input_file + " > " + output_file logger.info( "Running command: " + command ) return os.system( command ) @@ -109,13 +99,9 @@ def makeCallgrind( input_file, output_file ): from AthenaCommon.Logging import logging logger = logging.getLogger( "makeCallgrind" ) - # Locate the setup script: - from PerfMonGPerfTools.Utils import locateSetupScript - script = locateSetupScript() - # Construct and run the command: import os - command = "source " + script + " && pprof --callgrind `which python` " + \ + command = "pprof --callgrind `which python` " + \ input_file + " > " + output_file logger.info( "Running command: " + command ) return os.system( command ) diff --git a/Control/PerformanceMonitoring/PerfMonGPerfTools/share/DisableCoreDumpSvc_postInclude.py b/Control/PerformanceMonitoring/PerfMonGPerfTools/share/DisableCoreDumpSvc_postInclude.py index 4c0832c32feb7ea3827d41f727aa76a4b390d5c2..b0e325dd0a2952169af48186388dbadbf99f7c02 100644 --- a/Control/PerformanceMonitoring/PerfMonGPerfTools/share/DisableCoreDumpSvc_postInclude.py +++ b/Control/PerformanceMonitoring/PerfMonGPerfTools/share/DisableCoreDumpSvc_postInclude.py @@ -1,3 +1,5 @@ +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + # This posInclude fragment is used when setting up GPT profiling of an Athena job # to turn off CoreDumpSvc. CoreDumpSvc hooks into certain signal events, which # seems to interfere with GPerfTools and causes random crashes diff --git a/Control/PerformanceMonitoring/PerfMonGPerfTools/share/DisablePerfMon_jobOFragment.py b/Control/PerformanceMonitoring/PerfMonGPerfTools/share/DisablePerfMon_jobOFragment.py index a43ac3849c12aa67d44bbb258f45960b80096602..d9a823f8806517a088258054da04a9b75f17ee7f 100644 --- a/Control/PerformanceMonitoring/PerfMonGPerfTools/share/DisablePerfMon_jobOFragment.py +++ b/Control/PerformanceMonitoring/PerfMonGPerfTools/share/DisablePerfMon_jobOFragment.py @@ -1,3 +1,5 @@ +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + # $Id: DisablePerfMon_jobOFragment.py 631453 2014-11-27 09:26:40Z will $ # # This jobO fragment is used when setting up the profiling of an Athena job @@ -6,7 +8,7 @@ # # It should only be loaded once: -include.block( "PerfMonGPerfTools/DisablePerfMon_jobOFragment.py" ) +include.block( "PerfMonGPerfTools/DisablePerfMon_jobOFragment.py" ) # noqa: F821 # Disable PerfMon as much as we can: from PerfMonComps.PerfMonFlags import jobproperties as pmon_properties diff --git a/Control/PerformanceMonitoring/PerfMonGPerfTools/share/ProfileEventLoop_preInclude.py b/Control/PerformanceMonitoring/PerfMonGPerfTools/share/ProfileEventLoop_preInclude.py index 8d4a39effb4d42bdcfc620327c6ec106ecbf30e5..29718f612c0736a60144ee7ed30205cfa04977fc 100644 --- a/Control/PerformanceMonitoring/PerfMonGPerfTools/share/ProfileEventLoop_preInclude.py +++ b/Control/PerformanceMonitoring/PerfMonGPerfTools/share/ProfileEventLoop_preInclude.py @@ -1,3 +1,5 @@ +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + # $Id: ProfileEventLoop_preInclude.py 496380 2012-04-18 12:28:09Z ritsch $ # # This jobO fragment can be pre-included in Reco_trf.py jobs to profile @@ -5,7 +7,7 @@ # # First off, let's disable PerfMon. It doesn't mix well with GPT. -include( "PerfMonGPerfTools/DisablePerfMon_jobOFragment.py" ) +include( "PerfMonGPerfTools/DisablePerfMon_jobOFragment.py" ) # noqa: F821 # Set up the profiler service: from AthenaCommon.AppMgr import ServiceMgr @@ -18,7 +20,7 @@ ServiceMgr.ProfilerService.InitEvent = 10 ServiceMgr.ProfilerService.ProfileFileName = "gpt-execute.profile" # Set up the profiler service as the first service to be created: -theApp.CreateSvc.insert( 0, "GPT::ProfilerService/ProfilerService" ) +theApp.CreateSvc.insert( 0, "GPT::ProfilerService/ProfilerService" ) # noqa: F821 # Print a message with what happened: from AthenaCommon.Logging import logging diff --git a/Control/PerformanceMonitoring/PerfMonGPerfTools/share/ProfileJob_preInclude.py b/Control/PerformanceMonitoring/PerfMonGPerfTools/share/ProfileJob_preInclude.py index a149ea324a98998fd40ba1494e189e0a9f1ad0ef..507e2a5601c7c48dd4945c87ae8bde3a38b3c798 100644 --- a/Control/PerformanceMonitoring/PerfMonGPerfTools/share/ProfileJob_preInclude.py +++ b/Control/PerformanceMonitoring/PerfMonGPerfTools/share/ProfileJob_preInclude.py @@ -1,3 +1,5 @@ +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + # $Id: ProfileJob_preInclude.py 496380 2012-04-18 12:28:09Z ritsch $ # # This job fragment can be pre-included in Reco_trf.py jobs to profile @@ -11,7 +13,7 @@ # # First off, let's disable PerfMon. It doesn't mix well with GPT. -include( "PerfMonGPerfTools/DisablePerfMon_jobOFragment.py" ) +include( "PerfMonGPerfTools/DisablePerfMon_jobOFragment.py" ) # noqa: F821 # Set up the profiler service: from AthenaCommon.AppMgr import ServiceMgr @@ -23,7 +25,7 @@ ServiceMgr.ProfilerService.InitEvent = -1 ServiceMgr.ProfilerService.ProfileFileName = "gpt-fulljob.profile" # Set up the profiler service as the first service to be created: -theApp.CreateSvc.insert( 0, "GPT::ProfilerService/ProfilerService" ) +theApp.CreateSvc.insert( 0, "GPT::ProfilerService/ProfilerService" ) # noqa: F821 # Print a message with what happened: from AthenaCommon.Logging import logging diff --git a/Control/PerformanceMonitoring/PerfMonVTune/CMakeLists.txt b/Control/PerformanceMonitoring/PerfMonVTune/CMakeLists.txt index 51ae73f5f861936e0c7e2a7917ea2067ad9f859b..dd30bd6d2996d5527d8cedca28aa4c73f0d4d563 100644 --- a/Control/PerformanceMonitoring/PerfMonVTune/CMakeLists.txt +++ b/Control/PerformanceMonitoring/PerfMonVTune/CMakeLists.txt @@ -5,7 +5,7 @@ atlas_subdir( PerfMonVTune ) #### # VTune hack for the time-being -find_program( VTUNE_EXECUTABLE amplxe-cl ) +find_program( VTUNE_EXECUTABLE vtune ) get_filename_component( VTUNE_DIR ${VTUNE_EXECUTABLE} PATH ) set( ITT_PREFIX ${VTUNE_DIR}/.. ) @@ -13,6 +13,14 @@ find_path( ITT_INCLUDE_DIR NAMES ittnotify.h HINTS ${ITT_PREFIX}/include ) find_library( ITT_LIBRARY NAMES ittnotify HINTS ${ITT_PREFIX}/lib64 ) include_directories(${ITT_INCLUDE_DIR}) + +if ( NOT ITT_LIBRARY OR NOT ITT_INCLUDE_DIR ) + message( FATAL_ERROR + "\nYou must have VTune setup properly for compiling PerfMonVTune.\n" + "From within CERN this can be accomplished by doing:\n" + "source /cvmfs/projects.cern.ch/intelsw/psxe/linux/all-setup.sh\n" + "*BEFORE* setting up Athena." ) +endif() #### # Component(s) in the package: @@ -22,6 +30,6 @@ atlas_add_component( PerfMonVTune LINK_LIBRARIES GaudiKernel AthenaBaseComps AthenaKernel ${ITT_LIBRARY} ${CMAKE_DL_LIBS} ) # Install files from the package: -atlas_install_python_modules( python/*.py ) -atlas_install_joboptions( share/*.py ) -atlas_install_scripts( scripts/*.py ) +atlas_install_python_modules( python/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) +atlas_install_joboptions( share/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) +atlas_install_scripts( scripts/*.py POST_BUILD_CMD ${ATLAS_FLAKE8} ) diff --git a/Control/PerformanceMonitoring/PerfMonVTune/scripts/vtune_athena.py b/Control/PerformanceMonitoring/PerfMonVTune/scripts/vtune_athena.py index 673ebba0b9e564aacc78f0115e49e96a46454b21..8306d0c464861f082f1907efa4e88bc77b91b09c 100755 --- a/Control/PerformanceMonitoring/PerfMonVTune/scripts/vtune_athena.py +++ b/Control/PerformanceMonitoring/PerfMonVTune/scripts/vtune_athena.py @@ -1,14 +1,10 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 -# Copyright (C) 2002-2018 CERN for the benefit of the ATLAS collaboration +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration -import glob import logging -import multiprocessing -import os import subprocess import sys -import uuid # Setting logging options fmt = '%(asctime)s :: %(levelname)-8s :: %(message)s' @@ -25,32 +21,32 @@ console.setFormatter(formatter) logger.addHandler(console) #### -## Check Athena Setup +## Check Athena Setup #### def checkAthenaSetup(): try: - a = subprocess.check_output(['athena','--version']) + a = subprocess.check_output(['athena','--version']) logger.debug('Athena version information \n %s',a) - except: + except Exception: logger.fatal('Athena is not setup!') - sys.exit(-1) + sys.exit(-1) #### ## Check VTune Setup #### def checkVTuneSetup(): try: - a = subprocess.check_output(['amplxe-cl','--version']) + a = subprocess.check_output(['vtune','--version']) logger.debug('VTune version information \n %s',a) - except: + except Exception: logger.fatal('VTune is not setup!') - sys.exit(-1) + sys.exit(-1) #### -## AutoGen a jobOptions fragment +## AutoGen a jobOptions fragment #### def generateJOFragment(fileName,firstEvent,lastEvent): - logger.info('Creating jOptions fragment %s', fileName) + logger.info('Creating jOptions fragment %s', fileName) with open('{}'.format(fileName),'w') as f: f.write('# Auto generated jobOptions fragment to setup Athena VTune profiler') f.write('\ninclude(\'PerfMonVTune/VTuneProfileEventLoop_preInclude.py\')') @@ -122,11 +118,11 @@ def main(): checkAthenaSetup() checkVTuneSetup() - # Perpare the JO fragment + # Perpare the JO fragment joFragment = 'PerfMonVTune_autoSetup.py' - generateJOFragment(joFragment, options.start, options.stop) + generateJOFragment(joFragment, options.start, options.stop) - # Prepare the transformation command to execute + # Prepare the transformation command to execute if not options.tf: logger.fatal('The transformation command is empty, quitting...') sys.exit(-1) @@ -139,7 +135,7 @@ def main(): args.extend(['--preInclude',joFragment]) # Run the command - cmd = ( 'amplxe-cl' + + cmd = ( 'vtune' + ' -collect ' + options.collect + ' -strategy ' + options.strategy + ' -start-paused -- ' ) diff --git a/Control/PerformanceMonitoring/PerfMonVTune/share/VTuneProfileEventLoop_preInclude.py b/Control/PerformanceMonitoring/PerfMonVTune/share/VTuneProfileEventLoop_preInclude.py index 4240d9f37e01659bc1113164fa96764073f9a9d7..88d01d7a86a113218f92c88cb86ce75f7593ec37 100644 --- a/Control/PerformanceMonitoring/PerfMonVTune/share/VTuneProfileEventLoop_preInclude.py +++ b/Control/PerformanceMonitoring/PerfMonVTune/share/VTuneProfileEventLoop_preInclude.py @@ -1,3 +1,5 @@ +# Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration + # Set up the profiler service: from AthenaCommon.AppMgr import ServiceMgr from PerfMonVTune.PerfMonVTuneConf import VTuneProfilerService @@ -6,7 +8,7 @@ ServiceMgr += VTuneProfilerService("VTuneProfilerService") ServiceMgr.VTuneProfilerService.ResumeEvent = 10 # Set up the profiler service as the first service to be created: -theApp.CreateSvc.insert( 0, "VTuneProfilerService/VTuneProfilerService" ) +theApp.CreateSvc.insert( 0, "VTuneProfilerService/VTuneProfilerService" ) # noqa: F821 # Print a message with what happened: from AthenaCommon.Logging import logging