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

297 lines
9.4 KiB
Python

import os
import sys
from unittest.mock import patch
import pytest
import ray
from ray._private.accelerators import HPUAcceleratorManager, hpu
from ray.util.placement_group import placement_group
from ray.util.scheduling_strategies import PlacementGroupSchedulingStrategy
def test_user_configured_more_than_visible(monkeypatch, call_ray_stop_only):
# Test more hpus are configured than visible.
monkeypatch.setenv("HABANA_VISIBLE_MODULES", "0,1,2")
with pytest.raises(ValueError):
ray.init(resources={"HPU": 4})
@patch(
"ray._private.accelerators.HPUAcceleratorManager.get_current_node_num_accelerators", # noqa: E501
return_value=4,
)
def test_auto_detected_more_than_visible(
mock_get_num_accelerators, monkeypatch, shutdown_only
):
# Test more hpus are detected than visible.
monkeypatch.setenv("HABANA_VISIBLE_MODULES", "0,1,2")
ray.init()
_ = mock_get_num_accelerators.called
assert ray.available_resources()["HPU"] == 3
@patch(
"ray._private.accelerators.HPUAcceleratorManager.get_current_node_num_accelerators", # noqa: E501
return_value=2,
)
def test_auto_detect_resources(mock_get_num_accelerators, shutdown_only):
# Test that ray node resources are filled with auto detected count.
ray.init()
_ = mock_get_num_accelerators.called
assert ray.available_resources()["HPU"] == 2
def test_get_current_process_visible_accelerator_ids():
os.environ[hpu.HABANA_VISIBLE_DEVICES_ENV_VAR] = "0,1,2"
assert HPUAcceleratorManager.get_current_process_visible_accelerator_ids() == [
"0",
"1",
"2",
] # noqa: E501
del os.environ[hpu.HABANA_VISIBLE_DEVICES_ENV_VAR]
assert HPUAcceleratorManager.get_current_process_visible_accelerator_ids() is None
os.environ[hpu.HABANA_VISIBLE_DEVICES_ENV_VAR] = ""
assert HPUAcceleratorManager.get_current_process_visible_accelerator_ids() == []
del os.environ[hpu.HABANA_VISIBLE_DEVICES_ENV_VAR]
def test_set_current_process_visible_accelerator_ids():
HPUAcceleratorManager.set_current_process_visible_accelerator_ids(["0"])
assert os.environ[hpu.HABANA_VISIBLE_DEVICES_ENV_VAR] == "0"
HPUAcceleratorManager.set_current_process_visible_accelerator_ids(["0", "1"])
assert os.environ[hpu.HABANA_VISIBLE_DEVICES_ENV_VAR] == "0,1"
HPUAcceleratorManager.set_current_process_visible_accelerator_ids(["0", "1", "2"])
assert os.environ[hpu.HABANA_VISIBLE_DEVICES_ENV_VAR] == "0,1,2"
del os.environ[hpu.HABANA_VISIBLE_DEVICES_ENV_VAR]
@pytest.mark.parametrize(
"test_config",
[
(1, False),
(0.5, True),
(3, False),
],
)
def test_validate_resource_request_quantity(test_config):
num_hpus, expect_error = test_config
if expect_error:
assert (
HPUAcceleratorManager.validate_resource_request_quantity(num_hpus)[0]
is False
)
assert (
HPUAcceleratorManager.validate_resource_request_quantity(num_hpus)[1]
is not None
)
else:
assert (
HPUAcceleratorManager.validate_resource_request_quantity(num_hpus)[0]
is True
)
assert (
HPUAcceleratorManager.validate_resource_request_quantity(num_hpus)[1]
is None
)
def test_check_accelerator_info():
if HPUAcceleratorManager.is_initialized():
assert (
"Intel-GAUDI" in HPUAcceleratorManager.get_current_node_accelerator_type()
)
else:
assert HPUAcceleratorManager.get_current_node_accelerator_type() is None
assert HPUAcceleratorManager.get_resource_name() == "HPU"
def test_decorator_args():
# This is a valid way of using the decorator.
@ray.remote(resources={"HPU": 1}) # noqa: F811
class Actor: # noqa: F811
def __init__(self):
pass
# This is a valid way of using the decorator.
@ray.remote(num_cpus=1, resources={"HPU": 1}) # noqa: F811
class Actor: # noqa: F811
def __init__(self):
pass
def test_actor_deletion_with_hpus(shutdown_only):
ray.init(num_cpus=1, resources={"HPU": 1})
# When an actor that uses an HPU exits, make sure that the HPU resources
# are released.
@ray.remote(resources={"HPU": 1})
class Actor:
def getpid(self):
return os.getpid()
for _ in range(5):
# If we can successfully create an actor, that means that enough
# HPU resources are available.
a = Actor.remote()
ray.get(a.getpid.remote())
@pytest.mark.skipif(sys.platform == "win32", reason="Failing on Windows.")
def test_actor_hpus(ray_start_cluster):
cluster = ray_start_cluster
num_nodes = 2
num_hpus_per_raylet = 2
for i in range(num_nodes):
cluster.add_node(num_cpus=10 * 2, resources={"HPU": num_hpus_per_raylet})
ray.init(address=cluster.address)
@ray.remote(resources={"HPU": 1})
class Actor1:
def __init__(self):
resource_ids = ray.get_runtime_context().get_accelerator_ids()
self.hpu_ids = resource_ids.get("HPU")
def get_location_and_ids(self):
return (
ray.get_runtime_context().get_node_id(),
tuple(self.hpu_ids),
)
# Create one actor per HPU.
actors = [Actor1.remote() for _ in range(num_nodes * num_hpus_per_raylet)]
# Make sure that no two actors are assigned to the same HPU.
locations_and_ids = ray.get(
[actor.get_location_and_ids.remote() for actor in actors]
)
node_names = {location for location, hpu_id in locations_and_ids}
assert len(node_names) == num_nodes
location_actor_combinations = []
for node_name in node_names:
for hpu_id in range(num_hpus_per_raylet):
location_actor_combinations.append((node_name, (f"{hpu_id}",)))
assert set(locations_and_ids) == set(location_actor_combinations)
# Creating a new actor should fail because all of the HPUs are being
# used.
a = Actor1.remote()
ready_ids, _ = ray.wait([a.get_location_and_ids.remote()], timeout=0.01)
assert ready_ids == []
def test_actor_habana_visible_devices(shutdown_only):
"""Test user can overwrite HABANA_VISIBLE_MODULES
after the actor is created."""
ray.init(resources={"HPU": 1})
@ray.remote(resources={"HPU": 1})
class Actor:
def set_habana_visible_devices(self, habana_visible_devices):
os.environ["HABANA_VISIBLE_MODULES"] = habana_visible_devices
def get_habana_visible_devices(self):
return os.environ["HABANA_VISIBLE_MODULES"]
actor = Actor.remote()
assert ray.get(actor.get_habana_visible_devices.remote()) == "0"
ray.get(actor.set_habana_visible_devices.remote("0,1"))
assert ray.get(actor.get_habana_visible_devices.remote()) == "0,1"
def test_hpu_ids(shutdown_only):
num_hpus = 3
ray.init(num_cpus=num_hpus, resources={"HPU": num_hpus})
def get_hpu_ids(hpus_per_worker):
hpu_ids = ray.get_runtime_context().get_accelerator_ids()["HPU"]
assert len(hpu_ids) == hpus_per_worker
modules = os.environ.get("HABANA_VISIBLE_MODULES")
if modules is not None:
assert modules == ",".join([str(i) for i in hpu_ids]) # noqa
for hpu_id in hpu_ids:
assert hpu_id in [str(i) for i in range(num_hpus)]
return hpu_ids
f0 = ray.remote(resources={"HPU": 0})(lambda: get_hpu_ids(0))
f1 = ray.remote(resources={"HPU": 1})(lambda: get_hpu_ids(1))
list_of_ids = ray.get([f0.remote() for _ in range(10)])
assert list_of_ids == 10 * [[]]
ray.get([f1.remote() for _ in range(10)])
# Test that actors have HABANA_VISIBLE_MODULES set properly.
def _check_hpu_env(expected_num_hpus):
hpu_ids = ray.get_runtime_context().get_accelerator_ids()["HPU"]
assert len(hpu_ids) == expected_num_hpus
if expected_num_hpus > 0:
assert os.environ["HABANA_VISIBLE_MODULES"] == ",".join(
[str(i) for i in hpu_ids] # noqa
)
else:
assert os.environ.get("HABANA_VISIBLE_MODULES") is None
@ray.remote
class Actor:
def __init__(self, num_hpus):
self.num_hpus = num_hpus
_check_hpu_env(num_hpus)
self.x = num_hpus
def test(self):
_check_hpu_env(self.num_hpus)
return self.x
a0 = Actor.remote(0)
assert ray.get(a0.test.remote()) == 0
a1 = Actor.options(resources={"HPU": 1}).remote(1)
assert ray.get(a1.test.remote()) == 1
def test_hpu_with_placement_group(shutdown_only):
num_hpus = 2
ray.init(num_cpus=1, resources={"HPU": num_hpus})
@ray.remote(resources={"HPU": num_hpus})
class HPUActor:
def __init__(self):
pass
def ready(self):
hpu_ids = ray.get_runtime_context().get_accelerator_ids()["HPU"]
assert len(hpu_ids) == num_hpus
assert os.environ["HABANA_VISIBLE_MODULES"] == ",".join(
[str(i) for i in hpu_ids] # noqa
)
# Reserve a placement group of 1 bundle that reserves 1 CPU and 2 HPU.
pg = placement_group([{"CPU": 1, "HPU": num_hpus}])
# Wait until placement group is created.
ray.get(pg.ready(), timeout=10)
actor = HPUActor.options(
scheduling_strategy=PlacementGroupSchedulingStrategy(
placement_group=pg,
)
).remote()
ray.get(actor.ready.remote(), timeout=10)
if __name__ == "__main__":
sys.exit(pytest.main(["-sv", __file__]))