| #!/usr/bin/env fuchsia-vendored-python |
| # Copyright 2020 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """ |
| Compares two or more elf_sizes.json files. |
| """ |
| |
| import argparse |
| import csv |
| import json |
| import os |
| import subprocess |
| import sys |
| |
| from tabulate import tabulate |
| |
| |
| FIELDS = [ |
| "blob", |
| "bss", |
| "code", |
| "data", |
| "file", |
| "memory", |
| "rel", |
| "rela", |
| "relcount", |
| "relr", |
| "relro", |
| "rodata", |
| "zbi", |
| ] |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser(description=__doc__) |
| parser.add_argument("--field", choices=FIELDS, default="code") |
| parser.add_argument("file", nargs="+", metavar="elf_sizes.json") |
| args = parser.parse_args() |
| |
| files = {} |
| totals = [] |
| |
| def load(f): |
| data = json.load(f) |
| assert set(data["totals"].keys()) == set(FIELDS) |
| for file in data["files"]: |
| build_id = file["build_id"] |
| if build_id: |
| files.setdefault(file["path"], []).append(file) |
| totals.append(data["totals"]) |
| |
| for file in args.file: |
| with open(file) as f: |
| load(f) |
| |
| table = [] |
| header = ["path", "baseline"] |
| for i, _ in enumerate(args.file[1:]): |
| header.extend(["%s %d" % (args.field, i + 1), "ratio %d" % (i + 1)]) |
| |
| def compute_row(name, data, field): |
| if not field in data[0]: |
| return [0] * len(data) |
| baseline = data[0][field] |
| row = [name, baseline] |
| for f in data[1:]: |
| row.extend([f[field], float(f[field]) / baseline if baseline else 0.0]) |
| return row |
| |
| for path in sorted(files.keys()): |
| file = files[path] |
| if len(file) < 2: |
| print("%s not present in every elf_sizes.json" % path, file=sys.stderr) |
| continue |
| if len(set([f["build_id"] for f in file])) == 1: |
| print("%s is unchanged" % path, file=sys.stderr) |
| continue |
| table.append(compute_row(path, file, args.field)) |
| |
| table.append(compute_row("TOTAL", totals, args.field)) |
| |
| print(tabulate(table, headers=header, floatfmt=".3f")) |
| |
| return 0 |
| |
| |
| if __name__ == "__main__": |
| sys.exit(main()) |