162306a36Sopenharmony_ci#!/usr/bin/env python3
262306a36Sopenharmony_ci#
362306a36Sopenharmony_ci# Copyright 2004 Matt Mackall <mpm@selenic.com>
462306a36Sopenharmony_ci#
562306a36Sopenharmony_ci# inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen
662306a36Sopenharmony_ci#
762306a36Sopenharmony_ci# This software may be used and distributed according to the terms
862306a36Sopenharmony_ci# of the GNU General Public License, incorporated herein by reference.
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ciimport sys, os, re, argparse
1162306a36Sopenharmony_cifrom signal import signal, SIGPIPE, SIG_DFL
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cisignal(SIGPIPE, SIG_DFL)
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ciparser = argparse.ArgumentParser(description="Simple script used to compare the symbol sizes of 2 object files")
1662306a36Sopenharmony_cigroup = parser.add_mutually_exclusive_group()
1762306a36Sopenharmony_cigroup.add_argument('-c', help='categorize output based on symbol type', action='store_true')
1862306a36Sopenharmony_cigroup.add_argument('-d', help='Show delta of Data Section', action='store_true')
1962306a36Sopenharmony_cigroup.add_argument('-t', help='Show delta of text Section', action='store_true')
2062306a36Sopenharmony_ciparser.add_argument('-p', dest='prefix', help='Arch prefix for the tool being used. Useful in cross build scenarios')
2162306a36Sopenharmony_ciparser.add_argument('file1', help='First file to compare')
2262306a36Sopenharmony_ciparser.add_argument('file2', help='Second file to compare')
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ciargs = parser.parse_args()
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cire_NUMBER = re.compile(r'\.[0-9]+')
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cidef getsizes(file, format):
2962306a36Sopenharmony_ci    sym = {}
3062306a36Sopenharmony_ci    nm = "nm"
3162306a36Sopenharmony_ci    if args.prefix:
3262306a36Sopenharmony_ci        nm = "{}nm".format(args.prefix)
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci    with os.popen("{} --size-sort {}".format(nm, file)) as f:
3562306a36Sopenharmony_ci        for line in f:
3662306a36Sopenharmony_ci            if line.startswith("\n") or ":" in line:
3762306a36Sopenharmony_ci                continue
3862306a36Sopenharmony_ci            size, type, name = line.split()
3962306a36Sopenharmony_ci            if type in format:
4062306a36Sopenharmony_ci                # strip generated symbols
4162306a36Sopenharmony_ci                if name.startswith("__mod_"): continue
4262306a36Sopenharmony_ci                if name.startswith("__se_sys"): continue
4362306a36Sopenharmony_ci                if name.startswith("__se_compat_sys"): continue
4462306a36Sopenharmony_ci                if name.startswith("__addressable_"): continue
4562306a36Sopenharmony_ci                if name == "linux_banner": continue
4662306a36Sopenharmony_ci                if name == "vermagic": continue
4762306a36Sopenharmony_ci                # statics and some other optimizations adds random .NUMBER
4862306a36Sopenharmony_ci                name = re_NUMBER.sub('', name)
4962306a36Sopenharmony_ci                sym[name] = sym.get(name, 0) + int(size, 16)
5062306a36Sopenharmony_ci    return sym
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cidef calc(oldfile, newfile, format):
5362306a36Sopenharmony_ci    old = getsizes(oldfile, format)
5462306a36Sopenharmony_ci    new = getsizes(newfile, format)
5562306a36Sopenharmony_ci    grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0
5662306a36Sopenharmony_ci    delta, common = [], {}
5762306a36Sopenharmony_ci    otot, ntot = 0, 0
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci    for a in old:
6062306a36Sopenharmony_ci        if a in new:
6162306a36Sopenharmony_ci            common[a] = 1
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci    for name in old:
6462306a36Sopenharmony_ci        otot += old[name]
6562306a36Sopenharmony_ci        if name not in common:
6662306a36Sopenharmony_ci            remove += 1
6762306a36Sopenharmony_ci            down += old[name]
6862306a36Sopenharmony_ci            delta.append((-old[name], name))
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci    for name in new:
7162306a36Sopenharmony_ci        ntot += new[name]
7262306a36Sopenharmony_ci        if name not in common:
7362306a36Sopenharmony_ci            add += 1
7462306a36Sopenharmony_ci            up += new[name]
7562306a36Sopenharmony_ci            delta.append((new[name], name))
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci    for name in common:
7862306a36Sopenharmony_ci        d = new.get(name, 0) - old.get(name, 0)
7962306a36Sopenharmony_ci        if d>0: grow, up = grow+1, up+d
8062306a36Sopenharmony_ci        if d<0: shrink, down = shrink+1, down-d
8162306a36Sopenharmony_ci        delta.append((d, name))
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci    delta.sort(reverse=True)
8462306a36Sopenharmony_ci    return grow, shrink, add, remove, up, down, delta, old, new, otot, ntot
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cidef print_result(symboltype, symbolformat):
8762306a36Sopenharmony_ci    grow, shrink, add, remove, up, down, delta, old, new, otot, ntot = \
8862306a36Sopenharmony_ci    calc(args.file1, args.file2, symbolformat)
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci    print("add/remove: %s/%s grow/shrink: %s/%s up/down: %s/%s (%s)" % \
9162306a36Sopenharmony_ci          (add, remove, grow, shrink, up, -down, up-down))
9262306a36Sopenharmony_ci    print("%-40s %7s %7s %+7s" % (symboltype, "old", "new", "delta"))
9362306a36Sopenharmony_ci    for d, n in delta:
9462306a36Sopenharmony_ci        if d: print("%-40s %7s %7s %+7d" % (n, old.get(n,"-"), new.get(n,"-"), d))
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci    if otot:
9762306a36Sopenharmony_ci        percent = (ntot - otot) * 100.0 / otot
9862306a36Sopenharmony_ci    else:
9962306a36Sopenharmony_ci        percent = 0
10062306a36Sopenharmony_ci    print("Total: Before=%d, After=%d, chg %+.2f%%" % (otot, ntot, percent))
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ciif args.c:
10362306a36Sopenharmony_ci    print_result("Function", "tTwW")
10462306a36Sopenharmony_ci    print_result("Data", "dDbBvV")
10562306a36Sopenharmony_ci    print_result("RO Data", "rR")
10662306a36Sopenharmony_cielif args.d:
10762306a36Sopenharmony_ci    print_result("Data", "dDbBrRvV")
10862306a36Sopenharmony_cielif args.t:
10962306a36Sopenharmony_ci    print_result("Function", "tTwW")
11062306a36Sopenharmony_cielse:
11162306a36Sopenharmony_ci    print_result("Function", "tTdDbBrRvVwW")
112