Coverage for cuda/core/_memory/_synchronous_memory_resource.pyx: 95.74%
47 statements
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-10 02:27 +0000
« prev ^ index » next coverage.py v7.16.0, created at 2026-09-10 02:27 +0000
1# SPDX-FileCopyrightText: Copyright (c) 2024-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2#
3# SPDX-License-Identifier: Apache-2.0
5from __future__ import annotations
7from libc.stdint cimport uintptr_t
9from cuda.bindings cimport cydriver
10from cuda.core._context cimport Context
11from cuda.core._memory._buffer cimport Buffer, MemoryResource
12from cuda.core._resource_handles cimport (
13 ContextHandle,
14 create_context_bound_legacy_stream,
15 deviceptr_alloc_raw,
16 get_last_error,
17 get_primary_context,
18)
19from cuda.core._stream cimport Stream, Stream_accept, Stream_is_default_token
20from cuda.core._utils.cuda_utils cimport HANDLE_RETURN
22from typing import TYPE_CHECKING
24if TYPE_CHECKING:
25 from cuda.core.graph import GraphBuilder
26 from cuda.core.typing import DevicePointerType
28__all__ = []
31class _SynchronousMemoryResource(MemoryResource):
32 __slots__ = ("_context", "_device_id")
34 def __init__(self, device_id: int, context=None) -> None:
35 from .._device import Device 2? 1b2b3b4b5bX Y 6b7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 = f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k l m n o p q r s t u v w x y z A B V C D E W c
37 self._device_id = Device(device_id).device_id 21b2b3b4b5bX Y 6b7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 = f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k l m n o p q r s t u v w x y z A B V C D E W c
38 # Resolved lazily (in _resolve_context) so that construction with
39 # context=None does no CUDA work; the primary context is retained
40 # only once actually needed, on the first allocate()/deallocate().
41 self._context = context 21b2b3b4b5bX Y 6b7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 = f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k l m n o p q r s t u v w x y z A B V C D E W c
43 def _resolve_context(self) -> Context:
44 cdef ContextHandle h_context
45 if self._context is None: 21b2b3b4b5bX Y @ 6b[ 7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 = f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
46 h_context = get_primary_context(self._device_id) 1ab
47 if not h_context: 1ab
48 HANDLE_RETURN(get_last_error())
49 self._context = Context._from_handle( 1ab
50 Context, h_context, self._device_id) 1ab
51 return self._context 21b2b3b4b5bX Y @ 6b[ 7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 = f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
53 def allocate(
54 self,
55 size_t size,
56 *,
57 stream: Stream | GraphBuilder | None = None,
58 ) -> Buffer:
59 # cuMemAlloc/cuMemFree are synchronous; a caller-supplied stream is
60 # accepted (and validated) for interface conformance and, if it is a
61 # real stream, recorded as the stream that orders deallocation.
62 cdef Context context = self._resolve_context() 21b2b3b4b5bX Y @ 6b[ 7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 = f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
63 cdef Stream dealloc_stream = None 21b2b3b4b5bX Y @ 6b[ 7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 = f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
64 if stream is not None: 21b2b3b4b5bX Y @ 6b[ 7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 = f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
65 dealloc_stream = Stream_accept(stream) 21b2b3b4b5bX Y @ 6b[ 7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 = f 3 4 5 F G a 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
66 if dealloc_stream is None or Stream_is_default_token(dealloc_stream): 21b2b3b4b5bX Y @ 6b[ 7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 = f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
67 # A default-stream token carries no context of its own; Buffer._init
68 # would bind it to whichever context is current when it records the
69 # deallocation stream (and fail if none is). Bind it to this
70 # resource's context instead, so Buffer teardown frees in the right
71 # context no matter what is current then. Always the legacy token:
72 # a per-thread token would also arm the cross-thread PTDS warning,
73 # which is noise for a synchronous resource.
74 dealloc_stream = Stream._from_handle( 2d e = f F G a b ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0bH I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
75 Stream, create_context_bound_legacy_stream(context._h_context)) 2d e = f F G a b ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0bH I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
77 cdef cydriver.CUdeviceptr ptr = 0 21b2b3b4b5bX Y @ 6b[ 7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 = f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
78 if size: 2? 1b2b3b4b5bX Y @ 6b[ 7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 = f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
79 with nogil: 21b2b3b4b5bX Y @ 6b[ 7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
80 HANDLE_RETURN(deviceptr_alloc_raw(&ptr, size, context._h_context)) 21b2b3b4b5bX Y @ 6b[ 7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
81 return Buffer._init(<uintptr_t>ptr, size, self, stream=dealloc_stream) 21b2b3b4b5bX Y @ 6b[ 7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 = f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
83 def deallocate(
84 self,
85 ptr: DevicePointerType,
86 size_t size,
87 *,
88 stream: Stream | GraphBuilder | None = None,
89 ) -> None:
90 if stream is not None: 2?b@b[bX Y @ ]b[ ^bZ _b`b{b|bd }b~be acbcccdcecfcgchcicjckclc0 1 2 = f 3 4 5 F G a b 6 mcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8c9c!c#c$c%c'c(c)c*c+c,c-c7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
91 Stream_accept(stream).sync() 2?b@b[bX Y @ ]b[ ^bZ _b`b{b|bd }b~be acbcccdcecfcgchcicjckclc0 1 2 = f 3 4 5 F G a b 6 mcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8c9c!c#c$c%c'c(c)c*c+c,c-c7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
92 # No context switch here, by design (settled in the review of #2750):
93 # cuMemFree does not need a current context. The driver resolves the
94 # allocation's owning context from the pointer through unified
95 # addressing and frees it there (cuapiMemFree_common: "a current
96 # context is not required to free the device memory"). On the Buffer
97 # teardown path the C++ deleter has additionally already made the
98 # recorded deallocation context, bound by allocate() above, current.
99 cdef cydriver.CUdeviceptr devptr
100 if size: 2?b@b[bX Y @ ]b[ ^bZ _b`b{b|bd }b~be acbcccdcecfcgchcicjckclc0 1 2 = f 3 4 5 F G a b 6 mcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8c9c!c#c$c%c'c(c)c*c+c,c-c7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
101 devptr = <cydriver.CUdeviceptr><uintptr_t>int(ptr) 2?b@b[bX Y @ ]b[ ^bZ _b`b{b|bd }b~be acbcccdcecfcgchcicjckclc0 1 2 f 3 4 5 F G a b 6 mcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8c9c!c#c$c%c'c(c)c*c+c,c-c7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
102 with nogil: 2?b@b[bX Y @ ]b[ ^bZ _b`b{b|bd }b~be acbcccdcecfcgchcicjckclc0 1 2 f 3 4 5 F G a b 6 mcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8c9c!c#c$c%c'c(c)c*c+c,c-c7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
103 HANDLE_RETURN(cydriver.cuMemFree(devptr)) 2?b@b[bX Y @ ]b[ ^bZ _b`b{b|bd }b~be acbcccdcecfcgchcicjckclc0 1 2 f 3 4 5 F G a b 6 mcncocpcqcrcsctcucvcwcxcyczcAcBcCcDcEcFcGcHcIcJcKcLcMcNcOcPcQcRcScTcUcVcWcXcYcZc0c1c2c3c4c5c6c7c8c9c!c#c$c%c'c(c)c*c+c,c-c7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
105 @property
106 def is_device_accessible(self) -> bool:
107 return True 21b2b3b4b5bX Y @ 6b[ 7bZ 8b9b!b#bd $b%be 'b(b)b*b+b,b-b.b/b:b;b=b0 1 2 = f 3 4 5 F G a b 6 ] ^ _ ` { | } ~ abbbcbdbebfbgbhbibjbkblbmbnbobpbqbrbsbtbubvbwbxbybzbAbBbCbDbEbFbGbHbIbJbKbLbMbNbObPbQbRbSbTbUbVbWbXbYbZb0b7 H I J K L M N O P Q R S T g h U i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B / V : - C ; . D E W c
109 @property
110 def is_host_accessible(self) -> bool:
111 return False 1ac
113 @property
114 def device_id(self) -> int:
115 return self._device_id 2? .c/cX Y :cd ;ce =c?c@c[c= f a g h i j k 8 l 9 ! # m n o p $ q r % ' s t u v ( ) w * + x , y z A B - C . D E c