linux-yocto/scripts/bloat-o-meter
Nikolay Borisov 8b5db66798 scripts/bloat-o-meter: add -p argument
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>
2022-07-17 17:31:40 -07:00

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")