Skip to content

Commit 9309f4e

Browse files
Andy-Jostclaude
andcommitted
DO NOT MERGE: diagnose the memcpy update classification on Windows TCC
Temporary diagnostic for the platform difference seen in PR #3035: the executable update that replaces a captured memcpy node's device operand with pinned host memory is rejected on Linux and accepted on Windows TCC. The new test records pointer attributes for pool, cuMemAlloc, and VMM buffers, the memory types the driver records for a captured copy, and the outcome of definition-node and executable updates with host, same-kind, and cuMemAlloc replacements, then fails on purpose so the report lands in the job log. The PR test matrix is trimmed to one Linux row, one Windows TCC row, and one Windows MCDM row. Co-Authored-By: Claude Fable 5.1 <[email protected]>
1 parent 4c893de commit 9309f4e

2 files changed

Lines changed: 199 additions & 69 deletions

File tree

‎ci/test-matrix.yml‎

Lines changed: 4 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -40,55 +40,9 @@ platforms:
4040

4141
linux:
4242
pull-request:
43-
# linux-64
44-
- { ARCH: 'amd64', PY_VER: '3.10', CUDA_VER: '12.9.1', LOCAL_CTK: '1', GPU: 'v100', GPU_COUNT: '1', DRIVER: 'latest' }
45-
- { ARCH: 'amd64', PY_VER: '3.10', CUDA_VER: '13.0.2', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
46-
- { ARCH: 'amd64', PY_VER: '3.10', CUDA_VER: '13.4.2', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
47-
- { ARCH: 'amd64', PY_VER: '3.11', CUDA_VER: '12.9.1', LOCAL_CTK: '0', GPU: 'rtxpro6000', GPU_COUNT: '1', DRIVER: 'latest' }
48-
- { ARCH: 'amd64', PY_VER: '3.11', CUDA_VER: '13.0.2', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
49-
- { ARCH: 'amd64', PY_VER: '3.11', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
50-
# disabled: compute-sanitizer install broken on CUDA 12.9.1 local CTK (TODO: re-enable once fixed)
51-
# - { ARCH: 'amd64', PY_VER: '3.12', CUDA_VER: '12.9.1', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest', ENV: { CUDA_PYTHON_CUDA_PER_THREAD_DEFAULT_STREAM: '1' } }
52-
- { ARCH: 'amd64', PY_VER: '3.12', CUDA_VER: '13.0.2', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
43+
# TEMPORARY: trimmed to one Linux row plus one Windows TCC and one MCDM row for the
44+
# memcpy-update classification diagnostic. Do not merge.
5345
- { ARCH: 'amd64', PY_VER: '3.12', CUDA_VER: '13.4.2', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
54-
- { ARCH: 'amd64', PY_VER: '3.13', CUDA_VER: '12.9.1', LOCAL_CTK: '0', GPU: 'v100', GPU_COUNT: '1', DRIVER: 'latest' }
55-
- { ARCH: 'amd64', PY_VER: '3.13', CUDA_VER: '13.0.2', LOCAL_CTK: '1', GPU: 'rtxpro6000', GPU_COUNT: '1', DRIVER: 'latest' }
56-
- { ARCH: 'amd64', PY_VER: '3.13', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 'rtxpro6000', GPU_COUNT: '1', DRIVER: '610.43.02' }
57-
- { ARCH: 'amd64', PY_VER: '3.14', CUDA_VER: '12.9.1', LOCAL_CTK: '0', GPU: 't4', GPU_COUNT: '1', DRIVER: 'latest' }
58-
- { ARCH: 'amd64', PY_VER: '3.14', CUDA_VER: '13.0.2', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
59-
- { ARCH: 'amd64', PY_VER: '3.14', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: '610.43.02' }
60-
- { ARCH: 'amd64', PY_VER: '3.14t', CUDA_VER: '12.9.1', LOCAL_CTK: '1', GPU: 't4', GPU_COUNT: '1', DRIVER: 'latest' }
61-
- { ARCH: 'amd64', PY_VER: '3.14t', CUDA_VER: '13.0.2', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
62-
- { ARCH: 'amd64', PY_VER: '3.14t', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
63-
- { ARCH: 'amd64', PY_VER: '3.15', CUDA_VER: '13.4.2', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
64-
- { ARCH: 'amd64', PY_VER: '3.15t', CUDA_VER: '13.4.2', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
65-
# linux-aarch64
66-
- { ARCH: 'arm64', PY_VER: '3.10', CUDA_VER: '12.9.1', LOCAL_CTK: '1', GPU: 'a100', GPU_COUNT: '1', DRIVER: 'latest' }
67-
- { ARCH: 'arm64', PY_VER: '3.10', CUDA_VER: '13.0.2', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
68-
- { ARCH: 'arm64', PY_VER: '3.10', CUDA_VER: '13.4.2', LOCAL_CTK: '0', GPU: 'a100', GPU_COUNT: '1', DRIVER: 'latest' }
69-
- { ARCH: 'arm64', PY_VER: '3.11', CUDA_VER: '12.9.1', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
70-
- { ARCH: 'arm64', PY_VER: '3.11', CUDA_VER: '13.0.2', LOCAL_CTK: '1', GPU: 'a100', GPU_COUNT: '1', DRIVER: 'latest' }
71-
- { ARCH: 'arm64', PY_VER: '3.11', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
72-
# disabled: compute-sanitizer install broken on CUDA 12.9.1 local CTK (TODO: re-enable once fixed)
73-
# - { ARCH: 'arm64', PY_VER: '3.12', CUDA_VER: '12.9.1', LOCAL_CTK: '1', GPU: 'a100', GPU_COUNT: '1', DRIVER: 'latest' }
74-
- { ARCH: 'arm64', PY_VER: '3.12', CUDA_VER: '13.0.2', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
75-
- { ARCH: 'arm64', PY_VER: '3.12', CUDA_VER: '13.4.2', LOCAL_CTK: '0', GPU: 'a100', GPU_COUNT: '1', DRIVER: 'latest' }
76-
- { ARCH: 'arm64', PY_VER: '3.13', CUDA_VER: '12.9.1', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
77-
- { ARCH: 'arm64', PY_VER: '3.13', CUDA_VER: '13.0.2', LOCAL_CTK: '1', GPU: 'a100', GPU_COUNT: '1', DRIVER: 'latest' }
78-
- { ARCH: 'arm64', PY_VER: '3.13', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
79-
- { ARCH: 'arm64', PY_VER: '3.14', CUDA_VER: '12.9.1', LOCAL_CTK: '0', GPU: 'a100', GPU_COUNT: '1', DRIVER: 'latest' }
80-
- { ARCH: 'arm64', PY_VER: '3.14', CUDA_VER: '13.0.2', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
81-
- { ARCH: 'arm64', PY_VER: '3.14', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 'a100', GPU_COUNT: '1', DRIVER: 'latest' }
82-
- { ARCH: 'arm64', PY_VER: '3.14t', CUDA_VER: '12.9.1', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
83-
- { ARCH: 'arm64', PY_VER: '3.14t', CUDA_VER: '13.0.2', LOCAL_CTK: '0', GPU: 'a100', GPU_COUNT: '1', DRIVER: 'latest' }
84-
- { ARCH: 'arm64', PY_VER: '3.14t', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest' }
85-
# special runners
86-
- { ARCH: 'amd64', PY_VER: '3.13', CUDA_VER: '13.0.2', LOCAL_CTK: '1', GPU: 'h100', GPU_COUNT: '1', DRIVER: 'latest' }
87-
- { ARCH: 'amd64', PY_VER: '3.13', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 'h100', GPU_COUNT: '1', DRIVER: 'latest' }
88-
- { ARCH: 'amd64', PY_VER: '3.14', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 't4', GPU_COUNT: '2', DRIVER: 'latest' }
89-
- { ARCH: 'amd64', PY_VER: '3.14t', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 'h100', GPU_COUNT: '2', DRIVER: 'latest' }
90-
- { ARCH: 'amd64', PY_VER: '3.11', CUDA_VER: '12.9.1', LOCAL_CTK: '0', GPU: 't4', GPU_COUNT: '1', DRIVER: 'latest', FLAVOR: 'wsl' }
91-
- { ARCH: 'amd64', PY_VER: '3.12', CUDA_VER: '13.4.2', LOCAL_CTK: '0', GPU: 'rtx4090', GPU_COUNT: '1', DRIVER: 'latest', FLAVOR: 'wsl' }
9246
nightly:
9347
# nightly-pytorch
9448
- { ARCH: 'amd64', PY_VER: '3.12', CUDA_VER: '12.6.3', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest', ENV: { MODE: 'nightly-pytorch', TORCH_VER: '2.12.1', TORCH_CUDA: 'cu126' } }
@@ -119,29 +73,10 @@ linux:
11973

12074
windows:
12175
pull-request:
122-
# win-64
123-
- { ARCH: 'amd64', PY_VER: '3.10', CUDA_VER: '12.9.1', LOCAL_CTK: '0', GPU: 'rtx2080', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'WDDM' }
124-
- { ARCH: 'amd64', PY_VER: '3.10', CUDA_VER: '13.0.2', LOCAL_CTK: '1', GPU: 'rtxpro6000', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'TCC' }
125-
- { ARCH: 'amd64', PY_VER: '3.10', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 'rtxpro6000', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'TCC' }
126-
- { ARCH: 'amd64', PY_VER: '3.11', CUDA_VER: '12.9.1', LOCAL_CTK: '1', GPU: 'v100', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'MCDM' }
127-
- { ARCH: 'amd64', PY_VER: '3.11', CUDA_VER: '13.0.2', LOCAL_CTK: '0', GPU: 'rtx4090', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'WDDM' }
128-
- { ARCH: 'amd64', PY_VER: '3.11', CUDA_VER: '13.4.2', LOCAL_CTK: '0', GPU: 'rtx4090', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'WDDM' }
129-
- { ARCH: 'amd64', PY_VER: '3.12', CUDA_VER: '12.9.1', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'MCDM' }
130-
- { ARCH: 'amd64', PY_VER: '3.12', CUDA_VER: '13.0.2', LOCAL_CTK: '1', GPU: 'a100', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'TCC' }
76+
# TEMPORARY: trimmed to one Linux row plus one Windows TCC and one MCDM row for the
77+
# memcpy-update classification diagnostic. Do not merge.
13178
- { ARCH: 'amd64', PY_VER: '3.12', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 'a100', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'TCC' }
132-
- { ARCH: 'amd64', PY_VER: '3.13', CUDA_VER: '12.9.1', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'TCC' }
133-
- { ARCH: 'amd64', PY_VER: '3.13', CUDA_VER: '13.0.2', LOCAL_CTK: '0', GPU: 'rtxpro6000', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'MCDM' }
134-
- { ARCH: 'amd64', PY_VER: '3.13', CUDA_VER: '13.4.2', LOCAL_CTK: '0', GPU: 'rtxpro6000', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'MCDM', ENV: { CUDA_PYTHON_CUDA_PER_THREAD_DEFAULT_STREAM: '1' } }
135-
- { ARCH: 'amd64', PY_VER: '3.14', CUDA_VER: '12.9.1', LOCAL_CTK: '0', GPU: 'v100', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'TCC' }
136-
- { ARCH: 'amd64', PY_VER: '3.14', CUDA_VER: '13.0.2', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'MCDM' }
13779
- { ARCH: 'amd64', PY_VER: '3.14', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'MCDM' }
138-
- { ARCH: 'amd64', PY_VER: '3.14t', CUDA_VER: '12.9.1', LOCAL_CTK: '1', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'TCC' }
139-
- { ARCH: 'amd64', PY_VER: '3.14t', CUDA_VER: '13.0.2', LOCAL_CTK: '0', GPU: 'a100', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'MCDM' }
140-
- { ARCH: 'amd64', PY_VER: '3.14t', CUDA_VER: '13.4.2', LOCAL_CTK: '0', GPU: 'a100', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'MCDM' }
141-
- { ARCH: 'amd64', PY_VER: '3.15', CUDA_VER: '13.4.2', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'MCDM' }
142-
# special runners
143-
- { ARCH: 'amd64', PY_VER: '3.14', CUDA_VER: '13.4.2', LOCAL_CTK: '1', GPU: 't4', GPU_COUNT: '2', DRIVER: 'latest', DRIVER_MODE: 'TCC' }
144-
- { ARCH: 'amd64', PY_VER: '3.14', CUDA_VER: '13.4.2', LOCAL_CTK: '0', GPU: 'h100', GPU_COUNT: '2', DRIVER: 'latest', DRIVER_MODE: 'MCDM' }
14580
nightly:
14681
# nightly-pytorch
14782
- { ARCH: 'amd64', PY_VER: '3.12', CUDA_VER: '12.6.3', LOCAL_CTK: '0', GPU: 'l4', GPU_COUNT: '1', DRIVER: 'latest', DRIVER_MODE: 'TCC', ENV: { MODE: 'nightly-pytorch', TORCH_VER: '2.12.1', TORCH_CUDA: 'cu126' } }
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
"""TEMPORARY diagnostic for the Linux-vs-Windows-TCC difference seen in PR #3035.
6+
7+
On Linux the driver rejects an executable update that replaces a captured
8+
memcpy node's device operand with pinned host memory; Windows TCC accepts it.
9+
The driver source says the rejection comes from a check that only runs when
10+
the original operand was classified as a VA-range operand, which depends on
11+
whether the pointer lookup finds the pool object behind a pool-backed buffer.
12+
This test gathers the evidence on every CI row and FAILS ON PURPOSE so the
13+
report lands in the job log. Do not merge.
14+
"""
15+
16+
import ctypes
17+
import sys
18+
19+
import pytest
20+
21+
from cuda.core import Buffer, LegacyPinnedMemoryResource, VirtualMemoryResource, VirtualMemoryResourceOptions
22+
from cuda.core._utils.cuda_utils import CUDAError, driver, handle_return
23+
from cuda.core._utils.version import driver_version
24+
from cuda.core.graph import MemcpyNode
25+
26+
_ATTRS = [
27+
"MEMORY_TYPE",
28+
"MEMPOOL_HANDLE",
29+
"IS_MANAGED",
30+
"DEVICE_ORDINAL",
31+
"IS_LEGACY_CUDA_IPC_CAPABLE",
32+
"RANGE_START_ADDR",
33+
"RANGE_SIZE",
34+
"MAPPED",
35+
"ALLOWED_HANDLE_TYPES",
36+
"MAPPING_SIZE",
37+
"MAPPING_BASE_ADDR",
38+
"MEMORY_BLOCK_ID",
39+
"ACCESS_FLAGS",
40+
"BUFFER_ID",
41+
"CONTEXT",
42+
]
43+
44+
45+
def _attr(name, ptr):
46+
try:
47+
value = handle_return(
48+
driver.cuPointerGetAttribute(getattr(driver.CUpointer_attribute, f"CU_POINTER_ATTRIBUTE_{name}"), ptr)
49+
)
50+
except Exception as exc: # diagnostic: record anything
51+
return f"ERR({type(exc).__name__}: {str(exc)[:60]})"
52+
try:
53+
return f"0x{int(value):x}" if name.endswith(("ADDR", "HANDLE", "CONTEXT")) else str(int(value))
54+
except Exception: # diagnostic: record anything
55+
return repr(value)[:60]
56+
57+
58+
def _attempt(call):
59+
try:
60+
call()
61+
except CUDAError as exc:
62+
return f"REJECTED {str(exc)[:160]}"
63+
except Exception as exc: # diagnostic: record anything
64+
return f"RAISED {type(exc).__name__}: {str(exc)[:160]}"
65+
return "ACCEPTED"
66+
67+
68+
def _read(buffer, stream):
69+
host = LegacyPinnedMemoryResource().allocate(buffer.size)
70+
buffer.copy_to(host, stream=stream)
71+
stream.sync()
72+
return list((ctypes.c_uint8 * buffer.size).from_address(int(host.handle)))
73+
74+
75+
class _RawDevice:
76+
"""A cuMemAlloc buffer wrapped as a cuda.core Buffer (classic allocation)."""
77+
78+
def __init__(self, size):
79+
self.ptr = int(handle_return(driver.cuMemAlloc(size)))
80+
self.buffer = Buffer.from_handle(self.ptr, size)
81+
82+
def close(self):
83+
self.buffer.close()
84+
handle_return(driver.cuMemFree(self.ptr))
85+
86+
87+
def _allocators(device, stream):
88+
"""Yield (kind, allocate, raw_holders) for each allocation API under test."""
89+
pool = device.memory_resource
90+
yield "pool", lambda n: pool.allocate(n, stream=stream), []
91+
92+
raw = []
93+
94+
def allocate_raw(n):
95+
holder = _RawDevice(n)
96+
raw.append(holder)
97+
return holder.buffer
98+
99+
yield "cumemalloc", allocate_raw, raw
100+
if device.properties.virtual_memory_management_supported:
101+
vmm = VirtualMemoryResource(device, config=VirtualMemoryResourceOptions(handle_type=None))
102+
yield "vmm", lambda n: vmm.allocate(n), []
103+
104+
105+
def _probe_kind(device, stream, kind, allocate, host_src, lines):
106+
size = 64
107+
src = allocate(size)
108+
dst = allocate(size)
109+
n = dst.size # vmm rounds up
110+
src.fill(0x5A, stream=stream)
111+
dst.fill(0, stream=stream)
112+
stream.sync()
113+
lines.append(f"[{kind}] size={n}")
114+
for name, buf in (("src", src), ("dst", dst)):
115+
lines.append(f" {name} attrs: " + ", ".join(f"{a}={_attr(a, int(buf.handle))}" for a in _ATTRS))
116+
117+
builder = device.create_graph_builder().begin_building()
118+
dst.copy_from(src, stream=builder)
119+
builder.end_building()
120+
graph_def = builder.graph_definition
121+
node = next(x for x in graph_def.nodes() if isinstance(x, MemcpyNode))
122+
params = handle_return(driver.cuGraphMemcpyNodeGetParams(node.handle))
123+
lines.append(
124+
f" captured: srcMemoryType={int(params.srcMemoryType)} dstMemoryType={int(params.dstMemoryType)}"
125+
f" srcDevice=0x{int(params.srcDevice):x} dstDevice=0x{int(params.dstDevice):x} width={params.WidthInBytes}"
126+
)
127+
before = graph_def.instantiate()
128+
before.launch(stream)
129+
lines.append(f" baseline copy ok: {_read(dst, stream)[:4] == [0x5A] * 4}")
130+
131+
# 1. Replace src with pinned host memory (the PR #3035 scenario).
132+
ctypes.memset(int(host_src.handle), 0xA5, 64)
133+
lines.append(" def-node update(src=pinned host): " + _attempt(lambda: node.update(src=host_src)))
134+
params = handle_return(driver.cuGraphMemcpyNodeGetParams(node.handle))
135+
lines.append(
136+
f" recorded after: srcMemoryType={int(params.srcMemoryType)} dstMemoryType={int(params.dstMemoryType)}"
137+
)
138+
fresh = graph_def.instantiate()
139+
fresh.launch(stream)
140+
lines.append(f" fresh instantiate copies host bytes: {_read(dst, stream)[:4] == [0xA5] * 4}")
141+
dst.fill(0, stream=stream)
142+
stream.sync()
143+
outcome = _attempt(lambda: before.update(graph_def))
144+
lines.append(f" Graph.update() on earlier instantiation: {outcome}")
145+
if outcome == "ACCEPTED":
146+
before.launch(stream)
147+
lines.append(f" launch after accepted update copies host bytes: {_read(dst, stream)[:4] == [0xA5] * 4}")
148+
other = graph_def.instantiate()
149+
lines.append(
150+
" exec-view update(src=pinned host): " + _attempt(lambda: other[node].update(dst=dst, src=host_src, size=n))
151+
)
152+
153+
# 2. Control: replace src with another buffer of the same kind.
154+
same = allocate(size)
155+
same.fill(0x3C, stream=stream)
156+
stream.sync()
157+
lines.append(" def-node update(src=same kind): " + _attempt(lambda: node.update(src=same)))
158+
before2 = before
159+
lines.append(" Graph.update() on earlier instantiation: " + _attempt(lambda: before2.update(graph_def)))
160+
161+
# 3. Control: replace src with a classic cuMemAlloc buffer (different class on Linux).
162+
raw = _RawDevice(size)
163+
lines.append(" def-node update(src=cuMemAlloc buffer): " + _attempt(lambda: node.update(src=raw.buffer)))
164+
lines.append(" Graph.update() on earlier instantiation: " + _attempt(lambda: before2.update(graph_def)))
165+
raw.close()
166+
for b in (src, dst, same):
167+
b.close()
168+
169+
170+
@pytest.mark.agent_authored(model="claude-fable-5-1")
171+
def test_zz_tcc_memcpy_update_diag(init_cuda):
172+
device = init_cuda
173+
stream = device.create_stream()
174+
props = device.properties
175+
lines = [
176+
"=== TCC MEMCPY UPDATE DIAGNOSTIC ===",
177+
f"platform={sys.platform} device={device.name} driver={driver_version()}",
178+
f"tcc_driver={props.tcc_driver} unified_addressing={props.unified_addressing}"
179+
f" memory_pools_supported={props.memory_pools_supported}"
180+
f" vmm_supported={props.virtual_memory_management_supported}"
181+
f" concurrent_managed_access={props.concurrent_managed_access}",
182+
]
183+
host_src = LegacyPinnedMemoryResource().allocate(64)
184+
lines.append("pinned host attrs: " + ", ".join(f"{a}={_attr(a, int(host_src.handle))}" for a in _ATTRS))
185+
raws = []
186+
for kind, allocate, raw in _allocators(device, stream):
187+
try:
188+
_probe_kind(device, stream, kind, allocate, host_src, lines)
189+
except Exception as exc: # diagnostic: record anything
190+
lines.append(f"[{kind}] PROBE FAILED: {type(exc).__name__}: {str(exc)[:200]}")
191+
raws.extend(raw)
192+
for r in raws:
193+
r.close()
194+
lines.append("=== END DIAGNOSTIC ===")
195+
pytest.fail("\n".join(lines), pytrace=False)

0 commit comments

Comments
 (0)