ATLAS Offline Software
dso-stats.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 
3 # Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
4 
5 # @file: PyUtils/bin/dso-stats.py
6 # @purpose: compile statistics about shared libraries
7 # @author: Scott Snyder
8 
9 from __future__ import print_function
10 
11 import re
12 import sys
13 import os
14 import subprocess
15 
16 def getstatus(cmd):
17  sc,_ = subprocess.getstatusoutput(cmd)
18  return sc
19 subprocess.getstatus = getstatus
20 del getstatus
21 
22 def getoutput(cmd):
23  _,out = subprocess.getstatusoutput(cmd)
24  return out
25 subprocess.getoutput = getoutput
26 del getoutput
27 
28 
29 #lib = 'atlas-work4/InstallArea/i686-slc4-gcc34-dbg/lib/libAthenaROOTAccess.so'
30 def _getpagesz():
31  import resource
32  sz = resource.getpagesize()
33  del resource
34  return sz
35 PAGESIZE = int(_getpagesz())
36 del _getpagesz
37 
38 
39 pat = re.compile (' *[0-9]* ([^ ]+) *([0-9a-f]+)')
40 
41 format = "%(name)-30s %(dso)5s %(code)5s %(puredata)5s %(cpp)5s %(initdata)5s %(bss)5s %(tbss)5s %(frag)5s %(total)6s"
42 
43 def parse_lib (lib):
44  out = subprocess.getoutput ("objdump -h " + lib)
45  secs = []
46  for l in out.split ('\n'):
47  m = pat.match (l)
48  if m:
49  secs.append ((m.group(1), int(m.group(2), 16)))
50  return secs
51 
52 
53 def _frag (sz):
54  return ((sz + PAGESIZE-1) & (~(PAGESIZE-1))) - sz
55 
56 
57 def _cleanname (name):
58  if name == 'None':
59  return 'None'
60  name = os.path.basename (name)
61  name = os.path.splitext(name)[0]
62  if name.startswith ('lib'):
63  name = name[3:]
64  return name
65 
66 
67 def _form (x):
68  return int ((x+512) / 1024)
69 
70 class Data:
71  def __init__ (self, secs = None, name = None):
72  self.name = name
73  self.dso = 0
74  self.code = 0
75  self.puredata = 0
76  self.cpp = 0
77  self.java = 0
78  self.initdata = 0
79  self.bss = 0
80  self.tbss = 0
81  self.frag = 0
82 
83  self.ro = 0
84  self.rw = 0
85 
86  if secs:
87  self.add_secs (secs)
88  self.est_frag()
89  return
90 
91 
92  def __iadd__ (self, other):
93  self.dso += other.dso
94  self.code += other.code
95  self.puredata += other.puredata
96  self.cpp += other.cpp
97  self.java += other.java
98  self.initdata += other.initdata
99  self.bss += other.bss
100  self.tbss += other.tbss
101  self.ro += other.ro
102  self.rw += other.rw
103  self.frag += other.frag
104  return self
105 
106 
107  def est_frag (self):
108  self.frag += _frag (self.ro)
109  self.frag += _frag (self.rw)
110  self.frag += _frag (self.bss)
111  self.frag += _frag (self.tbss)
112  return
113 
114 
115  def total (self):
116  return (self.dso + self.code + self.puredata + self.cpp +
117  self.java + self.initdata + self.frag + self.bss + self.tbss)
118 
119 
120  def add_secs (self, secs):
121  for s, sz in secs:
122  if s in ['.hash', '.dynsym', '.dynstr', '.gnu.version',
123  '.gnu.version_r', '.rel.dyn', '.rel.plt',
124  '.init', '.plt', '.fini', '.init_array', '.fini_array',
125  '.gnu.hash', '.rela.dyn', '.rela.plt',
126  '.data.rel.ro']:
127  self.dso += sz
128  self.ro += sz
129 
130  elif s in ['.text']:
131  self.code += sz
132  self.ro += sz
133 
134  elif s in ['.rodata']:
135  self.puredata += sz
136  self.ro += sz
137 
138  elif s in ['.eh_frame_hdr', '.eh_frame', '.gcc_except_table']:
139  self.cpp += sz
140  self.ro += sz
141 
142  elif s in ['.ctors', '.dtors']:
143  self.cpp += sz
144  self.rw += sz
145 
146 
147  elif s in ['.jcr']:
148  self.java += sz
149  self.rw += sz
150 
151  elif s in ['.dynamic', '.got', '.got.plt', '.plt.got']:
152  self.dso += sz
153  self.rw += sz
154 
155  elif s in ['.data']:
156  self.initdata += sz
157  self.rw += sz
158 
159  elif s in ['.bss']:
160  self.bss += sz
161 
162  elif s in ['.tbss']:
163  self.tbss += sz
164 
165  elif s in ['.comment', '.gnu_debuglink'] or s.startswith ('.debug'):
166  pass
167 
168  else:
169  print ('** Unknown section [%s] **' % s, file=sys.stderr)
170 
171  return
172 
173 
174 
175  def dump (self, f):
176  kw = {}
177  kw['name'] = _cleanname (self.name)
178  kw['dso'] = _form (self.dso)
179  kw['code'] = _form (self.code)
180  kw['puredata'] = _form (self.puredata)
181  kw['cpp'] = _form (self.cpp)
182  kw['java'] = _form (self.java)
183  kw['initdata'] = _form (self.initdata)
184  kw['frag'] = _form (self.frag)
185  kw['bss'] = _form (self.bss)
186  kw['tbss'] = _form (self.tbss)
187  kw['total'] = _form (self.total())
188  print (format % kw, file=f)
189 
190 def main():
191 
192  import optparse
193  parser = optparse.OptionParser(description="compile size statistics for shared libraries",
194  usage="%prog LIB [LIB...]")
195 
196  (opt, args) = parser.parse_args()
197  if len(args)==0:
198  parser.error("Invalid number of arguments specified")
199 
200  libs = []
201  total = Data(name = 'Total')
202  for lib in args:
203  secs = parse_lib(lib)
204  data = Data (secs, name = lib)
205  libs.append (data)
206  total += data
207  libs.sort (key = lambda x: x.total(), reverse=True)
208  kw = {'name' : 'Name',
209  'dso' : 'DSO',
210  'code' : 'Code',
211  'puredata': 'Pure',
212  'cpp' : 'C++',
213  'java' : 'Java',
214  'initdata': 'data',
215  'bss' : 'BSS',
216  'tbss' : 'TBSS',
217  'frag' : 'Frag',
218  'total': 'Total'}
219  print (format % kw, file=sys.stdout)
220  for l in libs:
221  l.dump (sys.stdout)
222  total.dump (sys.stdout)
223 
224  return 0
225 
226 
227 if __name__ == "__main__":
228  try:
229  sys.exit(main())
230  except KeyboardInterrupt:
231  sys.exit(1)
232 
dso-stats.Data.code
code
Definition: dso-stats.py:74
dso-stats.Data
Definition: dso-stats.py:70
dso-stats.Data.total
def total(self)
Definition: dso-stats.py:115
dso-stats.getoutput
def getoutput(cmd)
Definition: dso-stats.py:22
dso-stats.Data.__init__
def __init__(self, secs=None, name=None)
Definition: dso-stats.py:71
dso-stats.Data.est_frag
def est_frag(self)
Definition: dso-stats.py:107
CaloCellPos2Ntuple.int
int
Definition: CaloCellPos2Ntuple.py:24
dso-stats._form
def _form(x)
Definition: dso-stats.py:67
dso-stats.Data.initdata
initdata
Definition: dso-stats.py:78
dso-stats.Data.cpp
cpp
Definition: dso-stats.py:76
dso-stats.parse_lib
def parse_lib(lib)
Definition: dso-stats.py:43
dso-stats.Data.__iadd__
def __iadd__(self, other)
Definition: dso-stats.py:92
dso-stats._getpagesz
def _getpagesz()
Definition: dso-stats.py:30
dso-stats.Data.frag
frag
Definition: dso-stats.py:81
dso-stats.getstatus
def getstatus(cmd)
Definition: dso-stats.py:16
dso-stats.Data.dump
def dump(self, f)
Definition: dso-stats.py:175
dso-stats.Data.bss
bss
Definition: dso-stats.py:79
dso-stats.Data.add_secs
def add_secs(self, secs)
Definition: dso-stats.py:120
dso-stats.Data.java
java
Definition: dso-stats.py:77
dso-stats.Data.name
name
Definition: dso-stats.py:72
dso-stats.Data.puredata
puredata
Definition: dso-stats.py:75
dso-stats.Data.rw
rw
Definition: dso-stats.py:84
dso-stats._cleanname
def _cleanname(name)
Definition: dso-stats.py:57
dso-stats._frag
def _frag(sz)
Definition: dso-stats.py:53
dso-stats.main
def main()
Definition: dso-stats.py:190
dso-stats.Data.ro
ro
Definition: dso-stats.py:83
dso-stats.Data.dso
dso
Definition: dso-stats.py:73
dso-stats.Data.tbss
tbss
Definition: dso-stats.py:80