|
2 | 2 | # SPDX-License-Identifier: Apache-2.0 |
3 | 3 |
|
4 | 4 |
|
| 5 | +import gc |
5 | 6 | import math |
| 7 | +import time |
6 | 8 |
|
7 | 9 | import pytest |
8 | 10 | from helpers.latch import LatchKernel |
|
15 | 17 | EventOptions, |
16 | 18 | ) |
17 | 19 |
|
| 20 | +# Short enough that a stalled host call fails fast; long enough that the |
| 21 | +# latch cannot time out on its own during the few calls it guards. |
| 22 | +_LATCH_TIMEOUT_SEC = 10 |
| 23 | + |
18 | 24 |
|
19 | 25 | def test_event_init_disabled(): |
20 | 26 | with pytest.raises(RuntimeError, match=r"^Event objects cannot be instantiated directly\."): |
@@ -120,22 +126,43 @@ def test_error_timing_recorded(): |
120 | 126 |
|
121 | 127 | @pytest.mark.skipif(Device().compute_capability.major < 7, reason="__nanosleep is only available starting Volta (sm70)") |
122 | 128 | @pytest.mark.thread_unsafe(reason="requires a barrier wait to avoid overlapping pinned latch allocations") |
| 129 | +@pytest.mark.agent_authored(model="claude-opus-5-5") |
123 | 130 | def test_error_timing_incomplete(): |
124 | 131 | device = Device() |
125 | 132 | device.set_current() |
126 | | - latch = LatchKernel(device) |
| 133 | + latch = LatchKernel(device, timeout_sec=_LATCH_TIMEOUT_SEC) |
127 | 134 | enabled = EventOptions(timing_enabled=True) |
128 | 135 | stream = device.create_stream() |
129 | 136 |
|
130 | 137 | event1 = stream.record(options=enabled) |
131 | | - latch.launch(stream) |
132 | | - event3 = stream.record(options=enabled) |
| 138 | + # Create event3 before the latch holds the stream, so that no event |
| 139 | + # creation runs while the stream is held. |
| 140 | + event3 = device.create_event(options=enabled) |
133 | 141 |
|
134 | | - # event3 will never complete because the latch has not been released |
135 | | - with pytest.raises(RuntimeError, match="^One or both events have not completed."): |
136 | | - event3 - event1 |
| 142 | + # A finalizer that frees memory synchronizes the context. If the cycle |
| 143 | + # collector runs one while the latch holds the stream, the host blocks |
| 144 | + # until the latch times out, and event3 completes (#3296). Collect now |
| 145 | + # and keep the collector off until the latch is released. |
| 146 | + gc.collect() |
| 147 | + gc_enabled = gc.isenabled() |
| 148 | + gc.disable() |
| 149 | + try: |
| 150 | + latch.launch(stream) |
| 151 | + start = time.monotonic() |
| 152 | + stream.record(event3) |
| 153 | + elapsed = time.monotonic() - start |
| 154 | + assert elapsed < _LATCH_TIMEOUT_SEC / 2, ( |
| 155 | + f"a host call blocked for {elapsed:.1f} s while the latch held the stream " |
| 156 | + f"(latch timeout {_LATCH_TIMEOUT_SEC} s)" |
| 157 | + ) |
| 158 | + # event3 cannot complete while the latch holds the stream |
| 159 | + with pytest.raises(RuntimeError, match="^One or both events have not completed."): |
| 160 | + event3 - event1 |
| 161 | + finally: |
| 162 | + latch.release() |
| 163 | + if gc_enabled: |
| 164 | + gc.enable() |
137 | 165 |
|
138 | | - latch.release() |
139 | 166 | event3.sync() |
140 | 167 | event3 - event1 # this should work |
141 | 168 |
|
|
0 commit comments