Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refine auto-parts logic #1098

Merged
merged 1 commit into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doc/newsfragments/2991_changed.auto_parts_refine.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Refine Auto-Part feature to handle corner cases when zero/negative/overly large number of parts are calculated.

41 changes: 34 additions & 7 deletions testplan/runnable/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,19 +592,46 @@ def _get_tasks(
)
num_of_parts = 1
else:
num_of_parts = math.ceil(
# the setup time shall take no more than 50% of runtime
cap = math.ceil(
time_info["execution_time"]
/ (
self.cfg.auto_part_runtime_limit
- time_info["setup_time"]
)
/ self.cfg.auto_part_runtime_limit
* 2
)
formula = f"""
num_of_parts = math.ceil(
time_info["execution_time"] {time_info["execution_time"]}
/ (
self.cfg.auto_part_runtime_limit {self.cfg.auto_part_runtime_limit}
- time_info["setup_time"] {time_info["setup_time"]}
)
)
"""
try:
num_of_parts = math.ceil(
time_info["execution_time"]
/ (
self.cfg.auto_part_runtime_limit
- time_info["setup_time"]
)
)
except ZeroDivisionError:
self.logger.error(
f"ZeroDivisionError occurred when calculating num_of_parts for {uid}, set to 1. {formula}"
)
num_of_parts = 1

if num_of_parts < 1:
self.logger.error(
f"Calculated num_of_parts for {uid} is {num_of_parts}, set to 1. {formula}"
)
num_of_parts = 1

if num_of_parts > cap:
self.logger.error(
f"Calculated num_of_parts for {uid} is {num_of_parts},"
" check the input runtime_data and auto_part_runtime_limit"
f"Calculated num_of_parts for {uid} is {num_of_parts} > cap {cap}, set to {cap}. {formula}"
)
num_of_parts = cap
if "weight" not in _task_arguments:
_task_arguments["weight"] = (
math.ceil(
Expand Down
60 changes: 60 additions & 0 deletions tests/functional/testplan/runners/pools/test_auto_part.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,63 @@ def test_auto_weight_discover():
assert task.weight == 140
mockplan.run()
assert pool.size == 1


def test_auto_parts_zero_neg_parts():
with tempfile.TemporaryDirectory() as runpath:
mockplan = TestplanMock(
"plan",
runpath=runpath,
merge_scheduled_parts=True,
auto_part_runtime_limit=45,
plan_runtime_target=200,
runtime_data={
"Proj1-suite": {
"execution_time": 50,
"setup_time": 50, # setup_time > runtime_limit -> negtive num_of_parts
}
},
)
pool = ProcessPool(name="MyPool", size="auto")
mockplan.add_resource(pool)
current_folder = os.path.dirname(os.path.realpath(__file__))
mockplan.schedule_all(
path=f"{current_folder}/discover_tasks",
name_pattern=r".*auto_parts_tasks\.py$",
resource="MyPool",
)
assert len(pool.added_items) == 1
for task in pool.added_items.values():
assert task.weight == 100
mockplan.run()
assert pool.size == 1


def test_auto_parts_cap_parts():
with tempfile.TemporaryDirectory() as runpath:
mockplan = TestplanMock(
"plan",
runpath=runpath,
merge_scheduled_parts=True,
auto_part_runtime_limit=45,
plan_runtime_target=200,
runtime_data={
"Proj1-suite": {
"execution_time": 60,
"setup_time": 44,
}
},
)
pool = ProcessPool(name="MyPool", size="auto")
mockplan.add_resource(pool)
current_folder = os.path.dirname(os.path.realpath(__file__))
mockplan.schedule_all(
path=f"{current_folder}/discover_tasks",
name_pattern=r".*auto_parts_tasks\.py$",
resource="MyPool",
)
assert len(pool.added_items) == 3
for task in pool.added_items.values():
assert task.weight == 64
mockplan.run()
assert pool.size == 1