Files
2026-07-13 13:17:40 +08:00

152 lines
4.7 KiB
Python

from unittest import mock
import ray
from ray.tests.conftest import * # noqa
from ray.tune.utils.resource_updater import _Resources, _ResourceUpdater
def test_resources_numerical_error():
resource = _Resources(cpu=0.99, gpu=0.99, custom_resources={"a": 0.99})
small_resource = _Resources(cpu=0.33, gpu=0.33, custom_resources={"a": 0.33})
for i in range(3):
resource = _Resources.subtract(resource, small_resource)
assert resource.is_nonnegative()
def test_resources_subtraction():
resource_1 = _Resources(
1,
0,
0,
1,
custom_resources={"a": 1, "b": 2},
extra_custom_resources={"a": 1, "b": 1},
)
resource_2 = _Resources(
1,
0,
0,
1,
custom_resources={"a": 1, "b": 2},
extra_custom_resources={"a": 1, "b": 1},
)
new_res = _Resources.subtract(resource_1, resource_2)
assert new_res.cpu == 0
assert new_res.gpu == 0
assert new_res.extra_cpu == 0
assert new_res.extra_gpu == 0
assert all(k == 0 for k in new_res.custom_resources.values())
assert all(k == 0 for k in new_res.extra_custom_resources.values())
def test_resources_different():
resource_1 = _Resources(1, 0, 0, 1, custom_resources={"a": 1, "b": 2})
resource_2 = _Resources(1, 0, 0, 1, custom_resources={"a": 1, "c": 2})
new_res = _Resources.subtract(resource_1, resource_2)
assert "c" in new_res.custom_resources
assert "b" in new_res.custom_resources
assert new_res.cpu == 0
assert new_res.gpu == 0
assert new_res.extra_cpu == 0
assert new_res.extra_gpu == 0
assert new_res.get("a") == 0
def test_resource_updater(ray_start_cluster):
cluster = ray_start_cluster
resource_updater = _ResourceUpdater(refresh_period=100)
# Before initialization, all resources are 0.
assert resource_updater.get_num_cpus() == 0
assert resource_updater.get_num_gpus() == 0
cluster.add_node(num_cpus=1, num_gpus=2)
cluster.wait_for_nodes()
ray.init(address=cluster.address)
# Resource updater will update resource immediately
# after ray is initialized for the first time.
assert resource_updater.get_num_cpus() == 1
assert resource_updater.get_num_gpus() == 2
# It will not update the resource before "refresh_period".
cluster.add_node(num_cpus=1, num_gpus=1)
cluster.wait_for_nodes()
assert resource_updater.get_num_cpus() == 1
assert resource_updater.get_num_gpus() == 2
resource_updater = _ResourceUpdater(refresh_period=0)
assert resource_updater.get_num_cpus() == 2
assert resource_updater.get_num_gpus() == 3
cluster.add_node(num_cpus=1, num_gpus=1)
cluster.wait_for_nodes()
assert resource_updater.get_num_cpus() == 3
assert resource_updater.get_num_gpus() == 4
def test_resource_updater_automatic():
"""Test that resources are automatically updated when they get out of sync.
We instantiate a resource updater. When the reported resources are less than
what is available, we don't force an update.
However, if any of the resources (cpu, gpu, or custom) are higher than what
the updater currently think is available, we force an update from the
Ray cluster.
"""
resource_updater = _ResourceUpdater()
resource_updater._avail_resources = _Resources(
cpu=2,
gpu=1,
memory=1,
object_store_memory=1,
custom_resources={"a": 4},
)
resource_updater._last_resource_refresh = 2
# Should not trigger
with mock.patch.object(
_ResourceUpdater,
"update_avail_resources",
wraps=resource_updater.update_avail_resources,
) as upd:
# No update
assert "2/2 CPUs" in resource_updater.debug_string(
total_allocated_resources={"CPU": 2, "GPU": 1, "a": 4}
)
assert upd.call_count == 0
# Too many CPUs
assert "4/2 CPUs" in resource_updater.debug_string(
total_allocated_resources={"CPU": 4, "GPU": 1, "a": 0}
)
assert upd.call_count == 1
# Too many GPUs
assert "8/1 GPUs" in resource_updater.debug_string(
total_allocated_resources={"CPU": 2, "GPU": 8, "a": 0}
)
assert upd.call_count == 2
# Too many `a`
assert "6/4 a" in resource_updater.debug_string(
total_allocated_resources={"CPU": 2, "GPU": 1, "a": 6}
)
assert upd.call_count == 3
# No update again
assert "2/2 CPUs" in resource_updater.debug_string(
total_allocated_resources={"CPU": 2, "GPU": 1, "a": 4}
)
assert upd.call_count == 3
if __name__ == "__main__":
import sys
import pytest
sys.exit(pytest.main(["-v", __file__]))