|
5 | 5 | This is used to test the scenario when a user initializes CUDA before importing nsight. |
6 | 6 | NCU attach-mode requires CUDA to not be initialized before the injection library is loaded |
7 | 7 | so profiling fails with an error like "Cuda is initialized before the tool". |
8 | | -""" |
9 | 8 |
|
10 | | -import subprocess |
11 | | -import sys |
12 | | -from pathlib import Path |
| 9 | +The test runs in a fresh subprocess via pytest-isolated, because nsight must not have |
| 10 | +been imported yet. The root conftest.py skips its tool setup in that subprocess. |
| 11 | +""" |
13 | 12 |
|
14 | 13 | import pytest |
15 | 14 | import torch |
16 | 15 |
|
17 | 16 |
|
18 | | -def main() -> None: |
19 | | - |
20 | | - torch.cuda.init() # any torch call that initializes CUDA would do |
21 | | - import nsight # this loads NCU, and the test needs it loaded after CUDA init |
22 | | - |
23 | | - @nsight.analyze.kernel() |
24 | | - def run_simple_kernel(n: int) -> None: |
25 | | - a = torch.randn(n, n, device="cuda") |
26 | | - b = torch.randn(n, n, device="cuda") |
27 | | - with nsight.annotate("test"): |
28 | | - _ = a @ b |
29 | | - |
30 | | - # under NSPY_NCU_INIT_AT_IMPORT=0 the load is deferred to here instead, still after CUDA init |
31 | | - run_simple_kernel(64) |
32 | | - |
33 | | - |
34 | | -def test() -> None: |
35 | | - """Run this program as a subprocess; profiling must fail with the expected error.""" |
36 | | - # Imported here, not at module scope: importing nsight before torch.cuda.init() |
37 | | - # in main() would defeat what this test exercises. |
38 | | - import nsight |
39 | | - |
40 | | - if nsight.get_active_tool() == nsight.Tool.CUPTI: |
| 17 | +@pytest.mark.isolated |
| 18 | +def test_cuda_init_before_nsight(request: pytest.FixtureRequest) -> None: |
| 19 | + """Profiling must fail with the expected error when CUDA is initialized first.""" |
| 20 | + if request.config.getoption("--tool-init") == "cupti": |
41 | 21 | pytest.skip( |
42 | 22 | "NCU-only test: validates injection failure when CUDA is pre-initialized" |
43 | 23 | ) |
44 | 24 |
|
45 | | - this_file = Path(__file__).resolve() |
46 | | - result = subprocess.run( |
47 | | - [sys.executable, str(this_file)], |
48 | | - capture_output=True, |
49 | | - text=True, |
50 | | - timeout=120, |
51 | | - cwd=this_file.parent.parent, |
52 | | - ) |
53 | | - |
54 | | - # Process should fail with a ProfilerException raised by begin_profiling() |
55 | | - assert result.returncode != 0, "Subprocess unexpectedly succeeded" |
56 | | - |
57 | | - stderr_lower = (result.stderr or "").lower() |
58 | | - # Expect the standardized injection error message with the code emitted by ncu injection |
59 | | - # When CUDA is already initialized before injection, we expect code 3 (NV_INJ_ERROR_NOT_INITIALIZED) |
60 | | - assert ( |
61 | | - "failed to begin profiling" in stderr_lower |
62 | | - ), f"Unexpected stderr: {result.stderr}" |
63 | | - assert ( |
64 | | - "(code=3)" in stderr_lower |
65 | | - ), f"Expected injection error code 3 in stderr, got: {result.stderr}" |
66 | | - |
| 25 | + torch.cuda.init() # any torch call that initializes CUDA would do |
67 | 26 |
|
68 | | -if __name__ == "__main__": |
69 | | - main() |
| 27 | + # Importing nsight (or, with --tool-init=none, the first decorated call) loads NCU, |
| 28 | + # and the test needs that to happen after CUDA init. |
| 29 | + with pytest.raises(Exception) as exc_info: |
| 30 | + import nsight |
| 31 | + |
| 32 | + @nsight.analyze.kernel() |
| 33 | + def run_simple_kernel(n: int) -> None: |
| 34 | + a = torch.randn(n, n, device="cuda") |
| 35 | + b = torch.randn(n, n, device="cuda") |
| 36 | + with nsight.annotate("test"): |
| 37 | + _ = a @ b |
| 38 | + |
| 39 | + run_simple_kernel(64) |
| 40 | + |
| 41 | + from nsight.exceptions import ProfilerException |
| 42 | + |
| 43 | + assert isinstance( |
| 44 | + exc_info.value, ProfilerException |
| 45 | + ), f"Unexpected exception: {exc_info.value!r}" |
| 46 | + message = str(exc_info.value).lower() |
| 47 | + # Expect the standardized injection error message with the code emitted by ncu injection. |
| 48 | + # When CUDA is already initialized before injection, we expect code 3 |
| 49 | + # (NV_INJ_ERROR_NOT_INITIALIZED) |
| 50 | + assert "failed to begin profiling" in message, f"Unexpected error: {message}" |
| 51 | + assert "(code=3)" in message, f"Expected injection error code 3, got: {message}" |
0 commit comments