已合并
支持c++外部流接口getStreamFromExternal #34383
pwc10490创建于 4月25日
支持c++外部流接口getStreamFromExternal #34383
已合并
共 14 个文件变更+712-10
| @@ -0,0 +1,349 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | + | ||
| 6 | + | ||
| 7 | + | ||
| 8 | + | ||
| 9 | + | ||
| 10 | +using namespace at; | ||
| 11 | + | ||
| 12 | +// Get NPU device - assumes torch_npu is already initialized via import | ||
| 13 | +static c10::Device get_npu_device() { | ||
| 14 | + return c10::Device(c10::DeviceType::PrivateUse1, 0); | ||
| 15 | +} | ||
| 16 | + | ||
| 17 | +// Test 1: External stream creation | ||
| 18 | +bool test_external_stream_creation() | ||
| 19 | +{ | ||
| 20 | + // Create ACL stream directly | ||
| 21 | + aclrtStream acl_stream = nullptr; | ||
| 22 | + auto ret = aclrtCreateStream(&acl_stream); | ||
| 23 | + if (ret != ACL_ERROR_NONE || acl_stream == nullptr) { | ||
| 24 | + return false; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + // Wrap as NPUStream | ||
| 28 | + c10_npu::NPUStream npu_stream = c10_npu::getStreamFromExternal(acl_stream, 0); | ||
| 29 | + | ||
| 30 | + // Verify stream_id (bit 30 marker for external) | ||
| 31 | + c10::StreamId stream_id = npu_stream.id(); | ||
| 32 | + if (!((static_cast<uint64_t>(stream_id) & (1ULL << 30)) != 0)) { | ||
| 33 | + aclrtDestroyStream(acl_stream); | ||
| 34 | + return false; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + // Verify aclrtStream is preserved | ||
| 38 | + if (npu_stream.stream() != acl_stream) { | ||
| 39 | + aclrtDestroyStream(acl_stream); | ||
| 40 | + return false; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + // Default stream should have different encoding (bit 30 = 0) | ||
| 44 | + c10_npu::NPUStream default_stream = c10_npu::getDefaultNPUStream(0); | ||
| 45 | + c10::StreamId default_id = default_stream.id(); | ||
| 46 | + if ((static_cast<uint64_t>(default_id) & (1ULL << 30)) != 0) { | ||
| 47 | + aclrtDestroyStream(acl_stream); | ||
| 48 | + return false; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + aclrtDestroyStream(acl_stream); | ||
| 52 | + return true; | ||
| 53 | +} | ||
| 54 | + | ||
| 55 | +// Test 2: External stream as current stream | ||
| 56 | +bool test_external_stream_as_current() | ||
| 57 | +{ | ||
| 58 | + aclrtStream acl_stream = nullptr; | ||
| 59 | + auto ret = aclrtCreateStream(&acl_stream); | ||
| 60 | + if (ret != ACL_ERROR_NONE) { | ||
| 61 | + return false; | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + c10_npu::NPUStream ext_stream = c10_npu::getStreamFromExternal(acl_stream, 0); | ||
| 65 | + | ||
| 66 | + // Set current stream to external | ||
| 67 | + c10_npu::setCurrentNPUStream(ext_stream); | ||
| 68 | + | ||
| 69 | + // Get current stream - should be the external stream | ||
| 70 | + c10_npu::NPUStream current = c10_npu::getCurrentNPUStream(0); | ||
| 71 | + if (current.id() != ext_stream.id()) { | ||
| 72 | + c10_npu::setCurrentNPUStream(c10_npu::getDefaultNPUStream(0)); | ||
| 73 | + aclrtDestroyStream(acl_stream); | ||
| 74 | + return false; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + // Reset to default stream | ||
| 78 | + c10_npu::setCurrentNPUStream(c10_npu::getDefaultNPUStream(0)); | ||
| 79 | + | ||
| 80 | + aclrtDestroyStream(acl_stream); | ||
| 81 | + return true; | ||
| 82 | +} | ||
| 83 | + | ||
| 84 | +// Test 3: Tensor operations on external stream | ||
| 85 | +bool test_operations_on_external_stream() | ||
| 86 | +{ | ||
| 87 | + auto npu_device = get_npu_device(); | ||
| 88 | + | ||
| 89 | + aclrtStream acl_stream = nullptr; | ||
| 90 | + auto ret = aclrtCreateStream(&acl_stream); | ||
| 91 | + if (ret != ACL_ERROR_NONE) { | ||
| 92 | + return false; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + c10_npu::NPUStream ext_stream = c10_npu::getStreamFromExternal(acl_stream, 0); | ||
| 96 | + | ||
| 97 | + // Set current stream to external | ||
| 98 | + c10_npu::setCurrentNPUStream(ext_stream); | ||
| 99 | + | ||
| 100 | + // Execute operations - should work synchronously on external stream | ||
| 101 | + auto a = torch::randn({2, 3}).to(npu_device); | ||
| 102 | + auto b = torch::randn({2, 3}).to(npu_device); | ||
| 103 | + auto c = a + b; | ||
| 104 | + | ||
| 105 | + bool success = (c.size(0) == 2 && c.size(1) == 3); | ||
| 106 | + | ||
| 107 | + // Reset to default stream BEFORE tensor destruction | ||
| 108 | + c10_npu::setCurrentNPUStream(c10_npu::getDefaultNPUStream(0)); | ||
| 109 | + | ||
| 110 | + aclrtDestroyStream(acl_stream); | ||
| 111 | + return success; | ||
| 112 | +} | ||
| 113 | + | ||
| 114 | +// Test 4: Event record restriction | ||
| 115 | +bool test_event_record_restriction() | ||
| 116 | +{ | ||
| 117 | + aclrtStream acl_stream = nullptr; | ||
| 118 | + auto ret = aclrtCreateStream(&acl_stream); | ||
| 119 | + if (ret != ACL_ERROR_NONE) { | ||
| 120 | + return false; | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + c10_npu::NPUStream ext_stream = c10_npu::getStreamFromExternal(acl_stream, 0); | ||
| 124 | + | ||
| 125 | + c10_npu::NPUEvent event; | ||
| 126 | + | ||
| 127 | + // record() should throw for external stream | ||
| 128 | + bool threw = false; | ||
| 129 | + try { | ||
| 130 | + event.record(ext_stream); | ||
| 131 | + } catch (const c10::Error&) { | ||
| 132 | + threw = true; | ||
| 133 | + } | ||
| 134 | + | ||
| 135 | + aclrtDestroyStream(acl_stream); | ||
| 136 | + return threw; | ||
| 137 | +} | ||
| 138 | + | ||
| 139 | +// Test 5: Event block restriction | ||
| 140 | +bool test_event_block_restriction() | ||
| 141 | +{ | ||
| 142 | + aclrtStream acl_stream = nullptr; | ||
| 143 | + auto ret = aclrtCreateStream(&acl_stream); | ||
| 144 | + if (ret != ACL_ERROR_NONE) { | ||
| 145 | + return false; | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + c10_npu::NPUStream ext_stream = c10_npu::getStreamFromExternal(acl_stream, 0); | ||
| 149 | + | ||
| 150 | + c10_npu::NPUEvent event; | ||
| 151 | + | ||
| 152 | + // block() should throw for external stream | ||
| 153 | + bool threw = false; | ||
| 154 | + try { | ||
| 155 | + event.block(ext_stream); | ||
| 156 | + } catch (const c10::Error&) { | ||
| 157 | + threw = true; | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + aclrtDestroyStream(acl_stream); | ||
| 161 | + return threw; | ||
| 162 | +} | ||
| 163 | + | ||
| 164 | +// Test 6: Graph capture restriction | ||
| 165 | +bool test_graph_capture_restriction() | ||
| 166 | +{ | ||
| 167 | + aclrtStream acl_stream = nullptr; | ||
| 168 | + auto ret = aclrtCreateStream(&acl_stream); | ||
| 169 | + if (ret != ACL_ERROR_NONE) { | ||
| 170 | + return false; | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + c10_npu::NPUStream ext_stream = c10_npu::getStreamFromExternal(acl_stream, 0); | ||
| 174 | + | ||
| 175 | + // Set current stream to external | ||
| 176 | + c10_npu::setCurrentNPUStream(ext_stream); | ||
| 177 | + | ||
| 178 | + c10_npu::NPUGraph graph; | ||
| 179 | + | ||
| 180 | + // capture_begin should throw | ||
| 181 | + bool threw = false; | ||
| 182 | + try { | ||
| 183 | + graph.capture_begin(); | ||
| 184 | + } catch (const c10::Error&) { | ||
| 185 | + threw = true; | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + // Reset to default stream | ||
| 189 | + c10_npu::setCurrentNPUStream(c10_npu::getDefaultNPUStream(0)); | ||
| 190 | + | ||
| 191 | + aclrtDestroyStream(acl_stream); | ||
| 192 | + return threw; | ||
| 193 | +} | ||
| 194 | + | ||
| 195 | +// Test 7: Query restriction | ||
| 196 | +bool test_query_restriction() | ||
| 197 | +{ | ||
| 198 | + aclrtStream acl_stream = nullptr; | ||
| 199 | + auto ret = aclrtCreateStream(&acl_stream); | ||
| 200 | + if (ret != ACL_ERROR_NONE) { | ||
| 201 | + return false; | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + c10_npu::NPUStream ext_stream = c10_npu::getStreamFromExternal(acl_stream, 0); | ||
| 205 | + | ||
| 206 | + // query() should throw | ||
| 207 | + bool threw = false; | ||
| 208 | + try { | ||
| 209 | + ext_stream.query(); | ||
| 210 | + } catch (const c10::Error&) { | ||
| 211 | + threw = true; | ||
| 212 | + } | ||
| 213 | + | ||
| 214 | + aclrtDestroyStream(acl_stream); | ||
| 215 | + return threw; | ||
| 216 | +} | ||
| 217 | + | ||
| 218 | +// Test 8: Synchronize restriction | ||
| 219 | +bool test_synchronize_restriction() | ||
| 220 | +{ | ||
| 221 | + aclrtStream acl_stream = nullptr; | ||
| 222 | + auto ret = aclrtCreateStream(&acl_stream); | ||
| 223 | + if (ret != ACL_ERROR_NONE) { | ||
| 224 | + return false; | ||
| 225 | + } | ||
| 226 | + | ||
| 227 | + c10_npu::NPUStream ext_stream = c10_npu::getStreamFromExternal(acl_stream, 0); | ||
| 228 | + | ||
| 229 | + // synchronize() should throw | ||
| 230 | + bool threw = false; | ||
| 231 | + try { | ||
| 232 | + ext_stream.synchronize(); | ||
| 233 | + } catch (const c10::Error&) { | ||
| 234 | + threw = true; | ||
| 235 | + } | ||
| 236 | + | ||
| 237 | + aclrtDestroyStream(acl_stream); | ||
| 238 | + return threw; | ||
| 239 | +} | ||
| 240 | + | ||
| 241 | +// Test 9: isSyncLaunchStream | ||
| 242 | +bool test_is_sync_launch_stream() | ||
| 243 | +{ | ||
| 244 | + aclrtStream acl_stream = nullptr; | ||
| 245 | + auto ret = aclrtCreateStream(&acl_stream); | ||
| 246 | + if (ret != ACL_ERROR_NONE) { | ||
| 247 | + return false; | ||
| 248 | + } | ||
| 249 | + | ||
| 250 | + c10_npu::NPUStream ext_stream = c10_npu::getStreamFromExternal(acl_stream, 0); | ||
| 251 | + | ||
| 252 | + // External stream should NOT be sync launch stream | ||
| 253 | + bool is_sync = ext_stream.isSyncLaunchStream(); | ||
| 254 | + | ||
| 255 | + aclrtDestroyStream(acl_stream); | ||
| 256 | + return !is_sync; | ||
| 257 | +} | ||
| 258 | + | ||
| 259 | +// Test 10: Multiple external streams | ||
| 260 | +bool test_multiple_external_streams() | ||
| 261 | +{ | ||
| 262 | + aclrtStream acl_stream1 = nullptr; | ||
| 263 | + aclrtStream acl_stream2 = nullptr; | ||
| 264 | + auto ret1 = aclrtCreateStream(&acl_stream1); | ||
| 265 | + auto ret2 = aclrtCreateStream(&acl_stream2); | ||
| 266 | + | ||
| 267 | + if (ret1 != ACL_ERROR_NONE || ret2 != ACL_ERROR_NONE) { | ||
| 268 | + if (acl_stream1) aclrtDestroyStream(acl_stream1); | ||
| 269 | + if (acl_stream2) aclrtDestroyStream(acl_stream2); | ||
| 270 | + return false; | ||
| 271 | + } | ||
| 272 | + | ||
| 273 | + c10_npu::NPUStream npu_stream1 = c10_npu::getStreamFromExternal(acl_stream1, 0); | ||
| 274 | + c10_npu::NPUStream npu_stream2 = c10_npu::getStreamFromExternal(acl_stream2, 0); | ||
| 275 | + | ||
| 276 | + // Stream IDs should be different | ||
| 277 | + bool ids_different = (npu_stream1.id() != npu_stream2.id()); | ||
| 278 | + | ||
| 279 | + // Both should have bit 30 marker | ||
| 280 | + bool both_external = ((static_cast<uint64_t>(npu_stream1.id()) & (1ULL << 30)) != 0) && | ||
| 281 | + ((static_cast<uint64_t>(npu_stream2.id()) & (1ULL << 30)) != 0); | ||
| 282 | + | ||
| 283 | + // aclrtStream values should be preserved | ||
| 284 | + bool streams_preserved = (npu_stream1.stream() == acl_stream1) && | ||
| 285 | + (npu_stream2.stream() == acl_stream2); | ||
| 286 | + | ||
| 287 | + aclrtDestroyStream(acl_stream1); | ||
| 288 | + aclrtDestroyStream(acl_stream2); | ||
| 289 | + | ||
| 290 | + return ids_different && both_external && streams_preserved; | ||
| 291 | +} | ||
| 292 | + | ||
| 293 | +// Test 11: Same acl_stream returns same NPUStream | ||
| 294 | +bool test_same_acl_stream_same_npu_stream() | ||
| 295 | +{ | ||
| 296 | + aclrtStream acl_stream = nullptr; | ||
| 297 | + auto ret = aclrtCreateStream(&acl_stream); | ||
| 298 | + if (ret != ACL_ERROR_NONE) { | ||
| 299 | + return false; | ||
| 300 | + } | ||
| 301 | + | ||
| 302 | + // Call getStreamFromExternal twice with same acl_stream | ||
| 303 | + c10_npu::NPUStream npu_stream1 = c10_npu::getStreamFromExternal(acl_stream, 0); | ||
| 304 | + c10_npu::NPUStream npu_stream2 = c10_npu::getStreamFromExternal(acl_stream, 0); | ||
| 305 | + | ||
| 306 | + // Should return same NPUStream (same stream_id) | ||
| 307 | + bool same = (npu_stream1.id() == npu_stream2.id()); | ||
| 308 | + | ||
| 309 | + aclrtDestroyStream(acl_stream); | ||
| 310 | + return same; | ||
| 311 | +} | ||
| 312 | + | ||
| 313 | +// Test 12: Pool stream vs external stream | ||
| 314 | +bool test_pool_vs_external_stream() | ||
| 315 | +{ | ||
| 316 | + aclrtStream acl_stream = nullptr; | ||
| 317 | + auto ret = aclrtCreateStream(&acl_stream); | ||
| 318 | + if (ret != ACL_ERROR_NONE) { | ||
| 319 | + return false; | ||
| 320 | + } | ||
| 321 | + | ||
| 322 | + c10_npu::NPUStream ext_stream = c10_npu::getStreamFromExternal(acl_stream, 0); | ||
| 323 | + c10_npu::NPUStream pool_stream = c10_npu::getNPUStreamFromPool(0); | ||
| 324 | + | ||
| 325 | + // External stream has bit 30 = 1 | ||
| 326 | + bool ext_has_marker = (static_cast<uint64_t>(ext_stream.id()) & (1ULL << 30)) != 0; | ||
| 327 | + | ||
| 328 | + // Pool stream has bit 30 = 0 | ||
| 329 | + bool pool_no_marker = (static_cast<uint64_t>(pool_stream.id()) & (1ULL << 30)) == 0; | ||
| 330 | + | ||
| 331 | + aclrtDestroyStream(acl_stream); | ||
| 332 | + return ext_has_marker && pool_no_marker; | ||
| 333 | +} | ||
| 334 | + | ||
| 335 | +PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) | ||
| 336 | +{ | ||
| 337 | + m.def("test_external_stream_creation", &test_external_stream_creation); | ||
| 338 | + m.def("test_external_stream_as_current", &test_external_stream_as_current); | ||
| 339 | + m.def("test_operations_on_external_stream", &test_operations_on_external_stream); | ||
| 340 | + m.def("test_event_record_restriction", &test_event_record_restriction); | ||
| 341 | + m.def("test_event_block_restriction", &test_event_block_restriction); | ||
| 342 | + m.def("test_graph_capture_restriction", &test_graph_capture_restriction); | ||
| 343 | + m.def("test_query_restriction", &test_query_restriction); | ||
| 344 | + m.def("test_synchronize_restriction", &test_synchronize_restriction); | ||
| 345 | + m.def("test_is_sync_launch_stream", &test_is_sync_launch_stream); | ||
| 346 | + m.def("test_multiple_external_streams", &test_multiple_external_streams); | ||
| 347 | + m.def("test_same_acl_stream_same_npu_stream", &test_same_acl_stream_same_npu_stream); | ||
| 348 | + m.def("test_pool_vs_external_stream", &test_pool_vs_external_stream); | ||
| 349 | +} | ||
| @@ -28,6 +28,9 @@ ext_modules = [ | |||
| 28 | NpuExtension( | 28 | NpuExtension( |
| 29 | 'torch_test_cpp_extension.npu_from_blob', ['test_from_blob.cpp'], | 29 | 'torch_test_cpp_extension.npu_from_blob', ['test_from_blob.cpp'], |
| 30 | extra_compile_args=CXX_FLAGS), | 30 | extra_compile_args=CXX_FLAGS), |
| 31 | + NpuExtension( | ||
| 32 | + 'torch_test_cpp_extension.npu_external_stream', ['external_stream_test.cpp'], | ||
| 33 | + extra_compile_args=CXX_FLAGS), | ||
| 31 | NpuExtension( | 34 | NpuExtension( |
| 32 | 'torch_test_cpp_extension.stable_libtorch', ['test_stable_libtorch.cpp'], | 35 | 'torch_test_cpp_extension.stable_libtorch', ['test_stable_libtorch.cpp'], |
| 33 | extra_compile_args=CXX_FLAGS), | 36 | extra_compile_args=CXX_FLAGS), |
| @@ -0,0 +1,85 @@ | |||
| 1 | +import os | ||
| 2 | +import sys | ||
| 3 | +from pathlib import Path | ||
| 4 | +import unittest | ||
| 5 | + | ||
| 6 | +REPO_ROOT = Path(__file__).resolve().parents[3] | ||
| 7 | +CPP_EXTENSIONS_DIR = REPO_ROOT / "test" / "cpp_extensions" | ||
| 8 | + | ||
| 9 | +os.environ["TORCH_DEVICE_BACKEND_AUTOLOAD"] = "0" | ||
| 10 | +for path in ("", str(REPO_ROOT)): | ||
| 11 | + while path in sys.path: | ||
| 12 | + sys.path.remove(path) | ||
| 13 | + | ||
| 14 | +sys.path.insert(0, str(CPP_EXTENSIONS_DIR)) | ||
| 15 | + | ||
| 16 | +import torch | ||
| 17 | +import torch_npu | ||
| 18 | +from torch_npu.testing.testcase import TestCase, run_tests | ||
| 19 | + | ||
| 20 | +from torch_test_cpp_extension.load_external_stream import load_external_stream_extension | ||
| 21 | + | ||
| 22 | +ext_stream_ext = load_external_stream_extension() | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +class TestExternalStream(TestCase): | ||
| 26 | + """Tests for external NPU stream functionality | ||
| 27 | + | ||
| 28 | + These tests verify: | ||
| 29 | + 1. External stream creation via getStreamFromExternal | ||
| 30 | + 2. Stream ID encoding (bit 30 marker for external streams) | ||
| 31 | + 3. Proper restrictions on external streams (event, graph, query, sync) | ||
| 32 | + 4. Basic operations work on external streams | ||
| 33 | + """ | ||
| 34 | + | ||
| 35 | + def test_external_stream_creation(self): | ||
| 36 | + """Test external stream creation and ID encoding""" | ||
| 37 | + self.assertTrue(ext_stream_ext.test_external_stream_creation()) | ||
| 38 | + | ||
| 39 | + def test_external_stream_as_current(self): | ||
| 40 | + """Test setCurrentNPUStream/getCurrentNPUStream with external stream""" | ||
| 41 | + self.assertTrue(ext_stream_ext.test_external_stream_as_current()) | ||
| 42 | + | ||
| 43 | + def test_operations_on_external_stream(self): | ||
| 44 | + """Test tensor operations on external stream""" | ||
| 45 | + self.assertTrue(ext_stream_ext.test_operations_on_external_stream()) | ||
| 46 | + | ||
| 47 | + def test_event_record_restriction(self): | ||
| 48 | + """Test NPUEvent.record() throws for external stream""" | ||
| 49 | + self.assertTrue(ext_stream_ext.test_event_record_restriction()) | ||
| 50 | + | ||
| 51 | + def test_event_block_restriction(self): | ||
| 52 | + """Test NPUEvent.block() throws for external stream""" | ||
| 53 | + self.assertTrue(ext_stream_ext.test_event_block_restriction()) | ||
| 54 | + | ||
| 55 | + def test_graph_capture_restriction(self): | ||
| 56 | + """Test NPUGraph.capture_begin() throws when current stream is external""" | ||
| 57 | + self.assertTrue(ext_stream_ext.test_graph_capture_restriction()) | ||
| 58 | + | ||
| 59 | + def test_query_restriction(self): | ||
| 60 | + """Test NPUStream.query() throws for external stream""" | ||
| 61 | + self.assertTrue(ext_stream_ext.test_query_restriction()) | ||
| 62 | + | ||
| 63 | + def test_synchronize_restriction(self): | ||
| 64 | + """Test NPUStream.synchronize() throws for external stream""" | ||
| 65 | + self.assertTrue(ext_stream_ext.test_synchronize_restriction()) | ||
| 66 | + | ||
| 67 | + def test_is_sync_launch_stream(self): | ||
| 68 | + """Test external stream is not a sync launch stream""" | ||
| 69 | + self.assertTrue(ext_stream_ext.test_is_sync_launch_stream()) | ||
| 70 | + | ||
| 71 | + def test_multiple_external_streams(self): | ||
| 72 | + """Test multiple external streams have unique IDs""" | ||
| 73 | + self.assertTrue(ext_stream_ext.test_multiple_external_streams()) | ||
| 74 | + | ||
| 75 | + def test_same_acl_stream_same_npu_stream(self): | ||
| 76 | + """Test getStreamFromExternal is idempotent""" | ||
| 77 | + self.assertTrue(ext_stream_ext.test_same_acl_stream_same_npu_stream()) | ||
| 78 | + | ||
| 79 | + def test_pool_vs_external_stream(self): | ||
| 80 | + """Test pool stream vs external stream ID encoding""" | ||
| 81 | + self.assertTrue(ext_stream_ext.test_pool_vs_external_stream()) | ||
| 82 | + | ||
| 83 | + | ||
| 84 | +if __name__ == "__main__": | ||
| 85 | + run_tests() | ||
| @@ -0,0 +1,56 @@ | |||
| 1 | +import importlib | ||
| 2 | +import os | ||
| 3 | +import subprocess | ||
| 4 | +import sys | ||
| 5 | +from pathlib import Path | ||
| 6 | + | ||
| 7 | + | ||
| 8 | +REPO_ROOT = Path(__file__).resolve().parents[3] | ||
| 9 | +BUILD_PACKAGES_DIR = REPO_ROOT / "build" / "packages" | ||
| 10 | +CPP_EXTENSIONS_DIR = REPO_ROOT / "test" / "cpp_extensions" | ||
| 11 | +MODULE_NAME = "torch_test_cpp_extension.npu_external_stream" | ||
| 12 | + | ||
| 13 | + | ||
| 14 | +def _build_pythonpath_for_subprocess(): | ||
| 15 | + parts = [] | ||
| 16 | + if BUILD_PACKAGES_DIR.exists(): | ||
| 17 | + parts.append(str(BUILD_PACKAGES_DIR)) | ||
| 18 | + existing = os.environ.get("PYTHONPATH") | ||
| 19 | + if existing: | ||
| 20 | + filtered = [p for p in existing.split(os.pathsep) if p != str(REPO_ROOT)] | ||
| 21 | + parts.extend(filtered) | ||
| 22 | + return os.pathsep.join(parts) | ||
| 23 | + | ||
| 24 | + | ||
| 25 | +def _build_extension_inplace(): | ||
| 26 | + env = os.environ.copy() | ||
| 27 | + pythonpath = _build_pythonpath_for_subprocess() | ||
| 28 | + if pythonpath: | ||
| 29 | + env["PYTHONPATH"] = pythonpath | ||
| 30 | + | ||
| 31 | + subprocess.run( | ||
| 32 | + [sys.executable, "setup.py", "build_ext", "--inplace"], | ||
| 33 | + cwd=str(CPP_EXTENSIONS_DIR), | ||
| 34 | + check=True, | ||
| 35 | + env=env, | ||
| 36 | + ) | ||
| 37 | + | ||
| 38 | + | ||
| 39 | +def load_external_stream_extension(): | ||
| 40 | + for path in ("", str(REPO_ROOT)): | ||
| 41 | + while path in sys.path: | ||
| 42 | + sys.path.remove(path) | ||
| 43 | + | ||
| 44 | + os.environ["TORCH_DEVICE_BACKEND_AUTOLOAD"] = "0" | ||
| 45 | + | ||
| 46 | + import torch # noqa: F401 | ||
| 47 | + | ||
| 48 | + import torch_npu # noqa: F401 | ||
O | |||
| 49 | + | ||
| 50 | + try: | ||
O 【openlibing.ci】识别到代码检查告警抑制注释,匹配工具:flake8,请Committer检视其合理性。 ![]() ![]() | |||
| 51 | + return importlib.import_module(MODULE_NAME) | ||
| 52 | + except ImportError: | ||
| 53 | + _build_extension_inplace() | ||
| 54 | + sys.modules.pop(MODULE_NAME, None) | ||
| 55 | + importlib.invalidate_caches() | ||
| 56 | + return importlib.import_module(MODULE_NAME) | ||
| @@ -1,4 +1,5 @@ | |||
| 1 | 1 | ||
| 2 | + | ||
| 2 | 3 | ||
| 3 | 4 | ||
| 4 | namespace at_npu { | 5 | namespace at_npu { |
| @@ -7,10 +8,12 @@ namespace native { | |||
| 7 | void NPUNativeFunctions::record_stream(at::Tensor& self, c10::Stream stream) | 8 | void NPUNativeFunctions::record_stream(at::Tensor& self, c10::Stream stream) |
| 8 | { | 9 | { |
| 9 | struct c10::StreamData3 data = stream.pack3(); | 10 | struct c10::StreamData3 data = stream.pack3(); |
| 11 | + auto npu_stream = c10_npu::NPUStream::unpack3( | ||
| 12 | + data.stream_id, data.device_index, data.device_type); | ||
| 13 | + c10_npu::detail::checkNotExternalStream(npu_stream, "record_stream"); | ||
| 10 | c10_npu::NPUCachingAllocator::recordStream( | 14 | c10_npu::NPUCachingAllocator::recordStream( |
| 11 | self.storage().data_ptr(), | 15 | self.storage().data_ptr(), |
| 12 | - c10_npu::NPUStream::unpack3( | 16 | + npu_stream); |
| 13 | - data.stream_id, data.device_index, data.device_type)); | ||
| 14 | } | 17 | } |
| 15 | 18 | ||
| 16 | } // namespace native | 19 | } // namespace native |
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | 6 | ||
| 7 | + | ||
| 7 | 8 | ||
| 8 | 9 | ||
| 9 | 10 | ||
| @@ -113,6 +114,7 @@ void NPUEvent::recordOnce(const NPUStream& stream) | |||
| 113 | 114 | ||
| 114 | void NPUEvent::record(const NPUStream& stream) | 115 | void NPUEvent::record(const NPUStream& stream) |
| 115 | { | 116 | { |
| 117 | + c10_npu::detail::checkNotExternalStream(stream, "NPUEvent::record"); | ||
| 116 | if (!is_created_) { | 118 | if (!is_created_) { |
| 117 | createEvent(stream.device_index()); | 119 | createEvent(stream.device_index()); |
| 118 | } | 120 | } |
| @@ -131,6 +133,7 @@ void NPUEvent::record(const NPUStream& stream) | |||
| 131 | 133 | ||
| 132 | void NPUEvent::block(const NPUStream& stream) | 134 | void NPUEvent::block(const NPUStream& stream) |
| 133 | { | 135 | { |
| 136 | + c10_npu::detail::checkNotExternalStream(stream, "NPUEvent::block"); | ||
| 134 | if (is_created_) { | 137 | if (is_created_) { |
| 135 | // If using multiple task queues or using IPC events across devices in a single process, | 138 | // If using multiple task queues or using IPC events across devices in a single process, |
| 136 | // it is necessary to ensure that the enqueued record is dequeued before wait. | 139 | // it is necessary to ensure that the enqueued record is dequeued before wait. |
| @@ -1,6 +1,7 @@ | |||
| 1 | 1 | ||
| 2 | 2 | ||
| 3 | 3 | ||
| 4 | + | ||
| 4 | 5 | ||
| 5 | 6 | ||
| 6 | 7 | ||
| @@ -48,11 +49,13 @@ MempoolId_t graph_pool_handle() | |||
| 48 | 49 | ||
| 49 | void graph_task_group_begin(c10_npu::NPUStream stream) | 50 | void graph_task_group_begin(c10_npu::NPUStream stream) |
| 50 | { | 51 | { |
| 52 | + c10_npu::detail::checkNotExternalStream(stream, "graph_task_group_begin"); | ||
| 51 | NPU_CHECK_ERROR(c10_npu::acl::AclmdlRICaptureTaskGrpBegin(stream)); | 53 | NPU_CHECK_ERROR(c10_npu::acl::AclmdlRICaptureTaskGrpBegin(stream)); |
| 52 | } | 54 | } |
| 53 | 55 | ||
| 54 | NPUTaskGroupHandle graph_task_group_end(c10_npu::NPUStream stream) | 56 | NPUTaskGroupHandle graph_task_group_end(c10_npu::NPUStream stream) |
| 55 | { | 57 | { |
| 58 | + c10_npu::detail::checkNotExternalStream(stream, "graph_task_group_end"); | ||
| 56 | aclrtTaskGrp group; | 59 | aclrtTaskGrp group; |
| 57 | NPU_CHECK_ERROR(c10_npu::acl::AclmdlRICaptureTaskGrpEnd(stream, &group)); | 60 | NPU_CHECK_ERROR(c10_npu::acl::AclmdlRICaptureTaskGrpEnd(stream, &group)); |
| 58 | NPUTaskGroupHandle handle; | 61 | NPUTaskGroupHandle handle; |
| @@ -62,28 +65,33 @@ NPUTaskGroupHandle graph_task_group_end(c10_npu::NPUStream stream) | |||
| 62 | 65 | ||
| 63 | void graph_task_update_begin(c10_npu::NPUStream stream, NPUTaskGroupHandle handle) | 66 | void graph_task_update_begin(c10_npu::NPUStream stream, NPUTaskGroupHandle handle) |
| 64 | { | 67 | { |
| 68 | + c10_npu::detail::checkNotExternalStream(stream, "graph_task_update_begin"); | ||
| 65 | NPU_CHECK_ERROR(c10_npu::acl::AclmdlRICaptureTaskUpdateBegin(stream, handle.task_group)); | 69 | NPU_CHECK_ERROR(c10_npu::acl::AclmdlRICaptureTaskUpdateBegin(stream, handle.task_group)); |
| 66 | } | 70 | } |
| 67 | 71 | ||
| 68 | void graph_task_update_end(c10_npu::NPUStream stream) | 72 | void graph_task_update_end(c10_npu::NPUStream stream) |
| 69 | { | 73 | { |
| 74 | + c10_npu::detail::checkNotExternalStream(stream, "graph_task_update_end"); | ||
| 70 | NPU_CHECK_ERROR(c10_npu::acl::AclmdlRICaptureTaskUpdateEnd(stream)); | 75 | NPU_CHECK_ERROR(c10_npu::acl::AclmdlRICaptureTaskUpdateEnd(stream)); |
| 71 | } | 76 | } |
| 72 | 77 | ||
| 73 | void super_kernel_scope_begin(const char* scope_name) | 78 | void super_kernel_scope_begin(const char* scope_name) |
| 74 | { | 79 | { |
| 75 | auto stream = c10_npu::getCurrentNPUStream(); | 80 | auto stream = c10_npu::getCurrentNPUStream(); |
| 81 | + c10_npu::detail::checkNotExternalStream(stream, "super_kernel_scope_begin"); | ||
| 76 | NPU_CHECK_ERROR(c10_npu::skapi::AclskScopeBegin(scope_name, stream)); | 82 | NPU_CHECK_ERROR(c10_npu::skapi::AclskScopeBegin(scope_name, stream)); |
| 77 | } | 83 | } |
| 78 | 84 | ||
| 79 | void super_kernel_scope_end(const char* scope_name) | 85 | void super_kernel_scope_end(const char* scope_name) |
| 80 | { | 86 | { |
| 81 | auto stream = c10_npu::getCurrentNPUStream(); | 87 | auto stream = c10_npu::getCurrentNPUStream(); |
| 88 | + c10_npu::detail::checkNotExternalStream(stream, "super_kernel_scope_end"); | ||
| 82 | NPU_CHECK_ERROR(c10_npu::skapi::AclskScopeEnd(scope_name, stream)); | 89 | NPU_CHECK_ERROR(c10_npu::skapi::AclskScopeEnd(scope_name, stream)); |
| 83 | } | 90 | } |
| 84 | 91 | ||
| 85 | void launch_callback(c10_npu::NPUStream stream, NPUCallbackFunc func, void *fnData) | 92 | void launch_callback(c10_npu::NPUStream stream, NPUCallbackFunc func, void *fnData) |
| 86 | { | 93 | { |
| 94 | + c10_npu::detail::checkNotExternalStream(stream, "launch_callback"); | ||
| 87 | aclrtCallbackBlockType type = aclrtCallbackBlockType::ACL_CALLBACK_BLOCK; | 95 | aclrtCallbackBlockType type = aclrtCallbackBlockType::ACL_CALLBACK_BLOCK; |
| 88 | NPU_CHECK_ERROR(c10_npu::acl::AclrtLaunchCallback(func, fnData, type, stream)); | 96 | NPU_CHECK_ERROR(c10_npu::acl::AclrtLaunchCallback(func, fnData, type, stream)); |
| 89 | } | 97 | } |
| @@ -95,11 +103,13 @@ void launch_host_func(c10_npu::NPUStream stream, NPUCallbackFunc func, void *fnD | |||
| 95 | 103 | ||
| 96 | void subscribe_report(uint64_t threadId, c10_npu::NPUStream stream) | 104 | void subscribe_report(uint64_t threadId, c10_npu::NPUStream stream) |
| 97 | { | 105 | { |
| 106 | + c10_npu::detail::checkNotExternalStream(stream, "subscribe_report"); | ||
| 98 | NPU_CHECK_ERROR(c10_npu::acl::AclrtSubscribeReport(threadId, stream)); | 107 | NPU_CHECK_ERROR(c10_npu::acl::AclrtSubscribeReport(threadId, stream)); |
| 99 | } | 108 | } |
| 100 | 109 | ||
| 101 | void unsubscribe_report(uint64_t threadId, c10_npu::NPUStream stream) | 110 | void unsubscribe_report(uint64_t threadId, c10_npu::NPUStream stream) |
| 102 | { | 111 | { |
| 112 | + c10_npu::detail::checkNotExternalStream(stream, "unsubscribe_report"); | ||
| 103 | NPU_CHECK_ERROR(c10_npu::acl::AclrtUnSubscribeReport(threadId, stream)); | 113 | NPU_CHECK_ERROR(c10_npu::acl::AclrtUnSubscribeReport(threadId, stream)); |
| 104 | } | 114 | } |
| 105 | 115 | ||
| @@ -177,6 +187,7 @@ void NPUGraph::capture_begin(MempoolId_t pool, aclmdlRICaptureMode capture_mode, | |||
| 177 | "To capture a new graph, create a new instance."); | 187 | "To capture a new graph, create a new instance."); |
| 178 | 188 | ||
| 179 | auto stream = c10_npu::getCurrentNPUStream(); | 189 | auto stream = c10_npu::getCurrentNPUStream(); |
| 190 | + c10_npu::detail::checkNotExternalStream(stream, "NPUGraph::capture_begin"); | ||
| 180 | 191 | ||
| 181 | TORCH_CHECK(stream != c10_npu::getDefaultNPUStream(), | 192 | TORCH_CHECK(stream != c10_npu::getDefaultNPUStream(), |
| 182 | "NPU graphs must be captured on a non-default stream. " | 193 | "NPU graphs must be captured on a non-default stream. " |
| @@ -246,6 +257,8 @@ void NPUGraph::capture_end() | |||
| 246 | NPUGRAPH_LOGD("[NPUGRAPH][Capture] end"); | 257 | NPUGRAPH_LOGD("[NPUGRAPH][Capture] end"); |
| 247 | auto stream = c10_npu::getCurrentNPUStream(); | 258 | auto stream = c10_npu::getCurrentNPUStream(); |
| 248 | 259 | ||
| 260 | + c10_npu::detail::checkNotExternalStream(stream, "NPUGraph::capture_end"); | ||
| 261 | + | ||
| 249 | TORCH_CHECK(stream == capture_stream_, | 262 | TORCH_CHECK(stream == capture_stream_, |
| 250 | "Capture must end on the same stream it began on."); | 263 | "Capture must end on the same stream it began on."); |
| 251 | 264 | ||
| @@ -291,9 +304,8 @@ void NPUGraph::replay() | |||
| 291 | // model_ri_ may be replayed in any stream. | 304 | // model_ri_ may be replayed in any stream. |
| 292 | auto stream = c10_npu::getCurrentNPUStream(); | 305 | auto stream = c10_npu::getCurrentNPUStream(); |
| 293 | NPU_CHECK_ERROR(c10_npu::acl::AclmdlRIExecuteAsync(model_ri_, stream)); | 306 | NPU_CHECK_ERROR(c10_npu::acl::AclmdlRIExecuteAsync(model_ri_, stream)); |
| 294 | - // With ASCEND_LAUNCH_BLOCKING enabled, after an aclgraph replay completes, | 307 | + if (c10_npu::option::OptionsManager::CheckBlockingEnable() && |
| 295 | - // we need to add an explicit synchronization step. | 308 | + !c10_npu::detail::isExternalStream(stream)) { |
| 296 | - if (c10_npu::option::OptionsManager::CheckBlockingEnable()) { | ||
| 297 | NPU_CHECK_ERROR(c10_npu::acl::AclrtSynchronizeStreamWithTimeout(stream)); | 309 | NPU_CHECK_ERROR(c10_npu::acl::AclrtSynchronizeStreamWithTimeout(stream)); |
| 298 | } | 310 | } |
| 299 | } | 311 | } |
| @@ -1,4 +1,5 @@ | |||
| 1 | 1 | ||
| 2 | + | ||
| 2 | 3 | ||
| 3 | 4 | ||
| 4 | namespace c10_npu { | 5 | namespace c10_npu { |
| @@ -8,6 +9,10 @@ CaptureStatus currentStreamCaptureStatusMayInitCtx() | |||
| 8 | return CaptureStatus::None; | 9 | return CaptureStatus::None; |
| 9 | } | 10 | } |
| 10 | 11 | ||
| 12 | + if (c10_npu::detail::isCurrentStreamExternal()) { | ||
| 13 | + return CaptureStatus::None; | ||
| 14 | + } | ||
| 15 | + | ||
| 11 | aclmdlRICaptureStatus is_capturing{ACL_MODEL_RI_CAPTURE_STATUS_NONE}; | 16 | aclmdlRICaptureStatus is_capturing{ACL_MODEL_RI_CAPTURE_STATUS_NONE}; |
| 12 | aclmdlRI model_ri; | 17 | aclmdlRI model_ri; |
| 13 | auto s = c10_npu::getCurrentNPUStream(); | 18 | auto s = c10_npu::getCurrentNPUStream(); |
| @@ -3,6 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | + | ||
| 7 | + | ||
| 6 | 8 | ||
| 7 | 9 | ||
| 8 | 10 | ||
| @@ -15,6 +17,7 @@ | |||
| 15 | 17 | ||
| 16 | 18 | ||
| 17 | 19 | ||
| 20 | + | ||
| 18 | 21 | ||
| 19 | 22 | ||
| 20 | 23 | ||
| @@ -44,7 +47,7 @@ struct LeakyStreamInternals { | |||
| 44 | } | 47 | } |
| 45 | 48 | ||
| 46 | c10::DeviceIndex device_index = -1; | 49 | c10::DeviceIndex device_index = -1; |
| 47 | - int32_t stream_id = -1; | 50 | + int64_t stream_id = 0x3FFFFFFF; // Invalid default: bit30=0 (non-external), >191 (non-internal) |
| 48 | aclrtStream stream = nullptr; | 51 | aclrtStream stream = nullptr; |
| 49 | ::std::unique_ptr<NPUQueueBase> repo = nullptr; | 52 | ::std::unique_ptr<NPUQueueBase> repo = nullptr; |
| 50 | bool is_data_preprocess_stream = false; | 53 | bool is_data_preprocess_stream = false; |
| @@ -89,6 +92,11 @@ static std::array< | |||
| 89 | static thread_local std::unique_ptr<LeakyStreamInternals* []> current_streams = nullptr; | 92 | static thread_local std::unique_ptr<LeakyStreamInternals* []> current_streams = nullptr; |
| 90 | 93 | ||
| 91 | static std::array<LeakyStreamInternals, kSyncLaunchStreamsPerPool> sync_launch_streams[C10_COMPILE_TIME_MAX_NPUS]; | 94 | static std::array<LeakyStreamInternals, kSyncLaunchStreamsPerPool> sync_launch_streams[C10_COMPILE_TIME_MAX_NPUS]; |
| 95 | +static std::array<std::vector<std::unique_ptr<LeakyStreamInternals>>, C10_COMPILE_TIME_MAX_NPUS> external_streams; | ||
| 96 | +static std::mutex external_streams_mutex; | ||
| 97 | + | ||
| 98 | +static constexpr uint64_t kExternalStreamIdMarker = 1ULL << 30; | ||
| 99 | +static constexpr uint64_t kExternalStreamIdIndexMask = kExternalStreamIdMarker - 1; | ||
| 92 | 100 | ||
| 93 | thread_local aclrtStream tls_prev_stream = nullptr; | 101 | thread_local aclrtStream tls_prev_stream = nullptr; |
| 94 | 102 | ||
| @@ -98,6 +106,7 @@ enum class StreamIdType : uint8_t { | |||
| 98 | SYNCLAUNCH = 0x2, | 106 | SYNCLAUNCH = 0x2, |
| 99 | NORMAL = 0x3, | 107 | NORMAL = 0x3, |
| 100 | HIGH = 0x4, | 108 | HIGH = 0x4, |
| 109 | + EXT = 0x5, // External stream type | ||
| 101 | }; | 110 | }; |
| 102 | 111 | ||
| 103 | std::ostream& operator<<(std::ostream& stream, StreamIdType s) | 112 | std::ostream& operator<<(std::ostream& stream, StreamIdType s) |
| @@ -118,6 +127,9 @@ std::ostream& operator<<(std::ostream& stream, StreamIdType s) | |||
| 118 | case StreamIdType::SYNCLAUNCH: | 127 | case StreamIdType::SYNCLAUNCH: |
| 119 | stream << "SYNCLAUNCH"; | 128 | stream << "SYNCLAUNCH"; |
| 120 | break; | 129 | break; |
| 130 | + case StreamIdType::EXT: | ||
| 131 | + stream << "EXT"; | ||
| 132 | + break; | ||
| 121 | default: | 133 | default: |
| 122 | stream << static_cast<uint8_t>(s); | 134 | stream << static_cast<uint8_t>(s); |
| 123 | break; | 135 | break; |
| @@ -147,20 +159,36 @@ int GetStreamsPerPool() | |||
| 147 | return StreamsPerPool; | 159 | return StreamsPerPool; |
| 148 | } | 160 | } |
| 149 | 161 | ||
| 162 | +static inline bool isExternalStreamId(c10::StreamId s) | ||
| 163 | +{ | ||
| 164 | + return (static_cast<uint64_t>(s) & kExternalStreamIdMarker) != 0; | ||
| 165 | +} | ||
| 166 | + | ||
| 150 | static inline StreamIdType streamIdType(c10::StreamId s) | 167 | static inline StreamIdType streamIdType(c10::StreamId s) |
| 151 | { | 168 | { |
| 169 | + if (isExternalStreamId(s)) { | ||
| 170 | + return StreamIdType::EXT; | ||
| 171 | + } | ||
| 152 | static int StreamsPerPoolBits = GetStreamsPerPoolBits(); | 172 | static int StreamsPerPoolBits = GetStreamsPerPoolBits(); |
| 153 | return static_cast<StreamIdType>((uint32_t)s >> StreamsPerPoolBits); | 173 | return static_cast<StreamIdType>((uint32_t)s >> StreamsPerPoolBits); |
| 154 | } | 174 | } |
| 155 | 175 | ||
| 156 | static inline size_t streamIdIndex(c10::StreamId s) | 176 | static inline size_t streamIdIndex(c10::StreamId s) |
| 157 | { | 177 | { |
| 178 | + if (isExternalStreamId(s)) { | ||
| 179 | + return static_cast<size_t>(static_cast<uint64_t>(s) & kExternalStreamIdIndexMask); | ||
| 180 | + } | ||
| 158 | static int StreamsPerPoolBits = GetStreamsPerPoolBits(); | 181 | static int StreamsPerPoolBits = GetStreamsPerPoolBits(); |
| 159 | return static_cast<size_t>((uint32_t)s & ((1 << StreamsPerPoolBits) - 1)); | 182 | return static_cast<size_t>((uint32_t)s & ((1 << StreamsPerPoolBits) - 1)); |
| 160 | } | 183 | } |
| 161 | 184 | ||
| 162 | c10::StreamId makeStreamId(StreamIdType st, size_t si) | 185 | c10::StreamId makeStreamId(StreamIdType st, size_t si) |
| 163 | { | 186 | { |
| 187 | + if (st == StreamIdType::EXT) { | ||
| 188 | + TORCH_CHECK(si <= kExternalStreamIdIndexMask, | ||
| 189 | + "Too many external NPU streams are registered.", PTA_ERROR(ErrCode::VALUE)); | ||
| 190 | + return static_cast<c10::StreamId>(kExternalStreamIdMarker | si); | ||
| 191 | + } | ||
| 164 | static int StreamsPerPoolBits = GetStreamsPerPoolBits(); | 192 | static int StreamsPerPoolBits = GetStreamsPerPoolBits(); |
| 165 | return static_cast<c10::StreamId>((static_cast<size_t>(st) << StreamsPerPoolBits) | si); | 193 | return static_cast<c10::StreamId>((static_cast<size_t>(st) << StreamsPerPoolBits) | si); |
| 166 | } | 194 | } |
| @@ -175,6 +203,9 @@ static bool pointer_within(const T* ptr, const A& arr) | |||
| 175 | static c10::StreamId NPUStream_getStreamId(const LeakyStreamInternals* ptr) | 203 | static c10::StreamId NPUStream_getStreamId(const LeakyStreamInternals* ptr) |
| 176 | { | 204 | { |
| 177 | c10::DeviceIndex device_index = ptr->device_index; | 205 | c10::DeviceIndex device_index = ptr->device_index; |
| 206 | + if (isExternalStreamId(ptr->stream_id)) { | ||
| 207 | + return static_cast<c10::StreamId>(ptr->stream_id); | ||
| 208 | + } | ||
| 178 | if (ptr == &default_streams[device_index]) { | 209 | if (ptr == &default_streams[device_index]) { |
| 179 | return makeStreamId(StreamIdType::DEFAULT, 0); | 210 | return makeStreamId(StreamIdType::DEFAULT, 0); |
| 180 | } | 211 | } |
| @@ -219,6 +250,7 @@ static void initGlobalStreamState() | |||
| 219 | } | 250 | } |
| 220 | // Initializes default streams | 251 | // Initializes default streams |
| 221 | default_streams[device_id].device_index = device_id; | 252 | default_streams[device_id].device_index = device_id; |
| 253 | + default_streams[device_id].stream_id = static_cast<int64_t>(makeStreamId(StreamIdType::DEFAULT, 0)); | ||
| 222 | for (const auto p : c10::irange(kMaxStreamPriorities)) { | 254 | for (const auto p : c10::irange(kMaxStreamPriorities)) { |
| 223 | npu_counters[p][device_id] = 0; | 255 | npu_counters[p][device_id] = 0; |
| 224 | } | 256 | } |
| @@ -230,6 +262,7 @@ static void initGlobalStreamState() | |||
| 230 | } | 262 | } |
| 231 | // Initializes secondary streams | 263 | // Initializes secondary streams |
| 232 | secondary_streams[device_id].device_index = device_id; | 264 | secondary_streams[device_id].device_index = device_id; |
| 265 | + secondary_streams[device_id].stream_id = static_cast<int64_t>(makeStreamId(StreamIdType::SECONDARY, 0)); | ||
| 233 | auto &secondary_streamsi = secondary_streams[device_id]; | 266 | auto &secondary_streamsi = secondary_streams[device_id]; |
| 234 | NPU_CHECK_ERROR( | 267 | NPU_CHECK_ERROR( |
| 235 | acl::AclrtCreateStreamWithConfig(&secondary_streamsi.stream, 0, (ACL_STREAM_FAST_LAUNCH | ACL_STREAM_FAST_SYNC))); | 268 | acl::AclrtCreateStreamWithConfig(&secondary_streamsi.stream, 0, (ACL_STREAM_FAST_LAUNCH | ACL_STREAM_FAST_SYNC))); |
| @@ -245,6 +278,8 @@ static void initDeviceStreamState(c10::DeviceIndex device_index, int p) | |||
| 245 | auto& npu_streami = npu_streams[p][device_index][i]; | 278 | auto& npu_streami = npu_streams[p][device_index][i]; |
| 246 | 279 | ||
| 247 | npu_streami.device_index = device_index; | 280 | npu_streami.device_index = device_index; |
| 281 | + npu_streami.stream_id = static_cast<int64_t>(makeStreamId( | ||
| 282 | + StreamIdType(static_cast<uint8_t>(StreamIdType::NORMAL) + p), i)); | ||
| 248 | 283 | ||
| 249 | NPU_CHECK_ERROR(acl::AclrtCreateStreamWithConfig( | 284 | NPU_CHECK_ERROR(acl::AclrtCreateStreamWithConfig( |
| 250 | &npu_streami.stream, 0, (ACL_STREAM_FAST_LAUNCH | ACL_STREAM_FAST_SYNC))); | 285 | &npu_streami.stream, 0, (ACL_STREAM_FAST_LAUNCH | ACL_STREAM_FAST_SYNC))); |
| @@ -304,6 +339,16 @@ LeakyStreamInternals* NPUStream_internals(NPUStream s) | |||
| 304 | StreamIdType st = streamIdType(s.unwrap().id()); | 339 | StreamIdType st = streamIdType(s.unwrap().id()); |
| 305 | size_t si = streamIdIndex(s.unwrap().id()); | 340 | size_t si = streamIdIndex(s.unwrap().id()); |
| 306 | switch (st) { | 341 | switch (st) { |
| 342 | + case StreamIdType::EXT: { | ||
| 343 | + size_t ext_si = streamIdIndex(s.unwrap().id()); | ||
| 344 | + std::lock_guard<std::mutex> lock(external_streams_mutex); | ||
| 345 | + TORCH_CHECK(ext_si < external_streams[device_index].size(), | ||
| 346 | + "Unrecognized external NPU stream ", s.unwrap(), PTA_ERROR(ErrCode::PARAM)); | ||
| 347 | + auto* ptr = external_streams[device_index][ext_si].get(); | ||
| 348 | + TORCH_CHECK(ptr != nullptr, | ||
| 349 | + "Invalid external NPU stream ", s.unwrap(), PTA_ERROR(ErrCode::PARAM)); | ||
| 350 | + return ptr; | ||
| 351 | + } | ||
| 307 | case StreamIdType::DEFAULT: | 352 | case StreamIdType::DEFAULT: |
| 308 | AT_ASSERTM( | 353 | AT_ASSERTM( |
| 309 | si == 0, | 354 | si == 0, |
| @@ -346,6 +391,10 @@ NPUStream NPUStream_fromInternals(const LeakyStreamInternals* ptr) | |||
| 346 | 391 | ||
| 347 | bool NPUStream::query() const | 392 | bool NPUStream::query() const |
| 348 | { | 393 | { |
| 394 | + TORCH_CHECK(!isExternalStreamId(this->id()), | ||
| 395 | + "Cannot query external NPU stream status. " | ||
| 396 | + "The caller must track stream completion externally.", | ||
| 397 | + PTA_ERROR(ErrCode::NOT_SUPPORT)); | ||
| 349 | c10::DeviceGuard guard{stream_.device()}; | 398 | c10::DeviceGuard guard{stream_.device()}; |
| 350 | acl::aclrtStreamStatus status = acl::ACL_STREAM_STATUS_RESERVED; | 399 | acl::aclrtStreamStatus status = acl::ACL_STREAM_STATUS_RESERVED; |
| 351 | NPU_CHECK_ERROR(acl::AclrtStreamQuery(stream(), &status)); | 400 | NPU_CHECK_ERROR(acl::AclrtStreamQuery(stream(), &status)); |
| @@ -357,15 +406,22 @@ bool NPUStream::query() const | |||
| 357 | 406 | ||
| 358 | void NPUStream::synchronize() const | 407 | void NPUStream::synchronize() const |
| 359 | { | 408 | { |
| 409 | + TORCH_CHECK(!isExternalStreamId(this->id()), | ||
| 410 | + "External NPU stream is not supported in NPUStream::synchronize. " | ||
| 411 | + "The caller is responsible for synchronization of external streams.", | ||
| 412 | + PTA_ERROR(ErrCode::NOT_SUPPORT)); | ||
| 360 | c10::DeviceGuard guard{stream_.device()}; | 413 | c10::DeviceGuard guard{stream_.device()}; |
| 361 | NPU_CHECK_ERROR(c10_npu::acl::AclrtSynchronizeStreamWithTimeout(stream())); | 414 | NPU_CHECK_ERROR(c10_npu::acl::AclrtSynchronizeStreamWithTimeout(stream())); |
| 362 | } | 415 | } |
| 363 | 416 | ||
| 364 | aclrtStream NPUStream::stream() const | 417 | aclrtStream NPUStream::stream() const |
| 365 | { | 418 | { |
| 419 | + auto cur_ptr = NPUStream_internals(*this); | ||
| 420 | + AT_ASSERT(cur_ptr, PTA_ERROR(ErrCode::PTR)); | ||
| 421 | + if (isExternalStreamId(this->id())) { | ||
| 422 | + return cur_ptr->stream; | ||
| 423 | + } | ||
| 366 | if (c10_npu::option::OptionsManager::GetPerStreamQueue()) { | 424 | if (c10_npu::option::OptionsManager::GetPerStreamQueue()) { |
| 367 | - auto cur_ptr = NPUStream_internals(*this); | ||
| 368 | - AT_ASSERT(cur_ptr, PTA_ERROR(ErrCode::PTR)); | ||
| 369 | if (!this->isSyncLaunchStream() && cur_ptr->repo->CheckInit()) { | 425 | if (!this->isSyncLaunchStream() && cur_ptr->repo->CheckInit()) { |
| 370 | NPUStatus ret = cur_ptr->repo->MakeSureQueueEmpty(); | 426 | NPUStatus ret = cur_ptr->repo->MakeSureQueueEmpty(); |
| 371 | if (ret != NPU_STATUS_SUCCESS) { | 427 | if (ret != NPU_STATUS_SUCCESS) { |
| @@ -385,8 +441,6 @@ aclrtStream NPUStream::stream() const | |||
| 385 | } | 441 | } |
| 386 | } | 442 | } |
| 387 | } | 443 | } |
| 388 | - auto cur_ptr = NPUStream_internals(*this); | ||
| 389 | - AT_ASSERT(cur_ptr, PTA_ERROR(ErrCode::PTR)); | ||
| 390 | return cur_ptr->stream; | 444 | return cur_ptr->stream; |
| 391 | } | 445 | } |
| 392 | 446 | ||
| @@ -427,6 +481,39 @@ NPUStream getDefaultNPUStream(c10::DeviceIndex device_index) | |||
| 427 | return NPUStream_fromInternals(&default_streams[device_index]); | 481 | return NPUStream_fromInternals(&default_streams[device_index]); |
| 428 | } | 482 | } |
| 429 | 483 | ||
| 484 | +NPUStream getStreamFromExternal(aclrtStream stream, c10::DeviceIndex device_index) | ||
| 485 | +{ | ||
| 486 | + TORCH_CHECK(stream != nullptr, "External NPU stream does not support nullptr.", PTA_ERROR(ErrCode::PARAM)); | ||
| 487 | + initNPUStreamsOnce(); | ||
| 488 | + if (device_index == -1) { | ||
| 489 | + device_index = current_device(); | ||
| 490 | + } | ||
| 491 | + check_npu(device_index); | ||
| 492 | + | ||
| 493 | + LeakyStreamInternals* ptr = nullptr; | ||
| 494 | + { | ||
| 495 | + std::lock_guard<std::mutex> lock(external_streams_mutex); | ||
| 496 | + auto& streams = external_streams[device_index]; | ||
| 497 | + for (const auto i : c10::irange(streams.size())) { | ||
| 498 | + if (streams[i]->stream == stream) { | ||
| 499 | + ptr = streams[i].get(); | ||
| 500 | + break; | ||
| 501 | + } | ||
| 502 | + } | ||
| 503 | + | ||
| 504 | + if (ptr == nullptr) { | ||
| 505 | + auto internals = std::make_unique<LeakyStreamInternals>(); | ||
| 506 | + internals->device_index = device_index; | ||
| 507 | + internals->stream_id = static_cast<int64_t>(makeStreamId(StreamIdType::EXT, streams.size())); | ||
| 508 | + internals->stream = stream; | ||
| 509 | + internals->repo.reset(); | ||
| 510 | + ptr = internals.get(); | ||
| 511 | + streams.emplace_back(std::move(internals)); | ||
| 512 | + } | ||
| 513 | + } | ||
| 514 | + return NPUStream_fromInternals(ptr); | ||
| 515 | +} | ||
| 516 | + | ||
| 430 | NPUStream getCurrentNPUStream(c10::DeviceIndex device_index) | 517 | NPUStream getCurrentNPUStream(c10::DeviceIndex device_index) |
| 431 | { | 518 | { |
| 432 | initNPUStreamsOnce(); | 519 | initNPUStreamsOnce(); |
| @@ -662,8 +749,15 @@ void enCurrentNPUStream(void* cur_paras, c10::DeviceIndex device_index, NPUStrea | |||
| 662 | if (c10_npu::option::OptionsManager::GetPerStreamQueue()) { | 749 | if (c10_npu::option::OptionsManager::GetPerStreamQueue()) { |
| 663 | LeakyStreamInternals* ptr = current_streams[device_index]; | 750 | LeakyStreamInternals* ptr = current_streams[device_index]; |
| 664 | if (task_stream != nullptr) { | 751 | if (task_stream != nullptr) { |
| 752 | + // Check before traversing the external_streams | ||
| 753 | + TORCH_CHECK(!isExternalStreamId(task_stream->id()), | ||
| 754 | + "External NPU stream is not supported by task queue enqueue.", | ||
| 755 | + PTA_ERROR(ErrCode::NOT_SUPPORT)); | ||
| 665 | ptr = NPUStream_internals(*task_stream); | 756 | ptr = NPUStream_internals(*task_stream); |
| 666 | } | 757 | } |
| 758 | + TORCH_CHECK(!isExternalStreamId(static_cast<c10::StreamId>(ptr->stream_id)), | ||
| 759 | + "External NPU stream is not supported by task queue enqueue.", | ||
| 760 | + PTA_ERROR(ErrCode::NOT_SUPPORT)); | ||
| 667 | // To prevent all taskqueue threads from being created during stream initialization, | 761 | // To prevent all taskqueue threads from being created during stream initialization, |
| 668 | // we initialize the taskqueue when enqueueing | 762 | // we initialize the taskqueue when enqueueing |
| 669 | // each stream init repo once | 763 | // each stream init repo once |
| @@ -733,6 +827,9 @@ bool NPUStream::getRepoStopFlag() | |||
| 733 | 827 | ||
| 734 | bool NPUStream::isSyncLaunchStream() const | 828 | bool NPUStream::isSyncLaunchStream() const |
| 735 | { | 829 | { |
| 830 | + if (isExternalStreamId(this->id())) { | ||
| 831 | + return false; | ||
| 832 | + } | ||
| 736 | auto ptr = NPUStream_internals(*this); | 833 | auto ptr = NPUStream_internals(*this); |
| 737 | AT_ASSERT(ptr, PTA_ERROR(ErrCode::PTR)); | 834 | AT_ASSERT(ptr, PTA_ERROR(ErrCode::PTR)); |
| 738 | return ptr->is_sync_launch; | 835 | return ptr->is_sync_launch; |
| @@ -749,6 +846,62 @@ aclrtStream NPUStream::stream(const bool need_empty) const | |||
| 749 | return stream(); | 846 | return stream(); |
| 750 | } | 847 | } |
| 751 | 848 | ||
| 849 | +namespace detail { | ||
| 850 | + | ||
| 851 | +bool isExternalStream(const NPUStream& stream) | ||
| 852 | +{ | ||
| 853 | + return isExternalStreamId(stream.id()); | ||
| 854 | +} | ||
| 855 | + | ||
| 856 | +bool isExternalStream(aclrtStream stream, c10::DeviceIndex device_index) | ||
| 857 | +{ | ||
| 858 | + initNPUStreamsOnce(); | ||
| 859 | + std::lock_guard<std::mutex> lock(external_streams_mutex); | ||
| 860 | + if (device_index != -1) { | ||
| 861 | + check_npu(device_index); | ||
| 862 | + const auto& streams = external_streams[device_index]; | ||
| 863 | + for (const auto& item : streams) { | ||
| 864 | + if (item->stream == stream) { | ||
| 865 | + return true; | ||
| 866 | + } | ||
| 867 | + } | ||
| 868 | + return false; | ||
| 869 | + } | ||
| 870 | + | ||
| 871 | + for (const auto device : c10::irange(num_npus)) { | ||
| 872 | + const auto& streams = external_streams[device]; | ||
| 873 | + for (const auto& item : streams) { | ||
| 874 | + if (item->stream == stream) { | ||
| 875 | + return true; | ||
| 876 | + } | ||
| 877 | + } | ||
| 878 | + } | ||
| 879 | + return false; | ||
| 880 | +} | ||
| 881 | + | ||
| 882 | +bool isCurrentStreamExternal(c10::DeviceIndex device_index) | ||
| 883 | +{ | ||
| 884 | + return isExternalStreamId(getCurrentNPUStream(device_index).id()); | ||
| 885 | +} | ||
| 886 | + | ||
| 887 | +void checkNotExternalStream(const NPUStream& stream, const char* api_name) | ||
| 888 | +{ | ||
| 889 | + TORCH_CHECK(!isExternalStream(stream), | ||
| 890 | + "External NPU stream is not supported in ", api_name, | ||
| 891 | + ". This path requires a torch_npu-managed stream.", | ||
| 892 | + PTA_ERROR(ErrCode::NOT_SUPPORT)); | ||
| 893 | +} | ||
| 894 | + | ||
| 895 | +void checkCurrentStreamNotExternal(c10::DeviceIndex device_index, const char* api_name) | ||
| 896 | +{ | ||
| 897 | + TORCH_CHECK(!isCurrentStreamExternal(device_index), | ||
| 898 | + "External NPU stream is not supported in ", api_name, | ||
| 899 | + ". This path requires a torch_npu-managed current stream.", | ||
| 900 | + PTA_ERROR(ErrCode::NOT_SUPPORT)); | ||
| 901 | +} | ||
| 902 | + | ||
| 903 | +} // namespace detail | ||
| 904 | + | ||
| 752 | void recovery_all_npu_streams(c10::DeviceIndex device_index) | 905 | void recovery_all_npu_streams(c10::DeviceIndex device_index) |
| 753 | { | 906 | { |
| 754 | if (!initialize_flag[device_index]) { | 907 | if (!initialize_flag[device_index]) { |
| @@ -784,6 +937,7 @@ static void initDeviceSyncLaunchStream(c10::DeviceIndex device_index) | |||
| 784 | 937 | ||
| 785 | sync_streami.device_index = device_index; | 938 | sync_streami.device_index = device_index; |
| 786 | sync_streami.is_sync_launch = true; | 939 | sync_streami.is_sync_launch = true; |
| 940 | + sync_streami.stream_id = static_cast<int64_t>(makeStreamId(StreamIdType::SYNCLAUNCH, i)); | ||
| 787 | 941 | ||
| 788 | NPU_CHECK_ERROR( | 942 | NPU_CHECK_ERROR( |
| 789 | acl::AclrtCreateStreamWithConfig(&sync_streami.stream, 0, ACL_STREAM_FAST_SYNC)); | 943 | acl::AclrtCreateStreamWithConfig(&sync_streami.stream, 0, ACL_STREAM_FAST_SYNC)); |
| @@ -120,6 +120,8 @@ C10_NPU_API NPUStream getNPUStreamFromPool(c10::DeviceIndex device = -1); | |||
| 120 | 120 | ||
| 121 | C10_NPU_API NPUStream getDefaultNPUStream(c10::DeviceIndex device_index = -1); | 121 | C10_NPU_API NPUStream getDefaultNPUStream(c10::DeviceIndex device_index = -1); |
| 122 | 122 | ||
| 123 | +C10_NPU_API NPUStream getStreamFromExternal(aclrtStream stream, c10::DeviceIndex device_index); | ||
| 124 | + | ||
| 123 | C10_NPU_API NPUStream getStreamFromPool(const bool isHighPriority, c10::DeviceIndex device_index); | 125 | C10_NPU_API NPUStream getStreamFromPool(const bool isHighPriority, c10::DeviceIndex device_index); |
| 124 | 126 | ||
| 125 | C10_NPU_API NPUStream getCurrentNPUStream(c10::DeviceIndex device_index = -1); | 127 | C10_NPU_API NPUStream getCurrentNPUStream(c10::DeviceIndex device_index = -1); |
| @@ -0,0 +1,19 @@ | |||
| 1 | + | ||
| 2 | + | ||
| 3 | + | ||
| 4 | + | ||
| 5 | +namespace c10_npu { | ||
| 6 | +namespace detail { | ||
| 7 | + | ||
| 8 | +bool isExternalStream(const NPUStream& stream); | ||
| 9 | + | ||
| 10 | +bool isExternalStream(aclrtStream stream, c10::DeviceIndex device_index = -1); | ||
| 11 | + | ||
| 12 | +bool isCurrentStreamExternal(c10::DeviceIndex device_index = -1); | ||
| 13 | + | ||
| 14 | +void checkNotExternalStream(const NPUStream& stream, const char* api_name); | ||
| 15 | + | ||
| 16 | +void checkCurrentStreamNotExternal(c10::DeviceIndex device_index, const char* api_name); | ||
| 17 | + | ||
| 18 | +} // namespace detail | ||
| 19 | +} // namespace c10_npu | ||
| @@ -1,6 +1,7 @@ | |||
| 1 | 1 | ||
| 2 | 2 | ||
| 3 | 3 | ||
| 4 | + | ||
| 4 | 5 | ||
| 5 | 6 | ||
| 6 | 7 | ||
| @@ -221,6 +222,7 @@ void EventTask::LaunchRecordTask(c10_npu::NPUStream npuStream, unsigned int flag | |||
| 221 | 222 | ||
| 222 | aclError LaunchRecordEventTask(aclrtEvent event, c10_npu::NPUStream npuStream, unsigned int flags) | 223 | aclError LaunchRecordEventTask(aclrtEvent event, c10_npu::NPUStream npuStream, unsigned int flags) |
| 223 | { | 224 | { |
| 225 | + c10_npu::detail::checkNotExternalStream(npuStream, "LaunchRecordEventTask"); | ||
| 224 | EventTask recordTask(event); | 226 | EventTask recordTask(event); |
| 225 | recordTask.LaunchRecordTask(npuStream, flags); | 227 | recordTask.LaunchRecordTask(npuStream, flags); |
| 226 | 228 | ||
| @@ -273,6 +275,7 @@ void EventTask::LaunchWaitTask(c10_npu::NPUStream npuStream, unsigned int flags) | |||
| 273 | 275 | ||
| 274 | aclError LaunchWaitEventTask(aclrtEvent event, c10_npu::NPUStream npuStream, unsigned int flags) | 276 | aclError LaunchWaitEventTask(aclrtEvent event, c10_npu::NPUStream npuStream, unsigned int flags) |
| 275 | { | 277 | { |
| 278 | + c10_npu::detail::checkNotExternalStream(npuStream, "LaunchWaitEventTask"); | ||
| 276 | EventTask waitTask(event); | 279 | EventTask waitTask(event); |
| 277 | waitTask.LaunchWaitTask(npuStream, flags); | 280 | waitTask.LaunchWaitTask(npuStream, flags); |
| 278 | 281 | ||
| @@ -42,6 +42,7 @@ | |||
| 42 | 42 | ||
| 43 | 43 | ||
| 44 | 44 | ||
| 45 | + | ||
| 45 | 46 | ||
| 46 | 47 | ||
| 47 | 48 | ||
| @@ -3869,6 +3870,9 @@ c10::intrusive_ptr<c10d::Work> ProcessGroupHCCL::collective( | |||
| 3869 | op_id_++; | 3870 | op_id_++; |
| 3870 | 3871 | ||
| 3871 | const auto devices = getDeviceList(inputs); | 3872 | const auto devices = getDeviceList(inputs); |
| 3873 | + for (const auto& device : devices) { | ||
| 3874 | + c10_npu::detail::checkCurrentStreamNotExternal(device.index(), "ProcessGroupHCCL::collective"); | ||
| 3875 | + } | ||
| 3872 | auto key = getKeyFromDevices(devices); | 3876 | auto key = getKeyFromDevices(devices); |
| 3873 | HcclCommConfig config = createHcclCommConfigWithOptions(); | 3877 | HcclCommConfig config = createHcclCommConfigWithOptions(); |
| 3874 | std::vector<std::shared_ptr<HCCLComm>> hcclComms = getHCCLComm(key, devices, HcclCommType::DEFAULT, &config); | 3878 | std::vector<std::shared_ptr<HCCLComm>> hcclComms = getHCCLComm(key, devices, HcclCommType::DEFAULT, &config); |
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | + | ||
| 6 | 7 | ||
| 7 | 8 | ||
| 8 | 9 | ||
| @@ -214,6 +215,9 @@ c10::intrusive_ptr<c10d::Work> ProcessGroupLCCL::collective(std::vector<at::Tens | |||
| 214 | PostProcess post, c10d::OpType opType) | 215 | PostProcess post, c10d::OpType opType) |
| 215 | { | 216 | { |
| 216 | const auto devices = getDeviceList(inputs); | 217 | const auto devices = getDeviceList(inputs); |
| 218 | + for (const auto& device : devices) { | ||
| 219 | + c10_npu::detail::checkCurrentStreamNotExternal(device.index(), "ProcessGroupLCCL::collective"); | ||
| 220 | + } | ||
| 217 | auto key = getKeyFromDevices(devices); | 221 | auto key = getKeyFromDevices(devices); |
| 218 | std::vector<at_npu::lccl::LcclComm> lcclComms; | 222 | std::vector<at_npu::lccl::LcclComm> lcclComms; |
| 219 | lcclComms = getLCCLComm(key, devices); | 223 | lcclComms = getLCCLComm(key, devices); |


此条代码评论区间+44至+48
【openlibing.ci】识别到代码检查告警抑制注释,匹配工具:flake8,请Committer检视其合理性。