forge/blade/lib/ray.py (129 lines of code) (raw):
import ray, os
import time
OBJECT_INFO_PREFIX = b"OI:"
OBJECT_LOCATION_PREFIX = b"OL:"
TASK_TABLE_PREFIX = b"TT:"
def init(mode):
os.environ['MKL_NUM_THREADS'] = '1'
os.environ['OMP_NUM_THREADS'] = '1'
if mode == 'local':
ray.init(local_mode=ray.PYTHON_MODE)
elif mode == 'default':
ray.init()
elif mode == 'remote':
print('Set up HOSTNAME')
ray.init(redis_address=os.environ['HOSTNAME'] + ':6379')
else:
print('Invalid ray mode (local/default/remote)')
exit(-1)
def clearbuffers():
start = time.time()
print('Clearing ray buffers...')
flush_task_and_object_metadata_unsafe()
flush_redis_unsafe()
print('Done. Free time: ', time.time() - start)
#Continuous moving average
class CMA():
def __init__(self):
self.t = 1.0
self.cma = None
def update(self, x):
if self.cma is None:
self.cma = x
return
self.cma = (x + self.t*self.cma)/(self.t+1)
self.t += 1.0
#Continuous moving average
class CMV():
def __init__(self):
self.cma = CMA()
self.cmv = None
def update(self, x):
if self.cmv is None:
self.cma.update(x)
self.cmv = 0
return
prevMean = self.cma.cma
self.cma.update(x)
self.cmv += (x-prevMean)*(x-self.cma.cma)
@property
def stats(self):
return self.cma.cma, self.cmv
class RayBenchmark:
def __init__(self):
self.cmv = CMV()
def startRecord(self):
self.start = time.time()
def stopRecord(self):
delta = time.time() - self.start
self.cmv.update(delta)
def reset(self):
self.cmv = CMV()
@property
def stats(self):
mean, var = self.cmv.stats
return {'mean': mean, 'var': var}
def put(*args, profile=None):
if profile is not None:
if not hasattr(put, 'bench'):
put.bench = {}
if not profile in put.bench:
put.bench[profile] = RayBenchmark()
put.bench[profile].startRecord()
ret = ray.put(*args)
if profile is not None:
put.bench[profile].stopRecord()
return ret
def get(*args, profile=None):
if profile is not None:
if not hasattr(get, 'bench'):
get.bench = {}
if not profile in get.bench:
get.bench[profile] = RayBenchmark()
get.bench[profile].startRecord()
ret = ray.get(*args)
if profile is not None:
get.bench[profile].stopRecord()
return ret
def profile():
stats = {}
for k, f in zip('put get'.split(), (put, get)):
if hasattr(f, 'bench'):
stats[k] = dict((k, v.stats) for k, v in put.bench.items())
return stats
def flush_redis_unsafe():
"""This removes some non-critical state from the primary Redis shard.
This removes the log files as well as the event log from Redis. This can
be used to try to address out-of-memory errors caused by the accumulation
of metadata in Redis. However, it will only partially address the issue as
much of the data is in the task table (and object table), which are not
flushed.
"""
if not hasattr(ray.worker.global_worker, "redis_client"):
raise Exception("ray.experimental.flush_redis_unsafe cannot be called "
"before ray.init() has been called.")
redis_client = ray.worker.global_worker.redis_client
# Delete the log files from the primary Redis shard.
keys = redis_client.keys("LOGFILE:*")
if len(keys) > 0:
num_deleted = redis_client.delete(*keys)
else:
num_deleted = 0
print("Deleted {} log files from Redis.".format(num_deleted))
# Delete the event log from the primary Redis shard.
keys = redis_client.keys("event_log:*")
if len(keys) > 0:
num_deleted = redis_client.delete(*keys)
else:
num_deleted = 0
print("Deleted {} event logs from Redis.".format(num_deleted))
def flush_task_and_object_metadata_unsafe():
"""This removes some critical state from the Redis shards.
This removes all of the object and task metadata. This can be used to try
to address out-of-memory errors caused by the accumulation of metadata in
Redis. However, after running this command, fault tolerance will most
likely not work.
"""
if not hasattr(ray.worker.global_worker, "redis_client"):
raise Exception("ray.experimental.flush_redis_unsafe cannot be called "
"before ray.init() has been called.")
def flush_shard(redis_client):
num_task_keys_deleted = 0
for key in redis_client.scan_iter(match=TASK_TABLE_PREFIX + b"*"):
num_task_keys_deleted += redis_client.delete(key)
print("Deleted {} task keys from Redis.".format(num_task_keys_deleted))
num_object_keys_deleted = 0
for key in redis_client.scan_iter(match=OBJECT_INFO_PREFIX + b"*"):
num_object_keys_deleted += redis_client.delete(key)
print("Deleted {} object info keys from Redis.".format(
num_object_keys_deleted))
num_object_location_keys_deleted = 0
for key in redis_client.scan_iter(match=OBJECT_LOCATION_PREFIX + b"*"):
num_object_location_keys_deleted += redis_client.delete(key)
print("Deleted {} object location keys from Redis.".format(
num_object_location_keys_deleted))
for redis_client in ray.worker.global_state.redis_clients:
flush_shard(redis_client)