Update scheduling algorithm
This commit is contained in:
+95
-70
@@ -4,8 +4,7 @@ from dataclasses import dataclass
|
||||
import os
|
||||
from test_config import build_bundle_test_configs
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass(frozen=False)
|
||||
class Test:
|
||||
test_id: str
|
||||
device: str
|
||||
@@ -17,18 +16,22 @@ class Test:
|
||||
config: dict[str, dict[str, str | None]]
|
||||
throttled: bool
|
||||
estimated_minutes: int
|
||||
status: str
|
||||
|
||||
# Bundle priority tiers for scheduling order (lower number = higher priority)
|
||||
BUNDLE_PRIORITY_TOP = 0 # Failed tests requiring rerun
|
||||
BUNDLE_PRIORITY_P2P_WITH_COE = 1 # P2P tests with COE pairs
|
||||
BUNDLE_PRIORITY_P2P_ONLY = 2 # P2P tests without COE pairs (RX/TX bundled)
|
||||
BUNDLE_PRIORITY_COE_ONLY = 3 # COE tests without P2P pairing (should be rare/unschedulable)
|
||||
BUNDLE_PRIORITY_P3P = 4 # P3P tests
|
||||
BUNDLE_PRIORITY_DUT_COMPLETED_MIRROR = 0 # REF-side tests whose DUT counterpart is already completed
|
||||
BUNDLE_PRIORITY_USER_TOP = 1 # User-specified top priority tests
|
||||
BUNDLE_PRIORITY_RERUN = 2 # Rerun tests (DUT or REF)
|
||||
BUNDLE_PRIORITY_MIRROR = 3
|
||||
BUNDLE_PRIORITY_P2P_WITH_COE = 4 # P2P tests with COE pairs
|
||||
BUNDLE_PRIORITY_P2P_ONLY = 5 # P2P tests without COE pairs (RX/TX bundled)
|
||||
BUNDLE_PRIORITY_COE_ONLY = 6 # COE tests without P2P pairing (should be rare/unschedulable)
|
||||
BUNDLE_PRIORITY_P3P = 6 # P3P tests
|
||||
|
||||
DUT = (os.getenv("DUT") or "DUT").strip()
|
||||
REF = (os.getenv("REF") or "REF").strip()
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@dataclass(frozen=False)
|
||||
class TestBundle:
|
||||
index: int
|
||||
tests: list[str]
|
||||
@@ -36,7 +39,8 @@ class TestBundle:
|
||||
device: str
|
||||
config: tuple[str, ...]
|
||||
priority: int
|
||||
|
||||
completed: int
|
||||
|
||||
def build_test_bundles(active_dut: dict[str, Test], active_ref: dict[str, Test], top_priority_tests: set[tuple[str, str]]) -> list[TestBundle]:
|
||||
"""Build deterministic bundles for DP scheduling."""
|
||||
|
||||
@@ -55,25 +59,6 @@ def build_test_bundles(active_dut: dict[str, Test], active_ref: dict[str, Test],
|
||||
deduped.append(test_id)
|
||||
return deduped
|
||||
|
||||
dut_top_priority: list[str] = []
|
||||
ref_top_priority: list[str] = []
|
||||
|
||||
for test_id, device in top_priority_tests:
|
||||
if device == DUT and test_id in active_dut:
|
||||
dut_top_priority.append(test_id)
|
||||
elif device == REF and test_id in active_ref:
|
||||
ref_top_priority.append(test_id)
|
||||
|
||||
if dut_top_priority:
|
||||
test_bundles.append(create_bundle(dut_top_priority, DUT, BUNDLE_PRIORITY_TOP, bundle_index, active_dut, active_ref))
|
||||
processed_dut.update(dut_top_priority)
|
||||
bundle_index += 1
|
||||
|
||||
if ref_top_priority:
|
||||
test_bundles.append(create_bundle(ref_top_priority, REF, BUNDLE_PRIORITY_TOP, bundle_index, active_dut, active_ref))
|
||||
processed_ref.update(ref_top_priority)
|
||||
bundle_index += 1
|
||||
|
||||
# Phase 1: DUT P2P bundles
|
||||
for dut_test_id, dut_test in active_dut.items():
|
||||
if dut_test_id in processed_dut or dut_test.test_type != "P2P":
|
||||
@@ -100,6 +85,15 @@ def build_test_bundles(active_dut: dict[str, Test], active_ref: dict[str, Test],
|
||||
priority = BUNDLE_PRIORITY_P2P_ONLY
|
||||
|
||||
dut_bundled_tests = dedupe_preserve_order(dut_bundled_tests)
|
||||
|
||||
# Check if any of the DUT tests in this bundle are in the top priority list
|
||||
if any((DUT, dut_test_id) in top_priority_tests for dut_test_id in dut_bundled_tests):
|
||||
priority = BUNDLE_PRIORITY_USER_TOP
|
||||
|
||||
# Check if any of the DUT tests in this bundle are reruns
|
||||
if any((dut_test.status == "rerun" for dut_test_id in dut_bundled_tests if (dut_test := active_dut.get(dut_test_id)))):
|
||||
priority = BUNDLE_PRIORITY_RERUN
|
||||
|
||||
test_bundles.append(
|
||||
create_bundle(dut_bundled_tests, DUT, priority, bundle_index, active_dut, active_ref)
|
||||
)
|
||||
@@ -112,6 +106,14 @@ def build_test_bundles(active_dut: dict[str, Test], active_ref: dict[str, Test],
|
||||
if ref_bundled_tests:
|
||||
ref_bundled_tests = dedupe_preserve_order(ref_bundled_tests)
|
||||
processed_ref.update(ref_bundled_tests)
|
||||
|
||||
# Check if any of the REF tests in this bundle are in the top priority list
|
||||
if any((REF, ref_test_id) in top_priority_tests for ref_test_id in ref_bundled_tests):
|
||||
priority = BUNDLE_PRIORITY_USER_TOP
|
||||
# Check if any of the REF tests in this bundle are reruns
|
||||
if any((ref_test.status == "rerun" for ref_test_id in ref_bundled_tests if (ref_test := active_ref.get(ref_test_id)))):
|
||||
priority = BUNDLE_PRIORITY_RERUN
|
||||
|
||||
test_bundles.append(
|
||||
create_bundle(ref_bundled_tests, REF, priority, bundle_index, active_dut, active_ref)
|
||||
)
|
||||
@@ -132,8 +134,18 @@ def build_test_bundles(active_dut: dict[str, Test], active_ref: dict[str, Test],
|
||||
processed_dut.add(th_ut_pair_id)
|
||||
|
||||
dut_bundled_tests = dedupe_preserve_order(dut_bundled_tests)
|
||||
priority = BUNDLE_PRIORITY_P3P
|
||||
|
||||
# Check if any of the DUT tests in this bundle are in the top priority list
|
||||
if any((DUT, dut_test_id) in top_priority_tests for dut_test_id in dut_bundled_tests):
|
||||
priority = BUNDLE_PRIORITY_USER_TOP
|
||||
|
||||
# Check if any of the DUT tests in this bundle are reruns
|
||||
if any((dut_test.status == "rerun" for dut_test_id in dut_bundled_tests if (dut_test := active_dut.get(dut_test_id)))):
|
||||
priority = BUNDLE_PRIORITY_RERUN
|
||||
|
||||
test_bundles.append(
|
||||
create_bundle(dut_bundled_tests, DUT, BUNDLE_PRIORITY_P3P, bundle_index, active_dut, active_ref)
|
||||
create_bundle(dut_bundled_tests, DUT, priority, bundle_index, active_dut, active_ref)
|
||||
)
|
||||
|
||||
ref_bundled_tests = [
|
||||
@@ -141,49 +153,66 @@ def build_test_bundles(active_dut: dict[str, Test], active_ref: dict[str, Test],
|
||||
for test_id in dut_bundled_tests
|
||||
if test_id in active_ref and test_id not in processed_ref
|
||||
]
|
||||
|
||||
# Check if any of the REF tests in this bundle are in the top priority list
|
||||
if any((REF, ref_test_id) in top_priority_tests for ref_test_id in ref_bundled_tests):
|
||||
priority = BUNDLE_PRIORITY_USER_TOP
|
||||
# Check if any of the REF tests in this bundle are reruns
|
||||
if any((ref_test.status == "rerun" for ref_test_id in ref_bundled_tests if (ref_test := active_ref.get(ref_test_id)))):
|
||||
priority = BUNDLE_PRIORITY_RERUN
|
||||
|
||||
if ref_bundled_tests:
|
||||
ref_bundled_tests = dedupe_preserve_order(ref_bundled_tests)
|
||||
processed_ref.update(ref_bundled_tests)
|
||||
test_bundles.append(
|
||||
create_bundle(ref_bundled_tests, REF, BUNDLE_PRIORITY_P3P, bundle_index, active_dut, active_ref)
|
||||
create_bundle(ref_bundled_tests, REF, priority, bundle_index, active_dut, active_ref)
|
||||
)
|
||||
|
||||
bundle_index += 1
|
||||
|
||||
# Phase 3: DUT leftovers (including COE-only)
|
||||
# Phase 3: DUT leftovers (COE-only)
|
||||
for dut_test_id in active_dut:
|
||||
if dut_test_id in processed_dut:
|
||||
continue
|
||||
print(f"Orphan COE-only DUT test found: {dut_test_id}")
|
||||
test_bundles.append(
|
||||
create_bundle([dut_test_id], DUT, BUNDLE_PRIORITY_COE_ONLY, bundle_index, active_dut, active_ref)
|
||||
)
|
||||
bundle_index += 1
|
||||
processed_dut.add(dut_test_id)
|
||||
|
||||
# Phase 4: unmatched REF P2P bundles
|
||||
# Phase 4: unmatched REF bundles, meaning DUT is completed
|
||||
for ref_test_id, ref_test in active_ref.items():
|
||||
if ref_test_id in processed_ref or ref_test.test_type != "P2P":
|
||||
if ref_test_id in processed_ref:
|
||||
continue
|
||||
|
||||
ref_bundled_tests = [ref_test_id]
|
||||
processed_ref.add(ref_test_id)
|
||||
|
||||
active_coe_pairings = [
|
||||
test_id
|
||||
for test_id in ref_test.coe_pairing
|
||||
if test_id in active_ref and test_id not in processed_ref
|
||||
]
|
||||
if ref_test.test_type == "P2P":
|
||||
active_coe_pairings = [
|
||||
test_id
|
||||
for test_id in ref_test.coe_pairing
|
||||
if test_id in active_ref and test_id not in processed_ref
|
||||
]
|
||||
|
||||
if active_coe_pairings:
|
||||
ref_bundled_tests.extend(active_coe_pairings)
|
||||
processed_ref.update(active_coe_pairings)
|
||||
priority = BUNDLE_PRIORITY_P2P_WITH_COE
|
||||
else:
|
||||
rx_tx_pair_id = get_rx_tx_pair_id(ref_test, REF, active_dut, active_ref)
|
||||
if rx_tx_pair_id and rx_tx_pair_id not in processed_ref:
|
||||
ref_bundled_tests.append(rx_tx_pair_id)
|
||||
processed_ref.add(rx_tx_pair_id)
|
||||
priority = BUNDLE_PRIORITY_P2P_ONLY
|
||||
if active_coe_pairings:
|
||||
ref_bundled_tests.extend(active_coe_pairings)
|
||||
processed_ref.update(active_coe_pairings)
|
||||
priority = BUNDLE_PRIORITY_DUT_COMPLETED_MIRROR
|
||||
else:
|
||||
rx_tx_pair_id = get_rx_tx_pair_id(ref_test, REF, active_dut, active_ref)
|
||||
if rx_tx_pair_id and rx_tx_pair_id not in processed_ref:
|
||||
ref_bundled_tests.append(rx_tx_pair_id)
|
||||
processed_ref.add(rx_tx_pair_id)
|
||||
priority = BUNDLE_PRIORITY_DUT_COMPLETED_MIRROR
|
||||
|
||||
if ref_test.test_type == "P3P":
|
||||
th_ut_pair_id = get_th_ut_pair_id(ref_test, REF, active_dut, active_ref)
|
||||
if th_ut_pair_id and th_ut_pair_id not in processed_ref:
|
||||
ref_bundled_tests.append(th_ut_pair_id)
|
||||
processed_ref.add(th_ut_pair_id)
|
||||
priority = BUNDLE_PRIORITY_DUT_COMPLETED_MIRROR
|
||||
|
||||
ref_bundled_tests = dedupe_preserve_order(ref_bundled_tests)
|
||||
test_bundles.append(
|
||||
@@ -191,31 +220,13 @@ def build_test_bundles(active_dut: dict[str, Test], active_ref: dict[str, Test],
|
||||
)
|
||||
bundle_index += 1
|
||||
|
||||
# Phase 5: unmatched REF P3P bundles
|
||||
for ref_test_id, ref_test in active_ref.items():
|
||||
if ref_test_id in processed_ref or ref_test.test_type != "P3P":
|
||||
continue
|
||||
|
||||
ref_bundled_tests = [ref_test_id]
|
||||
processed_ref.add(ref_test_id)
|
||||
|
||||
th_ut_pair_id = get_th_ut_pair_id(ref_test, REF, active_dut, active_ref)
|
||||
if th_ut_pair_id and th_ut_pair_id not in processed_ref:
|
||||
ref_bundled_tests.append(th_ut_pair_id)
|
||||
processed_ref.add(th_ut_pair_id)
|
||||
|
||||
ref_bundled_tests = dedupe_preserve_order(ref_bundled_tests)
|
||||
test_bundles.append(
|
||||
create_bundle(ref_bundled_tests, REF, BUNDLE_PRIORITY_P3P, bundle_index, active_dut, active_ref)
|
||||
)
|
||||
bundle_index += 1
|
||||
|
||||
# Phase 6: REF leftovers (including COE-only)
|
||||
# Phase 5: REF leftovers ( COE-only)
|
||||
for ref_test_id in active_ref:
|
||||
if ref_test_id in processed_ref:
|
||||
continue
|
||||
print(f"Orphan COE-only REF test found: {ref_test_id}")
|
||||
test_bundles.append(
|
||||
create_bundle([ref_test_id], REF, BUNDLE_PRIORITY_COE_ONLY, bundle_index, active_dut, active_ref)
|
||||
create_bundle([ref_test_id], REF, BUNDLE_PRIORITY_DUT_COMPLETED_MIRROR, bundle_index, active_dut, active_ref)
|
||||
)
|
||||
bundle_index += 1
|
||||
processed_ref.add(ref_test_id)
|
||||
@@ -256,6 +267,7 @@ def create_bundle(tests: list[str], device: str, priority: int, index: int, acti
|
||||
device=device,
|
||||
config=config,
|
||||
priority=priority,
|
||||
completed=0
|
||||
)
|
||||
|
||||
def bundle_pair_lookup(bundles: list[TestBundle], dut_bundles: list[TestBundle], ref_bundles: list[TestBundle]) -> list[TestBundle]:
|
||||
@@ -267,4 +279,17 @@ def bundle_pair_lookup(bundles: list[TestBundle], dut_bundles: list[TestBundle],
|
||||
return [b for b in ref_bundles if b.index in bundle_indexes]
|
||||
elif device == REF:
|
||||
return [b for b in dut_bundles if b.index in bundle_indexes]
|
||||
return []
|
||||
return []
|
||||
|
||||
def update_mirrored_bundle_priorities(knapsack_bundles: list[TestBundle], dut_pending: list[TestBundle], ref_pending: list[TestBundle]) -> tuple[list[TestBundle], list[TestBundle]]:
|
||||
bundle_pairs = bundle_pair_lookup(knapsack_bundles, dut_pending, ref_pending)
|
||||
|
||||
for bundle in dut_pending:
|
||||
if bundle.index in {b.index for b in bundle_pairs}:
|
||||
bundle.priority = BUNDLE_PRIORITY_MIRROR
|
||||
|
||||
for bundle in ref_pending:
|
||||
if bundle.index in {b.index for b in bundle_pairs}:
|
||||
bundle.priority = BUNDLE_PRIORITY_MIRROR
|
||||
|
||||
return dut_pending, ref_pending
|
||||
Reference in New Issue
Block a user