From: bakulinm <bakul...@gmail.com>

make check-avocado takes a lot of time, and avocado since version 91 has
multithreaded mode for running several tests simultaneously.
This patch allows to run "make check-avocado -j" to use all cores or,
for example, "make check-avocado -j4" to select number of workers to use.
By default ("make check-avocado") only one worker is used.

Changes:
1) Version of avocado in requirements.txt upgraded from 88.1 to <93
 (LTS version is used, as mentioned here
  https://avocado-framework.readthedocs.io/en/latest/releases/lts/92_0.html )
2) Makefile 4.1 (used in e.g. Ubuntu 18.04) doesn't provide number of jobs
 in $MAKEFLAGS, so python script from here
 https://stackoverflow.com/a/67247743/5936122 is used. Python script parses
 Makeflags, communicates with jobserver to get the number of available jobs
 and outputs it as a number, that is used as nrunner-max-parallel-tasks.
 If -j is used, it outputs total number of cores. If -j is not used at all,
 it returns 1. Limitations: script can probably report lower number of jobs
 than provided, if some slots are already taken by other makefiles, so make
 check-avocado should be run separately from other make tasks.

Signed-off-by: Maksim Bakulin <bakul...@ispras.ru>
Signed-off-by: Pavel Dovgalyuk <pavel.dovgal...@ispras.ru>
---
 tests/Makefile.include |   20 ++++++++++++++++++--
 tests/jobs.py          |   42 ++++++++++++++++++++++++++++++++++++++++++
 tests/requirements.txt |    2 +-
 3 files changed, 61 insertions(+), 3 deletions(-)
 create mode 100644 tests/jobs.py

diff --git a/tests/Makefile.include b/tests/Makefile.include
index 9422ddaece..6da5b6b45e 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -93,6 +93,9 @@ TESTS_VENV_DIR=$(BUILD_DIR)/tests/venv
 TESTS_VENV_REQ=$(SRC_PATH)/tests/requirements.txt
 TESTS_RESULTS_DIR=$(BUILD_DIR)/tests/results
 TESTS_PYTHON=$(TESTS_VENV_DIR)/bin/python3
+# 1 parallel task is used by default
+NRUNNER_MAX_TASKS=--nrunner-max-parallel-tasks
+
 ifndef AVOCADO_TESTS
        AVOCADO_TESTS=tests/avocado
 endif
@@ -111,6 +114,19 @@ quiet-venv-pip = $(quiet-@)$(call quiet-command-run, \
     $(TESTS_PYTHON) -m pip -q --disable-pip-version-check $1, \
     "VENVPIP","$1")
 
+
+get_avocado_max_tasks:
+# Make doesn't have easy ways to get number of jobs, using python for that
+# Python script communicates with jobserver to detect number of jobs
+       +$(eval MAKE_JOBS:=$$(shell python3 $(SRC_PATH)/tests/jobs.py 
$(MAKEFLAGS)))
+       @echo Using $(MAKE_JOBS) jobs for avocado testing
+# If 2 jobs or more are used set nrunner-max-parallel-tasks accordingly
+       @if [ ${MAKE_JOBS} -gt 1 ] ; then \
+               $(eval NRUNNER_MAX_TASKS=--nrunner-max-parallel-tasks 
$$(MAKE_JOBS)) true; \
+       fi
+
+$(TESTS_VENV_REQ): get_avocado_max_tasks
+
 $(TESTS_VENV_DIR): $(TESTS_VENV_REQ)
        $(call quiet-command, $(PYTHON) -m venv $@, VENV, $@)
        $(call quiet-venv-pip,install -e "$(SRC_PATH)/python/")
@@ -145,8 +161,8 @@ check-avocado: check-venv $(TESTS_RESULTS_DIR) get-vm-images
             $(if $(AVOCADO_TAGS),, --filter-by-tags-include-empty \
                        --filter-by-tags-include-empty-key) \
             $(AVOCADO_CMDLINE_TAGS) \
-            $(if $(GITLAB_CI),,--failfast) $(AVOCADO_TESTS), \
-            "AVOCADO", "tests/avocado")
+            $(if $(GITLAB_CI),,--failfast) $(AVOCADO_TESTS) 
$(NRUNNER_MAX_TASKS), \
+            "AVOCADO", "tests/avocado" \)
 
 check-acceptance-deprecated-warning:
        @echo
diff --git a/tests/jobs.py b/tests/jobs.py
new file mode 100644
index 0000000000..a339192d97
--- /dev/null
+++ b/tests/jobs.py
@@ -0,0 +1,42 @@
+import argparse, os
+import sys
+
+def safe_int(s):
+    try:
+        return int(s)
+    except:
+        return -1
+
+class JobserverArgs:
+    known_names = ["jobserver-fds","jobserver-auth"]
+    def __init__(self):
+        self.fds = "-1,-1"
+
+    @staticmethod
+    def from_argv():
+        ja = JobserverArgs()
+        parser = argparse.ArgumentParser()
+        for name in JobserverArgs.known_names:
+            parser.add_argument('--'+name, dest="fds")
+        parser.parse_known_args(namespace=ja)
+        return ja
+
+    def get_fds(self):
+        return tuple([safe_int(fd) for fd in (self.fds+",").split(",")][:2])
+
+fd_in, fd_out = JobserverArgs.from_argv().get_fds()
+
+if fd_in == -1 or fd_out == -1:
+# if no jobserver is used, but -j is present, use total number of cpu cores
+    if '-j' in sys.argv:
+        print(os.cpu_count())
+# use single thread
+    else:
+        print(1)
+else:
+    os.set_blocking(fd_in, False)
+
+    tokens = os.read(fd_in, 1024)
+    os.write(fd_out, tokens)
+
+    print(len(tokens)+1)
\ No newline at end of file
diff --git a/tests/requirements.txt b/tests/requirements.txt
index 0ba561b6bd..3b8c4d4706 100644
--- a/tests/requirements.txt
+++ b/tests/requirements.txt
@@ -2,5 +2,5 @@
 # in the tests/venv Python virtual environment. For more info,
 # refer to: https://pip.pypa.io/en/stable/user_guide/#id1
 # Note that qemu.git/python/ is always implicitly installed.
-avocado-framework==88.1
+avocado-framework<93
 pycdlib==1.11.0


Reply via email to