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