-
Notifications
You must be signed in to change notification settings - Fork 329
Test using pytest-run-parallel and related fixups in the tests #2194
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
base: main
Are you sure you want to change the base?
Changes from all commits
e5f4167
c2cf0f5
5e243f3
ec849fa
5cd6e49
0f41fe6
25966eb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,6 @@ | |
| import os | ||
| import pathlib | ||
| import sys | ||
| from contextlib import contextmanager | ||
|
|
||
| import pytest | ||
|
|
||
|
|
@@ -72,44 +71,16 @@ def pytest_terminal_summary(terminalreporter): | |
| oom_diagnostics.report_terminal_summary(terminalreporter) | ||
|
|
||
|
|
||
| @contextmanager | ||
| def _init_cuda_context(): | ||
| # TODO: rename this to e.g. init_context | ||
| device = Device(0) | ||
| device.set_current() | ||
|
|
||
| # Set option to avoid spin-waiting on synchronization. | ||
| if int(os.environ.get("CUDA_CORE_TEST_BLOCKING_SYNC", 0)) != 0: | ||
| handle_return( | ||
| driver.cuDevicePrimaryCtxSetFlags(device.device_id, driver.CUctx_flags.CU_CTX_SCHED_BLOCKING_SYNC) | ||
| ) | ||
|
|
||
| try: | ||
| yield device | ||
| finally: | ||
| # Force any pool/allocation whose only remaining reference was a local | ||
| # in this test's frame to actually get destroyed now, then drain the | ||
| # context so the stream-ordered frees that destruction enqueues retire | ||
| # before the next test runs. Without this, a memory pool's VA | ||
| # reservation is not returned until both have happened, and per-test | ||
| # leftovers accumulate across the run -- which is how full-suite runs | ||
| # can exhaust address space and hit CUDA_ERROR_OUT_OF_MEMORY on a | ||
| # device with plenty of free physical memory (issue #2381). gc.collect() | ||
| # must run first: cuCtxSynchronize alone cannot drain frees that were | ||
| # never enqueued because their owning object had not been collected yet. | ||
| gc.collect() | ||
| driver.cuCtxSynchronize() | ||
| _ = _device_unset_current() | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was causing issues for some graph tests (because a device sync disrupts graph capture). But, actually, it also seems to fix the That should allow a bunch of cleanups, but I would prefer to follow-up for it. |
||
|
|
||
|
|
||
| def _wrap_worker_cuda_test(func): | ||
| if getattr(func, "_cuda_core_worker_cuda_wrapped", False): | ||
| return func | ||
|
|
||
| @functools.wraps(func) | ||
| def wrapper(*args, **kwargs): | ||
| kwargs = dict(kwargs) # copy before mutating | ||
| with _init_cuda_context() as device: | ||
| device = Device(0) | ||
| device.set_current() | ||
| try: | ||
| if "init_cuda" in kwargs: | ||
| kwargs["init_cuda"] = device | ||
| if "mempool_device_x2" in kwargs: | ||
|
|
@@ -129,6 +100,12 @@ def wrapper(*args, **kwargs): | |
| groups, _ = device.resources.sm.split(SMResourceOptions(count=None)) | ||
| kwargs["green_ctx"] = device.create_context(ContextOptions(resources=[groups[0]])) | ||
| return func(*args, **kwargs) | ||
| finally: | ||
| # Unlike the `init_cuda` fixture we do not synchronize here | ||
| # to avoid doing so while other workers are still running. | ||
| # (E.g. for stream capture). The fixture cleanup is still run | ||
| # even with pytest-run-parallel after worker join. | ||
| _ = _device_unset_current() | ||
|
|
||
| wrapper._cuda_core_worker_cuda_wrapped = True | ||
| return wrapper | ||
|
|
@@ -186,8 +163,33 @@ def session_setup(): | |
|
|
||
| @pytest.fixture | ||
| def init_cuda(): | ||
| with _init_cuda_context() as device: | ||
| # TODO: rename this to e.g. init_context | ||
| device = Device(0) | ||
| device.set_current() | ||
|
|
||
| # Set option to avoid spin-waiting on synchronization. | ||
| if int(os.environ.get("CUDA_CORE_TEST_BLOCKING_SYNC", 0)) != 0: | ||
| handle_return( | ||
| driver.cuDevicePrimaryCtxSetFlags(device.device_id, driver.CUctx_flags.CU_CTX_SCHED_BLOCKING_SYNC) | ||
| ) | ||
|
|
||
| try: | ||
| yield device | ||
| finally: | ||
| # Force any pool/allocation whose only remaining reference was a local | ||
| # in this test's frame to actually get destroyed now, then drain the | ||
| # context so the stream-ordered frees that destruction enqueues retire | ||
| # before the next test runs. Without this, a memory pool's VA | ||
| # reservation is not returned until both have happened, and per-test | ||
| # leftovers accumulate across the run -- which is how full-suite runs | ||
| # can exhaust address space and hit CUDA_ERROR_OUT_OF_MEMORY on a | ||
| # device with plenty of free physical memory (issue #2381). gc.collect() | ||
| # must run first: cuCtxSynchronize alone cannot drain frees that were | ||
| # never enqueued because their owning object had not been collected yet. | ||
| # With pytest-run-parallel this runs after worker join. | ||
| gc.collect() | ||
| driver.cuCtxSynchronize() | ||
| _ = _device_unset_current() | ||
|
|
||
|
|
||
| def _device_unset_current() -> bool: | ||
|
|
||
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.
This triggered a failure. Could also just mark the test as unsafe, but mutating global state here seems wrong (e.g. what if the user wants to raise
DeprecationWarnings?).