From 1a14a6320e893b3392a72a9eb5db9c0b5e7d08e5 Mon Sep 17 00:00:00 2001 From: Li Wei Date: Fri, 3 Jul 2026 11:16:48 +0900 Subject: [PATCH] DAOS-18610 tests: Fix container/boundary timeouts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test employs 30000 threads via concurrent.futures.ThreadPoolExecutor. Each thread creates a container and sleeps 2 s. In el8’s Python 3.6, this ThreadPoolExecutor allows (os.cpu_count() or 1) * 5 threads to run at the same time, whereas in el9’s Python 3.9, it only allows min(32, (os.cpu_count() or 1) + 4). Log messages produced by my debug PR confirm the latter to be 32, which must be way smaller than the former. If we consider only the time taken by the sleep in every thread, then it takes at least 2 * (30000 / 32) = 1875 s to finish 30000 such threads, already longer than the test timeout of 1200 s. This patch specifies max_workers explicitly to limit the delay caused by sleeping. Test-tag: pr test_container_boundary Signed-off-by: Li Wei --- src/tests/ftest/container/boundary.py | 7 ++++--- src/tests/ftest/util/thread_manager.py | 8 ++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/tests/ftest/container/boundary.py b/src/tests/ftest/container/boundary.py index a6687a7a93a..915b9a4cd7a 100644 --- a/src/tests/ftest/container/boundary.py +++ b/src/tests/ftest/container/boundary.py @@ -1,6 +1,6 @@ """ (C) Copyright 2022-2023 Intel Corporation. - (C) Copyright 2025 Hewlett Packard Enterprise Development LP + (C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP SPDX-License-Identifier: BSD-2-Clause-Patent """ @@ -104,9 +104,10 @@ def create_pools(self, num_pools, num_containers): self.fail('{} pool create threads failed'.format(num_failed)) self.log.info('Created %d pools', num_pools) - # Create all containers for all pools in parallel + # Create all containers for all pools in parallel (specifying max_workers because of the + # 2-second sleep in every thread) container_manager = ThreadManager( - self.create_container_and_test, self.get_remaining_time() - 30) + self.create_container_and_test, self.get_remaining_time() - 30, max_workers=1024) all_pool_cont_args = list(itertools.product(self.pool, range(num_containers))) self.random.shuffle(all_pool_cont_args) for pool, cont_num in all_pool_cont_args: diff --git a/src/tests/ftest/util/thread_manager.py b/src/tests/ftest/util/thread_manager.py index 6e30c6bdee4..1e93ceeafa3 100644 --- a/src/tests/ftest/util/thread_manager.py +++ b/src/tests/ftest/util/thread_manager.py @@ -1,5 +1,6 @@ """ (C) Copyright 2021-2023 Intel Corporation. +(C) Copyright 2026 Hewlett Packard Enterprise Development LP SPDX-License-Identifier: BSD-2-Clause-Patent """ @@ -77,16 +78,19 @@ class ThreadManager(): # pylint: disable=too-many-ancestors,too-few-public-methods """Class to manage running any method as multiple threads.""" - def __init__(self, method, timeout=None): + def __init__(self, method, timeout=None, max_workers=None): """Initialize a ThreadManager object with the the method to run as a thread. Args: method (callable): python method to execute in each thread timeout (int, optional): timeout for all thread execution. Defaults to None. + max_workers (int, optional): maximum number of threads to run concurrently. + Defaults to None. """ self.log = getLogger() self.method = method self.timeout = timeout + self.max_workers = max_workers self.job_kwargs = [] self.futures = {} @@ -112,7 +116,7 @@ def run(self): """ results = [] - with ThreadPoolExecutor() as thread_executor: + with ThreadPoolExecutor(max_workers=self.max_workers) as thread_executor: self.log.info("Submitting %d threads ...", len(self.job_kwargs)) # Keep track of thread ids by assigning an index to each Future object futures = {