Ray, Tune, and RLlib support for memory, object_store_memory options (#5226)

This commit is contained in:
Eric Liang
2019-08-22 14:01:10 +08:00
committed by Robert Nishihara
parent c852213b83
commit e2e30ca507
40 changed files with 1006 additions and 296 deletions
+2 -2
View File
@@ -62,7 +62,7 @@ class Cluster(object):
All nodes are by default started with the following settings:
cleanup=True,
num_cpus=1,
object_store_memory=100 * (2**20) # 100 MB
object_store_memory=150 * 1024 * 1024 # 150 MiB
Args:
node_args: Keyword arguments used in `start_ray_head` and
@@ -74,7 +74,7 @@ class Cluster(object):
default_kwargs = {
"num_cpus": 1,
"num_gpus": 0,
"object_store_memory": 100 * (2**20), # 100 MB
"object_store_memory": 150 * 1024 * 1024, # 150 MiB
}
ray_params = ray.parameter.RayParams(**node_args)
ray_params.update_if_absent(**default_kwargs)
+1 -1
View File
@@ -38,7 +38,7 @@ def get_default_fixture_ray_kwargs():
internal_config = get_default_fixure_internal_config()
ray_kwargs = {
"num_cpus": 1,
"object_store_memory": 10**8,
"object_store_memory": 150 * 1024 * 1024,
"_internal_config": internal_config,
}
return ray_kwargs
@@ -37,7 +37,9 @@ def warmup():
def test_task_submission(benchmark, num_tasks):
num_cpus = 16
ray.init(
num_cpus=num_cpus, object_store_memory=10**7, ignore_reinit_error=True)
num_cpus=num_cpus,
object_store_memory=150 * 1024 * 1024,
ignore_reinit_error=True)
# warm up the plasma store
warmup()
benchmark(benchmark_task_submission, num_tasks)
@@ -57,11 +59,11 @@ def test_task_forward(benchmark, num_tasks):
do_init=True,
num_nodes=1,
num_cpus=16,
object_store_memory=10**7,
object_store_memory=150 * 1024 * 1024,
) as cluster:
cluster.add_node(
num_cpus=16,
object_store_memory=10**7,
object_store_memory=150 * 1024 * 1024,
resources={"my_resource": 100},
)
+9 -6
View File
@@ -444,7 +444,8 @@ def test_actor_deletion(ray_start_regular):
def test_actor_deletion_with_gpus(shutdown_only):
ray.init(num_cpus=1, num_gpus=1, object_store_memory=int(10**8))
ray.init(
num_cpus=1, num_gpus=1, object_store_memory=int(150 * 1024 * 1024))
# When an actor that uses a GPU exits, make sure that the GPU resources
# are released.
@@ -516,7 +517,7 @@ def test_resource_assignment(shutdown_only):
num_cpus=16,
num_gpus=1,
resources={"Custom": 1},
object_store_memory=int(10**8))
object_store_memory=int(150 * 1024 * 1024))
class Actor(object):
def __init__(self):
@@ -1296,7 +1297,8 @@ def test_actors_and_tasks_with_gpus(ray_start_cluster):
def test_actors_and_tasks_with_gpus_version_two(shutdown_only):
# Create tasks and actors that both use GPUs and make sure that they
# are given different GPUs
ray.init(num_cpus=10, num_gpus=10, object_store_memory=int(10**8))
ray.init(
num_cpus=10, num_gpus=10, object_store_memory=int(150 * 1024 * 1024))
@ray.remote(num_gpus=1)
def f():
@@ -1330,7 +1332,8 @@ def test_actors_and_tasks_with_gpus_version_two(shutdown_only):
def test_blocking_actor_task(shutdown_only):
ray.init(num_cpus=1, num_gpus=1, object_store_memory=int(10**8))
ray.init(
num_cpus=1, num_gpus=1, object_store_memory=int(150 * 1024 * 1024))
@ray.remote(num_gpus=1)
def f():
@@ -1740,7 +1743,7 @@ def test_nondeterministic_reconstruction_concurrent_forks(
@pytest.fixture
def setup_queue_actor():
ray.init(num_cpus=1, object_store_memory=int(10**8))
ray.init(num_cpus=1, object_store_memory=int(150 * 1024 * 1024))
@ray.remote
class Queue(object):
@@ -2105,7 +2108,7 @@ def test_creating_more_actors_than_resources(shutdown_only):
@pytest.mark.parametrize(
"ray_start_object_store_memory", [10**8], indirect=True)
"ray_start_object_store_memory", [150 * 1024 * 1024], indirect=True)
def test_actor_eviction(ray_start_object_store_memory):
object_store_memory = ray_start_object_store_memory
+11 -9
View File
@@ -967,11 +967,9 @@ def test_many_fractional_resources(shutdown_only):
stop_time = time.time() + 10
correct_available_resources = False
while time.time() < stop_time:
if ray.available_resources() == {
"CPU": 2.0,
"GPU": 2.0,
"Custom": 2.0,
}:
if (ray.available_resources()["CPU"] == 2.0
and ray.available_resources()["GPU"] == 2.0
and ray.available_resources()["Custom"] == 2.0):
correct_available_resources = True
break
if not correct_available_resources:
@@ -2324,6 +2322,9 @@ def test_zero_capacity_deletion_semantics(shutdown_only):
MAX_RETRY_ATTEMPTS = 5
retry_count = 0
del resources["memory"]
del resources["object_store_memory"]
while resources and retry_count < MAX_RETRY_ATTEMPTS:
time.sleep(0.1)
resources = ray.available_resources()
@@ -2537,8 +2538,9 @@ def test_global_state_api(shutdown_only):
ray.init(num_cpus=5, num_gpus=3, resources={"CustomResource": 1})
resources = {"CPU": 5, "GPU": 3, "CustomResource": 1}
assert ray.cluster_resources() == resources
assert ray.cluster_resources()["CPU"] == 5
assert ray.cluster_resources()["GPU"] == 3
assert ray.cluster_resources()["CustomResource"] == 1
assert ray.objects() == {}
@@ -2807,7 +2809,7 @@ def test_initialized_local_mode(shutdown_only_with_initialization_check):
def test_wait_reconstruction(shutdown_only):
ray.init(num_cpus=1, object_store_memory=10**8)
ray.init(num_cpus=1, object_store_memory=int(10**8))
@ray.remote
def f():
@@ -3025,7 +3027,7 @@ def test_shutdown_disconnect_global_state():
@pytest.mark.parametrize(
"ray_start_object_store_memory", [10**8], indirect=True)
"ray_start_object_store_memory", [150 * 1024 * 1024], indirect=True)
def test_redis_lru_with_set(ray_start_object_store_memory):
x = np.zeros(8 * 10**7, dtype=np.uint8)
x_id = ray.put(x)
+1 -1
View File
@@ -16,7 +16,7 @@ def get_ray_result(cython_func, *args):
class CythonTest(unittest.TestCase):
def setUp(self):
ray.init(object_store_memory=int(10**8))
ray.init(object_store_memory=int(150 * 1024 * 1024))
def tearDown(self):
ray.shutdown()
+5 -5
View File
@@ -725,7 +725,7 @@ def test_connect_with_disconnected_node(shutdown_only):
@pytest.mark.parametrize(
"ray_start_cluster_head", [{
"num_cpus": 5,
"object_store_memory": 10**7
"object_store_memory": 10**8
}],
indirect=True)
@pytest.mark.parametrize("num_actors", [1, 2, 5])
@@ -733,7 +733,7 @@ def test_parallel_actor_fill_plasma_retry(ray_start_cluster_head, num_actors):
@ray.remote
class LargeMemoryActor(object):
def some_expensive_task(self):
return np.zeros(10**7 // 2, dtype=np.uint8)
return np.zeros(10**8 // 2, dtype=np.uint8)
actors = [LargeMemoryActor.remote() for _ in range(num_actors)]
for _ in range(10):
@@ -745,14 +745,14 @@ def test_parallel_actor_fill_plasma_retry(ray_start_cluster_head, num_actors):
@pytest.mark.parametrize(
"ray_start_cluster_head", [{
"num_cpus": 2,
"object_store_memory": 10**7
"object_store_memory": 10**8
}],
indirect=True)
def test_fill_plasma_exception(ray_start_cluster_head):
@ray.remote
class LargeMemoryActor(object):
def some_expensive_task(self):
return np.zeros(10**7 + 2, dtype=np.uint8)
return np.zeros(10**8 + 2, dtype=np.uint8)
def test(self):
return 1
@@ -764,4 +764,4 @@ def test_fill_plasma_exception(ray_start_cluster_head):
ray.get(actor.test.remote())
with pytest.raises(plasma.PlasmaStoreFull):
ray.put(np.zeros(10**7 + 2, dtype=np.uint8))
ray.put(np.zeros(10**8 + 2, dtype=np.uint8))
+85
View File
@@ -0,0 +1,85 @@
import numpy as np
import unittest
import ray
import pyarrow
MB = 1024 * 1024
OBJECT_EVICTED = ray.exceptions.UnreconstructableError
OBJECT_TOO_LARGE = pyarrow._plasma.PlasmaStoreFull
@ray.remote
class LightActor(object):
def __init__(self):
pass
def sample(self):
return "tiny_return_value"
@ray.remote
class GreedyActor(object):
def __init__(self):
pass
def sample(self):
return np.zeros(20 * MB, dtype=np.uint8)
class TestMemoryLimits(unittest.TestCase):
def testWithoutQuota(self):
self.assertRaises(OBJECT_EVICTED, lambda: self._run(None, None, None))
self.assertRaises(OBJECT_EVICTED,
lambda: self._run(100 * MB, None, None))
self.assertRaises(OBJECT_EVICTED,
lambda: self._run(None, 100 * MB, None))
def testQuotasProtectSelf(self):
self._run(100 * MB, 100 * MB, None)
def testQuotasProtectOthers(self):
self._run(None, None, 100 * MB)
def testQuotaTooLarge(self):
self.assertRaisesRegexp(ray.memory_monitor.RayOutOfMemoryError,
".*Failed to set object_store_memory.*",
lambda: self._run(300 * MB, None, None))
def testTooLargeAllocation(self):
try:
ray.init(num_cpus=1, driver_object_store_memory=100 * MB)
ray.put(np.zeros(50 * MB, dtype=np.uint8))
self.assertRaises(
OBJECT_TOO_LARGE,
lambda: ray.put(np.zeros(200 * MB, dtype=np.uint8)))
finally:
ray.shutdown()
def _run(self, driver_quota, a_quota, b_quota):
print("*** Testing ***", driver_quota, a_quota, b_quota)
try:
ray.init(
num_cpus=1,
object_store_memory=300 * MB,
driver_object_store_memory=driver_quota)
z = ray.put("hi")
a = LightActor._remote(object_store_memory=a_quota)
b = GreedyActor._remote(object_store_memory=b_quota)
for _ in range(5):
r_a = a.sample.remote()
for _ in range(20):
ray.get(b.sample.remote())
ray.get(r_a)
ray.get(z)
except Exception as e:
print("Raised exception", type(e), e)
raise e
finally:
print(ray.worker.global_worker.plasma_client.debug_string())
ray.shutdown()
if __name__ == "__main__":
unittest.main(verbosity=2)
+155
View File
@@ -0,0 +1,155 @@
import numpy as np
import unittest
import ray
from ray import tune
from ray.rllib import _register_all
MB = 1024 * 1024
@ray.remote(memory=100 * MB)
class Actor(object):
def __init__(self):
pass
def ping(self):
return "ok"
@ray.remote(object_store_memory=100 * MB)
class Actor2(object):
def __init__(self):
pass
def ping(self):
return "ok"
def train_oom(config, reporter):
ray.put(np.zeros(200 * 1024 * 1024))
reporter(result=123)
class TestMemoryScheduling(unittest.TestCase):
def testMemoryRequest(self):
try:
ray.init(num_cpus=1, memory=200 * MB)
# fits first 2
a = Actor.remote()
b = Actor.remote()
ok, _ = ray.wait(
[a.ping.remote(), b.ping.remote()],
timeout=60.0,
num_returns=2)
self.assertEqual(len(ok), 2)
# does not fit
c = Actor.remote()
ok, _ = ray.wait([c.ping.remote()], timeout=5.0)
self.assertEqual(len(ok), 0)
finally:
ray.shutdown()
def testObjectStoreMemoryRequest(self):
try:
ray.init(num_cpus=1, object_store_memory=300 * MB)
# fits first 2 (70% allowed)
a = Actor2.remote()
b = Actor2.remote()
ok, _ = ray.wait(
[a.ping.remote(), b.ping.remote()],
timeout=60.0,
num_returns=2)
self.assertEqual(len(ok), 2)
# does not fit
c = Actor2.remote()
ok, _ = ray.wait([c.ping.remote()], timeout=5.0)
self.assertEqual(len(ok), 0)
finally:
ray.shutdown()
def testTuneDriverHeapLimit(self):
try:
_register_all()
result = tune.run(
"PG",
stop={"timesteps_total": 10000},
config={
"env": "CartPole-v0",
"memory": 100 * 1024 * 1024, # too little
},
raise_on_failed_trial=False)
self.assertEqual(result.trials[0].status, "ERROR")
self.assertTrue(
"RayOutOfMemoryError: Heap memory usage for ray_PG_" in
result.trials[0].error_msg)
finally:
ray.shutdown()
def testTuneDriverStoreLimit(self):
try:
_register_all()
self.assertRaisesRegexp(
ray.tune.error.TuneError,
".*Insufficient cluster resources.*",
lambda: tune.run(
"PG",
stop={"timesteps_total": 10000},
config={
"env": "CartPole-v0",
# too large
"object_store_memory": 10000 * 1024 * 1024,
}))
finally:
ray.shutdown()
def testTuneWorkerHeapLimit(self):
try:
_register_all()
result = tune.run(
"PG",
stop={"timesteps_total": 10000},
config={
"env": "CartPole-v0",
"num_workers": 1,
"memory_per_worker": 100 * 1024 * 1024, # too little
},
raise_on_failed_trial=False)
self.assertEqual(result.trials[0].status, "ERROR")
self.assertTrue(
"RayOutOfMemoryError: Heap memory usage for ray_Rollout" in
result.trials[0].error_msg)
finally:
ray.shutdown()
def testTuneWorkerStoreLimit(self):
try:
_register_all()
self.assertRaisesRegexp(
ray.tune.error.TuneError,
".*Insufficient cluster resources.*",
lambda:
tune.run("PG", stop={"timesteps_total": 0}, config={
"env": "CartPole-v0",
"num_workers": 1,
# too large
"object_store_memory_per_worker": 10000 * 1024 * 1024,
}))
finally:
ray.shutdown()
def testTuneObjectLimitApplied(self):
try:
result = tune.run(
train_oom,
resources_per_trial={"object_store_memory": 150 * 1024 * 1024},
raise_on_failed_trial=False)
self.assertTrue(result.trials[0].status, "ERROR")
self.assertTrue("PlasmaStoreFull: object does not fit" in
result.trials[0].error_msg)
finally:
ray.shutdown()
if __name__ == "__main__":
unittest.main(verbosity=2)
+9
View File
@@ -73,6 +73,15 @@ def verify_load_metrics(monitor, expected_resource_usage=None, timeout=10):
monitor.process_messages()
resource_usage = monitor.load_metrics.get_resource_usage()
if "memory" in resource_usage[1]:
del resource_usage[1]["memory"]
if "object_store_memory" in resource_usage[2]:
del resource_usage[1]["object_store_memory"]
if "memory" in resource_usage[2]:
del resource_usage[2]["memory"]
if "object_store_memory" in resource_usage[2]:
del resource_usage[2]["object_store_memory"]
if expected_resource_usage is None:
if all(x for x in resource_usage[1:]):
break
+3 -3
View File
@@ -52,11 +52,11 @@ def test_object_broadcast(ray_start_cluster_with_resource):
def f(x):
return
x = np.zeros(10**8, dtype=np.uint8)
x = np.zeros(150 * 1024 * 1024, dtype=np.uint8)
@ray.remote
def create_object():
return np.zeros(10**8, dtype=np.uint8)
return np.zeros(150 * 1024 * 1024, dtype=np.uint8)
object_ids = []
@@ -219,7 +219,7 @@ def test_object_transfer_retry(ray_start_cluster):
"object_manager_pull_timeout_ms": repeated_push_delay * 1000 / 4,
"object_manager_default_chunk_size": 1000
})
object_store_memory = 10**8
object_store_memory = 150 * 1024 * 1024
cluster.add_node(
object_store_memory=object_store_memory, _internal_config=config)
cluster.add_node(
+2 -2
View File
@@ -25,7 +25,7 @@ def ray_start_sharded(request):
# Start the Ray processes.
ray.init(
object_store_memory=int(0.1 * 10**9),
object_store_memory=int(0.5 * 10**9),
num_cpus=10,
num_redis_shards=num_redis_shards,
redis_max_memory=10**7)
@@ -200,7 +200,7 @@ def test_wait(ray_start_combination):
def ray_start_reconstruction(request):
num_nodes = request.param
plasma_store_memory = int(0.1 * 10**9)
plasma_store_memory = int(0.5 * 10**9)
cluster = Cluster(
initialize_head=True,
@@ -10,7 +10,10 @@ import ray
class TestUnreconstructableErrors(unittest.TestCase):
def setUp(self):
ray.init(object_store_memory=10000000, redis_max_memory=10000000)
ray.init(
num_cpus=1,
object_store_memory=150 * 1024 * 1024,
redis_max_memory=10000000)
def tearDown(self):
ray.shutdown()
@@ -18,8 +21,8 @@ class TestUnreconstructableErrors(unittest.TestCase):
def testDriverPutEvictedCannotReconstruct(self):
x_id = ray.put(np.zeros(1 * 1024 * 1024))
ray.get(x_id)
for _ in range(10):
ray.put(np.zeros(1 * 1024 * 1024))
for _ in range(20):
ray.put(np.zeros(10 * 1024 * 1024))
self.assertRaises(ray.exceptions.UnreconstructableError,
lambda: ray.get(x_id))