Coverage for cuda/core/_memory/_synchronous_memory_resource.pyx: 95.74%
47 statements
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-05 01:11 +0000
« prev ^ index » next coverage.py v7.17.2, created at 2026-11-05 01:11 +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._rt 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] ^ KbLbc _ ` { | MbNbOb? @ PbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbsbk cbic0 tbdbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
37 self._device_id = Device(device_id).device_id 2^ KbLbc _ ` { | MbNbOb? @ PbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbsbk cbic0 tbdbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
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 2^ KbLbc _ ` { | MbNbOb? @ PbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbsbk cbic0 tbdbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
43 def _resolve_context(self) -> Context:
44 cdef ContextHandle h_context
45 if self._context is None: 2] ^ KbLbc _ ` { | MbNbOb? @ ubPbvbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbsbk cb0 tbdbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
46 h_context = get_primary_context(self._device_id) 2c tba b
47 if not h_context: 2c tba b
48 HANDLE_RETURN(get_last_error())
49 self._context = Context._from_handle( 2c tba b
50 Context, h_context, self._device_id) 2] c tba b
51 return self._context 2^ KbLbc _ ` { | MbNbOb? @ ubPbvbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbsbk cb0 tbdbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
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() 2^ KbLbc _ ` { | MbNbOb? @ ubPbvbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbsbk cb0 tbdbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
63 cdef Stream dealloc_stream = None 2^ KbLbc _ ` { | MbNbOb? @ ubPbvbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbsbk cb0 tbdbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
64 if stream is not None: 2^ KbLbc _ ` { | MbNbOb? @ ubPbvbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbsbk cb0 tbdbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
65 dealloc_stream = Stream_accept(stream) 2^ KbLbc _ ` { | MbNbOb? @ ubPbvbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbsbk cb0 dbebfbgb[ hbibjbkblbmb1 2 a nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
66 if dealloc_stream is None or Stream_is_default_token(dealloc_stream): 2^ KbLbc _ ` { | MbNbOb? @ ubPbvbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbsbk cb0 tbdbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
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( 2i j sbk 0 tb1 2 a b wbxbybzbAbBbCbDbEbFbGbHbIbJbd e f 3 4 5 g 6 7 8 9 ! # $ % ' ( ) * + , l m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
75 Stream, create_context_bound_legacy_stream(context._h_context)) 2] i j sbk 0 tb1 2 a b wbxbybzbAbBbCbDbEbFbGbHbIbJbd e f 3 4 5 g 6 7 8 9 ! # $ % ' ( ) * + , l m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
77 cdef cydriver.CUdeviceptr ptr = 0 2^ KbLbc _ ` { | MbNbOb? @ ubPbvbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbsbk cb0 tbdbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
78 if size: 2^ KbLbc _ ` { | MbNbOb? @ ubPbvbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbsbk cb0 tbdbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
79 with nogil: 2^ KbLbc _ ` { | MbNbOb? @ ubPbvbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbk cb0 tbdbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
80 HANDLE_RETURN(deviceptr_alloc_raw(&ptr, size, context._h_context)) 2^ KbLbc _ ` { | MbNbOb? @ ubPbvbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbk cb0 tbdbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
81 return Buffer._init(<uintptr_t>ptr, size, self, stream=dealloc_stream) 2] ^ KbLbc _ ` { | MbNbOb? @ ubPbvbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbsbk cb0 dbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
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^ c _ ` { | 9b!b#b? @ ub$bvb%b} 'b(b)b*bi +b,bj -b.b/b:b;b=b?b@b[b]b^b_b~ abbbsbk cb0 dbebfbgb[ hbibjbkblbmb1 2 a b nb`b{b|b}b~bacbcccdcecfcgchcobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
91 Stream_accept(stream).sync() 2^ c _ ` { | 9b!b#b? @ ub$bvb%b} 'b(b)b*bi +b,bj -b.b/b:b;b=b?b@b[b]b^b_b~ abbbsbk cb0 dbebfbgb[ hbibjbkblbmb1 2 a b nb`b{b|b}b~bacbcccdcecfcgchcobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
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^ c _ ` { | 9b!b#b? @ ub$bvb%b} 'b(b)b*bi +b,bj -b.b/b:b;b=b?b@b[b]b^b_b~ abbbsbk cb0 dbebfbgb[ hbibjbkblbmb1 2 a b nb`b{b|b}b~bacbcccdcecfcgchcobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
101 devptr = <cydriver.CUdeviceptr><uintptr_t>int(ptr) 2^ c _ ` { | 9b!b#b? @ ub$bvb%b} 'b(b)b*bi +b,bj -b.b/b:b;b=b?b@b[b]b^b_b~ abbbk cb0 dbebfbgb[ hbibjbkblbmb1 2 a b nb`b{b|b}b~bacbcccdcecfcgchcobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
102 with nogil: 2^ c _ ` { | 9b!b#b? @ ub$bvb%b} 'b(b)b*bi +b,bj -b.b/b:b;b=b?b@b[b]b^b_b~ abbbk cb0 dbebfbgb[ hbibjbkblbmb1 2 a b nb`b{b|b}b~bacbcccdcecfcgchcobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
103 HANDLE_RETURN(cydriver.cuMemFree(devptr)) 2^ c _ ` { | 9b!b#b? @ ub$bvb%b} 'b(b)b*bi +b,bj -b.b/b:b;b=b?b@b[b]b^b_b~ abbbk cb0 dbebfbgb[ hbibjbkblbmb1 2 a b nb`b{b|b}b~bacbcccdcecfcgchcobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
105 @property
106 def is_device_accessible(self) -> bool:
107 return True 2^ KbLbc _ ` { | MbNbOb? @ ubPbvbQb} RbSbTbUbi VbWbj XbYbZb0b1b2b3b4b5b6b7b8b~ abbbsbk cb0 dbebfbgb[ hbibjbkblbmb1 2 a b nbwbxbybzbAbBbCbDbEbFbGbHbIbJbobpbd e f 3 4 5 g qb6 7 8 9 ! # $ % ' ( ) * + , rbl m - n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S . / : T U ; V W X = Y Z h
109 @property
110 def is_host_accessible(self) -> bool:
111 return False 1[adefgh
113 @property
114 def device_id(self) -> int:
115 return self._device_id 2] jckc? @ lci mcj ncocpcqcsbk a d e f g l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z h