qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [PULL 0/3] Block patches
@ 2021-12-22 16:52 Hanna Reitz
  2021-12-22 16:52 ` [PULL 1/3] iotests/testrunner.py: add doc string for run_test() Hanna Reitz
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Hanna Reitz @ 2021-12-22 16:52 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, Hanna Reitz, Richard Henderson, qemu-devel

The following changes since commit 8c5f94cd4182753959c8be8de415120dc879d8f0:

  Merge tag 'pull-loong-20211221-2' of https://gitlab.com/rth7680/qemu into staging (2021-12-21 13:30:35 -0800)

are available in the Git repository at:

  https://gitlab.com/hreitz/qemu.git tags/pull-block-2021-12-22

for you to fetch changes up to 722f87df2545b308aec49b459b028f0802b4fd9e:

  iotests: check: multiprocessing support (2021-12-22 16:29:48 +0100)

----------------------------------------------------------------
Block patches:
- Added support to the iotests for running tests in several parallel
  jobs (using the new -j parameter)

----------------------------------------------------------------
Vladimir Sementsov-Ogievskiy (3):
  iotests/testrunner.py: add doc string for run_test()
  iotests/testrunner.py: move updating last_elapsed to run_tests
  iotests: check: multiprocessing support

 tests/qemu-iotests/check         |  4 +-
 tests/qemu-iotests/testrunner.py | 86 ++++++++++++++++++++++++++++----
 2 files changed, 80 insertions(+), 10 deletions(-)

-- 
2.33.1



^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PULL 1/3] iotests/testrunner.py: add doc string for run_test()
  2021-12-22 16:52 [PULL 0/3] Block patches Hanna Reitz
@ 2021-12-22 16:52 ` Hanna Reitz
  2021-12-22 16:52 ` [PULL 2/3] iotests/testrunner.py: move updating last_elapsed to run_tests Hanna Reitz
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Hanna Reitz @ 2021-12-22 16:52 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, Hanna Reitz, Richard Henderson, qemu-devel

From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>

We are going to modify these methods and will add more documentation in
further commit. As a preparation add basic documentation.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20211203122223.2780098-2-vsementsov@virtuozzo.com>
Reviewed-by: John Snow <jsnow@redhat.com>
Tested-by: John Snow <jsnow@redhat.com>
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
---
 tests/qemu-iotests/testrunner.py | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
index 0e29c2fddd..fa842252d3 100644
--- a/tests/qemu-iotests/testrunner.py
+++ b/tests/qemu-iotests/testrunner.py
@@ -220,6 +220,12 @@ def find_reference(self, test: str) -> str:
         return f'{test}.out'
 
     def do_run_test(self, test: str) -> TestResult:
+        """
+        Run one test
+
+        :param test: test file path
+        """
+
         f_test = Path(test)
         f_bad = Path(f_test.name + '.out.bad')
         f_notrun = Path(f_test.name + '.notrun')
@@ -287,6 +293,13 @@ def do_run_test(self, test: str) -> TestResult:
 
     def run_test(self, test: str,
                  test_field_width: Optional[int] = None) -> TestResult:
+        """
+        Run one test and print short status
+
+        :param test: test file path
+        :param test_field_width: width for first field of status format
+        """
+
         last_el = self.last_elapsed.get(test)
         start = datetime.datetime.now().strftime('%H:%M:%S')
 
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PULL 2/3] iotests/testrunner.py: move updating last_elapsed to run_tests
  2021-12-22 16:52 [PULL 0/3] Block patches Hanna Reitz
  2021-12-22 16:52 ` [PULL 1/3] iotests/testrunner.py: add doc string for run_test() Hanna Reitz
@ 2021-12-22 16:52 ` Hanna Reitz
  2021-12-22 16:52 ` [PULL 3/3] iotests: check: multiprocessing support Hanna Reitz
  2021-12-23  2:33 ` [PULL 0/3] Block patches Richard Henderson
  3 siblings, 0 replies; 5+ messages in thread
From: Hanna Reitz @ 2021-12-22 16:52 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, Hanna Reitz, Richard Henderson, qemu-devel

From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>

We are going to use do_run_test() in multiprocessing environment, where
we'll not be able to change original runner object.

Happily, the only thing we change is that last_elapsed and it's simple
to do it in run_tests() instead. All other accesses to self in
do_runt_test() and in run_test() are read-only.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20211203122223.2780098-3-vsementsov@virtuozzo.com>
Reviewed-by: John Snow <jsnow@redhat.com>
Tested-by: John Snow <jsnow@redhat.com>
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
---
 tests/qemu-iotests/testrunner.py | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
index fa842252d3..a9f2feb58c 100644
--- a/tests/qemu-iotests/testrunner.py
+++ b/tests/qemu-iotests/testrunner.py
@@ -287,7 +287,6 @@ def do_run_test(self, test: str) -> TestResult:
                               diff=diff, casenotrun=casenotrun)
         else:
             f_bad.unlink()
-            self.last_elapsed.update(test, elapsed)
             return TestResult(status='pass', elapsed=elapsed,
                               casenotrun=casenotrun)
 
@@ -353,6 +352,9 @@ def run_tests(self, tests: List[str]) -> bool:
                     print('\n'.join(res.diff))
             elif res.status == 'not run':
                 notrun.append(name)
+            elif res.status == 'pass':
+                assert res.elapsed is not None
+                self.last_elapsed.update(t, res.elapsed)
 
             sys.stdout.flush()
             if res.interrupted:
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PULL 3/3] iotests: check: multiprocessing support
  2021-12-22 16:52 [PULL 0/3] Block patches Hanna Reitz
  2021-12-22 16:52 ` [PULL 1/3] iotests/testrunner.py: add doc string for run_test() Hanna Reitz
  2021-12-22 16:52 ` [PULL 2/3] iotests/testrunner.py: move updating last_elapsed to run_tests Hanna Reitz
@ 2021-12-22 16:52 ` Hanna Reitz
  2021-12-23  2:33 ` [PULL 0/3] Block patches Richard Henderson
  3 siblings, 0 replies; 5+ messages in thread
From: Hanna Reitz @ 2021-12-22 16:52 UTC (permalink / raw)
  To: qemu-block; +Cc: Kevin Wolf, Hanna Reitz, Richard Henderson, qemu-devel

From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>

Add -j <JOBS> parameter, to run tests in several jobs simultaneously.
For realization - simply utilize multiprocessing.Pool class.

Notes:

1. Of course, tests can't run simultaneously in same TEST_DIR. So,
   use subdirectories TEST_DIR/testname/ and SOCK_DIR/testname/
   instead of simply TEST_DIR and SOCK_DIR

2. multiprocessing.Pool.starmap function doesn't support passing
   context managers, so we can't simply pass "self". Happily, we need
   self only for read-only access, and it just works if it is defined
   in global space. So, add a temporary link TestRunner.shared_self
   during run_tests().

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20211203122223.2780098-4-vsementsov@virtuozzo.com>
Reviewed-by: John Snow <jsnow@redhat.com>
Tested-by: John Snow <jsnow@redhat.com>
Signed-off-by: Hanna Reitz <hreitz@redhat.com>
---
 tests/qemu-iotests/check         |  4 +-
 tests/qemu-iotests/testrunner.py | 69 ++++++++++++++++++++++++++++----
 2 files changed, 64 insertions(+), 9 deletions(-)

diff --git a/tests/qemu-iotests/check b/tests/qemu-iotests/check
index 43a4b694cc..0c27721a41 100755
--- a/tests/qemu-iotests/check
+++ b/tests/qemu-iotests/check
@@ -34,6 +34,8 @@ def make_argparser() -> argparse.ArgumentParser:
                    help='show me, do not run tests')
     p.add_argument('-makecheck', action='store_true',
                    help='pretty print output for make check')
+    p.add_argument('-j', dest='jobs', type=int, default=1,
+                   help='run tests in multiple parallel jobs')
 
     p.add_argument('-d', dest='debug', action='store_true', help='debug')
     p.add_argument('-p', dest='print', action='store_true',
@@ -165,6 +167,6 @@ if __name__ == '__main__':
         with TestRunner(env, makecheck=args.makecheck,
                         color=args.color) as tr:
             paths = [os.path.join(env.source_iotests, t) for t in tests]
-            ok = tr.run_tests(paths)
+            ok = tr.run_tests(paths, args.jobs)
             if not ok:
                 sys.exit(1)
diff --git a/tests/qemu-iotests/testrunner.py b/tests/qemu-iotests/testrunner.py
index a9f2feb58c..0feaa396d0 100644
--- a/tests/qemu-iotests/testrunner.py
+++ b/tests/qemu-iotests/testrunner.py
@@ -26,6 +26,7 @@
 import json
 import termios
 import sys
+from multiprocessing import Pool
 from contextlib import contextmanager
 from typing import List, Optional, Iterator, Any, Sequence, Dict, \
         ContextManager
@@ -126,6 +127,31 @@ def __init__(self, status: str, description: str = '',
 
 
 class TestRunner(ContextManager['TestRunner']):
+    shared_self = None
+
+    @staticmethod
+    def proc_run_test(test: str, test_field_width: int) -> TestResult:
+        # We are in a subprocess, we can't change the runner object!
+        runner = TestRunner.shared_self
+        assert runner is not None
+        return runner.run_test(test, test_field_width, mp=True)
+
+    def run_tests_pool(self, tests: List[str],
+                       test_field_width: int, jobs: int) -> List[TestResult]:
+
+        # passing self directly to Pool.starmap() just doesn't work, because
+        # it's a context manager.
+        assert TestRunner.shared_self is None
+        TestRunner.shared_self = self
+
+        with Pool(jobs) as p:
+            results = p.starmap(self.proc_run_test,
+                                zip(tests, [test_field_width] * len(tests)))
+
+        TestRunner.shared_self = None
+
+        return results
+
     def __init__(self, env: TestEnv, makecheck: bool = False,
                  color: str = 'auto') -> None:
         self.env = env
@@ -219,11 +245,16 @@ def find_reference(self, test: str) -> str:
 
         return f'{test}.out'
 
-    def do_run_test(self, test: str) -> TestResult:
+    def do_run_test(self, test: str, mp: bool) -> TestResult:
         """
         Run one test
 
         :param test: test file path
+        :param mp: if true, we are in a multiprocessing environment, use
+                   personal subdirectories for test run
+
+        Note: this method may be called from subprocess, so it does not
+        change ``self`` object in any way!
         """
 
         f_test = Path(test)
@@ -249,6 +280,12 @@ def do_run_test(self, test: str) -> TestResult:
 
         args = [str(f_test.resolve())]
         env = self.env.prepare_subprocess(args)
+        if mp:
+            # Split test directories, so that tests running in parallel don't
+            # break each other.
+            for d in ['TEST_DIR', 'SOCK_DIR']:
+                env[d] = os.path.join(env[d], f_test.name)
+                Path(env[d]).mkdir(parents=True, exist_ok=True)
 
         t0 = time.time()
         with f_bad.open('w', encoding="utf-8") as f:
@@ -291,23 +328,32 @@ def do_run_test(self, test: str) -> TestResult:
                               casenotrun=casenotrun)
 
     def run_test(self, test: str,
-                 test_field_width: Optional[int] = None) -> TestResult:
+                 test_field_width: Optional[int] = None,
+                 mp: bool = False) -> TestResult:
         """
         Run one test and print short status
 
         :param test: test file path
         :param test_field_width: width for first field of status format
+        :param mp: if true, we are in a multiprocessing environment, don't try
+                   to rewrite things in stdout
+
+        Note: this method may be called from subprocess, so it does not
+        change ``self`` object in any way!
         """
 
         last_el = self.last_elapsed.get(test)
         start = datetime.datetime.now().strftime('%H:%M:%S')
 
         if not self.makecheck:
-            self.test_print_one_line(test=test, starttime=start,
-                                     lasttime=last_el, end='\r',
+            self.test_print_one_line(test=test,
+                                     status = 'started' if mp else '...',
+                                     starttime=start,
+                                     lasttime=last_el,
+                                     end = '\n' if mp else '\r',
                                      test_field_width=test_field_width)
 
-        res = self.do_run_test(test)
+        res = self.do_run_test(test, mp)
 
         end = datetime.datetime.now().strftime('%H:%M:%S')
         self.test_print_one_line(test=test, status=res.status,
@@ -321,7 +367,7 @@ def run_test(self, test: str,
 
         return res
 
-    def run_tests(self, tests: List[str]) -> bool:
+    def run_tests(self, tests: List[str], jobs: int = 1) -> bool:
         n_run = 0
         failed = []
         notrun = []
@@ -332,9 +378,16 @@ def run_tests(self, tests: List[str]) -> bool:
 
         test_field_width = max(len(os.path.basename(t)) for t in tests) + 2
 
-        for t in tests:
+        if jobs > 1:
+            results = self.run_tests_pool(tests, test_field_width, jobs)
+
+        for i, t in enumerate(tests):
             name = os.path.basename(t)
-            res = self.run_test(t, test_field_width=test_field_width)
+
+            if jobs > 1:
+                res = results[i]
+            else:
+                res = self.run_test(t, test_field_width)
 
             assert res.status in ('pass', 'fail', 'not run')
 
-- 
2.33.1



^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PULL 0/3] Block patches
  2021-12-22 16:52 [PULL 0/3] Block patches Hanna Reitz
                   ` (2 preceding siblings ...)
  2021-12-22 16:52 ` [PULL 3/3] iotests: check: multiprocessing support Hanna Reitz
@ 2021-12-23  2:33 ` Richard Henderson
  3 siblings, 0 replies; 5+ messages in thread
From: Richard Henderson @ 2021-12-23  2:33 UTC (permalink / raw)
  To: Hanna Reitz, qemu-block; +Cc: Kevin Wolf, qemu-devel

On 12/22/21 8:52 AM, Hanna Reitz wrote:
> The following changes since commit 8c5f94cd4182753959c8be8de415120dc879d8f0:
> 
>    Merge tag 'pull-loong-20211221-2' of https://gitlab.com/rth7680/qemu into staging (2021-12-21 13:30:35 -0800)
> 
> are available in the Git repository at:
> 
>    https://gitlab.com/hreitz/qemu.git tags/pull-block-2021-12-22
> 
> for you to fetch changes up to 722f87df2545b308aec49b459b028f0802b4fd9e:
> 
>    iotests: check: multiprocessing support (2021-12-22 16:29:48 +0100)
> 
> ----------------------------------------------------------------
> Block patches:
> - Added support to the iotests for running tests in several parallel
>    jobs (using the new -j parameter)
> 
> ----------------------------------------------------------------
> Vladimir Sementsov-Ogievskiy (3):
>    iotests/testrunner.py: add doc string for run_test()
>    iotests/testrunner.py: move updating last_elapsed to run_tests
>    iotests: check: multiprocessing support
> 
>   tests/qemu-iotests/check         |  4 +-
>   tests/qemu-iotests/testrunner.py | 86 ++++++++++++++++++++++++++++----
>   2 files changed, 80 insertions(+), 10 deletions(-)

Applied, thanks.

r~


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-12-23  2:34 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2021-12-22 16:52 [PULL 0/3] Block patches Hanna Reitz
2021-12-22 16:52 ` [PULL 1/3] iotests/testrunner.py: add doc string for run_test() Hanna Reitz
2021-12-22 16:52 ` [PULL 2/3] iotests/testrunner.py: move updating last_elapsed to run_tests Hanna Reitz
2021-12-22 16:52 ` [PULL 3/3] iotests: check: multiprocessing support Hanna Reitz
2021-12-23  2:33 ` [PULL 0/3] Block patches Richard Henderson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).