diff mbox series

[RFC] gitlab: add new dynamic check-gcov target for coverage

Message ID 20221114134954.1670860-1-alex.bennee@linaro.org
State New
Headers show
Series [RFC] gitlab: add new dynamic check-gcov target for coverage | expand

Commit Message

Alex Bennée Nov. 14, 2022, 1:49 p.m. UTC
The aim of this was to expand the coverage checking to only target
builds affected by the current branch. Unfortunately first time out
the build falls over at the asset uploading stage exceeding some size
limit.

So for now I'm posting this as a proof-of-concept until I can figure
out a better way forward. The highlighting of which changes are tested
in the GitLab UI is quite nice though.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
---
 .gitlab-ci.d/buildtest.yml   | 24 ++++++++--
 .gitlab-ci.d/pick-targets.py | 87 ++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+), 4 deletions(-)
 create mode 100755 .gitlab-ci.d/pick-targets.py
diff mbox series

Patch

diff --git a/.gitlab-ci.d/buildtest.yml b/.gitlab-ci.d/buildtest.yml
index d21b4a1fd4..aa2c52ab11 100644
--- a/.gitlab-ci.d/buildtest.yml
+++ b/.gitlab-ci.d/buildtest.yml
@@ -479,20 +479,36 @@  build-gprof-gcov:
   variables:
     IMAGE: ubuntu2004
     CONFIGURE_ARGS: --enable-gprof --enable-gcov
-    TARGETS: aarch64-softmmu ppc64-softmmu s390x-softmmu x86_64-softmmu
+    TARGETS: aarch64-softmmu ppc64-linux-user
   artifacts:
     expire_in: 1 days
     paths:
       - build
 
-check-gprof-gcov:
+# This is special as the target list is dynamic
+build-gcov:
+  extends: .native_build_job_template
+  needs:
+    job: amd64-ubuntu2004-container
+  before_script:
+    - TARGETS=$(.gitlab-ci.d/pick-targets.py)
+  variables:
+    IMAGE: ubuntu2004
+    CONFIGURE_ARGS: --enable-gcov
+  artifacts:
+    expire_in: 1 days
+    paths:
+      - build
+      
+# This is special
+check-gcov:
   extends: .native_test_job_template
   needs:
-    - job: build-gprof-gcov
+    - job: build-gcov
       artifacts: true
   variables:
     IMAGE: ubuntu2004
-    MAKE_CHECK_ARGS: check
+    MAKE_CHECK_ARGS: check check-avocado
   after_script:
     - cd build
     - gcovr --xml-pretty --exclude-unreachable-branches --print-summary
diff --git a/.gitlab-ci.d/pick-targets.py b/.gitlab-ci.d/pick-targets.py
new file mode 100755
index 0000000000..db1eff0119
--- /dev/null
+++ b/.gitlab-ci.d/pick-targets.py
@@ -0,0 +1,87 @@ 
+#!/usr/bin/env python3
+#
+# pick-targets: pick a set of targets that are worth testing.
+#
+# Running code coverage is too expensive to run over all the builds.
+# Try and figure out a subset of targets that would be worth running
+# for the files touched between origin/master and the current HEAD.
+#
+# Copyright (C) 2022 Linaro Ltd
+#
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import os
+import os.path
+import sys
+import subprocess
+
+# Dumb mapping from a target directory name to a list of
+# targets. Should we bother for those we know we don't have compilers for?
+multi_targets = {
+    'arm'        : ['arm', 'aarch64'],
+    'i386'       : ['i386', 'x86_64'],
+    'microblaze' : ['microblaze' ], # no softmmu, 'microblazel' ],
+    'mips'       : ['mips', 'mips64', 'mips64el', 'mipsel' ],
+    'ppc'        : ['ppc', 'ppc64' ],
+    'riscv'      : ['riscv32', 'riscv64'],
+    'sh4'        : ['sh4', 'sh4eb'],
+    'sparc'      : ['sparc', 'sparc64'],
+    'xtensa'     : ['xtensa', 'xtensaeb']
+}
+
+def map_dir_to_targets(name):
+    if name in multi_targets:
+        return multi_targets[name]
+    else:
+        return name
+
+namespace = "qemu-project"
+if len(sys.argv) >= 2:
+    namespace = sys.argv[1]
+
+cwd = os.getcwd()
+reponame = os.path.basename(cwd)
+repourl = f"https://gitlab.com/{namespace}/{reponame}"
+
+# Add remote, fetch master and save the common ancestor
+subprocess.check_call(["git", "remote", "add", "pick-target", repourl])
+subprocess.check_call(["git", "fetch", "pick-target", "master"],
+                      stdout=subprocess.DEVNULL,
+                      stderr=subprocess.DEVNULL)
+
+ancestor = subprocess.check_output(["git", "merge-base",
+                                    "pick-target/master", "HEAD"],
+                                   universal_newlines=True)
+
+ancestor = ancestor.strip()
+
+subprocess.check_call(["git", "remote", "rm", "pick-target"])
+
+# calculate the diff and extract list of touched files
+diff = subprocess.check_output(["git", "diff", "--numstat",
+                                 f"{ancestor}..HEAD"])
+
+files = [l.split("\t")[2] for l in diff.decode().split("\n") if "\t" in l]
+
+# Build options to track
+system = False
+user = False
+targets = []
+
+for f in files:
+    if f.startswith("hw"):
+        system = True
+    if f.startswith("linux-user"):
+        user = True
+    if f.startswith("target"):
+        t = f.split("/")[1]
+        targets.extend(map_dir_to_targets(t))
+
+target_list = []
+for t in sorted(set(targets)):
+    if system:
+        target_list.append(f"{t}-softmmu")
+    if user:
+        target_list.append(f"{t}-linux-user")
+
+print(" ".join(target_list))