Coverage for cuda / core / _device_resources.pyx: 75.27%
283 statements
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-22 01:37 +0000
« prev ^ index » next coverage.py v7.14.0, created at 2026-05-22 01:37 +0000
1# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2#
3# SPDX-License-Identifier: Apache-2.0
5from __future__ import annotations
7from collections.abc import Sequence as SequenceABC
8from dataclasses import dataclass
10from libc.stdint cimport intptr_t
11from libc.stdlib cimport free, malloc
12from libc.string cimport memset
14from cuda.bindings cimport cydriver
15from cuda.core._resource_handles cimport ContextHandle, GreenCtxHandle, as_cu, get_context_green_ctx
16from cuda.core._utils.cuda_utils cimport check_or_create_options, HANDLE_RETURN
17from cuda.core._utils.cuda_utils import is_sequence
18from cuda.core._utils.version cimport cy_binding_version, cy_driver_version
21__all__ = [
22 "DeviceResources",
23 "SMResource",
24 "SMResourceOptions",
25 "WorkqueueResource",
26 "WorkqueueResourceOptions",
27]
30# Module-level cached version checks (trinary: 0=unchecked, 1=supported, -1=unsupported)
31cdef int _green_ctx_checked = 0
32cdef int _workqueue_checked = 0
33cdef str _green_ctx_err_msg = ""
34cdef str _workqueue_err_msg = ""
37cdef inline int _check_green_ctx_support() except?-1:
38 global _green_ctx_checked, _green_ctx_err_msg
39 if _green_ctx_checked == 1: 1axybtcdmzrwefghijABCDoEpFlGqHkInJsKuLMNUOWPVQR
40 return 0 1aybtcdmzrwefghijABCDoEpFlGqHkInJsKuLMNUOWPVQR
41 if _green_ctx_checked == -1: 1x
42 raise RuntimeError(_green_ctx_err_msg)
43 cdef tuple drv = cy_driver_version() 1x
44 cdef tuple bind = cy_binding_version() 1x
45 if drv < (12, 4, 0): 1x
46 _green_ctx_err_msg = (
47 "Green context support requires CUDA driver 12.4 or newer "
48 f"(current driver: {'.'.join(map(str, drv))})"
49 )
50 _green_ctx_checked = -1
51 raise RuntimeError(_green_ctx_err_msg)
52 if bind < (12, 4, 0): 1x
53 _green_ctx_err_msg = (
54 "Green context support requires cuda.bindings 12.4 or newer "
55 f"(current bindings: {'.'.join(map(str, bind))})"
56 )
57 _green_ctx_checked = -1
58 raise RuntimeError(_green_ctx_err_msg)
59 _green_ctx_checked = 1 1x
60 return 0 1x
63cdef inline int _check_workqueue_support() except?-1:
64 global _workqueue_checked, _workqueue_err_msg
65 if _workqueue_checked == 1: 1twUOWPVQR
66 return 0 1twUOWPVQR
67 if _workqueue_checked == -1: 1t
68 raise RuntimeError(_workqueue_err_msg)
69 cdef tuple drv = cy_driver_version() 1t
70 cdef tuple bind = cy_binding_version() 1t
71 if drv < (13, 1, 0): 1t
72 _workqueue_err_msg = (
73 "WorkqueueResource requires CUDA driver 13.1 or newer "
74 f"(current driver: {'.'.join(map(str, drv))})"
75 )
76 _workqueue_checked = -1
77 raise RuntimeError(_workqueue_err_msg)
78 if bind < (13, 1, 0): 1t
79 _workqueue_err_msg = (
80 "WorkqueueResource requires cuda.bindings 13.1 or newer "
81 f"(current bindings: {'.'.join(map(str, bind))})"
82 )
83 _workqueue_checked = -1
84 raise RuntimeError(_workqueue_err_msg)
85 _workqueue_checked = 1 1t
86 return 0 1t
89@dataclass
90cdef class SMResourceOptions:
91 """Customizable :obj:`SMResource.split` options.
93 Each field accepts a scalar (for a single group) or a ``Sequence``
94 (for multiple groups). ``count`` drives the number of groups; other
95 ``Sequence`` fields must match its length.
97 Attributes
98 ----------
99 count : int or Sequence[int], optional
100 Requested SM count per group. ``None`` means discovery mode
101 (auto-detect). (Default to ``None``)
102 coscheduled_sm_count : int or Sequence[int], optional
103 Minimum number of SMs guaranteed to be co-scheduled in each
104 group. (Default to ``None``)
105 preferred_coscheduled_sm_count : int or Sequence[int], optional
106 Preferred co-scheduled SM count; the driver tries to satisfy
107 this but may fall back to ``coscheduled_sm_count``.
108 (Default to ``None``)
109 backfill : bool or Sequence[bool], optional
110 If ``True``, allow the driver to relax the co-scheduling
111 constraint when assigning SMs. This enables requesting
112 arbitrary aligned SM counts that the driver would otherwise
113 reject due to hardware topology constraints.
114 (Default to ``False``)
115 """
117 count: int | SequenceABC | None = None
118 coscheduled_sm_count: int | SequenceABC | None = None
119 preferred_coscheduled_sm_count: int | SequenceABC | None = None
120 backfill: bool | SequenceABC = False
123@dataclass
124cdef class WorkqueueResourceOptions:
125 """Customizable :obj:`WorkqueueResource.configure` options.
127 Attributes
128 ----------
129 sharing_scope : str, optional
130 Workqueue sharing scope. Accepted values: ``"device_ctx"``
131 or ``"green_ctx_balanced"``. (Default to ``None``)
132 """
134 sharing_scope: str | None = None
137cdef inline int _validate_split_field_length(
138 object value, str field_name, int n_groups, bint count_is_scalar
139) except?-1:
140 if count_is_scalar: 1abcdmrefghijoplqknsuTS
141 if is_sequence(value): 1bcdrefghijoplqsuT
142 raise ValueError( 1T
143 f"{field_name} is a Sequence but count is scalar; " 1T
144 "count must be a Sequence to specify multiple groups"
145 )
146 elif is_sequence(value) and len(value) != n_groups: 1amknS
147 raise ValueError( 1S
148 f"{field_name} has length {len(value)}, expected {n_groups} " 1S
149 "(must match count)"
150 )
151 return 0 1abcdmrefghijoplqknsu
154cdef inline int _resolve_group_count(SMResourceOptions options) except?-1:
155 cdef object count = options.count 1abcdmrefghijoplqknsuTS
156 cdef int n_groups
157 cdef bint count_is_scalar
159 if count is None or isinstance(count, int): 1abcdmrefghijoplqknsuTS
160 n_groups = 1 1bcdrefghijoplqsuT
161 count_is_scalar = True 1bcdrefghijoplqsuT
162 elif is_sequence(count): 1amknS
163 n_groups = len(count) 1amknS
164 if n_groups == 0: 1amknS
165 raise ValueError("count sequence must not be empty")
166 count_is_scalar = False 1amknS
167 else:
168 raise TypeError(f"count must be int, Sequence, or None, got {type(count)}")
170 _validate_split_field_length( 1abcdmrefghijoplqknsuTS
171 options.coscheduled_sm_count, 1abcdmrefghijoplqknsuTS
172 "coscheduled_sm_count",
173 n_groups,
174 count_is_scalar,
175 )
176 _validate_split_field_length( 1abcdmrefghijoplqknsu
177 options.preferred_coscheduled_sm_count, 1abcdmrefghijoplqknsu
178 "preferred_coscheduled_sm_count",
179 n_groups,
180 count_is_scalar,
181 )
182 _validate_split_field_length( 1abcdmrefghijoplqknsu
183 options.backfill, 1abcdmrefghijoplqknsu
184 "backfill",
185 n_groups,
186 count_is_scalar,
187 )
188 return n_groups 1abcdmrefghijoplqknsu
191cdef inline object _broadcast_field(object value, int n_groups):
192 if is_sequence(value): 1abcdmrefghijoplqknsu
193 return list(value) 1amkn
194 return [value] * n_groups 1abcdmrefghijoplqknsu
197cdef inline unsigned int _to_sm_count(object value) except? 0:
198 """Convert a count value to unsigned int. None maps to 0 (discovery)."""
199 if value is None: 1abcdmrefghijoplqknsu
200 return 0 1bcdrefghijopls
201 if value < 0: 1amqknu
202 raise ValueError(f"count must be non-negative, got {value}") 1u
203 return <unsigned int>(value) 1amqkn
206IF CUDA_CORE_BUILD_MAJOR >= 13:
207 from cuda.core._resource_handles cimport sm_resource_split, has_sm_resource_split
209cdef int _structured_split_checked = 0
211cdef inline bint _can_use_structured_sm_split():
212 """Check if cuDevSmResourceSplit (13.1+) is available. Cached."""
213 global _structured_split_checked
214 if _structured_split_checked != 0: 1abcdmrefghijoplqknsu
215 return _structured_split_checked == 1 1bcdmrefghijoplqknsu
216 IF CUDA_CORE_BUILD_MAJOR >= 13:
217 if (has_sm_resource_split() 1a
218 and cy_driver_version() >= (13, 1, 0) 1a
219 and cy_binding_version() >= (13, 1, 0)): 1a
220 _structured_split_checked = 1 1a
221 return True 1a
222 _structured_split_checked = -1
223 return False
226cdef object _resolve_split_by_count_request(SMResourceOptions options):
227 cdef int n_groups = _resolve_group_count(options)
228 cdef list counts = _broadcast_field(options.count, n_groups)
229 cdef object first = counts[0]
230 cdef object value
231 cdef unsigned int min_count
233 if options.coscheduled_sm_count is not None:
234 raise RuntimeError(
235 "SMResourceOptions.coscheduled_sm_count requires the CUDA 13.1 "
236 "structured SM split API"
237 )
238 if options.preferred_coscheduled_sm_count is not None:
239 raise RuntimeError(
240 "SMResourceOptions.preferred_coscheduled_sm_count requires the "
241 "CUDA 13.1 structured SM split API"
242 )
244 for value in counts[1:]:
245 if value != first:
246 raise RuntimeError(
247 "CUDA 12 SM splitting only supports homogeneous count values; "
248 "use CUDA 13.1 or newer for per-group counts"
249 )
251 min_count = _to_sm_count(first)
252 return n_groups, min_count
255IF CUDA_CORE_BUILD_MAJOR >= 13:
256 cdef inline int _fill_group_params(
257 cydriver.CU_DEV_SM_RESOURCE_GROUP_PARAMS* params,
258 int n_groups,
259 SMResourceOptions options,
260 ) except?-1:
261 cdef list counts = _broadcast_field(options.count, n_groups) 1abcdmrefghijoplqknsu
262 cdef list coscheduled = _broadcast_field(options.coscheduled_sm_count, n_groups) 1abcdmrefghijoplqknsu
263 cdef list preferred = _broadcast_field(options.preferred_coscheduled_sm_count, n_groups) 1abcdmrefghijoplqknsu
264 cdef list backfills = _broadcast_field(options.backfill, n_groups) 1abcdmrefghijoplqknsu
265 cdef int i
267 for i in range(n_groups): 1abcdmrefghijoplqknsu
268 memset(¶ms[i], 0, sizeof(cydriver.CU_DEV_SM_RESOURCE_GROUP_PARAMS)) 1abcdmrefghijoplqknsu
269 params[i].smCount = _to_sm_count(counts[i]) 1abcdmrefghijoplqknsu
270 if coscheduled[i] is not None: 1abcdmrefghijoplqkns
271 params[i].coscheduledSmCount = <unsigned int>(coscheduled[i])
272 if preferred[i] is not None: 1abcdmrefghijoplqkns
273 params[i].preferredCoscheduledSmCount = <unsigned int>(preferred[i])
274 params[i].flags = ( 1abcdmrefghijoplqkns
275 cydriver.CUdevSmResourceGroup_flags.CU_DEV_SM_RESOURCE_GROUP_BACKFILL 1k
276 if backfills[i] else 0 1abcdmrefghijoplqkns
277 )
278 return 0 1abcdmrefghijoplqkns
281 cdef object _split_with_general_api(SMResource sm, SMResourceOptions options, bint dry_run):
282 cdef int n_groups = _resolve_group_count(options) 1abcdmrefghijoplqknsu
283 cdef cydriver.CUdevResource* result = NULL 1abcdmrefghijoplqknsu
284 cdef cydriver.CUdevResource remaining
285 cdef cydriver.CUdevResource synth
286 cdef cydriver.CU_DEV_SM_RESOURCE_GROUP_PARAMS* params = NULL 1abcdmrefghijoplqknsu
287 cdef list groups = [] 1abcdmrefghijoplqknsu
288 cdef int i
290 params = <cydriver.CU_DEV_SM_RESOURCE_GROUP_PARAMS*>malloc( 1abcdmrefghijoplqknsu
291 n_groups * sizeof(cydriver.CU_DEV_SM_RESOURCE_GROUP_PARAMS)
292 )
293 if params == NULL: 1abcdmrefghijoplqknsu
294 raise MemoryError()
296 try: 1abcdmrefghijoplqknsu
297 _fill_group_params(params, n_groups, options) 1abcdmrefghijoplqknsu
299 if not dry_run: 1abcdmrefghijoplqkns
300 result = <cydriver.CUdevResource*>malloc( 1abcdmrefghijoplqkn
301 n_groups * sizeof(cydriver.CUdevResource)
302 )
303 if result == NULL: 1abcdmrefghijoplqkn
304 raise MemoryError()
306 memset(&remaining, 0, sizeof(cydriver.CUdevResource)) 1abcdmrefghijoplqkns
307 with nogil: 1abcdmrefghijoplqkns
308 HANDLE_RETURN(sm_resource_split( 1abcdmrefghijoplqkns
309 result,
310 <unsigned int>(n_groups),
311 &sm._resource,
312 &remaining,
313 0,
314 <void*>params,
315 ))
317 if result != NULL: 1abcdmrefghijoplqkns
318 for i in range(n_groups): 1abcdmrefghijoplqkn
319 groups.append(SMResource._from_split_resource(result[i], sm, True)) 1abcdmrefghijoplqkn
320 return groups, SMResource._from_split_resource(remaining, sm, True) 1abcdmrefghijoplqkn
322 for i in range(n_groups): 1ls
323 memset(&synth, 0, sizeof(cydriver.CUdevResource)) 1ls
324 synth.type = cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_SM 1ls
325 synth.sm.smCount = params[i].smCount 1ls
326 groups.append(SMResource._from_split_resource(synth, sm, False)) 1ls
327 return groups, SMResource._from_split_resource(remaining, sm, False) 1ls
328 finally:
329 if params != NULL: 1abcdmrefghijoplqkns
330 free(params) 1abcdmrefghijoplqknsu
331 if result != NULL: 1abcdmrefghijoplqknsu
332 free(result) 1abcdmrefghijoplqkn
333ELSE:
334 cdef object _split_with_general_api(SMResource sm, SMResourceOptions options, bint dry_run):
335 raise RuntimeError(
336 "SMResource.split() requires cuda.core to be built with CUDA 13.x bindings"
337 )
340cdef object _split_with_count_api(SMResource sm, SMResourceOptions options, bint dry_run):
341 cdef object request = _resolve_split_by_count_request(options)
342 cdef unsigned int nb_groups = <unsigned int>(request[0])
343 cdef unsigned int min_count = <unsigned int>(request[1])
344 cdef unsigned int actual_groups = nb_groups
345 cdef cydriver.CUdevResource* result = NULL
346 cdef cydriver.CUdevResource remaining
347 cdef list groups = []
348 cdef int i
350 result = <cydriver.CUdevResource*>malloc(nb_groups * sizeof(cydriver.CUdevResource))
351 if result == NULL:
352 raise MemoryError()
354 try:
355 memset(&remaining, 0, sizeof(cydriver.CUdevResource))
356 with nogil:
357 HANDLE_RETURN(cydriver.cuDevSmResourceSplitByCount(
358 result,
359 &actual_groups,
360 &sm._resource,
361 &remaining,
362 0,
363 min_count,
364 ))
366 for i in range(actual_groups):
367 if dry_run:
368 groups.append(SMResource._from_split_resource(result[i], sm, False))
369 else:
370 groups.append(SMResource._from_split_resource(result[i], sm, True))
371 if dry_run:
372 return groups, SMResource._from_split_resource(remaining, sm, False)
373 return groups, SMResource._from_split_resource(remaining, sm, True)
374 finally:
375 free(result)
378cdef inline unsigned int _sm_resource_granularity(int device_id) except? 0:
379 cdef int major
381 with nogil:
382 HANDLE_RETURN(cydriver.cuDeviceGetAttribute(
383 &major,
384 cydriver.CUdevice_attribute.CU_DEVICE_ATTRIBUTE_COMPUTE_CAPABILITY_MAJOR,
385 <cydriver.CUdevice>(device_id),
386 ))
387 if major >= 9:
388 return 8
389 return 2
392cdef inline unsigned int _fallback_if_zero(unsigned int value, unsigned int fallback) noexcept:
393 if value != 0: 1abcdmrefghijoplqkns
394 return value 1abcdmrefghijoplqkn
395 return fallback 1bcdrefghijoplks
398cdef class SMResource:
399 """Represent an SM (streaming multiprocessor) resource partition.
401 Instances are returned by :obj:`DeviceResources.sm` or
402 :meth:`SMResource.split` and cannot be instantiated directly.
403 """
405 def __init__(self, *args, **kwargs):
406 raise RuntimeError( 1Y
407 "SMResource cannot be instantiated directly. "
408 "Use dev.resources.sm or SMResource.split()."
409 )
411 @staticmethod
412 cdef SMResource _from_dev_resource(cydriver.CUdevResource res, int device_id):
413 cdef SMResource self = SMResource.__new__(SMResource) 1axybtcdzwefghijABCDEFGHIJKLMN
414 self._resource = res 1axybtcdzwefghijABCDEFGHIJKLMN
415 self._sm_count = res.sm.smCount 1axybtcdzwefghijABCDEFGHIJKLMN
416 IF CUDA_CORE_BUILD_MAJOR >= 13:
417 self._min_partition_size = res.sm.minSmPartitionSize 1axybtcdzwefghijABCDEFGHIJKLMN
418 self._coscheduled_alignment = res.sm.smCoscheduledAlignment 1axybtcdzwefghijABCDEFGHIJKLMN
419 self._flags = res.sm.flags 1axybtcdzwefghijABCDEFGHIJKLMN
420 ELSE:
421 self._min_partition_size = _sm_resource_granularity(device_id)
422 self._coscheduled_alignment = self._min_partition_size
423 self._flags = 0
424 self._is_usable = True 1axybtcdzwefghijABCDEFGHIJKLMN
425 return self 1axybtcdzwefghijABCDEFGHIJKLMN
427 @staticmethod
428 cdef SMResource _from_split_resource(cydriver.CUdevResource res, SMResource parent, bint is_usable):
429 cdef SMResource self = SMResource.__new__(SMResource) 1abcdmrefghijoplqkns
430 self._resource = res 1abcdmrefghijoplqkns
431 self._sm_count = res.sm.smCount 1abcdmrefghijoplqkns
432 IF CUDA_CORE_BUILD_MAJOR >= 13:
433 self._min_partition_size = _fallback_if_zero( 1abcdmrefghijoplqkns
434 res.sm.minSmPartitionSize,
435 parent._min_partition_size,
436 )
437 self._coscheduled_alignment = _fallback_if_zero( 1abcdmrefghijoplqkns
438 res.sm.smCoscheduledAlignment,
439 parent._coscheduled_alignment,
440 )
441 self._flags = res.sm.flags 1abcdmrefghijoplqkns
442 ELSE:
443 self._min_partition_size = parent._min_partition_size
444 self._coscheduled_alignment = parent._coscheduled_alignment
445 self._flags = parent._flags
446 self._is_usable = is_usable 1abcdmrefghijoplqkns
447 return self 1abcdmrefghijoplqkns
449 @property
450 def handle(self) -> int:
451 """Return the address of the underlying ``CUdevResource`` struct."""
452 return <intptr_t>(&self._resource) 1X
454 @property
455 def sm_count(self) -> int:
456 """Total SMs available in this resource."""
457 return self._sm_count 1aytmXoplqkn
459 @property
460 def min_partition_size(self) -> int:
461 """Minimum SM count required to create a partition."""
462 return self._min_partition_size 1amZXoqknTS
464 @property
465 def coscheduled_alignment(self) -> int:
466 """Number of SMs guaranteed to be co-scheduled."""
467 return self._coscheduled_alignment 1ZXpk
469 @property
470 def flags(self) -> int:
471 """Raw flags from the underlying SM resource."""
472 return self._flags 1X
474 def split(self, options not None, *, bint dry_run=False):
475 """Split this SM resource into groups and a remainder.
477 Parameters
478 ----------
479 options : :obj:`SMResourceOptions`
480 Split configuration (count, co-scheduling constraints).
481 dry_run : bool, optional
482 If ``True``, return filled-in metadata without creating
483 usable resource objects. (Default to ``False``)
485 Returns
486 -------
487 tuple[list[:obj:`SMResource`], :obj:`SMResource`]
488 ``(groups, remainder)`` where each group holds a disjoint
489 SM partition and *remainder* holds any unassigned SMs.
490 """
491 cdef SMResourceOptions opts = check_or_create_options( 1abcdmrefghijoplqknsuTS
492 SMResourceOptions, options, "SM resource options"
493 )
494 _resolve_group_count(opts) 1abcdmrefghijoplqknsuTS
495 _check_green_ctx_support() 1abcdmrefghijoplqknsu
496 if _can_use_structured_sm_split(): 1abcdmrefghijoplqknsu
497 return _split_with_general_api(self, opts, dry_run) 1abcdmrefghijoplqknsu
498 # SplitByCount requires the same 12.4+ as green ctx support (already checked above)
499 return _split_with_count_api(self, opts, dry_run)
502cdef class WorkqueueResource:
503 """Represent a workqueue resource for a device or green context.
505 Merges ``CU_DEV_RESOURCE_TYPE_WORKQUEUE_CONFIG`` and
506 ``CU_DEV_RESOURCE_TYPE_WORKQUEUE`` under one user-facing type.
507 Instances are returned by :obj:`DeviceResources.workqueue` and
508 cannot be instantiated directly.
509 """
511 def __init__(self, *args, **kwargs):
512 raise RuntimeError( 1Y
513 "WorkqueueResource cannot be instantiated directly. "
514 "Use dev.resources.workqueue."
515 )
517 @staticmethod
518 cdef WorkqueueResource _from_dev_resources(
519 cydriver.CUdevResource wq_config,
520 cydriver.CUdevResource wq,
521 ):
522 cdef WorkqueueResource self = WorkqueueResource.__new__(WorkqueueResource) 1twOPQR
523 self._wq_config_resource = wq_config 1twOPQR
524 self._wq_resource = wq 1twOPQR
525 return self 1twOPQR
527 @property
528 def handle(self) -> int:
529 """Return the address of the underlying config ``CUdevResource`` struct."""
530 return <intptr_t>(&self._wq_config_resource) 1t0
532 def configure(self, options not None):
533 """Configure the workqueue resource in place.
535 Parameters
536 ----------
537 options : :obj:`WorkqueueResourceOptions`
538 Configuration options (sharing scope, etc.).
539 """
540 cdef WorkqueueResourceOptions opts = check_or_create_options( 1UWV
541 WorkqueueResourceOptions, options, "Workqueue resource options"
542 )
543 _check_green_ctx_support() 1UWV
544 _check_workqueue_support() 1UWV
545 if opts.sharing_scope is None: 1UWV
546 return None 1W
548 IF CUDA_CORE_BUILD_MAJOR >= 13:
549 if opts.sharing_scope == "device_ctx": 1UV
550 self._wq_config_resource.wqConfig.sharingScope = (
551 cydriver.CUdevWorkqueueConfigScope.CU_WORKQUEUE_SCOPE_DEVICE_CTX
552 )
553 elif opts.sharing_scope == "green_ctx_balanced": 1UV
554 self._wq_config_resource.wqConfig.sharingScope = ( 1V
555 cydriver.CUdevWorkqueueConfigScope.CU_WORKQUEUE_SCOPE_GREEN_CTX_BALANCED
556 )
557 else:
558 raise ValueError( 1U
559 f"Unknown sharing_scope: {opts.sharing_scope!r}. " 1U
560 "Expected 'device_ctx' or 'green_ctx_balanced'."
561 )
562 ELSE:
563 raise RuntimeError(
564 "WorkqueueResource requires cuda.core to be built with CUDA 13.x bindings"
565 )
568cdef class DeviceResources:
569 """Namespace for hardware resource queries.
571 When obtained via :obj:`Device.resources`, queries return full device
572 resources. When obtained via :obj:`Context.resources` or
573 :obj:`Stream.resources`, queries return the resources provisioned for
574 that context.
576 This class cannot be instantiated directly.
577 """
579 def __init__(self, *args, **kwargs):
580 raise RuntimeError( 1Y
581 "DeviceResources cannot be instantiated directly. "
582 "Use dev.resources or ctx.resources."
583 )
585 @staticmethod
586 cdef DeviceResources _init(int device_id):
587 cdef DeviceResources self = DeviceResources.__new__(DeviceResources) 1xbcdzwefghijABCDEFGHIJKLMNOPQR
588 self._device_id = device_id 1xbcdzwefghijABCDEFGHIJKLMNOPQR
589 # _h_context is default empty — queries use cuDeviceGetDevResource
590 return self 1xbcdzwefghijABCDEFGHIJKLMNOPQR
592 @staticmethod
593 cdef DeviceResources _init_from_ctx(ContextHandle h_context, int device_id):
594 cdef DeviceResources self = DeviceResources.__new__(DeviceResources) 1ayt
595 self._device_id = device_id 1ayt
596 self._h_context = h_context 1ayt
597 return self 1ayt
599 cdef inline int _query_sm(self, cydriver.CUdevResource* res) except?-1 nogil:
600 """Query SM resource from either device or context."""
601 cdef GreenCtxHandle h_green
602 if self._h_context: 1axybtcdzwefghijABCDEFGHIJKLMN
603 h_green = get_context_green_ctx(self._h_context) 1ayt
604 if h_green: 1ayt
605 HANDLE_RETURN(cydriver.cuGreenCtxGetDevResource( 1ayt
606 as_cu(h_green), res,
607 cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_SM,
608 ))
609 else:
610 HANDLE_RETURN(cydriver.cuCtxGetDevResource(
611 as_cu(self._h_context), res,
612 cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_SM,
613 ))
614 else:
615 HANDLE_RETURN(cydriver.cuDeviceGetDevResource( 1xbcdzwefghijABCDEFGHIJKLMN
616 <cydriver.CUdevice>(self._device_id), res,
617 cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_SM, 1xbcdzwefghijABCDEFGHIJKLMN
618 ))
619 return 0 1axybtcdzwefghijABCDEFGHIJKLMN
621 @property
622 def sm(self) -> SMResource:
623 """Return the :obj:`SMResource` for this device or context."""
624 _check_green_ctx_support() 1axybtcdzwefghijABCDEFGHIJKLMN
625 cdef cydriver.CUdevResource res
626 with nogil: 1axybtcdzwefghijABCDEFGHIJKLMN
627 self._query_sm(&res) 1axybtcdzwefghijABCDEFGHIJKLMN
628 return SMResource._from_dev_resource(res, self._device_id) 1axybtcdzwefghijABCDEFGHIJKLMN
630 @property
631 def workqueue(self) -> WorkqueueResource:
632 """Return the :obj:`WorkqueueResource` for this device or context."""
633 _check_green_ctx_support() 1twOPQR
634 _check_workqueue_support() 1twOPQR
635 cdef cydriver.CUdevResource _wq_config
636 cdef cydriver.CUdevResource _wq
638 IF CUDA_CORE_BUILD_MAJOR >= 13:
639 cdef GreenCtxHandle h_green
640 if self._h_context: 1twOPQR
641 h_green = get_context_green_ctx(self._h_context) 1t
642 if h_green: 1t
643 # Green context query
644 with nogil: 1t
645 HANDLE_RETURN(cydriver.cuGreenCtxGetDevResource( 1t
646 as_cu(h_green),
647 &_wq_config,
648 cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_WORKQUEUE_CONFIG,
649 ))
650 HANDLE_RETURN(cydriver.cuGreenCtxGetDevResource( 1t
651 as_cu(h_green),
652 &_wq,
653 cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_WORKQUEUE,
654 ))
655 else:
656 # Primary context query
657 with nogil:
658 HANDLE_RETURN(cydriver.cuCtxGetDevResource(
659 as_cu(self._h_context),
660 &_wq_config,
661 cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_WORKQUEUE_CONFIG,
662 ))
663 HANDLE_RETURN(cydriver.cuCtxGetDevResource(
664 as_cu(self._h_context),
665 &_wq,
666 cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_WORKQUEUE,
667 ))
668 else:
669 # Device-level query
670 with nogil: 1wOPQR
671 HANDLE_RETURN(cydriver.cuDeviceGetDevResource( 1wOPQR
672 <cydriver.CUdevice>(self._device_id),
673 &_wq_config,
674 cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_WORKQUEUE_CONFIG,
675 ))
676 HANDLE_RETURN(cydriver.cuDeviceGetDevResource( 1wOPQR
677 <cydriver.CUdevice>(self._device_id),
678 &_wq,
679 cydriver.CUdevResourceType.CU_DEV_RESOURCE_TYPE_WORKQUEUE,
680 ))
681 return WorkqueueResource._from_dev_resources(_wq_config, _wq) 1twOPQR
682 ELSE:
683 raise RuntimeError(
684 "WorkqueueResource requires cuda.core to be built with CUDA 13.x bindings"
685 )