gpu-scheduler-openenv / tests /test_simulator.py
SulmanK's picture
Restore full project documentation and add Hugging Face Space integration
09f204f
Raw
History Blame Contribute Delete
3.85 kB
from env.models import SchedulingAction
from env.simulator import GPUSchedulingSimulator
def test_valid_assignment_completes_job():
simulator = GPUSchedulingSimulator.from_hand_authored("deadline_crunch")
result = simulator.step(
SchedulingAction(
action="place",
job_id="req-4",
gpu_id="small-1",
rationale="Short urgent job fits and should clear quickly.",
)
)
assert result.score > 0
assert simulator.jobs["req-4"].status == "completed"
assert simulator.metrics.completed_jobs == 1
def test_invalid_assignment_is_penalized():
simulator = GPUSchedulingSimulator.from_hand_authored("deadline_crunch")
result = simulator.step(
SchedulingAction(
action="place",
job_id="req-5",
gpu_id="small-1",
rationale="This should fail due to VRAM pressure.",
)
)
assert result.score < 0
assert simulator.metrics.invalid_actions == 1
assert simulator.jobs["req-5"].status == "pending"
def test_defer_advances_time():
simulator = GPUSchedulingSimulator.from_hand_authored("deadline_crunch")
initial_tick = simulator.current_tick
result = simulator.step(SchedulingAction(action="defer", rationale="Holding for a better placement."))
assert result.observation.current_tick == initial_tick + 1
assert simulator.metrics.total_reward == result.score
def test_wait_can_outperform_greedy_large_gpu_assignment():
waiting_simulator = GPUSchedulingSimulator.from_hand_authored("wait_for_capacity")
greedy_simulator = GPUSchedulingSimulator.from_hand_authored("wait_for_capacity")
defer_result = waiting_simulator.step(
SchedulingAction(
action="defer",
rationale="Cheaper capacity frees next step, so paying for the large GPU now is wasteful.",
)
)
greedy_result = greedy_simulator.step(
SchedulingAction(
action="place",
job_id="queued-b",
gpu_id="large-1",
rationale="Use the only idle GPU immediately.",
)
)
assert defer_result.score > greedy_result.score
assert waiting_simulator.jobs["queued-b"].status == "pending"
assert greedy_simulator.jobs["queued-b"].status == "running"
def test_wait_can_preserve_large_gpu_for_visible_heavy_workload():
waiting_simulator = GPUSchedulingSimulator.from_hand_authored("reserve_large_gpu")
greedy_simulator = GPUSchedulingSimulator.from_hand_authored("reserve_large_gpu")
defer_result = waiting_simulator.step(
SchedulingAction(
action="defer",
rationale="Hold the expensive large GPU until the cheaper GPUs finish warmup.",
)
)
greedy_result = greedy_simulator.step(
SchedulingAction(
action="place",
job_id="reserve-small",
gpu_id="large-1",
rationale="Use the only idle GPU immediately.",
)
)
assert defer_result.score > greedy_result.score
assert waiting_simulator.jobs["reserve-heavy"].status == "pending"
assert greedy_simulator.jobs["reserve-small"].status == "running"
def test_seeded_scenario_is_deterministic():
sim_a = GPUSchedulingSimulator.from_seed(42)
sim_b = GPUSchedulingSimulator.from_seed(42)
assert sim_a.observe().model_dump() == sim_b.observe().model_dump()
def test_scenario_terminates_after_jobs_resolve():
simulator = GPUSchedulingSimulator.from_hand_authored("deadline_crunch")
done = False
while not done:
result = simulator.step(SchedulingAction(action="defer", rationale="Let the pending queue age."))
done = result.done
assert simulator.current_tick <= simulator.tick_limit
assert all(job.status in {"completed", "missed"} for job in simulator.jobs.values())