Skip to content

Commit e36f1c1

Browse files
authored
Merge branch 'main' into ipc-mempool-channel
2 parents 948af33 + 85ff9c2 commit e36f1c1

File tree

21 files changed

+204
-101
lines changed

21 files changed

+204
-101
lines changed

.bandit

Lines changed: 0 additions & 5 deletions
This file was deleted.

.github/workflows/bandit.yml

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,27 @@ jobs:
1919
permissions:
2020
security-events: write
2121
steps:
22-
- name: Perform Bandit Analysis
23-
# KEEP IN SYNC WITH bandit rev in .pre-commit-config.yaml
24-
# Current runner uses Python 3.8, so the action installs bandit==1.7.10
25-
# via `pip install bandit[sarif]`. If runner Python moves to >=3.9,
26-
# the action will resolve to 1.8.x and you'll need to bump pre-commit.
27-
# (Bandit >=1.8.0 dropped Python 3.8 via Requires-Python metadata.)
28-
uses: PyCQA/bandit-action@8a1b30610f61f3f792fe7556e888c9d7dffa52de # v1.0.0
22+
- name: Checkout
23+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
24+
25+
- name: Install uv
26+
uses: astral-sh/setup-uv@b75a909f75acd358c2196fb9a5f1299a9a8868a4 # v6.7.0
27+
28+
- name: Get ignore codes
29+
id: ignore-codes
30+
# This are computed so that we can run only the `S` (bandit)
31+
# checks. Passing --select to ruff overrides any config files
32+
# (ruff.toml, pyproject.toml, etc), so to avoid having keep everything
33+
# in sync we grab them from the TOML programmatically
34+
run: |
35+
set -euxo pipefail
36+
37+
echo "codes=$(uvx toml2json ./ruff.toml | jq -r '.lint.ignore | map(select(test("^S\\d+"))) | join(",")')" >> "$GITHUB_OUTPUT"
38+
- name: Perform Bandit Analysis using Ruff
39+
uses: astral-sh/ruff-action@57714a7c8a2e59f32539362ba31877a1957dded1 # v3.5.1
40+
with:
41+
args: "check --select S --ignore ${{ steps.ignore-codes.outputs.codes }} --output-format sarif --output-file results.sarif"
42+
- name: Upload SARIF file
43+
uses: github/codeql-action/upload-sarif@v3
44+
with:
45+
sarif_file: results.sarif

.pre-commit-config.yaml

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ ci:
1515
# pre-commit autoupdate --freeze
1616
repos:
1717
- repo: https://github.com/astral-sh/ruff-pre-commit
18-
rev: 0b19ef1fd6ad680ed7752d6daba883ce1265a6de # frozen: v0.12.2
18+
rev: f298305809c552671cc47e0fec0ba43e96c146a2 # frozen: v0.13.2
1919
hooks:
2020
- id: ruff
2121
args: [--fix, --show-fixes]
@@ -40,7 +40,7 @@ repos:
4040

4141
# Standard hooks
4242
- repo: https://github.com/pre-commit/pre-commit-hooks
43-
rev: "v5.0.0"
43+
rev: "3e8a8703264a2f4a69428a0aa4dcb512790b2c8c" # frozen: v6.0.0
4444
hooks:
4545
- id: check-added-large-files
4646
- id: check-case-conflict
@@ -58,22 +58,14 @@ repos:
5858

5959
# Checking for common mistakes
6060
- repo: https://github.com/pre-commit/pygrep-hooks
61-
rev: "v1.10.0"
61+
rev: "3a6eb0fadf60b3cccfd80bad9dbb6fae7e47b316" # frozen: v1.10.0
6262
hooks:
6363
- id: rst-backticks
6464
- id: rst-directive-colons
6565
- id: rst-inline-touching-normal
6666

67-
- repo: https://github.com/PyCQA/bandit
68-
rev: "36fd65054fc8864b4037d0918904f9331512feb5" # frozen: 1.7.10 KEEP IN SYNC WITH .github/workflows/bandit.yml
69-
hooks:
70-
- id: bandit
71-
args:
72-
- --ini
73-
- .bandit
74-
7567
- repo: https://github.com/pre-commit/mirrors-mypy
76-
rev: 0f86793af5ef5f6dc63c8d04a3cabfa3ea8f9c6a # frozen: v1.16.1
68+
rev: 9f70dc58c23dfcca1b97af99eaeee3140a807c7e # frozen: v1.18.2
7769
hooks:
7870
- id: mypy
7971
name: mypy-pathfinder

cuda_bindings/cuda/bindings/utils/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
22
# SPDX-License-Identifier: LicenseRef-NVIDIA-SOFTWARE-LICENSE
3-
43
from typing import Any, Callable
54

65
from ._ptx_utils import get_minimal_required_cuda_ver_from_ptx_ver, get_ptx_ver

cuda_bindings/tests/test_cuda.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ def test_get_error_name_and_string():
653653
@pytest.mark.skipif(not callableBinary("nvidia-smi"), reason="Binary existance needed")
654654
def test_device_get_name():
655655
# TODO: Refactor this test once we have nvml bindings to avoid the use of subprocess
656-
import subprocess # nosec B404
656+
import subprocess
657657

658658
(err,) = cuda.cuInit(0)
659659
assert err == cuda.CUresult.CUDA_SUCCESS
@@ -663,8 +663,10 @@ def test_device_get_name():
663663
assert err == cuda.CUresult.CUDA_SUCCESS
664664

665665
p = subprocess.check_output(
666-
["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"], shell=False, stderr=subprocess.PIPE
667-
) # nosec B603, B607
666+
["nvidia-smi", "--query-gpu=name", "--format=csv,noheader"], # noqa: S607
667+
shell=False,
668+
stderr=subprocess.PIPE,
669+
)
668670

669671
delimiter = b"\r\n" if platform.system() == "Windows" else b"\n"
670672
expect = p.split(delimiter)

cuda_bindings/tests/test_nvvm.py

Lines changed: 17 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,12 @@
44

55
import binascii
66
import re
7-
import textwrap
87
from contextlib import contextmanager
98

109
import pytest
1110
from cuda.bindings import nvvm
1211

13-
MINIMAL_NVVMIR_FIXTURE_PARAMS = ["txt", "bitcode_static"]
14-
try:
15-
import llvmlite.binding as llvmlite_binding # Optional test dependency.
16-
except ImportError:
17-
llvmlite_binding = None
18-
else:
19-
MINIMAL_NVVMIR_FIXTURE_PARAMS.append("bitcode_dynamic")
20-
21-
MINIMAL_NVVMIR_TXT = b"""\
12+
MINIMAL_NVVMIR_TXT_TEMPLATE = b"""\
2213
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-i128:128:128-f32:32:32-f64:64:64-v16:16:16-v32:32:32-v64:64:64-v128:128:128-n16:32:64"
2314
2415
target triple = "nvptx64-nvidia-cuda"
@@ -130,43 +121,24 @@
130121
"6e673e0000000000",
131122
}
132123

133-
MINIMAL_NVVMIR_CACHE = {}
134-
135124

136-
@pytest.fixture(params=MINIMAL_NVVMIR_FIXTURE_PARAMS)
125+
@pytest.fixture(params=("txt", "bitcode_static"))
137126
def minimal_nvvmir(request):
138-
for pass_counter in range(2):
139-
nvvmir = MINIMAL_NVVMIR_CACHE.get(request.param, -1)
140-
if nvvmir != -1:
141-
if nvvmir is None:
142-
pytest.skip(f"UNAVAILABLE: {request.param}")
143-
return nvvmir
144-
if pass_counter:
145-
raise AssertionError("This code path is meant to be unreachable.")
146-
# Build cache entries, then try again (above).
147-
major, minor, debug_major, debug_minor = nvvm.ir_version()
148-
txt = MINIMAL_NVVMIR_TXT % (major, debug_major)
149-
if llvmlite_binding is None:
150-
bitcode_dynamic = None
151-
else:
152-
bitcode_dynamic = llvmlite_binding.parse_assembly(txt.decode()).as_bitcode()
153-
bitcode_static = MINIMAL_NVVMIR_BITCODE_STATIC.get((major, debug_major))
154-
if bitcode_static is not None:
155-
bitcode_static = binascii.unhexlify(bitcode_static)
156-
MINIMAL_NVVMIR_CACHE["txt"] = txt
157-
MINIMAL_NVVMIR_CACHE["bitcode_dynamic"] = bitcode_dynamic
158-
MINIMAL_NVVMIR_CACHE["bitcode_static"] = bitcode_static
159-
if bitcode_static is None:
160-
if bitcode_dynamic is None:
161-
raise RuntimeError("Please `pip install llvmlite` to generate `bitcode_static` (see PR #443)")
162-
bitcode_hex = binascii.hexlify(bitcode_dynamic).decode("ascii")
163-
print("\n\nMINIMAL_NVVMIR_BITCODE_STATIC = { # PLEASE ADD TO test_nvvm.py")
164-
print(f" ({major}, {debug_major}): # (major, debug_major)")
165-
lines = textwrap.wrap(bitcode_hex, width=80)
166-
for line in lines[:-1]:
167-
print(f' "{line}"')
168-
print(f' "{lines[-1]}",')
169-
print("}\n", flush=True)
127+
major, minor, debug_major, debug_minor = nvvm.ir_version()
128+
129+
if request.param == "txt":
130+
return MINIMAL_NVVMIR_TXT_TEMPLATE % (major, debug_major)
131+
132+
bitcode_static_binascii = MINIMAL_NVVMIR_BITCODE_STATIC.get((major, debug_major))
133+
if bitcode_static_binascii:
134+
return binascii.unhexlify(bitcode_static_binascii)
135+
raise RuntimeError(
136+
"Static bitcode for NVVM IR version "
137+
f"{major}.{debug_major} is not available in this test.\n"
138+
"Maintainers: Please run the helper script to generate it and add the "
139+
"output to the MINIMAL_NVVMIR_BITCODE_STATIC dict:\n"
140+
" ../../toolshed/build_static_bitcode_input.py"
141+
)
170142

171143

172144
@pytest.fixture(params=[nvvm.compile_program, nvvm.verify_program])

cuda_bindings/tests/test_utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import platform
55
import random
6-
import subprocess # nosec B404
6+
import subprocess
77
import sys
88
from pathlib import Path
99

@@ -72,7 +72,7 @@ def test_ptx_utils(kernel, actual_ptx_ver, min_cuda_ver):
7272
),
7373
)
7474
def test_get_handle(target):
75-
ptr = random.randint(1, 1024)
75+
ptr = random.randint(1, 1024) # noqa: S311
7676
obj = target(ptr)
7777
handle = get_cuda_native_handle(obj)
7878
assert handle == ptr
@@ -105,6 +105,6 @@ def test_get_handle_error(target):
105105
],
106106
)
107107
def test_cyclical_imports(module):
108-
subprocess.check_call( # nosec B603
108+
subprocess.check_call( # noqa: S603
109109
[sys.executable, Path(__file__).parent / "utils" / "check_cyclical_import.py", f"cuda.bindings.{module}"],
110110
)

cuda_core/cuda/core/experimental/_event.pyx

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ from cuda.core.experimental._utils.cuda_utils import (
1818
driver,
1919
handle_return,
2020
)
21-
21+
import sys
2222
if TYPE_CHECKING:
2323
import cuda.bindings
2424
from cuda.core.experimental._device import Device
@@ -108,15 +108,20 @@ cdef class Event:
108108
self._ctx_handle = ctx_handle
109109
return self
110110

111-
cpdef close(self):
112-
"""Destroy the event."""
111+
cdef _shutdown_safe_close(self, is_shutting_down=sys.is_finalizing):
112+
if is_shutting_down and is_shutting_down():
113+
return
113114
if self._handle is not None:
114115
err, = driver.cuEventDestroy(self._handle)
115116
self._handle = None
116117
raise_if_driver_error(err)
117118

119+
cpdef close(self):
120+
"""Destroy the event."""
121+
self._shutdown_safe_close(is_shutting_down=None)
122+
118123
def __del__(self):
119-
self.close()
124+
self._shutdown_safe_close()
120125

121126
def __isub__(self, other):
122127
return NotImplemented

cuda_core/cuda/core/experimental/_memory.pyx

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ from cuda.core.experimental._utils.cuda_utils cimport (
99
_check_driver_error as raise_if_driver_error,
1010
check_or_create_options,
1111
)
12+
import sys
1213

1314
from dataclasses import dataclass
1415
from typing import Optional, TypeVar, Union, TYPE_CHECKING
@@ -72,7 +73,16 @@ cdef class Buffer:
7273
return self
7374

7475
def __del__(self):
75-
self.close()
76+
self._shutdown_safe_close()
77+
78+
cdef _shutdown_safe_close(self, stream: Stream = None, is_shutting_down=sys.is_finalizing):
79+
if is_shutting_down and is_shutting_down():
80+
return
81+
if self._ptr and self._mr is not None:
82+
self._mr.deallocate(self._ptr, self._size, stream)
83+
self._ptr = 0
84+
self._mr = None
85+
self._ptr_obj = None
7686

7787
def __reduce__(self):
7888
return Buffer.from_ipc_descriptor, (self.memory_resource, self.get_ipc_descriptor())
@@ -89,11 +99,7 @@ cdef class Buffer:
8999
The stream object to use for asynchronous deallocation. If None,
90100
the behavior depends on the underlying memory resource.
91101
"""
92-
if self._ptr and self._mr is not None:
93-
self._mr.deallocate(self._ptr, self._size, stream)
94-
self._ptr = 0
95-
self._mr = None
96-
self._ptr_obj = None
102+
self._shutdown_safe_close(stream, is_shutting_down=None)
97103

98104
@property
99105
def handle(self) -> DevicePointerT:

cuda_core/cuda/core/experimental/_memoryview.pyx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,23 @@ cdef class StridedMemoryView:
105105
else:
106106
pass
107107

108+
def __dealloc__(self):
109+
if self.dl_tensor == NULL:
110+
return
111+
112+
if cpython.PyCapsule_IsValid(
113+
self.metadata, DLPACK_VERSIONED_TENSOR_USED_NAME):
114+
data = cpython.PyCapsule_GetPointer(
115+
self.metadata, DLPACK_VERSIONED_TENSOR_USED_NAME)
116+
dlm_tensor_ver = <DLManagedTensorVersioned*>data
117+
dlm_tensor_ver.deleter(dlm_tensor_ver)
118+
elif cpython.PyCapsule_IsValid(
119+
self.metadata, DLPACK_TENSOR_USED_NAME):
120+
data = cpython.PyCapsule_GetPointer(
121+
self.metadata, DLPACK_TENSOR_USED_NAME)
122+
dlm_tensor = <DLManagedTensor*>data
123+
dlm_tensor.deleter(dlm_tensor)
124+
108125
@property
109126
def shape(self) -> tuple[int]:
110127
if self._shape is None and self.exporting_obj is not None:

0 commit comments

Comments
 (0)