1#!/usr/bin/env python3
2# Copyright (c) 2021 Intel Corporation
3#
4# SPDX-License-Identifier: Apache-2.0
5
6# A script to diff between two ram or rom reports generated by
7# size_report. When you call call the ram_report or rom_report targets you
8# end up with a json file in the build directory that can be used as input
9# for this script.
10
11# The output shows which symbols increased and which decreased in size and
12# also tracked added/remove symbols as well.
13
14# Example:
15#    ./scripts/footprint/fpdiff.py ram1.json ram2.json
16
17from anytree.importer import DictImporter
18from anytree import PreOrderIter, AnyNode
19from anytree.search  import find
20
21import colorama
22from colorama import Fore
23import json
24import argparse
25
26importer = DictImporter()
27
28def parse_args():
29    parser = argparse.ArgumentParser(
30                description="Compare footprint sizes of two builds.", allow_abbrev=False)
31    parser.add_argument("file1", help="First file")
32    parser.add_argument("file2", help="Second file")
33
34    return parser.parse_args()
35
36def main():
37    colorama.init()
38
39    args = parse_args()
40
41    with open(args.file1, "r") as f:
42        data1 = json.load(f)
43
44    with open(args.file2, "r") as f:
45        data2 = json.load(f)
46
47    for idx, ch in enumerate(data1['symbols']['children']):
48        root1 = importer.import_(ch)
49        if idx >= len(data2['symbols']['children']):
50            root2 = AnyNode(identifier=None)
51        else:
52            root2 = importer.import_(data2['symbols']['children'][idx])
53        print(f"{root1.name}\n+++++++++++++++++++++")
54
55        for node in PreOrderIter(root1):
56            # pylint: disable=undefined-loop-variable
57            n = find(root2, lambda node2: node2.identifier == node.identifier)
58            if n:
59                if n.size != node.size:
60                    diff = n.size - node.size
61                    if diff == 0:
62                        continue
63                    if not n.children or not n.parent:
64                        if diff < 0:
65                            print(f"{n.identifier} -> {Fore.GREEN}{diff}{Fore.RESET}")
66                        else:
67                            print(f"{n.identifier} -> {Fore.RED}+{diff}{Fore.RESET}")
68
69            else:
70                if not node.children:
71                    print(f"{node.identifier} ({Fore.GREEN}-{node.size}{Fore.RESET}) disappeared.")
72
73        for node in PreOrderIter(root2):
74            n = find(root1, lambda node2: node2.identifier == node.identifier)
75            if not n:
76                if not node.children and node.size != 0:
77                    print(f"{node.identifier} ({Fore.RED}+{node.size}{Fore.RESET}) is new.")
78
79
80if __name__ == "__main__":
81    main()
82