def test_args_stars_after(ray_start_shared_local_modes): def star_args_after(a="hello", b="heo", *args, **kwargs): return a, b, args, kwargs class TestActor: def star_args_after(self, a="hello", b="heo", *args, **kwargs): return a, b, args, kwargs def test_function(fn, remote_fn): assert fn("hi", "hello", 2) == ray.get(remote_fn.remote("hi", "hello", 2)) assert fn("hi", "hello", 2, hi="hi") == ray.get( remote_fn.remote("hi", "hello", 2, hi="hi")) assert fn(hi="hi") == ray.get(remote_fn.remote(hi="hi")) remote_test_function = ray.remote(test_function) remote_star_args_after = ray.remote(star_args_after) test_function(star_args_after, remote_star_args_after) ray.get( remote_test_function.remote(star_args_after, remote_star_args_after)) remote_actor_class = ray.remote(TestActor) remote_actor = remote_actor_class.remote() actor_method = remote_actor.star_args_after local_actor = TestActor() local_method = local_actor.star_args_after test_function(local_method, actor_method) ray.get(remote_test_function.remote(local_method, actor_method))
def test_wait(ray_start_regular_shared): with ray_start_client_server() as ray: objectref = ray.put("hello world") ready, remaining = ray.wait([objectref]) assert remaining == [] retval = ray.get(ready[0]) assert retval == "hello world" objectref2 = ray.put(5) ready, remaining = ray.wait([objectref, objectref2]) assert (ready, remaining) == ([objectref], [objectref2]) or \ (ready, remaining) == ([objectref2], [objectref]) ready_retval = ray.get(ready[0]) remaining_retval = ray.get(remaining[0]) assert (ready_retval, remaining_retval) == ("hello world", 5) \ or (ready_retval, remaining_retval) == (5, "hello world") with pytest.raises(Exception): # Reference not in the object store. ray.wait([ClientObjectRef("blabla")]) with pytest.raises(AssertionError): ray.wait("blabla") with pytest.raises(AssertionError): ray.wait(ClientObjectRef("blabla")) with pytest.raises(AssertionError): ray.wait(["blabla"])
def test_duplicate_args(ray_start_regular_shared): @ray.remote def f(arg1, arg2, arg1_duplicate, kwarg1=None, kwarg2=None, kwarg1_duplicate=None): assert arg1 == kwarg1 assert arg1 != arg2 assert arg1 == arg1_duplicate assert kwarg1 != kwarg2 assert kwarg1 == kwarg1_duplicate # Test by-value arguments. arg1 = [1] arg2 = [2] ray.get( f.remote( arg1, arg2, arg1, kwarg1=arg1, kwarg2=arg2, kwarg1_duplicate=arg1)) # Test by-reference arguments. arg1 = ray.put([1]) arg2 = ray.put([2]) ray.get( f.remote( arg1, arg2, arg1, kwarg1=arg1, kwarg2=arg2, kwarg1_duplicate=arg1))
def test_custom_classes(ray_start_regular_shared): class Foo: def __init__(self, x): self.x = x @ray.remote class Actor: def __init__(self, f2): self.f1 = Foo(1) self.f2 = f2 def get_values1(self): return self.f1, self.f2 def get_values2(self, f3): return self.f1, self.f2, f3 actor = Actor.remote(Foo(2)) results1 = ray.get(actor.get_values1.remote()) assert results1[0].x == 1 assert results1[1].x == 2 results2 = ray.get(actor.get_values2.remote(Foo(3))) assert results2[0].x == 1 assert results2[1].x == 2 assert results2[2].x == 3
def check(source_actor, dest_actor, is_large, out_of_band): print("CHECKING", "actor" if source_actor else "task", "to", "actor" if dest_actor else "task", "large_object" if is_large else "small_object", "out_of_band" if out_of_band else "in_band") if source_actor: a = Actor.remote() if is_large: x_id = a.large_value.remote() else: x_id = a.small_value.remote() else: if is_large: x_id = large_value.remote() else: x_id = small_value.remote() if out_of_band: x_id = [x_id] if dest_actor: b = Actor.remote() x = ray.get(b.echo.remote(x_id)) else: x = ray.get(echo.remote(x_id)) if is_large: assert isinstance(x, np.ndarray) else: assert isinstance(x, int)
def test_inherit_actor_from_class(ray_start_regular_shared): # Make sure we can define an actor by inheriting from a regular class. # Note that actors cannot inherit from other actors. class Foo: def __init__(self, x): self.x = x def f(self): return self.x def g(self, y): return self.x + y @ray.remote class Actor(Foo): def __init__(self, x): Foo.__init__(self, x) def get_value(self): return self.f() actor = Actor.remote(1) assert ray.get(actor.get_value.remote()) == 1 assert ray.get(actor.g.remote(5)) == 6
def test_actor_pass_by_ref(ray_start_regular_shared): @ray.remote class Actor: def __init__(self): pass def f(self, x): return x * 2 @ray.remote def f(x): return x @ray.remote def error(): sys.exit(0) a = Actor.remote() assert ray.get(a.f.remote(f.remote(1))) == 2 fut = [a.f.remote(f.remote(i)) for i in range(100)] assert ray.get(fut) == [i * 2 for i in range(100)] # propagates errors for pass by ref with pytest.raises(Exception): ray.get(a.f.remote(error.remote()))
def test_wait(ray_start_regular_shared): server = ray_client_server.serve("localhost:50051", test_mode=True) ray.connect("localhost:50051") objectref = ray.put("hello world") ready, remaining = ray.wait([objectref]) assert remaining == [] retval = ray.get(ready[0]) assert retval == "hello world" objectref2 = ray.put(5) ready, remaining = ray.wait([objectref, objectref2]) assert (ready, remaining) == ([objectref], [objectref2]) or \ (ready, remaining) == ([objectref2], [objectref]) ready_retval = ray.get(ready[0]) remaining_retval = ray.get(remaining[0]) assert (ready_retval, remaining_retval) == ("hello world", 5) \ or (ready_retval, remaining_retval) == (5, "hello world") with pytest.raises(Exception): # Reference not in the object store. ray.wait([ClientObjectRef("blabla")]) with pytest.raises(AssertionError): ray.wait("blabla") with pytest.raises(AssertionError): ray.wait(ClientObjectRef("blabla")) with pytest.raises(AssertionError): ray.wait(["blabla"]) ray.disconnect() server.stop(0)
def test_actor_pass_by_ref_order_optimization(shutdown_only): ray.init(num_cpus=4) @ray.remote class Actor: def __init__(self): pass def f(self, x): pass a = Actor.remote() @ray.remote def fast_value(): print("fast value") pass @ray.remote def slow_value(): print("start sleep") time.sleep(30) @ray.remote def runner(f): print("runner", a, f) return ray.get(a.f.remote(f.remote())) runner.remote(slow_value) time.sleep(1) x2 = runner.remote(fast_value) start = time.time() ray.get(x2) delta = time.time() - start assert delta < 10, "did not skip slow value"
def test_args_starkwargs(ray_start_shared_local_modes): def starkwargs(a, b, **kwargs): return a, b, kwargs class TestActor: def starkwargs(self, a, b, **kwargs): return a, b, kwargs def test_function(fn, remote_fn): assert fn(1, 2, x=3) == ray.get(remote_fn.remote(1, 2, x=3)) with pytest.raises(TypeError): remote_fn.remote(3) remote_test_function = ray.remote(test_function) remote_starkwargs = ray.remote(starkwargs) test_function(starkwargs, remote_starkwargs) ray.get(remote_test_function.remote(starkwargs, remote_starkwargs)) remote_actor_class = ray.remote(TestActor) remote_actor = remote_actor_class.remote() actor_method = remote_actor.starkwargs local_actor = TestActor() local_method = local_actor.starkwargs test_function(local_method, actor_method) ray.get(remote_test_function.remote(local_method, actor_method))
def test_args_named_and_star(ray_start_shared_local_modes): def hello(a, x="hello", **kwargs): return a, x, kwargs class TestActor: def hello(self, a, x="hello", **kwargs): return a, x, kwargs def test_function(fn, remote_fn): assert fn(1, x=2, y=3) == ray.get(remote_fn.remote(1, x=2, y=3)) assert fn(1, 2, y=3) == ray.get(remote_fn.remote(1, 2, y=3)) assert fn(1, y=3) == ray.get(remote_fn.remote(1, y=3)) assert fn(1, ) == ray.get(remote_fn.remote(1, )) assert fn(1) == ray.get(remote_fn.remote(1)) with pytest.raises(TypeError): remote_fn.remote(1, 2, x=3) remote_test_function = ray.remote(test_function) remote_hello = ray.remote(hello) test_function(hello, remote_hello) ray.get(remote_test_function.remote(hello, remote_hello)) remote_actor_class = ray.remote(TestActor) remote_actor = remote_actor_class.remote() actor_method = remote_actor.hello local_actor = TestActor() local_method = local_actor.hello test_function(local_method, actor_method) ray.get(remote_test_function.remote(local_method, actor_method))
def test_wait_makes_object_local(ray_start_cluster): cluster = ray_start_cluster cluster.add_node(num_cpus=0) cluster.add_node(num_cpus=2) ray.init(address=cluster.address) @ray.remote class Foo: def method(self): return np.zeros(1024 * 1024) a = Foo.remote() # Test get makes the object local. x_id = a.method.remote() assert not ray.worker.global_worker.core_worker.object_exists(x_id) ray.get(x_id) assert ray.worker.global_worker.core_worker.object_exists(x_id) # Test wait makes the object local. x_id = a.method.remote() assert not ray.worker.global_worker.core_worker.object_exists(x_id) ok, _ = ray.wait([x_id]) assert len(ok) == 1 assert ray.worker.global_worker.core_worker.object_exists(x_id)
def test_running_function_on_all_workers(ray_start_regular): def f(worker_info): sys.path.append("fake_directory") ray.worker.global_worker.run_function_on_all_workers(f) @ray.remote def get_path1(): return sys.path assert "fake_directory" == ray.get(get_path1.remote())[-1] def f(worker_info): sys.path.pop(-1) ray.worker.global_worker.run_function_on_all_workers(f) # Create a second remote function to guarantee that when we call # get_path2.remote(), the second function to run will have been run on # the worker. @ray.remote def get_path2(): return sys.path assert "fake_directory" not in ray.get(get_path2.remote())
def test_multiple_waits_and_gets(shutdown_only): # It is important to use three workers here, so that the three tasks # launched in this experiment can run at the same time. ray.init(num_cpus=3) @ray.remote def f(delay): time.sleep(delay) return 1 @ray.remote def g(input_list): # The argument input_list should be a list containing one object ref. ray.wait([input_list[0]]) @ray.remote def h(input_list): # The argument input_list should be a list containing one object ref. ray.get(input_list[0]) # Make sure that multiple wait requests involving the same object ref # all return. x = f.remote(1) ray.get([g.remote([x]), g.remote([x])]) # Make sure that multiple get requests involving the same object ref all # return. x = f.remote(1) ray.get([h.remote([x]), h.remote([x])])
def test_ray_options(shutdown_only): ray.init(num_cpus=10, num_gpus=10, resources={"custom1": 2}) @ray.remote(num_cpus=2, num_gpus=3, memory=150 * 2**20, resources={"custom1": 1}) def foo(): import time # Sleep for a heartbeat period to ensure resources changing reported. time.sleep(0.1) return ray.available_resources() without_options = ray.get(foo.remote()) with_options = ray.get( foo.options(num_cpus=3, num_gpus=4, memory=50 * 2**20, resources={ "custom1": 0.5 }).remote()) to_check = ["CPU", "GPU", "memory", "custom1"] for key in to_check: assert without_options[key] != with_options[key], key assert without_options != with_options
def test_put_get(shutdown_only): ray.init(num_cpus=0) for i in range(100): value_before = i * 10**6 object_ref = ray.put(value_before) value_after = ray.get(object_ref) assert value_before == value_after for i in range(100): value_before = i * 10**6 * 1.0 object_ref = ray.put(value_before) value_after = ray.get(object_ref) assert value_before == value_after for i in range(100): value_before = "h" * i object_ref = ray.put(value_before) value_after = ray.get(object_ref) assert value_before == value_after for i in range(100): value_before = [1] * i object_ref = ray.put(value_before) value_after = ray.get(object_ref) assert value_before == value_after
def test_distributed_actor_handle_deletion(ray_start_regular_shared): @ray.remote class Actor: def method(self): return 1 def getpid(self): return os.getpid() @ray.remote def f(actor, signal): ray.get(signal.wait.remote()) return ray.get(actor.method.remote()) SignalActor = create_remote_signal_actor(ray) signal = SignalActor.remote() a = Actor.remote() pid = ray.get(a.getpid.remote()) # Pass the handle to another task that cannot run yet. x_id = f.remote(a, signal) # Delete the original handle. The actor should not get killed yet. del a # Once the task finishes, the actor process should get killed. ray.get(signal.send.remote()) assert ray.get(x_id) == 1 wait_for_pid_to_exit(pid)
def test_multiple_return_values(ray_start_regular_shared): @ray.remote class Foo: def method0(self): return 1 @ray.method(num_returns=1) def method1(self): return 1 @ray.method(num_returns=2) def method2(self): return 1, 2 @ray.method(num_returns=3) def method3(self): return 1, 2, 3 f = Foo.remote() id0 = f.method0.remote() assert ray.get(id0) == 1 id1 = f.method1.remote() assert ray.get(id1) == 1 id2a, id2b = f.method2.remote() assert ray.get([id2a, id2b]) == [1, 2] id3a, id3b, id3c = f.method3.remote() assert ray.get([id3a, id3b, id3c]) == [1, 2, 3]
def f(block, accepted_resources): true_resources = { resource: value[0][1] for resource, value in ray.get_resource_ids().items() } if block: ray.get(g.remote()) return dicts_equal(true_resources, accepted_resources)
def testNoArgs(self): @ray.remote def no_op(): pass self.ray_start() ray.get(no_op.remote())
def test_get_multiple(ray_start_regular_shared): object_refs = [ray.put(i) for i in range(10)] assert ray.get(object_refs) == list(range(10)) # Get a random choice of object refs with duplicates. indices = list(np.random.choice(range(10), 5)) indices += indices results = ray.get([object_refs[i] for i in indices]) assert results == indices
def test_illegal_api_calls(ray_start_regular): # Verify that we cannot call put on an ObjectRef. x = ray.put(1) with pytest.raises(Exception): ray.put(x) # Verify that we cannot call get on a regular value. with pytest.raises(Exception): ray.get(3)
def test_function(fn, remote_fn): assert fn(1, x=2, y=3) == ray.get(remote_fn.remote(1, x=2, y=3)) assert fn(1, 2, y=3) == ray.get(remote_fn.remote(1, 2, y=3)) assert fn(1, y=3) == ray.get(remote_fn.remote(1, y=3)) assert fn(1, ) == ray.get(remote_fn.remote(1, )) assert fn(1) == ray.get(remote_fn.remote(1)) with pytest.raises(TypeError): remote_fn.remote(1, 2, x=3)
def test_options_name(ray_start_regular_shared): @ray.remote class Foo: def method(self, name): assert setproctitle.getproctitle() == f"ray::{name}" f = Foo.remote() ray.get(f.method.options(name="foo").remote("foo")) ray.get(f.method.options(name="bar").remote("bar"))
def test_passing_arguments_by_value_out_of_the_box( ray_start_shared_local_modes): @ray.remote def f(x): return x # Test passing lambdas. def temp(): return 1 assert ray.get(f.remote(temp))() == 1 assert ray.get(f.remote(lambda x: x + 1))(3) == 4 # Test sets. assert ray.get(f.remote(set())) == set() s = {1, (1, 2, "hi")} assert ray.get(f.remote(s)) == s # Test types. assert ray.get(f.remote(int)) == int assert ray.get(f.remote(float)) == float assert ray.get(f.remote(str)) == str class Foo: def __init__(self): pass # Make sure that we can put and get a custom type. Note that the result # won't be "equal" to Foo. ray.get(ray.put(Foo))
def test_grpc_message_size(shutdown_only): ray.init(num_cpus=1) @ray.remote def bar(*a): return # 50KiB, not enough to spill to plasma, but will be inlined. def f(): return np.zeros(50000, dtype=np.uint8) # Executes a 10MiB task spec ray.get(bar.remote(*[f() for _ in range(200)]))
def test_options_num_returns(ray_start_regular_shared): @ray.remote class Foo: def method(self): return 1, 2 f = Foo.remote() obj = f.method.remote() assert ray.get(obj) == (1, 2) obj1, obj2 = f.method.options(num_returns=2).remote() assert ray.get([obj1, obj2]) == [1, 2]
def test_internal_free(shutdown_only): ray.init(num_cpus=1) @ray.remote class Sampler: def sample(self): return [1, 2, 3, 4, 5] def sample_big(self): return np.zeros(1024 * 1024) sampler = Sampler.remote() # Free deletes from in-memory store. obj_ref = sampler.sample.remote() ray.get(obj_ref) ray.internal.free(obj_ref) with pytest.raises(Exception): ray.get(obj_ref) # Free deletes big objects from plasma store. big_id = sampler.sample_big.remote() ray.get(big_id) ray.internal.free(big_id) time.sleep(1) # wait for delete RPC to propagate with pytest.raises(Exception): ray.get(big_id)
def test_submit_api(shutdown_only): ray.init(num_cpus=2, num_gpus=1, resources={"Custom": 1}) @ray.remote def f(n): return list(range(n)) @ray.remote def g(): return ray.get_gpu_ids() assert f._remote([0], num_returns=0) is None id1 = f._remote(args=[1], num_returns=1) assert ray.get(id1) == [0] id1, id2 = f._remote(args=[2], num_returns=2) assert ray.get([id1, id2]) == [0, 1] id1, id2, id3 = f._remote(args=[3], num_returns=3) assert ray.get([id1, id2, id3]) == [0, 1, 2] assert ray.get( g._remote(args=[], num_cpus=1, num_gpus=1, resources={"Custom": 1})) == [0] infeasible_id = g._remote(args=[], resources={"NonexistentCustom": 1}) assert ray.get(g._remote()) == [] ready_ids, remaining_ids = ray.wait([infeasible_id], timeout=0.05) assert len(ready_ids) == 0 assert len(remaining_ids) == 1 @ray.remote class Actor: def __init__(self, x, y=0): self.x = x self.y = y def method(self, a, b=0): return self.x, self.y, a, b def gpu_ids(self): return ray.get_gpu_ids() @ray.remote class Actor2: def __init__(self): pass def method(self): pass a = Actor._remote(args=[0], kwargs={"y": 1}, num_gpus=1, resources={"Custom": 1}) a2 = Actor2._remote() ray.get(a2.method._remote()) id1, id2, id3, id4 = a.method._remote(args=["test"], kwargs={"b": 2}, num_returns=4) assert ray.get([id1, id2, id3, id4]) == [0, 1, "test", 2]
def test_actor_creation_latency(ray_start_regular_shared): # This test is just used to test the latency of actor creation. @ray.remote class Actor: def get_value(self): return 1 start = datetime.datetime.now() actor_handles = [Actor.remote() for _ in range(100)] actor_create_time = datetime.datetime.now() for actor_handle in actor_handles: ray.get(actor_handle.get_value.remote()) end = datetime.datetime.now() print("actor_create_time_consume = {}, total_time_consume = {}".format( actor_create_time - start, end - start))