| ############################################################################ | |
| # Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | |
| ############################################################################ | |
| """Overcommit with GRES or mixed tres-per-task. | |
| Ticket 25536: overcommit placement must remain disabled when tres_per_task | |
| includes gres or other non-cpu TRES, even if cpu=N is also present. Only a | |
| cpu-only tres_per_task (e.g. from -cN) is allowed to keep the overcommit | |
| placement path. | |
| """ | |
| import pytest | |
| import atf | |
| @pytest.fixture(scope="module", autouse=True) | |
| def setup(): | |
| atf.require_config_parameter_includes("GresTypes", "gpu") | |
| atf.require_config_parameter("SelectType", "select/cons_tres") | |
| atf.require_config_parameter("SelectTypeParameters", "CR_CPU") | |
| atf.require_nodes(1, [("Gres", "gpu:2"), ("CPUs", 1)]) | |
| for tty_num in range(2): | |
| atf.require_tty(tty_num) | |
| atf.require_config_parameter( | |
| "Name", {"gpu": {"File": "/dev/tty[0-1]"}}, source="gres" | |
| ) | |
| atf.require_slurm_running() | |
| def test_overcommit_gres_per_task(): | |
| """Verify a gres-only tres-per-task request is not overcommit-placed. | |
| On the one-CPU node the two tasks need two CPUs; with overcommit | |
| correctly disabled for gres tres_per_task the request cannot be | |
| satisfied, so sbatch rejects it at submit. | |
| """ | |
| atf.run_command( | |
| "sbatch -N1 -n2 -O --tres-per-task=gres/gpu:1 -t1 --wrap '/bin/true'", | |
| xfail=True, | |
| fatal=True, | |
| ) | |
| @pytest.mark.xfail( | |
| atf.get_version("sbin/slurmctld") < (25, 5), | |
| reason="Ticket 21764: Issue with cpus_per_task not set from tres_per_task. Fixed in 25.05.", | |
| ) | |
| def test_overcommit_mixed_tres_per_task(): | |
| """Verify mixed cpu+gres tres-per-task keeps overcommit placement disabled. | |
| The cpu=1 component alone would keep the overcommit path, but the gres | |
| component must disable it, so the job is accepted yet never placed. | |
| """ | |
| job_id = atf.submit_job_sbatch( | |
| "-N1 -n2 -O --tres-per-task=cpu=1,gres/gpu:1 -t1 --wrap '/bin/true'", | |
| fatal=True, | |
| ) | |
| # Bounded negative wait: the job must never complete, so cap the wait | |
| # instead of using atf's longer default. | |
| assert not atf.wait_for_job_state( | |
| job_id, "COMPLETED", timeout=15 | |
| ), "mixed tres_per_task must not get the overcommit placement path" |