aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2023-04-04 17:02:01 +0100
committerPeter Maydell <peter.maydell@linaro.org>2023-04-04 17:02:01 +0100
commit8a712df4d4d736b7fe6441626677bfd271d95b15 (patch)
treecfffe53ccb3c6a5365f32d23abae8c3fc26b3587 /scripts
parent992473749f7cf127e71bb8263c02577cca303055 (diff)
parentc8cb603293fd329f2a62ade76ec9de3f462fc5c3 (diff)
downloadqemu-8a712df4d4d736b7fe6441626677bfd271d95b15.zip
qemu-8a712df4d4d736b7fe6441626677bfd271d95b15.tar.gz
qemu-8a712df4d4d736b7fe6441626677bfd271d95b15.tar.bz2
Merge tag 'pull-for-8.0-040423-2' of https://gitlab.com/stsquad/qemu into staging
Final test and misc fixes: - add basic coverage analysis script - gdbstub only build one of libgdb_user/softmmu - don't break BSD gdb by advertising AUXV feature - add MAINTAINERS section for policy docs - update hexagon toolchain - explicitly invoke iotests with python for BSDs benefit - use system python on NetBSD - add some tests for the new KVM Xen guest support # -----BEGIN PGP SIGNATURE----- # # iQEzBAABCgAdFiEEZoWumedRZ7yvyN81+9DbCVqeKkQFAmQsOscACgkQ+9DbCVqe # KkSm6Af/X+vvzdlmXgGt3uw2odqV6KMfXEkds5lHZIIqQhsLvV0mrkTcIKTswWhL # JRC7jiPmn5hfwvgDy5WfcczGzELSqfBgqHsm9zqVcboTGgJfr2eMtoUlMCQi6lFR # InomhTb+VzPxuUx82oryufm7bsopG8C+HVr3ZtHNFI3usIrLlscZstkiYMueGUCb # PJ60mykfd7hegaTgwKNbUXqZ+Oy/u4W7UPWBkrR7xJzW623t7S5EWV2ZNbdJgKO6 # utY3VGikir/OcnNKy7NuXp2t3K+5KALFZW3Jbav8hVLy5biMGYUF8886B0FL2m+n # E44J67crEYNJMamtzYJ+FdkGEMrS5Q== # =yCka # -----END PGP SIGNATURE----- # gpg: Signature made Tue 04 Apr 2023 15:57:11 BST # gpg: using RSA key 6685AE99E75167BCAFC8DF35FBD0DB095A9E2A44 # gpg: Good signature from "Alex Bennée (Master Work Key) <alex.bennee@linaro.org>" [full] # Primary key fingerprint: 6685 AE99 E751 67BC AFC8 DF35 FBD0 DB09 5A9E 2A44 * tag 'pull-for-8.0-040423-2' of https://gitlab.com/stsquad/qemu: tests/avocado: Test Xen guest support under KVM gitlab: fix typo tests/vm: use the default system python for NetBSD tests/qemu-iotests: explicitly invoke 'check' via 'python' Use hexagon toolchain version 16.0.0 metadata: add .git-blame-ignore-revs MAINTAINERS: add a section for policy documents gdbstub: don't report auxv feature unless on Linux gdbstub: Only build libgdb_user.fa / libgdb_softmmu.fa if necessary scripts/coverage: initial coverage comparison script Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/coverage/compare_gcov_json.py119
1 files changed, 119 insertions, 0 deletions
diff --git a/scripts/coverage/compare_gcov_json.py b/scripts/coverage/compare_gcov_json.py
new file mode 100755
index 0000000..1b92dc2
--- /dev/null
+++ b/scripts/coverage/compare_gcov_json.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python3
+#
+# Compare output of two gcovr JSON reports and report differences. To
+# generate the required output first:
+# - create two build dirs with --enable-gcov
+# - run set of tests in each
+# - run make coverage-html in each
+# - run gcovr --json --exclude-unreachable-branches \
+# --print-summary -o coverage.json --root ../../ . *.p
+#
+# Author: Alex Bennée <alex.bennee@linaro.org>
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+
+import argparse
+import json
+import sys
+from pathlib import Path
+
+def create_parser():
+ parser = argparse.ArgumentParser(
+ prog='compare_gcov_json',
+ description='analyse the differences in coverage between two runs')
+
+ parser.add_argument('-a', type=Path, default=None,
+ help=('First file to check'))
+
+ parser.add_argument('-b', type=Path, default=None,
+ help=('Second file to check'))
+
+ parser.add_argument('--verbose', action='store_true', default=False,
+ help=('A minimal verbosity level that prints the '
+ 'overall result of the check/wait'))
+ return parser
+
+
+# See https://gcovr.com/en/stable/output/json.html#json-format-reference
+def load_json(json_file_path: Path, verbose = False) -> dict[str, set[int]]:
+
+ with open(json_file_path) as f:
+ data = json.load(f)
+
+ root_dir = json_file_path.absolute().parent
+ covered_lines = dict()
+
+ for filecov in data["files"]:
+ file_path = Path(filecov["file"])
+
+ # account for generated files - map into src tree
+ resolved_path = Path(file_path).absolute()
+ if resolved_path.is_relative_to(root_dir):
+ file_path = resolved_path.relative_to(root_dir)
+ # print(f"remapped {resolved_path} to {file_path}")
+
+ lines = filecov["lines"]
+
+ executed_lines = set(
+ linecov["line_number"]
+ for linecov in filecov["lines"]
+ if linecov["count"] != 0 and not linecov["gcovr/noncode"]
+ )
+
+ # if this file has any coverage add it to the system
+ if len(executed_lines) > 0:
+ if verbose:
+ print(f"file {file_path} {len(executed_lines)}/{len(lines)}")
+ covered_lines[str(file_path)] = executed_lines
+
+ return covered_lines
+
+def find_missing_files(first, second):
+ """
+ Return a list of files not covered in the second set
+ """
+ missing_files = []
+ for f in sorted(first):
+ file_a = first[f]
+ try:
+ file_b = second[f]
+ except KeyError:
+ missing_files.append(f)
+
+ return missing_files
+
+def main():
+ """
+ Script entry point
+ """
+ parser = create_parser()
+ args = parser.parse_args()
+
+ if not args.a or not args.b:
+ print("We need two files to compare")
+ sys.exit(1)
+
+ first_coverage = load_json(args.a, args.verbose)
+ second_coverage = load_json(args.b, args.verbose)
+
+ first_missing = find_missing_files(first_coverage,
+ second_coverage)
+
+ second_missing = find_missing_files(second_coverage,
+ first_coverage)
+
+ a_name = args.a.parent.name
+ b_name = args.b.parent.name
+
+ print(f"{b_name} missing coverage in {len(first_missing)} files")
+ for f in first_missing:
+ print(f" {f}")
+
+ print(f"{a_name} missing coverage in {len(second_missing)} files")
+ for f in second_missing:
+ print(f" {f}")
+
+
+if __name__ == '__main__':
+ main()