file_size_ana.py
Go to the documentation of this file.
1 #!/bin/env python
2 
3 import argparse
4 import sys, os
5 import re
6 from math import *
7 import code
8 
9 parser = argparse.ArgumentParser()
10 
11 parser.add_argument('-t', '--text', action = 'store_true',
12  help = 'textual output')
13 parser.add_argument('-r', '--radial', action = 'store_true',
14  help = 'pie-chart-style output')
15 parser.add_argument('-l', '--linear', action = 'store_true',
16  help = 'bar-chart-style output')
17 parser.add_argument('-j', '--json', action = 'store_true',
18  help = 'json output')
19 parser.add_argument('-b', '--batch', action = 'store_true',
20  help = 'don\'t open windows for graphics')
21 
22 parser.add_argument('-f', '--focus', default='', metavar='BR', help = 'center this branch')
23 
24 parser.add_argument('filename.root',
25  help = 'the CAF or ART file to analyze')
26 
27 opts = vars(parser.parse_args())
28 
29 if not (opts['text'] or opts['radial'] or opts ['linear'] or opts['json']):
30  print 'You must specify at least one of --text, --radial, --linear, or --json'
31  exit()
32 
33 # ROOT seems unhappy about having its arguments messed with. Import it too late
34 # for it to notice
35 from ROOT import *
36 
37 class Node:
38  def __init__(self, t, s):
39  self.title = t
40  self.size = s
41  self.children = []
42 
43  def __str__(self):
44  return self.title + ':\t' + str(self.FullSize())
45 
46  def __repr__(self):
47  return '(' + self.title + ', ' + str(self.FullSize()) + ')'
48 
49  def FullSize(self):
50  return sum([c.FullSize() for c in self.children], self.size)
51 
52 ##### Parse the file #####
53 
54 # First, figure out what sort of file it is
55 se = sys.stderr
56 sys.stderr = open(os.devnull, 'w') # swallow errors about missing dictionaries
57 f = TFile(opts['filename.root'],"READ")
58 sys.stderr = se # put it back
59 
60 isArt = bool(f.Get('Events'))
61 
62 if isArt:
63  treeNames = ['Events', 'Runs', 'SubRuns',
64  'EventHistory', 'MetaData', 'Parentage',
65  'EventMetaData', 'SubRunMetaData', 'RunMetaData']
66 else:
67  treeNames = ['recTree', 'spillTree']
68 
69  if not f.Get('recTree'):
70  print 'This doesn\'t appear to be an ART or CAF file. Aborting.'
71  exit(1)
72 
73 
74 nodes = {}
75 
76 # Recurse through the tree and store the size on disk of every branch
77 def AddNodes(branch):
78  title = branch.GetName()
79 
80  # In ART files you get type_label_instance_process.therest
81  # Transform to label.instance.type.therest
82  m = re.match('(.*)_(.*)_(.*)_(.*)\\.(.*)', title)
83  if m:
84  # Often instance is blank
85  if len(m.group(3)) > 0:
86  title = m.group(2)+'.'+m.group(3)+'.'+m.group(1)+'.'+m.group(5)
87  else:
88  title = m.group(2)+'.'+m.group(1)+'.'+m.group(5)
89 
90  label = title.split('.')[-1]
91  nodes[title] = Node(label, branch.GetZipBytes())
92  for b in branch.GetListOfBranches(): AddNodes(b)
93 
94 
95 for n in treeNames:
96  for b in f.Get(n).GetListOfBranches(): AddNodes(b)
97 
98 
99 ##### Insert implicit nodes #####
100 
101 progress = True
102 while progress:
103  progress = False
104  newnodes = {}
105 
106  for key in nodes:
107  node = nodes[key]
108 
109  parentKey = '.'.join(key.split('.')[:-1])
110 
111  if parentKey.endswith('.obj'): parentKey = parentKey[:-4]
112 
113  if parentKey not in nodes:
114  label = parentKey.split('.')[-1]
115  newnodes[parentKey] = Node(label, 0)
116  progress = True
117 
118  nodes.update(newnodes)
119 
120 
121 ##### Link up the nodes tree #####
122 
123 root = nodes[opts['focus']]
124 
125 if opts['focus'] == '':
126  if isArt:
127  root.title = 'Events'
128  else:
129  root.title = 'rec'
130 
131 for key in nodes:
132  node = nodes[key]
133 
134  parentKey = '.'.join(key.split('.')[:-1])
135 
136  if parentKey.endswith('.obj'): parentKey = parentKey[:-4]
137 
138  parent = nodes[parentKey]
139  if parent is not node: # special case root node
140  parent.children.append(node)
141 
142 
143 ##### Display the node tree #####
144 
145 curNodes = [root]
146 
147 def prettyPrint(node, total, depth = 100, indent = ''):
148  if depth == 0: return
149  if node.FullSize() == 0: return
150  percent = int((100*node.FullSize())/total+.5)
151  if percent > 0:
152  print indent, node, '\t('+str(percent)+'%)'
153  else:
154  print indent, node
155 
156  for c in sorted(node.children, key = lambda n: -n.FullSize()):
157  prettyPrint(c, node.FullSize(), depth-1, indent+'\t')
158 
159 
160 
161 if opts['text']:
162  # Empirically this is the maximum depth
163  for depth in range(1, 7):
164  prettyPrint(root, root.FullSize(), depth)
165  print
166  print
167 
168 
169 
170 def toJSON(node, indent = ''):
171  ret = ''
172 
173  if len(node.children) == 0:
174  ret += indent+'{"name": "'+node.title+'", "size": '+str(node.FullSize())+'}'
175  else:
176  ret += indent+'{"name": "'+node.title+'", "children": [\n'
177 
178  ret += ',\n'.join([toJSON(c, indent+' ') for c in sorted(node.children, key = lambda n: -n.FullSize()) if c.FullSize() > 0])
179  ret += ' ] }'
180 
181  return ret
182 
183 
184 if opts['json']:
185  print toJSON(root)
186 
187 
188 
189 
190 gs = []
191 # When ROOT objects get garbage-collected they disappear from the screen
192 # again. Need to leak them like in C++
193 def New(cons, *args):
194  ret = cons(*args)
195  gs.append(ret)
196  return ret
197 
198 
199 def RingChart(node, total, depth = 1, startang = 0):
200  span = 360.*node.FullSize()/total
201  meanang = (startang+span/2)*3.14159/180
202 
203  if span < .5: return
204 
205  arc = New(TArc, 200, 200, 20*depth, startang, startang+span)
206  arc.SetLineWidth(2)
207 
208  for c in sorted(node.children, key = lambda n: -n.FullSize()):
209  RingChart(c, total, depth+1, startang)
210  startang += (360.*c.FullSize())/total
211 
212  arc.Draw()
213 
214  meanr = 20*depth-10
215  if depth == 1: meanr = 0
216  if span > 10:
217  label = New(TLatex, 200+meanr*cos(meanang),
218  200+meanr*sin(meanang),
219  node.title)
220  textscale = .06*span/len(node.title)
221  if textscale > 1: textscale = 1
222  label.SetTextSize(label.GetTextSize()*textscale)
223  label.SetTextAlign(22)
224  textang = meanang*180/3.14159265358979-90
225  if textang > +90: textang -= 180
226  if textang < -90: textang += 180
227  if depth > 1: label.SetTextAngle(textang)
228  label.Draw()
229  elif span > 1:
230  label = New(TLatex, 200+meanr*cos(meanang),
231  200+meanr*sin(meanang),
232  node.title)
233  textscale = .06*span
234  if textscale > 1: textscale = 1
235  label.SetTextSize(label.GetTextSize()*textscale)
236  label.SetTextAlign(22)
237  textang = meanang*180/3.14159265358979
238  while textang > +90: textang -= 180
239  while textang < -90: textang += 180
240  if depth > 1: label.SetTextAngle(textang)
241  label.Draw()
242 
243 
244 
245 def BarChart(node, total, depth = 0, startpos = 0):
246  span = 100.*node.FullSize()/total
247  meanpos = startpos+span/2
248  meany = -(depth*20+10)
249 
250  if span < .3: return
251 
252  box = New(TBox, startpos, -depth*20, startpos+span, -(depth*20+20))
253  box.SetLineWidth(2)
254  box.SetFillStyle(0)
255 
256  for c in sorted(node.children, key = lambda n: -n.FullSize()):
257  BarChart(c, total, depth+1, startpos)
258  startpos += (100.*c.FullSize())/total
259 
260  box.Draw()
261 
262  if span > 20:
263  label = New(TLatex, meanpos, meany, node.title)
264  textscale = .4*min(20, span)/len(node.title)
265  if textscale > 2: textscale = 2
266  label.SetTextSize(label.GetTextSize()*textscale)
267  label.SetTextAlign(22)
268  label.Draw()
269  elif span > 1:
270  label = New(TLatex, meanpos, meany, node.title)
271  textscale = .4*min(20, span)/len(node.title)
272  if textscale > 1: textscale = 1
273  label.SetTextSize(label.GetTextSize()*textscale)
274  label.SetTextAlign(22)
275  label.SetTextAngle(90)
276  label.Draw()
277 
278 
279 if opts['radial']:
280  canv = New(TCanvas, 'rings', 'rings', 1000, 1000)
281 
282  axes = New(TH2F, "", "", 100, 70, 330, 100, 70, 330)
283  axes.Draw()
284 
285  axes.GetXaxis().SetTickLength(0)
286  axes.GetYaxis().SetTickLength(0)
287  gPad.SetLeftMargin(0)
288  gPad.SetRightMargin(0)
289  gPad.SetBottomMargin(0)
290  gPad.SetTopMargin(0)
291  gStyle.SetOptStat(0)
292 
293  RingChart(root, root.FullSize())
294 
295  gPad.Print("rings.png")
296  gPad.Print("rings.eps")
297 
298 
299 if opts['linear']:
300  canv = New(TCanvas, 'bars', 'bars', 1000, 1000)
301 
302  axes = New(TH2F, "", "", 100, -10, 110, 100, -110, +10)
303  axes.Draw()
304 
305  axes.GetXaxis().SetTickLength(0)
306  axes.GetYaxis().SetTickLength(0)
307  gPad.SetLeftMargin(0)
308  gPad.SetRightMargin(0)
309  gPad.SetBottomMargin(0)
310  gPad.SetTopMargin(0)
311  gStyle.SetOptStat(0)
312 
313  BarChart(root, root.FullSize())
314 
315  gPad.Print("bars.png")
316  gPad.Print("bars.eps")
317 
318 
319 if (opts['radial'] or opts['linear']) and not opts['batch']:
320  # Just want the console to hang around so the user can look at the plots
321  # without them disappearing. Ctrl-D or "exit()" to quit.
322  print 'Ctrl-D to quit'
323  code.interact(local = locals(), banner='')
def __init__(self, t, s)
def New(cons, args)
def BarChart(node, total, depth=0, startpos=0)
def AddNodes(branch)
const std::map< std::pair< std::string, std::string >, Variable > vars
procfile open("FD_BRL_v0.txt")
static float min(const float a, const float b, const float c)
Definition: absgeo.cxx:45
def prettyPrint(node, total, depth=100, indent='')
T sin(T number)
Definition: d0nt_math.hpp:132
exit(0)
T cos(T number)
Definition: d0nt_math.hpp:78
def toJSON(node, indent='')
def RingChart(node, total, depth=1, startang=0)
Double_t sum
Definition: plot.C:31