-
Notifications
You must be signed in to change notification settings - Fork 91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JIT-unspill: support spilling to/from disk #708
JIT-unspill: support spilling to/from disk #708
Conversation
Codecov Report
@@ Coverage Diff @@
## branch-21.10 #708 +/- ##
================================================
+ Coverage 87.63% 89.16% +1.52%
================================================
Files 15 15
Lines 1658 1901 +243
================================================
+ Hits 1453 1695 +242
- Misses 205 206 +1
Continue to review full report at Codecov.
|
5c22aaa
to
d1db7eb
Compare
This PR introduce a `ProxyManager` that replaces the current implementation of proxy tracking: ```python class ProxyManager: """ This class together with Proxies, ProxiesOnHost, and ProxiesOnDevice implements the tracking of all known proxies and their total host/device memory usage. It turns out having to re-calculate memory usage continuously is too expensive. The idea is to have the ProxifyHostFile or the proxies themself update their location (device or host). The manager then tallies the total memory usage. Notice, the manager only keeps weak references to the proxies. """ ``` Additionally, this PR fixes a rare deadlock by having all proxies and the `ProxyManager` use the same lock. Finally, this PR will make it much easier to implement spilling to disk: #708. Notice, from the user's perspective, this PR shouldn't change anything. Authors: - Mads R. B. Kristensen (https://github.com/madsbk) Approvers: - Peter Andreas Entschev (https://github.com/pentschev) URL: #712
44a7efb
to
06e18e7
Compare
ddc2dc5
to
3dc8c4c
Compare
cdbd8e7
to
7544003
Compare
@VibhuJawa @randerzander @ChrisJar, FYI this PR is ready for testing. I am currently debugging a |
After much debugging I think this is because of the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @madsbk for the work here. This looks great, and a very clever solution! I've added a few comments and suggestions.
Co-authored-by: Peter Andreas Entschev <[email protected]>
And a better help text Co-authored-by: Peter Andreas Entschev <[email protected]>
…nto jit_unspill_from_disk
Co-authored-by: Peter Andreas Entschev <[email protected]>
15d8700
to
5936f96
Compare
On this PR i got the below error some times when running the workflow at #657 (comment) on 8 GPUs of a dgx-2 with /raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/dask_cudf/core.py:312: UserWarning: Rearranging data by column hash. Divisions will lost. Set ignore_index=False to preserve Index values.
warnings.warn(
distributed.worker - WARNING - Compute Failed
Function: <dask.layers.CallableLazyImport object at 0x7f07ca
args: ([<dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07c13c5c00 of cudf.core.dataframe.DataFrame (serialized='dask')>, <dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07c8d4b240 of cudf.core.dataframe.DataFrame at 0x7f07c1897b80>, <dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07c96ae540 of cudf.core.dataframe.DataFrame (serialized='cuda')>, <dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07bee35f80 of cudf.core.dataframe.DataFrame (serialized='cuda')>, <dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07c1690f40 of cudf.core.dataframe.DataFrame (serialized='cuda')>, <dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07bee21380 of cudf.core.dataframe.DataFrame (serialized='cuda')>, <dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07c1d277c0 of cudf.core.dataframe.DataFrame (serialized='cuda')>, <dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07bed14f80 of cudf.core.dataframe.DataFrame (serialized='cuda')>, <dask_cu
kwargs: {}
Exception: RuntimeError('dictionary changed size during iteration') Full Trace: /raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/dask_cudf/core.py:312: UserWarning: Rearranging data by column hash. Divisions will lost. Set ignore_index=False to preserve Index values.
warnings.warn(
distributed.worker - WARNING - Compute Failed
Function: <dask.layers.CallableLazyImport object at 0x7f07ca
args: ([<dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07c13c5c00 of cudf.core.dataframe.DataFrame (serialized='dask')>, <dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07c8d4b240 of cudf.core.dataframe.DataFrame at 0x7f07c1897b80>, <dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07c96ae540 of cudf.core.dataframe.DataFrame (serialized='cuda')>, <dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07bee35f80 of cudf.core.dataframe.DataFrame (serialized='cuda')>, <dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07c1690f40 of cudf.core.dataframe.DataFrame (serialized='cuda')>, <dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07bee21380 of cudf.core.dataframe.DataFrame (serialized='cuda')>, <dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07c1d277c0 of cudf.core.dataframe.DataFrame (serialized='cuda')>, <dask_cuda.proxify_device_objects.FrameProxyObject at 0x7f07bed14f80 of cudf.core.dataframe.DataFrame (serialized='cuda')>, <dask_cu
kwargs: {}
Exception: RuntimeError('dictionary changed size during iteration')
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
/tmp/ipykernel_96220/4026179359.py in <module>
----> 1 main(client,data_path,n_input_parts=n_parts)
/tmp/ipykernel_96220/344834194.py in main(client, data_path, n_input_parts)
93 reviewed_sales = reviewed_sales.persist()
94 wait(reviewed_sales)
---> 95 print(len(reviewed_sales))
96
97 return
/raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/dask/dataframe/core.py in __len__(self)
3957 return super().__len__()
3958 else:
-> 3959 return len(s)
3960
3961 def __contains__(self, key):
/raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/dask/dataframe/core.py in __len__(self)
590
591 def __len__(self):
--> 592 return self.reduction(
593 len, np.sum, token="len", meta=int, split_every=False
594 ).compute()
/raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/dask/base.py in compute(self, **kwargs)
286 dask.base.compute
287 """
--> 288 (result,) = compute(self, traverse=False, **kwargs)
289 return result
290
/raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/dask/base.py in compute(*args, **kwargs)
568 postcomputes.append(x.__dask_postcompute__())
569
--> 570 results = schedule(dsk, keys, **kwargs)
571 return repack([f(r, *a) for r, (f, a) in zip(results, postcomputes)])
572
/raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/distributed/client.py in get(self, dsk, keys, workers, allow_other_workers, resources, sync, asynchronous, direct, retries, priority, fifo_timeout, actors, **kwargs)
2687 should_rejoin = False
2688 try:
-> 2689 results = self.gather(packed, asynchronous=asynchronous, direct=direct)
2690 finally:
2691 for f in futures.values():
/raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/distributed/client.py in gather(self, futures, errors, direct, asynchronous)
1964 else:
1965 local_worker = None
-> 1966 return self.sync(
1967 self._gather,
1968 futures,
/raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/distributed/client.py in sync(self, func, asynchronous, callback_timeout, *args, **kwargs)
858 return future
859 else:
--> 860 return sync(
861 self.loop, func, *args, callback_timeout=callback_timeout, **kwargs
862 )
/raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/distributed/utils.py in sync(loop, func, callback_timeout, *args, **kwargs)
324 if error[0]:
325 typ, exc, tb = error[0]
--> 326 raise exc.with_traceback(tb)
327 else:
328 return result[0]
/raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/distributed/utils.py in f()
307 if callback_timeout is not None:
308 future = asyncio.wait_for(future, callback_timeout)
--> 309 result[0] = yield future
310 except Exception:
311 error[0] = sys.exc_info()
/raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/tornado/gen.py in run(self)
760
761 try:
--> 762 value = future.result()
763 except Exception:
764 exc_info = sys.exc_info()
/raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/distributed/client.py in _gather(self, futures, errors, direct, local_worker)
1829 exc = CancelledError(key)
1830 else:
-> 1831 raise exception.with_traceback(traceback)
1832 raise exc
1833 if errors == "skip":
/raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/dask/layers.py in __call__()
34 from distributed.utils import import_term
35
---> 36 return import_term(self.function_path)(*args, **kwargs)
37
38
~/dask-sql/dask-cuda/dask_cuda/proxify_device_objects.py in wrapper()
156 @functools.wraps(func)
157 def wrapper(*args, **kwargs):
--> 158 ret = func(*args, **kwargs)
159 if dask.config.get("jit-unspill-compatibility-mode", default=False):
160 ret = unproxify_device_objects(ret, skip_explicit_proxies=False)
/raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/dask/dataframe/core.py in _concat()
122 args[0]
123 if not args2
--> 124 else methods.concat(args2, uniform=True, ignore_index=ignore_index)
125 )
126
/raid/vjawa/conda/envs/rapids-21.10-sep-10-dask-sql-gpu-bdb/lib/python3.8/site-packages/dask/dataframe/dispatch.py in concat()
59 else:
60 func = concat_dispatch.dispatch(type(dfs[0]))
---> 61 return func(
62 dfs,
63 axis=axis,
~/dask-sql/dask-cuda/dask_cuda/proxy_object.py in wrapper()
801 @functools.wraps(func)
802 def wrapper(*args, **kwargs):
--> 803 args = [unproxy(d) for d in args]
804 kwargs = {k: unproxy(v) for k, v in kwargs.items()}
805 return func(*args, **kwargs)
~/dask-sql/dask-cuda/dask_cuda/proxy_object.py in <listcomp>()
801 @functools.wraps(func)
802 def wrapper(*args, **kwargs):
--> 803 args = [unproxy(d) for d in args]
804 kwargs = {k: unproxy(v) for k, v in kwargs.items()}
805 return func(*args, **kwargs)
~/dask-sql/dask-cuda/dask_cuda/proxy_object.py in unproxy()
121 except AttributeError:
122 if type(obj) in (list, tuple, set, frozenset):
--> 123 return type(obj)(unproxy(o) for o in obj)
124 return obj
125
~/dask-sql/dask-cuda/dask_cuda/proxy_object.py in <genexpr>()
121 except AttributeError:
122 if type(obj) in (list, tuple, set, frozenset):
--> 123 return type(obj)(unproxy(o) for o in obj)
124 return obj
125
~/dask-sql/dask-cuda/dask_cuda/proxy_object.py in unproxy()
118 """
119 try:
--> 120 obj = obj._obj_pxy_deserialize()
121 except AttributeError:
122 if type(obj) in (list, tuple, set, frozenset):
~/dask-sql/dask-cuda/dask_cuda/proxy_object.py in _obj_pxy_deserialize()
368 and self._obj_pxy["serializer"] != "cuda"
369 ):
--> 370 manager.maybe_evict(self.__sizeof__())
371
372 # Deserialize the proxied object
~/dask-sql/dask-cuda/dask_cuda/proxify_host_file.py in maybe_evict()
346
347 def maybe_evict(self, extra_dev_mem=0) -> None:
--> 348 self.maybe_evict_from_device(extra_dev_mem)
349 self.maybe_evict_from_host()
350
~/dask-sql/dask-cuda/dask_cuda/proxify_host_file.py in maybe_evict_from_device()
307
308 with self.lock:
--> 309 total_dev_mem_usage, dev_buf_access = self.get_dev_access_info()
310 total_dev_mem_usage += extra_dev_mem
311 if total_dev_mem_usage > self._device_memory_limit:
~/dask-sql/dask-cuda/dask_cuda/proxify_host_file.py in get_dev_access_info()
282 total_dev_mem_usage = 0
283 dev_buf_access = []
--> 284 for dev_buf, proxies in self.get_dev_buffer_to_proxies().items():
285 last_access = max(p._obj_pxy.get("last_access", 0) for p in proxies)
286 size = sizeof(dev_buf)
~/dask-sql/dask-cuda/dask_cuda/proxify_host_file.py in get_dev_buffer_to_proxies()
271 # parts of the same device buffer.
272 ret = defaultdict(list)
--> 273 for proxy in self._dev:
274 for dev_buffer in proxy._obj_pxy_get_device_memory_objects():
275 ret[dev_buffer].append(proxy)
~/dask-sql/dask-cuda/dask_cuda/proxify_host_file.py in __iter__()
78
79 def __iter__(self) -> Iterator[ProxyObject]:
---> 80 for p in self._proxy_id_to_proxy.values():
81 ret = p()
82 if ret is not None:
RuntimeError: dictionary changed size during iteration |
Overall looks good to me @madsbk , I've added one last suggestion. Probably we want to address #708 (comment) here before merging too? |
Co-authored-by: Peter Andreas Entschev <[email protected]>
Thanks for the review and suggestions @pentschev! |
I am not able to reproduce the error on exp01 :/ |
After creating a fresh environment , i was not able to reproduce the error too . Also, wanted to let you know that based on testing , this PR enables some workflows to run on machines with lesser resources ( GPU memory and host memory) where it previously failed. Thanks again @madsbk for working though the issue . Please feel free to merge the PR from my end. |
Overall this looks good to me, we also had the report with the error below: Traceback (most recent call last):
File "/raid1/cjarrett/miniconda3/envs/cudf-gpu-bdb/lib/python3.8/site-packages/distributed/nanny.py", line 844, in _run
worker = Worker(**worker_kwargs)
File "/raid1/cjarrett/miniconda3/envs/cudf-gpu-bdb/lib/python3.8/site-packages/distributed/worker.py", line 633, in __init__
self.data = data[0](**data[1])
TypeError: __init__() got an unexpected keyword argument 'memory_limit' Should we address this here before merging @madsbk ? |
True, forgot about that one.
No, let me fix that issue before merging. I will look at it first thing
tomorrow.
…On Tue, Sep 21, 2021, 17:34 Peter Andreas Entschev ***@***.***> wrote:
Overall this looks good to me, we also had the report with the error below:
Traceback (most recent call last):
File "/raid1/cjarrett/miniconda3/envs/cudf-gpu-bdb/lib/python3.8/site-packages/distributed/nanny.py", line 844, in _run
worker = Worker(**worker_kwargs)
File "/raid1/cjarrett/miniconda3/envs/cudf-gpu-bdb/lib/python3.8/site-packages/distributed/worker.py", line 633, in __init__
self.data = data[0](**data[1])TypeError: __init__() got an unexpected keyword argument 'memory_limit'
Should we address this here before merging @madsbk
<https://github.com/madsbk> ?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#708 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAH6FQAIYYARFGK7DL5X4U3UDCQXDANCNFSM5CQAMRJQ>
.
Triage notifications on the go with GitHub Mobile for iOS
<https://apps.apple.com/app/apple-store/id1477376905?ct=notification-email&mt=8&pt=524675>
or Android
<https://play.google.com/store/apps/details?id=com.github.android&referrer=utm_campaign%3Dnotification-email%26utm_medium%3Demail%26utm_source%3Dgithub>.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks a lot for all the work here Mads!
@gpucibot merge |
Thanks Mads for the PR and Peter for reviewing! Also thanks Vibhu for testing 😄 |
Closes #657 by implementing support of spilling to/from disk.
In this first iteration, we still only track CUDA objects thus regular CPU objects, such as ndarrays, are not spilled.
Spilling to disk is enabled by default and has the same parameters as
DeviceHostFile
. An new parametershared_filesystem
specifies whether thelocal_directory
is shared between all workers or not. Normally this defaults toFalse
but in the case ofLocalCUDACluster
it defaults toTrue
.