xref: /openbmc/qemu/.gitlab-ci.d/check-units.py (revision 6d1829fce4ea50d343f2df63eeff96685a359bf5)
1*3df360cbSAlex Bennée#!/usr/bin/env python3
2*3df360cbSAlex Bennée#
3*3df360cbSAlex Bennée# check-units.py: check the number of compilation units and identify
4*3df360cbSAlex Bennée#                 those that are rebuilt multiple times
5*3df360cbSAlex Bennée#
6*3df360cbSAlex Bennée# Copyright (C) 2025 Linaro Ltd.
7*3df360cbSAlex Bennée#
8*3df360cbSAlex Bennée# SPDX-License-Identifier: GPL-2.0-or-later
9*3df360cbSAlex Bennée
10*3df360cbSAlex Bennéefrom os import access, R_OK, path
11*3df360cbSAlex Bennéefrom sys import argv, exit
12*3df360cbSAlex Bennéeimport json
13*3df360cbSAlex Bennéefrom collections import Counter
14*3df360cbSAlex Bennée
15*3df360cbSAlex Bennée
16*3df360cbSAlex Bennéedef extract_build_units(cc_path):
17*3df360cbSAlex Bennée    """
18*3df360cbSAlex Bennée    Extract the build units and their counds from compile_commands.json file.
19*3df360cbSAlex Bennée
20*3df360cbSAlex Bennée    Returns:
21*3df360cbSAlex Bennée        Hash table of ["unit"] = count
22*3df360cbSAlex Bennée    """
23*3df360cbSAlex Bennée
24*3df360cbSAlex Bennée    j = json.load(open(cc_path, 'r'))
25*3df360cbSAlex Bennée    files = [f['file'] for f in j]
26*3df360cbSAlex Bennée    build_units = Counter(files)
27*3df360cbSAlex Bennée
28*3df360cbSAlex Bennée    return build_units
29*3df360cbSAlex Bennée
30*3df360cbSAlex Bennée
31*3df360cbSAlex Bennéedef analyse_units(build_units):
32*3df360cbSAlex Bennée    """
33*3df360cbSAlex Bennée    Analyse the build units and report stats and the top 10 rebuilds
34*3df360cbSAlex Bennée    """
35*3df360cbSAlex Bennée
36*3df360cbSAlex Bennée    print(f"Total source files: {len(build_units.keys())}")
37*3df360cbSAlex Bennée    print(f"Total build units: {sum(units.values())}")
38*3df360cbSAlex Bennée
39*3df360cbSAlex Bennée    # Create a sorted list by number of rebuilds
40*3df360cbSAlex Bennée    sorted_build_units = sorted(build_units.items(),
41*3df360cbSAlex Bennée                                key=lambda item: item[1],
42*3df360cbSAlex Bennée                                reverse=True)
43*3df360cbSAlex Bennée
44*3df360cbSAlex Bennée    print("Most rebuilt units:")
45*3df360cbSAlex Bennée    for unit, count in sorted_build_units[:20]:
46*3df360cbSAlex Bennée        print(f"  {unit} built {count} times")
47*3df360cbSAlex Bennée
48*3df360cbSAlex Bennée    print("Least rebuilt units:")
49*3df360cbSAlex Bennée    for unit, count in sorted_build_units[-10:]:
50*3df360cbSAlex Bennée        print(f"  {unit} built {count} times")
51*3df360cbSAlex Bennée
52*3df360cbSAlex Bennée
53*3df360cbSAlex Bennéeif __name__ == "__main__":
54*3df360cbSAlex Bennée    if len(argv) != 2:
55*3df360cbSAlex Bennée        script_name = path.basename(argv[0])
56*3df360cbSAlex Bennée        print(f"Usage: {script_name} <path_to_compile_commands.json>")
57*3df360cbSAlex Bennée        exit(1)
58*3df360cbSAlex Bennée
59*3df360cbSAlex Bennée    cc_path = argv[1]
60*3df360cbSAlex Bennée    if path.isfile(cc_path) and access(cc_path, R_OK):
61*3df360cbSAlex Bennée        units = extract_build_units(cc_path)
62*3df360cbSAlex Bennée        analyse_units(units)
63*3df360cbSAlex Bennée        exit(0)
64*3df360cbSAlex Bennée    else:
65*3df360cbSAlex Bennée        print(f"{cc_path} doesn't exist or isn't readable")
66*3df360cbSAlex Bennée        exit(1)
67