poky/scripts/buildstats-summary
Ross Burton 9dd8d5d6d2 buildstats-summary: look for buildstats if not specified
If the user hasn't specified a buildstats directory, use the latest
entry under $BUILDDIR.

(From OE-Core rev: aeb69fbe130dca37b39d4065ec983441e0052803)

Signed-off-by: Ross Burton <ross.burton@arm.com>
Signed-off-by: Mathieu Dubois-Briand <mathieu.dubois-briand@bootlin.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
2024-10-25 15:25:32 +01:00

3.5 KiB
Executable File

#!/usr/bin/env python3

Dump a summary of the specified buildstats to the terminal, filtering and

sorting by walltime.

SPDX-License-Identifier: GPL-2.0-only

import argparse import dataclasses import datetime import enum import os import pathlib import sys

scripts_path = os.path.dirname(os.path.realpath(file)) sys.path.append(os.path.join(scripts_path, "lib")) import buildstats

@dataclasses.dataclass class Task: recipe: str task: str start: datetime.datetime duration: datetime.timedelta

class Sorting(enum.Enum): start = 1 duration = 2

# argparse integration
def __str__(self) -> str:
    return self.name

def __repr__(self) -> str:
    return self.name

@staticmethod
def from_string(s: str):
    try:
        return Sorting[s]
    except KeyError:
        return s

def read_buildstats(path: pathlib.Path) -> buildstats.BuildStats: if not path.exists(): raise Exception(f"No such file or directory: {path}") if path.is_file(): return buildstats.BuildStats.from_file_json(path) if (path / "build_stats").is_file(): return buildstats.BuildStats.from_dir(path) raise Exception(f"Cannot find buildstats in {path}")

def dump_buildstats(args, bs: buildstats.BuildStats): tasks = [] for recipe in bs.values(): for task, stats in recipe.tasks.items(): t = Task( recipe.name, task, datetime.datetime.fromtimestamp(stats["start_time"]), datetime.timedelta(seconds=int(stats.walltime)), ) tasks.append(t)

tasks.sort(key=lambda t: getattr(t, args.sort.name))

minimum = datetime.timedelta(seconds=args.shortest)
highlight = datetime.timedelta(seconds=args.highlight)

for t in tasks:
    if t.duration >= minimum:
        line = f"{t.duration}    {t.recipe}:{t.task}"
        if args.highlight and t.duration >= highlight:
            print(f"\033[1m{line}\033[0m")
        else:
            print(line)

def main(argv=None) -> int: parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter )

parser.add_argument(
    "buildstats",
    metavar="BUILDSTATS",
    nargs="?",
    type=pathlib.Path,
    help="Buildstats file, or latest if not specified",
)
parser.add_argument(
    "--sort",
    "-s",
    type=Sorting.from_string,
    choices=list(Sorting),
    default=Sorting.start,
    help="Sort tasks",
)
parser.add_argument(
    "--shortest",
    "-t",
    type=int,
    default=1,
    metavar="SECS",
    help="Hide tasks shorter than SECS seconds",
)
parser.add_argument(
    "--highlight",
    "-g",
    type=int,
    default=60,
    metavar="SECS",
    help="Highlight tasks longer than SECS seconds (0 disabled)",
)

args = parser.parse_args(argv)

# If a buildstats file wasn't specified, try to find the last one
if not args.buildstats:
    try:
        builddir = pathlib.Path(os.environ["BUILDDIR"])
        buildstats_dir = builddir / "tmp" / "buildstats"
        args.buildstats = sorted(buildstats_dir.iterdir())[-1]
    except KeyError:
        print("Build environment has not been configured, cannot find buildstats")
        return 1

bs = read_buildstats(args.buildstats)
dump_buildstats(args, bs)

return 0

if name == "main": sys.exit(main())