blob: a805c70005a168425c893899f3021bef89cd4945 [file] [edit]
############################################################################
# Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
############################################################################
"""Profile GPU columns stay zero for a step without GPU usage samples.
With gres/gpu, gres/gpumem, and gres/gpuutil tracked in
AccountingStorageTRES, slurmstepd resolves both GPU usage TRES positions
and fills the GPUMemMB and GPUUtilization profile columns from the step
usage slots, which JobAcctGatherParams=DisableGPUAcct, with the cgroup
device memory accounting off, leaves at the INFINITE64 no-sample sentinel
whether or not the node has GPUs. Before slurmd 26.11 that sentinel
reached the dataset as a GPUMemMB sample of 17592186044415 (INFINITE64
divided by 1048576). The gres TRES require slurmdbd, so the module needs
accounting and no GPU hardware.
"""
import pytest
import atf
import hdf5_profile
gpu_cols = ["GPUMemMB", "GPUUtilization"]
@pytest.fixture(scope="module", autouse=True)
def setup(hdf5_dir):
atf.require_version(
(26, 11),
"sbin/slurmd",
reason="MR 4338: the profile records unsampled GPU TRES as zero since 26.11",
)
atf.require_config_parameter("AcctGatherProfileType", "acct_gather_profile/hdf5")
atf.require_config_parameter(
"ProfileHDF5Dir",
hdf5_dir,
source="acct_gather",
)
atf.require_config_parameter(
"JobAcctGatherType",
"jobacct_gather/cgroup",
)
# Track the GPU usage TRES so the profile emits both GPU columns from
# the step usage slots. The gres TRES require slurmdbd, so bring
# accounting up first.
atf.require_accounting(modify=True)
atf.require_config_parameter_includes("AccountingStorageTRES", "gres/gpu")
atf.require_config_parameter_includes("AccountingStorageTRES", "gres/gpumem")
atf.require_config_parameter_includes("AccountingStorageTRES", "gres/gpuutil")
# Keep GPU usage samples out of the step usage slots so they hold the
# no-sample sentinel deterministically, with or without GPUs on the node.
atf.require_config_parameter_includes("JobAcctGatherParams", "DisableGPUAcct")
# The cgroup plugin fills the gpumem slot from the dmem controller when
# ConstrainDeviceMemory is on, DisableGPUAcct notwithstanding.
atf.require_config_parameter("ConstrainDeviceMemory", [None, "no"], source="cgroup")
atf.require_slurm_running()
@pytest.fixture(scope="module")
def hdf5_dir():
return hdf5_profile.profile_hdf5_dir()
@pytest.fixture(scope="module")
def user_profile_dir(hdf5_dir):
return hdf5_profile.profile_user_dir(hdf5_dir)
@pytest.fixture(scope="module")
def job_id(user_profile_dir):
yield from hdf5_profile.run_profile_job(user_profile_dir, "test_149_4")
@pytest.fixture(scope="module")
def node_profiles(user_profile_dir, job_id):
return hdf5_profile.wait_for_node_profiles(user_profile_dir, job_id, 1)
@pytest.fixture(scope="module")
def hdf5_file(job_id, node_profiles):
return hdf5_profile.merge_job_profiles(job_id)
def test_gpu_columns_zero_without_gpu_samples(job_id, hdf5_file):
"""GPUMemMB and GPUUtilization are exactly 0 in every profile sample.
Both GPU usage TRES are tracked, so slurmstepd fills both columns of
every sample from the step usage slots, and DisableGPUAcct, with
ConstrainDeviceMemory off, leaves those slots at the INFINITE64 no-sample
sentinel, which hdf5_profile.assert_gpu_columns_zero requires the profile
to record as 0.
"""
rows = hdf5_profile.read_sh5util_csv(
job_id, hdf5_file, "-E --level=Node:TimeSeries", gpu_cols
)
hdf5_profile.assert_gpu_columns_zero(rows)