Skip to content

Ft testing test fixes - #2454

Open
seberg wants to merge 18 commits into
NVIDIA:mainfrom
seberg:ft-testing-test-fixes
Open

Ft testing test fixes#2454
seberg wants to merge 18 commits into
NVIDIA:mainfrom
seberg:ft-testing-test-fixes

Conversation

@seberg

Copy link
Copy Markdown
Contributor

Split from #2194 with all test changes. Split out for two reasons:

  1. A bit shorter.
  2. By the time this is merged, the original PR may need further fixups anyway...

(adding a few inline comments)

CC @Andy-Jost

@github-actionsgithub-actionsBot added cuda.bindings Everything related to the cuda.bindings module cuda.core Everything related to the cuda.core module labels Jul 29, 2026

env = os.environ.copy()
env["CUDA_BINDINGS_SKIP_EXAMPLE"] = "100"
env["MPLBACKEND"] = "Agg" # avoid plt.show() from blocking

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dunno if others get a pop-up for these tests, I did and with parallel testing, it might be a 100 windows :).

def test_graphdef_handle_valid(sample_graphdef):
def test_graphdef_handle_valid(init_cuda):
"""GraphDefinition has a valid non-null handle."""
sample_graphdef = GraphDefinition()

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Admittedly, we could also do the fixture hack, but somehow this felt just as well for now...


# Indirect-parametrize helpers: request.getfixturevalue() runs here, in the
# fixture (main thread), so the resolved object is already available when the
# test function runs in a worker thread.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Admittedly, the workers may not be valid on other threads, but we don't actually use CUDA API anywhere...

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a better approach. Suggested comment:

# Resolve fixture names during pytest setup, before pytest-run-parallel starts
# worker threads. The workers then share the resolved, read-only test object.

Comment threadcuda_core/tests/helpers/latch.py Outdated

// Check for timeout
if (clock64() - start >= timeout_cycles) {
signal.store(-1, cuda::memory_order_relaxed);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I was just debugging/trying to understand where things are hanging.

Either way, the main point here is that we need to compile the kernel only once, because otherwise compiling the kernel itself will block other things and break other threads.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nvm, I pulled out the latch.py fixes... They are correct, but the fact that there are allocations, makes them a bit unreliable and the only way to fix it is to introduce that barrier_wait fixture (I had forgotten about it).

And I don't like that fixtures quite enough yet, maybe after pytest-run-parallel has better infrastructure for it.

assert list(out) == [0xCD] * 4


@pytest.mark.thread_unsafe(reason="deferred cleanup on main thread which would wait")

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are three tests here that fail with _wait_until@Andy-Jost. I just skipped them, the reason seems to be that cleanup can never happen as long as the main thread is waiting in thread.join()?

I suspect that is a potential but very minor issue (you would think eventually this cleanup happens). But wanted to make a comment. I didn't try to understand what is going on here exactly!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue is that deferred cleanup requires Python's main thread.

  1. pytest main thread: start workers -> join workers (blocking)
  2. pytest worker thread: del graph -> _wait_until
  3. CUDA calls back to Python from a separate thread and cuda.core schedules the destruction with Py_AddPendingCall
  4. Python's pending callbacks only run on the main thread.

pytest-run-parallel needs to give pending calls a chance to run. Instead of a blocking worker.join:

while any(worker.is_alive() for worker in workers):
for worker in workers:
worker.join(timeout=0.01)

The test also needs to be updated to use threading.main_thread().ident rather than threading.get_ident()

@sebergseberg added the enhancement Any code-related improvements label Jul 29, 2026
@sebergseberg self-assigned this Jul 29, 2026
@sebergseberg added this to the cuda.core next milestone Jul 29, 2026
@sebergseberg added the P1 Medium priority - Should do label Jul 29, 2026
@github-actions

Copy link
Copy Markdown

seberg added 17 commits July 29, 2026 21:41
- thread_unsafe: nvml init ref-count, graphMem attr, mock-based tests,
OpenGL, peer-access pool state, multiprocessing warning, program-cache
race reproduction, and functools.cache mutation tests
- parallel_threads_limit: IPC / worker-pool tests that spawn subprocesses
or open file descriptors (limit 4), example tests (limit 8), and the
event-registration test whose timeouts are slow
Signed-off-by: Sebastian Berg <sebastianb@nvidia.com>
Signed-off-by: Sebastian Berg <sebastianb@nvidia.com>
…unsafe always
Signed-off-by: Sebastian Berg <sebastianb@nvidia.com>
…empool
Signed-off-by: Sebastian Berg <sebastianb@nvidia.com>
Signed-off-by: Sebastian Berg <sebastianb@nvidia.com>
Signed-off-by: Sebastian Berg <sebastianb@nvidia.com>
After my first AI try was a crazy mess, the second run actually found
a neat solution...
These objects can be created in the main thread, but we can't create
them on the fly in many threads as it was...
Signed-off-by: Sebastian Berg <sebastianb@nvidia.com>
For some reason the latch kernel helper test started failing now
(it did not before my update from CUDA 13.2 to 13.3?).
The reason isn't that it is not thread-safe, but that something
(presumably module loading/unloading) causes synchronizations which
in turn cause threads having to wait on their LatchKernel to finish.
And of course the test itself really needs that not to happen.
Making sure there is only one LatchKernel compiled and loaded exactly
once seems to avoid this problem.
Signed-off-by: Sebastian Berg <sebastianb@nvidia.com>
Concurrent LatchKernel runs can overlap pinned flag alloc/free across
workers; mark them thread-unsafe until a barrier_wait is restored.
Also drop the compile-once LatchKernel helper changes for now.
@seberg
sebergforce-pushed the ft-testing-test-fixes branch from 40a0175 to 0bde899CompareJuly 29, 2026 19:41

@Andy-JostAndy-Jost left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Getting the graph-cleanup tests running seems to require a change to pytest-run-parallel. Can we merge this and follow up with a PR there?

assert list(out) == [0xCD] * 4


@pytest.mark.thread_unsafe(reason="deferred cleanup on main thread which would wait")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The issue is that deferred cleanup requires Python's main thread.

  1. pytest main thread: start workers -> join workers (blocking)
  2. pytest worker thread: del graph -> _wait_until
  3. CUDA calls back to Python from a separate thread and cuda.core schedules the destruction with Py_AddPendingCall
  4. Python's pending callbacks only run on the main thread.

pytest-run-parallel needs to give pending calls a chance to run. Instead of a blocking worker.join:

while any(worker.is_alive() for worker in workers):
for worker in workers:
worker.join(timeout=0.01)

The test also needs to be updated to use threading.main_thread().ident rather than threading.get_ident()


# Indirect-parametrize helpers: request.getfixturevalue() runs here, in the
# fixture (main thread), so the resolved object is already available when the
# test function runs in a worker thread.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like a better approach. Suggested comment:

# Resolve fixture names during pytest setup, before pytest-run-parallel starts
# worker threads. The workers then share the resolved, read-only test object.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cuda.bindingsEverything related to the cuda.bindings modulecuda.coreEverything related to the cuda.core moduleenhancementAny code-related improvementsP1Medium priority - Should do

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@seberg@Andy-Jost