linux-yocto/scripts/bloat-o-meter
Geert Uytterhoeven 198430f7f7 scripts/bloat-o-meter: count weak symbol sizes
Currently, bloat-o-meter does not take into account weak symbols, and
thus ignores any size changes in code or data marked __weak.

Fix this by handling weak code ("w"/"W") and data ("v"/"V").

Link: https://lkml.kernel.org/r/a1e7abd2571c3bbfe75345d6ee98b276d2d5c39d.1692200010.git.geert+renesas@glider.be
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
Cc: Arnd Bergmann <arnd@arndb.de>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2023-08-21 13:46:25 -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(reverse=True)
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", "tTwW") print_result("Data", "dDbBvV") print_result("RO Data", "rR") elif args.d: print_result("Data", "dDbBrRvV") elif args.t: print_result("Function", "tTwW") else: print_result("Function", "tTdDbBrRvVwW")