5 __author__ =
"Frank Winklmeier"
6 __version__ =
"$Revision: 270227 $"
7 __doc__ =
"Script to create dependency tree of perfmon stats"
13 import PerfMonComps.PerfMonSerializer
as pmon_ser
29 def set(self, line, i):
30 """Set members via match object or stream line and index i"""
34 step = fields[0][1:-1]
35 self.
step = step.split(
'/')[0]
51 """Resource user with dependents
58 def _show(self, level=0, showFct=None):
59 if showFct
and not showFct(self):
62 indent = (
' '*level*(
not opt.flat))
63 s =
'\n' + indent + self.
_node()
66 s += d._show(level+1, showFct)
72 def show(self, showFct=None):
79 """Remove all objects passing purgeFct()
91 self.
dep = [ d
for d
in self.
dep if d.name
is not None ]
94 """Component (Algorithm, Tool, Service, etc.)
101 """Calculate self dvmem (subtract dvmem of all direct children)
102 Additional classes to be considered children can be supplied as list.
106 if isinstance(d, Comp)
or (children
and d.__class__
in children):
117 return '|%s %s [%.0f kB, %.0f kB]' % (
126 super(Callback, self).
__init__(name)
137 super(SharedLib, self).
__init__(name)
145 fields = line.split()
147 step = fields[0][1:-1]
148 step = step.split(
'/')[0]
149 comp = fields[0][len(step)+2:]
154 """Get resource user tree"""
160 if line.startswith((
'#',
'/io/')):
164 if step
not in steps:
178 current.dep.append(comp)
188 if name != current.name:
189 raise RuntimeError(
"stop for %s within scope of %s" % (name, current.name) )
191 current.set(line, idx)
195 offset = current.name.split(
']+')[1]
196 i = current.name.find(
'[')
198 current.name =
'%s{+%s}' % (current.name[:i],offset)
208 """Read components for evt slice
210 reEvent = re.compile(
r'AthenaEventLoopMgr\s*INFO\s*===>>> done processing event.*')
214 m = reEvent.match(line)
225 ## FIX ME : This bit needs to be checked
226 ## It's not obvious what reAud is inteded to be...
227 m = reAud.match(line)
228 if m and m.group('slice')!='evt':
231 if m and m.group('action')=='start':
232 comp = Comp(m.group('comp'))
234 if comp.name not in comps[evt]:
235 comps[evt][comp.name] = []
236 comps[evt][comp.name].append(comp)
238 if m and m.group('action')=='stop':
239 comp = comps[evt][comp.name][-1]
248 """Calculate average of list of resources"""
251 a =
Comp(res[0].name)
255 a.dmalloc += r.dmalloc
256 a.nmalloc += r.nmalloc
258 a.dvmem /=
float(len(res))
259 a.dmalloc /=
float(len(res))
260 a.nmalloc /=
float(len(res))
267 for evt
in comps[sliceObj]:
268 for comp
in evt.keys():
271 tmp[comp] += evt[comp]
274 for comp
in tmp.keys():
275 avg.append(
resAvg(tmp[comp]))
283 Create flat list of components from resource tree.
284 Call with resList = [].
287 if isinstance(r, ResUser):
295 def diff(table, opt, attrgetter=operator.attrgetter(
'dvmem')):
298 for i,t
in enumerate(table):
300 label = comp.symbol +
' ' + comp.name
302 tmp[label] = [0]*len(table)
303 tmp[label][i] = attrgetter(comp)
306 if opt.min
is not None:
307 limit = opt.min + 0.00001
308 cmpTable = [ [k]+v
for k,v
in tmp.iteritems()
if abs(v[1]-v[0])>limit ]
310 cmpTable = [ [k]+v
for k,v
in tmp.iteritems() ]
312 if opt.diff
and len(table)==2:
313 cmpTable.sort(
lambda x,y : (
int(x[2]-x[1])-
int(y[2]-y[1])), reverse=
True )
315 print(
"%-60s %10.0f %10.0f %10.0f" % (c[0],c[1],c[2],c[2]-c[1]) )
317 cmpTable.sort(
lambda x,y :
int(x[1]-y[1]), reverse=
True)
319 print(
"%-60s" % c[0], )
320 print(
"%10.0f "*(len(c)-1) % tuple(c[1:]) )
326 for c
in sorted(compList,key=operator.attrgetter(
'dvmem'), reverse=
True):
328 avgmalloc = c.dmalloc*1024/c.nmalloc
331 print(
"%-60s %10.0f %10.0f %10.0f %10.0f" %\
332 (c.name,c.dvmem,c.dmalloc,c.nmalloc,avgmalloc) )
336 parser = argparse.ArgumentParser(
337 description=
"Create callgraph profile from log file",
338 usage=
"%prog [Options] LOGFILE [LOGFILE]")
340 arg = parser.add_argument
343 help=
'list of files to process')
345 arg(
"-m",
"--min", action=
"store", type=
"float",
346 help=
"only show entries with VMem>MIN in kB")
348 arg(
"-d",
"--diff", action=
"store_true",
349 help=
"show difference (only for two files)")
351 arg(
"-s",
"--self", action=
"store_true",
352 help=
"use self instead of inclusive VMem for sorting/filtering")
354 arg(
"-l",
"--libself", action=
"store_true",
355 help=
"include libraries into self-VMem")
357 arg(
"-c",
"--slice", action=
"store", default=
"ini",
358 help=
"slice to analyze [ini]")
360 arg(
"-f",
"--flat", action=
"store_true",
361 help=
"do not indent tree")
364 opt= parser.parse_args()
366 if len(opt.files)==0:
370 if opt.diff
and len(opt.files)!=2:
371 print(
"Can only calculate difference if two files are given" )
376 slices += [
'cbk',
'dso']
392 fstream = pmon_ser.extract_pmon_files(f)[
'data']
395 resTreeList.append(z[:])
399 children = [SharedLib]
402 for r
in resTreeList[-1]:
409 for i,f
in enumerate(opt.files):
410 print(
"# [%d] %s" % (i+1,f) )
412 print(
"# [3] difference [2]-[1]" )
417 diff(table, opt, operator.attrgetter(
'dvmem_self'))
423 resTree = resTreeList[0]
425 if opt.min
is not None:
428 result = c.dvmem_self
if (opt.self
is True and hasattr(c,
'dvmem_self'))
else c.dvmem
431 r.show(
lambda c: vmem(c)>opt.min)
439 if __name__ ==
"__main__":
448 except KeyboardInterrupt: