diff options
-rwxr-xr-x | scripts/bloat-o-meter | 72 |
1 files changed, 46 insertions, 26 deletions
diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter index eb6fb87d5..aa126969c 100755 --- a/scripts/bloat-o-meter +++ b/scripts/bloat-o-meter | |||
@@ -21,51 +21,68 @@ for f in sys.argv[1:3]: | |||
21 | sys.stderr.write("Error: file '%s' does not exist\n" % f) | 21 | sys.stderr.write("Error: file '%s' does not exist\n" % f) |
22 | usage() | 22 | usage() |
23 | 23 | ||
24 | nm_args = " ".join(sys.argv[3:]) | 24 | sym_args = " ".join(sys.argv[3:]) |
25 | def getsizes(file): | 25 | def getsizes(file): |
26 | sym = {} | 26 | sym, alias = {}, {} |
27 | for l in os.popen("nm --size-sort %s %s" % (nm_args, file)).readlines(): | 27 | dynsym_filter = re.compile("^\s+\d+:\s+[\dA-Fa-f]+\s+\d+\s+\w+\s+\w+\s+\w+\s+\w+\s+\w+\n$") |
28 | l = l.strip() | 28 | for l in os.popen("readelf -W -s %s %s" % (sym_args, file)).readlines(): |
29 | # Skip empty lines | 29 | if not dynsym_filter.match(l): continue |
30 | if not len(l): continue | 30 | num, value, size, typ, bind, vis, ndx, name = l.strip().split() |
31 | # Skip archive members | 31 | if ndx == "UND": continue # skip undefined |
32 | if len(l.split()) == 1 and l.endswith(':'): | 32 | if typ in ["SECTION", "FILES"]: continue # skip sections and files |
33 | continue | 33 | if "." in name: name = "static." + name.split(".")[0] |
34 | size, type, name = l.split() | 34 | value = int(value, 16) |
35 | if type in "tTdDbBrR": | 35 | size = int(size) |
36 | if "." in name: name = "static." + name.split(".")[0] | 36 | if bind != "GLOBAL": # see if it is an alias |
37 | sym[name] = sym.get(name, 0) + int(size, 16) | 37 | alias[name] = {"addr" : value, "size": size} |
38 | for l in os.popen("readelf -S " + file).readlines(): | 38 | else: |
39 | sym[name] = {"addr" : value, "size": size} | ||
40 | for a_nam, a_dat in alias.iteritems(): | ||
41 | impl = [k for k, v in sym.iteritems() if v.get("addr") == a_dat["addr"]] | ||
42 | # If the non-GLOBAL sym has an implementation elsewhere then | ||
43 | # it's an alias, disregard it. | ||
44 | if not impl: | ||
45 | # If this non-GLOBAL sym does not have an implementation at | ||
46 | # another address, then treat it as a normal symbol. | ||
47 | sym[a_nam] = a_dat | ||
48 | for l in os.popen("readelf -W -S " + file).readlines(): | ||
39 | x = l.split() | 49 | x = l.split() |
40 | if len(x)<6 or x[1] != ".rodata": continue | 50 | if len(x)<6: continue |
41 | sym[".rodata"] = int(x[5], 16) | 51 | # Should take these into account too! |
52 | #if x[1] not in [".text", ".rodata", ".symtab", ".strtab"]: continue | ||
53 | if x[1] not in [".rodata"]: continue | ||
54 | sym[x[1]] = {"addr" : int(x[3], 16), "size" : int(x[5], 16)} | ||
42 | return sym | 55 | return sym |
43 | 56 | ||
44 | old = getsizes(sys.argv[1]) | 57 | old = getsizes(sys.argv[1]) |
45 | new = getsizes(sys.argv[2]) | 58 | new = getsizes(sys.argv[2]) |
46 | grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0 | 59 | grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0 |
47 | delta, common = [], {} | 60 | delta, common = [], [] |
48 | 61 | ||
49 | for a in old: | 62 | for a in old.iterkeys(): |
50 | if a in new: | 63 | if a in new: |
51 | common[a] = 1 | 64 | common.append(a) |
52 | 65 | ||
53 | for name in old: | 66 | for name in old: |
54 | if name not in common: | 67 | if name not in common: |
55 | remove += 1 | 68 | remove += 1 |
56 | down += old[name] | 69 | sz = old[name].get("size", 0) |
57 | delta.append((-old[name], name)) | 70 | down += sz |
71 | delta.append((-sz, name)) | ||
58 | 72 | ||
59 | for name in new: | 73 | for name in new: |
60 | if name not in common: | 74 | if name not in common: |
61 | add += 1 | 75 | add += 1 |
62 | up += new[name] | 76 | sz = new[name].get("size", 0) |
63 | delta.append((new[name], name)) | 77 | up += sz |
78 | delta.append((sz, name)) | ||
64 | 79 | ||
65 | for name in common: | 80 | for name in common: |
66 | d = new.get(name, 0) - old.get(name, 0) | 81 | d = new[name].get("size", 0) - old[name].get("size", 0) |
67 | if d>0: grow, up = grow+1, up+d | 82 | if d>0: grow, up = grow+1, up+d |
68 | if d<0: shrink, down = shrink+1, down-d | 83 | elif d<0: shrink, down = shrink+1, down-d |
84 | else: | ||
85 | continue | ||
69 | delta.append((d, name)) | 86 | delta.append((d, name)) |
70 | 87 | ||
71 | delta.sort() | 88 | delta.sort() |
@@ -73,7 +90,10 @@ delta.reverse() | |||
73 | 90 | ||
74 | print "%-48s %7s %7s %+7s" % ("function", "old", "new", "delta") | 91 | print "%-48s %7s %7s %+7s" % ("function", "old", "new", "delta") |
75 | for d, n in delta: | 92 | for d, n in delta: |
76 | if d: print "%-48s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d) | 93 | if d: |
94 | old_sz = old.get(n, {}).get("size", "-") | ||
95 | new_sz = new.get(n, {}).get("size", "-") | ||
96 | print "%-48s %7s %7s %+7d" % (n, old_sz, new_sz, d) | ||
77 | print "-"*78 | 97 | print "-"*78 |
78 | total="(add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s)%%sTotal: %s bytes"\ | 98 | total="(add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s)%%sTotal: %s bytes"\ |
79 | % (add, remove, grow, shrink, up, -down, up-down) | 99 | % (add, remove, grow, shrink, up, -down, up-down) |