Merge master into unify/skills-20261111
This commit is contained in:
commit
4df1c2e48c
2 files changed
+36
-9
No files matched your search
@@ -406,7 +406,10 @@ def evaluate(entries: list[dict], free_gb: float, floor: float, stage: str, memo
|
|||||||
holds it, so a lower entry never takes a higher entry's slot; one
|
holds it, so a lower entry never takes a higher entry's slot; one
|
||||||
blocked by disk or budget reserves its need against the entries after it.
|
blocked by disk or budget reserves its need against the entries after it.
|
||||||
A hotfix entry that passes every check but the host load holds back
|
A hotfix entry that passes every check but the host load holds back
|
||||||
every entry after it, so lighter jobs cannot keep the load up. An
|
every entry after it, so lighter jobs cannot keep the load up. While no
|
||||||
|
queue job is active, any other entry the host load alone keeps out
|
||||||
|
reserves nothing and holds nothing back: that load lies outside the
|
||||||
|
queue, so holding the queue frees none of it. An
|
||||||
exclusive entry that only running jobs of other kinds keep out holds
|
exclusive entry that only running jobs of other kinds keep out holds
|
||||||
back every entry after it but light ones, so none overtakes it. A waiting
|
back every entry after it but light ones, so none overtakes it. A waiting
|
||||||
entry whose holder has not polled for CLAIM_SECONDS reserves nothing and
|
entry whose holder has not polled for CLAIM_SECONDS reserves nothing and
|
||||||
@@ -435,13 +438,17 @@ def evaluate(entries: list[dict], free_gb: float, floor: float, stage: str, memo
|
|||||||
if reason is not None and kind in exclusive:
|
if reason is not None and kind in exclusive:
|
||||||
drain = entry["id"]
|
drain = entry["id"]
|
||||||
if reason is None:
|
if reason is None:
|
||||||
reason, used, available = resources(need, share, used, available, floor, budget, taken)
|
reason, after, left = resources(need, share, used, available, floor, budget, taken)
|
||||||
if reason is None and entry["hotfix"] and entry["id"] in loaded:
|
if reason is None and entry["id"] in loaded and (entry["hotfix"] or not active):
|
||||||
reason, held = loaded[entry["id"]], entry["id"]
|
reason = loaded[entry["id"]]
|
||||||
elif reason is None:
|
if entry["hotfix"]:
|
||||||
taken += 1
|
held = entry["id"]
|
||||||
counts[kind] += 1
|
else:
|
||||||
busy.add(workdir)
|
used, available = after, left
|
||||||
|
if reason is None:
|
||||||
|
taken += 1
|
||||||
|
counts[kind] += 1
|
||||||
|
busy.add(workdir)
|
||||||
verdicts[entry["id"]] = reason
|
verdicts[entry["id"]] = reason
|
||||||
for entry in waiting:
|
for entry in waiting:
|
||||||
if silent(entry, now):
|
if silent(entry, now):
|
||||||
|
|||||||
+21
-1
@@ -296,9 +296,29 @@ class TestEvaluate(unittest.TestCase):
|
|||||||
self.decide([hotfix, light], loaded={"j1": load}),
|
self.decide([hotfix, light], loaded={"j1": load}),
|
||||||
{"j1": load, "j2": "waits behind hotfix j1, which the host load holds back"},
|
{"j1": load, "j2": "waits behind hotfix j1, which the host load holds back"},
|
||||||
)
|
)
|
||||||
self.assertEqual(self.decide([job(1), light], loaded={"j1": load}), {"j1": None, "j2": None})
|
self.assertEqual(self.decide([job(1), light], loaded={"j1": load}), {"j1": load, "j2": None})
|
||||||
self.assertEqual(self.decide([hotfix, light]), {"j1": None, "j2": None})
|
self.assertEqual(self.decide([hotfix, light]), {"j1": None, "j2": None})
|
||||||
|
|
||||||
|
def test_with_no_job_active_a_head_the_host_load_alone_keeps_out_reserves_nothing_and_with_one_active_it_does(self):
|
||||||
|
load = "RAM 55 % used + 41 % still to come reach the limit 90 %"
|
||||||
|
head, twin = job(1, kind="quality-high"), job(2, kind="quality-high", task="work/b")
|
||||||
|
gate, light = job(3, task="work/b"), job(4, kind="test-nostack", task="work/c")
|
||||||
|
shares = {"j1": {"ram": 41, "cpu": 62}, "j2": {"ram": 41, "cpu": 62}, "j3": {"ram": 20, "cpu": 40}, "j4": {"ram": 6, "cpu": 40}}
|
||||||
|
rules = {"slot_limits": {"quality-high": 1, "test": 5, "test-nostack": 6}, "exclusive": {"quality-high", "test"}, "light": {"test-nostack"}}
|
||||||
|
loaded = {"j1": load, "j2": load}
|
||||||
|
self.assertEqual(
|
||||||
|
self.decide([head, twin, gate, light], loaded=loaded, footprints=shares, **rules),
|
||||||
|
{"j1": load, "j2": load, "j3": None, "j4": None},
|
||||||
|
)
|
||||||
|
running = job(5, kind="test-nostack", task="work/c", status="active")
|
||||||
|
self.assertEqual(
|
||||||
|
self.decide([running, head, twin, gate, light], loaded=loaded, footprints=shares | {"j5": {"ram": 6, "cpu": 11}}, **rules),
|
||||||
|
{
|
||||||
|
"j1": None, "j2": "all 1 quality-high slots taken", "j3": "test runs only beside test-nostack, but quality-high runs",
|
||||||
|
"j4": "CPU 73 % in use or reserved + 40 % > budget 100 %; reserved",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestHistory(unittest.TestCase):
|
class TestHistory(unittest.TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
Reference in new issue
Block a user