7 from __future__
import print_function
9 """ A set of classes and utilities to post-process/analyze a (set of)
14 __author__ =
'Sebastien Binet'
15 __version__ =
"$Revision: 1.20 $"
16 __doc__ =
"A set of classes and utilities to post-process/analyze a (set of) perfmon tuples."
26 mplconfig_dir = tempfile.mkdtemp(prefix=
'matplotlib-%s-' % os.getpid())
27 os.environ[
'MPLCONFIGDIR'] = mplconfig_dir
32 if os.system(
'/bin/rm -rf %s' % mplconfig_dir):
33 print (
"** could not remove temporary $MPLCONFIGDIR **")
35 atexit.register(del_mplconfig_dir)
39 if 'matplotlib.backends' not in sys.modules:
41 import matplotlib.pyplot
as pyplot
43 _rc[
'legend.fontsize'] =
'medium'
44 _rc[
'axes.titlesize'] =
'medium'
45 _rc[
'xtick.labelsize'] =
'small'
46 _rc[
'ytick.labelsize'] =
'small'
47 _rc[
'font.size'] = 7.0
48 _rc[
'figure.dpi'] = 100
49 _rc[
'figure.subplot.bottom'] = 0.05
50 _rc[
'figure.subplot.hspace'] = 0.3
51 _rc[
'figure.subplot.right'] = 0.95
52 _rc[
'figure.subplot.top'] = 0.95
53 _rc[
'figure.subplot.wspace'] = 0.3
55 _pyplot_legend = pyplot.legend
60 pyplot.legend = my_legend
62 pylab.legend = my_legend
65 from .DataLoader
import DataLoader
67 __do_monitoring =
False
70 global __do_monitoring
72 from resource
import RUSAGE_SELF,getrusage
73 cpu = getrusage( RUSAGE_SELF )
77 print (
"cpu: u=",cpu.ru_utime * 1e3)
78 print (
"cpu: s=",cpu.ru_stime * 1e3)
79 print (
"time: ",start)
85 logger = logging.StreamHandler(sys.stdout)
86 logger.setLevel(logging.DEBUG)
88 formatter = logging.Formatter(
'%(name)-12s: %(levelname)-8s %(message)s')
90 logger.setFormatter(formatter)
92 logging.getLogger(
'').addHandler(logger)
95 log = logging.getLogger(
"AppMgr")
98 log = logging.getLogger(
"AnaMgr-" +
str(i).zfill(3))
100 log = logging.getLogger(
"Ana-chk")
101 log.setLevel( logging.ERROR )
102 log = logging.getLogger(
"Ana-ref")
103 log.setLevel( logging.ERROR )
104 log = logging.getLogger(
"Analyzer")
105 log.setLevel( logging.ERROR )
122 The main class to perform an analysis on perfmon data
126 analyzers = (
"cpu",
"mem"),
131 self.
msg = logging.getLogger(
"AppMgr")
132 self.
msg.
info(
"Initializing the application manager..." )
135 self.
outputFile = os.path.splitext(outFileName)[0]
137 dsLabels = [
str(i).zfill(3)
for i
in range(len(inputFileNames)) ]
138 elif len(dsLabels) < len(inputFileNames):
139 dsLabels += [
str(i).zfill(3)
for i
in range(len(dsLabels),
140 len(inputFileNames)) ]
142 for idx,inFileName
in enumerate(inputFileNames) ]
145 self.
monComps = MonitoredComponent.instances
147 filtered = [ m
for m
in MonitoredComponent.instances.values()
148 if m.name
in (
'TopAlg',
'Streams',
150 'PerfMonSliceIo' )
or \
152 self.
msg.
info(
"\tafter filtering: [%i]", len(filtered) )
156 elif ':' not in fitSlice:
158 nbins = len(bins[1:])
160 fitSlice =
float(fitSlice)
163 if fitSlice <= 0.
or fitSlice > 1.:
165 "You have to give a fitSlice in (0.,1.] (got: %r)" %
168 _ratio = (1.-
float(fitSlice))*nbins
173 elif nbins > 95
and nbins < 115 :
183 self.
msg.
info(
"Initializing the application manager... [DONE]" )
188 main entry point to run the post-processing of a perfmon job
190 self.
msg.
info(
"running app..." )
196 self.
msg.warning(
"Not running on same number of evts !" )
197 self.
msg.warning(
" [%s] : %r",
200 self.
msg.warning(
" [%s] : %r",
204 self.
msg.
info(
"nbr of datasets: %i", len(DataSetMgr.instances.keys()) )
205 from .
import Analyzer
206 self.
msg.
info(
"running analyzers..." )
208 self.
msg.
debug(
" ==> [%s]... (%s)", monComp.name, monComp.type )
210 if (monComp.name
in [
'TopAlg',
'Streams' ]
or
212 for monVar
in monVars:
213 analyzer = Analyzer.getAnalyzer(monVar, monComp.name)
214 analyzer.run(monComp)
217 self.
msg.
debug(
" skipped [%s]", monComp.name )
220 self.
msg.
info(
"creating summary..." )
222 from .
import SummaryCreator
225 MonitoredComponent.instances )
227 self.
msg.
info(
"creating output files..." )
232 self.
msg.
info(
"running app... [DONE]" )
233 return ExitCodes.SUCCESS
236 """hook for the user to filter out some MonitoredComponent"""
238 from .UserFct
import FilterFct
243 self.
msg.
debug(
"create ROOT file..." )
244 from .PyRootLib
import importRoot
247 outFile = ROOT.fopen( outName,
'RECREATE' )
248 for dsName
in DataSetMgr.names():
250 outFile.mkdir( dsName )
252 for m
in MonitoredComponent.instances.values():
253 if (
not m.name.startswith(
'PerfMonSlice')
and
256 if dsName
not in m.data:
259 for h
in m.data[dsName][
'histos'].
values():
260 self.
msg.
debug(
"writing %s/%s", dsName, h.GetName() )
263 if os.path.exists( outName ):
264 self.
msg.
info(
" --> (%10.3f kB) [%s]",
265 os.stat(outName).st_size / 1024.,
267 self.
msg.
debug(
"create ROOT file... [DONE]" )
273 for k
in [
'ini',
'1st',
'evt',
'fin',
'io' ]:
274 if 'fig' in self.
summary.sum[k]:
276 if isinstance(f, list):
280 jobSlice = MonitoredComponent.instances[
'PerfMonSlice']
281 for k
in [
'cpu',
'mem',
'io' ]:
283 if fig
in jobSlice.figs:
284 figs.append( jobSlice.figs[fig] )
288 for m
in MonitoredComponent.instances.values():
291 if m.type
in (
'alg',
'algtool',
'svc'):
292 algFigs += m.figs.values()
294 ioFigs += m.figs.values()
303 pdf.save( self.
outputFile+
".pdf", figs, orientation=
'landscape' )
306 if os.path.exists( outName ):
307 self.
msg.
info(
" --> (%10.3f kB) [%s]",
308 os.stat(outName).st_size / 1024.,
313 """Fill an ASCII with the summary data in a 'nice' format
316 o =
open( outName,
'w' )
318 print (
":"*80, file=o)
319 for c
in (
'slice',
'comps' ):
320 for i
in (
'ini',
'1st',
'evt',
'fin'):
321 print (
"=== [%s - %s] ===" % (i,c), file=o)
322 for j
in (
'mem',
'cpu',
'allocs', ):
323 for z
in _txt[i][j][c]:
325 print (
":"*80, file=o)
326 print (
"="*80, file=o)
329 if os.path.exists( outName ):
330 self.
msg.
info(
" --> (%10.3f kB) [%s]",
331 os.stat(outName).st_size / 1024.,
337 The main class to analyze the content of a perfmon tuple
341 object.__init__(self)
343 if isinstance(name, str):
347 self.
msg = logging.getLogger(
"AnaMgr-%s" % self.
name)
355 DataSetMgr.instances[self.
name].label = dsLabel
365 compNames =
set(
list(data[
'meta'][
'components' ].
keys()) +
366 data[
'meta'][
'iocontainers'] )
367 storeNames = [ k
for k
in six.iterkeys(data[
'data'])
if k !=
'meta' ]
368 compNames = [ c
for c
in compNames ]
371 dataSetName = self.
name
372 for compName
in compNames:
374 monData = monComp.data[dataSetName]
375 for storeName
in storeNames:
377 monData[storeName] = data[
'data'][storeName][compName]
379 monData[storeName] =
None
380 if storeName ==
'io' and compName ==
'PerfMonSlice':
381 monData[storeName] = data[
'data'][
'io'][
'PerfMonSliceIo']
384 self.
bins = numpy.arange(len(data[
'data'][
'evt'][
'PerfMonSlice']))
387 _compsDb = data[
'meta'][
'components' ]
388 _comps =
list(data[
'meta'][
'components' ].
keys())
389 _ioconts = data[
'meta'][
'iocontainers']
390 for monComp
in MonitoredComponent.instances.values():
391 if monComp.type
is not None:
393 monName = monComp.name
394 if monName
in _comps:
395 monComp.type = _compsDb[monName]
396 if isinstance(monComp.type,dict):
397 monComp.type = _compsDb[monName][
'type']
401 elif monName
in _ioconts:
410 dataSet.bins = self.bins
412 self.msg.
debug(
"Loading perfmon data... [OK]" )
417 An object modelling a (Gaudi) component which has been monitored with the
418 PerfMon services and tools
432 kw[
'dataSetName'] = p[1]
441 obj = object.__new__(cls)
454 object.__init__(self)
463 if dataSetName
not in self.
data:
464 self.
data[dataSetName] = {}
467 if k
not in self.
data[dataSetName]:
468 self.
data[dataSetName][k] = {}
474 Return the list of monitored variables for this component
475 ex: ['io','cpu','mem']
479 for storeName,store
in ds.items():
480 monKeys += [ k.split(
"/")[0]
for k
in store.keys() ]
481 return [ k
for k
in set(monKeys) ]
484 """Borg-class (python-singleton) to hold the different 'dataset'
496 kw[
'name' ] = args[0]
498 kw[
'data' ] = args[1]
500 kw[
'label'] = args[2]
507 obj = object.__new__(cls)
522 keys =
list(DataSetMgr.instances.keys())
524 return [DataSetMgr.instances[k].label
for k
in keys]
528 keys =
list(DataSetMgr.instances.keys())
536 color = iter(
list(pylab.cm.colors.cnames.keys())[1:])
541 object.__init__(self)
558 """Borg-class (python-singleton) to hold different Pdf files, containing
578 obj = object.__new__(cls)
592 object.__init__(self)
596 def save(self, pdfFileName, figs, orientation='portrait'):
598 from matplotlib.backends.backend_pdf
import PdfPages
602 if os.path.exists( pdfFileName ):
603 os.remove( pdfFileName )
604 out = PdfPages(pdfFileName)
605 for idx,fig
in enumerate(figs):
618 def legend(*args, **kwargs):
620 Overwrites the pylab legend function.
622 It adds another location identifier 'outer right'
623 which locates the legend on the right side of the plot
625 The args and kwargs are forwarded to the pylab legend function
631 if loc[0] == 'outer':
632 # make a legend with out the location
633 # remove the location setting from the kwargs
635 leg = pylab.legend(loc=(0,0), *args, **kwargs)
636 frame = leg.get_frame()
637 currentAxes = pylab.gca()
638 currentAxesPos = currentAxes.get_position()
639 # scale plot by the part which is taken by the legend
640 plotScaling = frame.get_width()/currentAxesPos[2]
642 if loc[1] == 'right':
644 currentAxes.set_position((currentAxesPos[0],currentAxesPos[1],
645 currentAxesPos[2] * (1-plotScaling),
647 # set x and y coordinates of legend
648 leg._loc = (1 + leg.axespad, 1 - frame.get_height())
651 #if loc[1] == 'left':
653 # currentAxes.set_position((currentAxesPos[0] +frame.get_width(),
655 # currentAxesPos[2] *(1-plotScaling),
656 # currentAxesPos[3]))
657 # # set x and y coordinates of legend
658 # leg._loc = (1 -.05 - leg.axespad - frame.get_width(), 1 -frame.get_height())
660 pylab.draw_if_interactive()
663 return pylab.legend(*args, **kwargs)