3 # Copyright 2004 Matt Mackall <mpm@selenic.com>
5 # Inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen
7 # This software may be used and distributed according to the terms
8 # of the GNU General Public License, incorporated herein by reference.
13 sys
.stderr
.write("usage: %s [-t] file1 file2\n" % sys
.argv
[0])
17 flag_timing
, dashes
= (False, False)
19 for f
in sys
.argv
[1:]:
21 if f
== "--": # sym_args
24 if f
== "-t": # timings
27 if not os
.path
.exists(f
):
28 sys
.stderr
.write("Error: file '%s' does not exist\n" % f
)
36 if f1
is None or f2
is None:
39 sym_args
= " ".join(sys
.argv
[3 + flag_timing
+ dashes
:])
41 sym
, alias
, lut
= {}, {}, {}
42 for l
in os
.popen("readelf -W -s %s %s" % (sym_args
, file)).readlines():
44 if not (len(l
) and l
[0].isdigit() and len(l
.split()) == 8):
46 num
, value
, size
, typ
, bind
, vis
, ndx
, name
= l
.split()
47 if ndx
== "UND": continue # skip undefined
48 if typ
in ["SECTION", "FILES"]: continue # skip sections and files
49 if "." in name
: name
= "static." + name
.split(".")[0]
50 value
= int(value
, 16)
51 size
= int(size
, 16) if size
.startswith('0x') else int(size
)
52 if vis
!= "DEFAULT" and bind
!= "GLOBAL": # see if it is an alias
53 alias
[(value
, size
)] = {"name" : name
}
55 sym
[name
] = {"addr" : value
, "size": size
}
56 lut
[(value
, size
)] = 0
57 for addr
, sz
in iter(alias
.keys()):
58 # If the non-GLOBAL sym has an implementation elsewhere then
59 # it's an alias, disregard it.
60 if not (addr
, sz
) in lut
:
61 # If this non-GLOBAL sym does not have an implementation at
62 # another address, then treat it as a normal symbol.
63 sym
[alias
[(addr
, sz
)]["name"]] = {"addr" : addr
, "size": sz
}
64 for l
in os
.popen("readelf -W -S " + file).readlines():
67 # Should take these into account too!
68 #if x[1] not in [".text", ".rodata", ".symtab", ".strtab"]: continue
69 if x
[1] not in [".rodata"]: continue
70 sym
[x
[1]] = {"addr" : int(x
[3], 16), "size" : int(x
[5], 16)}
74 start_t1
= int(time
.time() * 1e9
)
77 end_t1
= int(time
.time() * 1e9
)
78 start_t2
= int(time
.time() * 1e9
)
81 end_t2
= int(time
.time() * 1e9
)
82 start_t3
= int(time
.time() * 1e9
)
83 grow
, shrink
, add
, remove
, up
, down
= 0, 0, 0, 0, 0, 0
84 delta
, common
= [], {}
86 for name
in iter(old
.keys()):
91 if name
not in common
:
93 sz
= old
[name
]["size"]
95 delta
.append((-sz
, name
))
98 if name
not in common
:
100 sz
= new
[name
]["size"]
102 delta
.append((sz
, name
))
105 d
= new
[name
].get("size", 0) - old
[name
].get("size", 0)
106 if d
>0: grow
, up
= grow
+1, up
+d
107 elif d
<0: shrink
, down
= shrink
+1, down
-d
110 delta
.append((d
, name
))
115 end_t3
= int(time
.time() * 1e9
)
117 print("%-48s %7s %7s %+7s" % ("function", "old", "new", "delta"))
120 old_sz
= old
.get(n
, {}).get("size", "-")
121 new_sz
= new
.get(n
, {}).get("size", "-")
122 print("%-48s %7s %7s %+7d" % (n
, old_sz
, new_sz
, d
))
124 total
="(add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s)%%sTotal: %s bytes"\
125 % (add
, remove
, grow
, shrink
, up
, -down
, up
-down
)
126 print(total
% (" "*(80-len(total
))))
128 print("\n%d/%d; %d Parse origin/new; processing nsecs" %
129 (end_t1
-start_t1
, end_t2
-start_t2
, end_t3
-start_t3
))
130 print("total nsecs: %d" % (end_t3
-start_t1
))