
When doing cross platform development on a machine sometimes it might be useful to invoke bloat-o-meter for files which haven't been build with the native toolchain. In cases when the host nm doesn't support the target one then a toolchain-specific nm could be used. Add this ability by adding the -p allowing invocations as: ./scripts/bloat-o-meter -p riscv64-unknown-linux-gnu- file1.o file2.o Link: https://lkml.kernel.org/r/20220701113513.1938008-2-nborisov@suse.com Signed-off-by: Nikolay Borisov <nborisov@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
3.8 KiB
Executable File
#!/usr/bin/env python3
Copyright 2004 Matt Mackall mpm@selenic.com
inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
import sys, os, re, argparse from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE, SIG_DFL)
parser = argparse.ArgumentParser(description="Simple script used to compare the symbol sizes of 2 object files") group = parser.add_mutually_exclusive_group() group.add_argument('-c', help='categorize output based on symbol type', action='store_true') group.add_argument('-d', help='Show delta of Data Section', action='store_true') group.add_argument('-t', help='Show delta of text Section', action='store_true') parser.add_argument('-p', dest='prefix', help='Arch prefix for the tool being used. Useful in cross build scenarios') parser.add_argument('file1', help='First file to compare') parser.add_argument('file2', help='Second file to compare')
args = parser.parse_args()
re_NUMBER = re.compile(r'.[0-9]+')
def getsizes(file, format): sym = {} nm = "nm" if args.prefix: nm = "{}nm".format(args.prefix)
with os.popen("{} --size-sort {}".format(nm, file)) as f:
for line in f:
if line.startswith("\n") or ":" in line:
continue
size, type, name = line.split()
if type in format:
# strip generated symbols
if name.startswith("__mod_"): continue
if name.startswith("__se_sys"): continue
if name.startswith("__se_compat_sys"): continue
if name.startswith("__addressable_"): continue
if name == "linux_banner": continue
if name == "vermagic": continue
# statics and some other optimizations adds random .NUMBER
name = re_NUMBER.sub('', name)
sym[name] = sym.get(name, 0) + int(size, 16)
return sym
def calc(oldfile, newfile, format): old = getsizes(oldfile, format) new = getsizes(newfile, format) grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0 delta, common = [], {} otot, ntot = 0, 0
for a in old:
if a in new:
common[a] = 1
for name in old:
otot += old[name]
if name not in common:
remove += 1
down += old[name]
delta.append((-old[name], name))
for name in new:
ntot += new[name]
if name not in common:
add += 1
up += new[name]
delta.append((new[name], name))
for name in common:
d = new.get(name, 0) - old.get(name, 0)
if d>0: grow, up = grow+1, up+d
if d<0: shrink, down = shrink+1, down-d
delta.append((d, name))
delta.sort()
delta.reverse()
return grow, shrink, add, remove, up, down, delta, old, new, otot, ntot
def print_result(symboltype, symbolformat):
grow, shrink, add, remove, up, down, delta, old, new, otot, ntot =
calc(args.file1, args.file2, symbolformat)
print("add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \
(add, remove, grow, shrink, up, -down, up-down))
print("%-40s %7s %7s %+7s" % (symboltype, "old", "new", "delta"))
for d, n in delta:
if d: print("%-40s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d))
if otot:
percent = (ntot - otot) * 100.0 / otot
else:
percent = 0
print("Total: Before=%d, After=%d, chg %+.2f%%" % (otot, ntot, percent))
if args.c: print_result("Function", "tT") print_result("Data", "dDbB") print_result("RO Data", "rR") elif args.d: print_result("Data", "dDbBrR") elif args.t: print_result("Function", "tT") else: print_result("Function", "tTdDbBrR")