changeset 928:92d0dded0933

more non regression perfs
author Alain Mazy <am@orthanc.team>
date Mon, 15 Jun 2026 10:54:23 +0200
parents fe40df898a4d
children 39b1a8e7436c
files NewTests/NonRegressionPerfs/test_non_regression_perfs.py
diffstat 1 files changed, 51 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/NewTests/NonRegressionPerfs/test_non_regression_perfs.py	Mon Jun 15 09:36:05 2026 +0200
+++ b/NewTests/NonRegressionPerfs/test_non_regression_perfs.py	Mon Jun 15 10:54:23 2026 +0200
@@ -5,9 +5,10 @@
 from orthanc_tools import OrthancTestDbPopulator
 from helpers import Helpers, wait_container_healthy
 from contextlib import contextmanager
-from typing import Callable, Tuple
+from typing import Callable, Tuple, Optional, Dict
 from urllib.parse import urlparse
 import shutil
+import concurrent.futures
 
 import pathlib
 import os
@@ -15,23 +16,6 @@
 here = pathlib.Path(__file__).parent.resolve()
 
 
-# test_configs = {
-#     "ref": {
-#         "orthanc-url": "http://localhost:8142"
-#     },
-#     "new": {
-#         "orthanc-url": "http://localhost:8143"
-#     },
-#     "ref-s3": {
-#         "orthanc-url": "http://localhost:8242"
-#     },
-#     "new-s3": {
-#         "orthanc-url": "http://localhost:8243"
-#     }
-# }
-
-# test_results = {}
-
 # Download a file localy (only the first time) and return its local_path and content
 def download_test_file(url: str) -> Tuple[str, bytes]:
     local_path = here / "DownloadedTestFiles" / urlparse(url).path.split('/')[-1]
@@ -54,32 +38,25 @@
         print("Cleaning old compose")
         subprocess.run(["docker", "compose", "down", "-v", "--remove-orphans"], check=True)
 
-
-    # @classmethod
-    # def setUpClass(cls):
-    #     os.chdir(here)
-    #     subprocesss_env = os.environ.copy()
-    #     subprocesss_env["ORTHANC_IMAGE_UNDER_TESTS"] = Helpers.orthanc_under_tests_docker_image
+    @classmethod
+    def setUpClass(cls):
+        os.chdir(here)
+        subprocesss_env = os.environ.copy()
+        subprocesss_env["ORTHANC_IMAGE_UNDER_TESTS"] = Helpers.orthanc_under_tests_docker_image
 
-    #     # print("Pullling containers")
-    #     # subprocess.run(["docker", "compose", "pull"], env=subprocesss_env, check=True)
-
-    #     print("Launching containers")
-    #     subprocess.run(["docker", "compose", "up", "-d"], env=subprocesss_env, check=True)
-        
-    #     o_ref = OrthancApiClient(test_configs["ref"]["orthanc-url"])
-    #     o_new = OrthancApiClient(test_configs["new"]["orthanc-url"])
-
-    #     o_ref.wait_started()
-    #     o_new.wait_started()
+        print("Pullling containers")
+        subprocess.run(["docker", "compose", "pull"], env=subprocesss_env, check=True)
 
 
-    @classmethod
-    def tearDownClass(cls):
-        cls.cleanup()
 
-
-    def measure(self, test_name: str, perform_test: Callable[[OrthancApiClient], None], test_configs, test_results, reapeat_count: int = 1, tolerance_pct = 0.25) -> None:
+    def measure(self, 
+                test_name: str, 
+                perform_test: Callable[[OrthancApiClient], None], 
+                test_configs = Dict[str, Dict], 
+                test_results = Dict[str, Dict], 
+                reapeat_count: int = 1, 
+                parallel_count: Optional[int] = None,
+                tolerance_pct = 0.25) -> None:
 
         test_results[test_name] = {}
 
@@ -88,7 +65,12 @@
 
             start_time = time.perf_counter()
             for i in range(0, reapeat_count):
-                perform_test(o)
+                if not parallel_count: # execute with a single thread
+                    perform_test(o)
+                else: # execute in parallel + wait they all complete
+                    with concurrent.futures.ThreadPoolExecutor() as executor:
+                        futures = [executor.submit(perform_test, o) for i in range(parallel_count)]
+                        results = [future.result() for future in concurrent.futures.as_completed(futures)]
 
             end_time = time.perf_counter()
             test_results[test_name][test_config_name] = (end_time - start_time) * 1000
@@ -108,7 +90,7 @@
             delta_text = f"- {abs((delta_perf*100)):>8.1f} %"
             failed = False
 
-        print(f"{test_name:<50} | {ref_time:>20.3f} | {new_time:>20.3f} | {delta_text:>20}")
+        print(f"{test_name:<60} | {ref_time:>20.3f} | {new_time:>20.3f} | {delta_text:>20}")
         test_results[test_name]["success"] = not failed
 
 
@@ -152,9 +134,6 @@
         subprocesss_env = os.environ.copy()
         subprocesss_env["ORTHANC_IMAGE_UNDER_TESTS"] = Helpers.orthanc_under_tests_docker_image
 
-        # print("Pullling containers")
-        # subprocess.run(["docker", "compose", "pull"], env=subprocesss_env, check=True)
-
         print("Launching containers")
         subprocess.run(["docker", "compose", "up", "-d"], env=subprocesss_env, check=True)
         
@@ -165,8 +144,8 @@
         o_new.wait_started()
 
         print(f"---------- {config_name} -----------")
-        print(f"{'TEST NAME':<50} | {'REF ORTHANC [ms]':>20} | {'NEW ORTHANC [ms]':>20} | {'DELTA [PCT]':>20}")
-        print(f"{'-'*119}")
+        print(f"{'TEST NAME':<60} | {'REF ORTHANC [ms]':>20} | {'NEW ORTHANC [ms]':>20} | {'DELTA [PCT]':>20}")
+        print(f"{'-'*129}")
 
         self.measure(test_name="populate 3000 instances with 5 workers",
                      perform_test=lambda o: OrthancTestDbPopulator(o, studies_count=5, series_count=3, instances_count=120, random_seed=65, worker_threads_count=5).execute(),
@@ -180,6 +159,31 @@
                      test_configs=test_configs,
                      test_results=test_results)
         
+        self.measure(test_name="download archives with transcoding 5x5 (sequential)",
+                     perform_test=lambda o: [o.get_binary(endpoint=f"/studies/{i}/archive?transcode=1.2.840.10008.1.2.4.70") for i in o.studies.get_all_ids()],
+                     reapeat_count=5,
+                     test_configs=test_configs,
+                     test_results=test_results)
+
+        self.measure(test_name="download archives with transcoding 5x5 (parallel)",
+                     perform_test=lambda o: [o.get_binary(endpoint=f"/studies/{i}/archive?transcode=1.2.840.10008.1.2.4.70") for i in o.studies.get_all_ids()],
+                     reapeat_count=1,
+                     parallel_count=5,
+                     test_configs=test_configs,
+                     test_results=test_results)
+
+        self.measure(test_name="get simplified tags 1x1000 (sequential)",
+                     perform_test=lambda o: [o.instances.get_tags(i) for i in o.instances.get_all_ids()[:1000]],
+                     reapeat_count=1,
+                     test_configs=test_configs,
+                     test_results=test_results)
+
+        self.measure(test_name="get simplified tags 5x1000 (parallel)",
+                     perform_test=lambda o: [o.instances.get_tags(i) for i in o.instances.get_all_ids()[:1000]],
+                     parallel_count=5,
+                     test_configs=test_configs,
+                     test_results=test_results)
+
         reg_of_path, reg_of_content = download_test_file("https://public-files.orthanc.team/test-files/429_MB_REG_OF.dcm")
         reg_ow_path, reg_ow_content = download_test_file("https://public-files.orthanc.team/test-files/429_MB_REG_OW.dcm")