nbxtensor 0.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nbxtensor/THIRD_PARTY_NOTICES.md +287 -0
- nbxtensor/__init__.py +17 -0
- nbxtensor/backend/__init__.py +1 -0
- nbxtensor/backend/capabilities.py +207 -0
- nbxtensor/backend/cpu/__init__.py +1 -0
- nbxtensor/backend/cpu/blas.py +102 -0
- nbxtensor/backend/cpu/pool.py +204 -0
- nbxtensor/backend/cpu_backend.py +162 -0
- nbxtensor/backend/device_facts.py +105 -0
- nbxtensor/backend/device_files.py +129 -0
- nbxtensor/backend/device_names.py +18 -0
- nbxtensor/backend/devices/amd/cdna.yml +228 -0
- nbxtensor/backend/devices/amd/cdna2.yml +228 -0
- nbxtensor/backend/devices/amd/cdna3.yml +227 -0
- nbxtensor/backend/devices/apple/apple_m1.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m1_max.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m1_pro.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m1_ultra.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m2.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m2_max.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m2_pro.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m2_ultra.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m3.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m3_max.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m3_pro.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m3_ultra.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m4.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m4_max.yml +266 -0
- nbxtensor/backend/devices/apple/apple_m4_pro.yml +308 -0
- nbxtensor/backend/devices/apple/apple_m5.yml +269 -0
- nbxtensor/backend/devices/apple/apple_m5_max.yml +269 -0
- nbxtensor/backend/devices/apple/apple_m5_pro.yml +269 -0
- nbxtensor/backend/devices/apple/apple_m5_ultra.yml +269 -0
- nbxtensor/backend/devices/apple/apple_m6.yml +269 -0
- nbxtensor/backend/devices/apple/apple_silicon.yml +263 -0
- nbxtensor/backend/devices/nvidia/ampere.yml +214 -0
- nbxtensor/backend/devices/nvidia/hopper.yml +213 -0
- nbxtensor/backend/devices/nvidia/volta.yml +411 -0
- nbxtensor/backend/faults.py +151 -0
- nbxtensor/backend/host_memory.py +185 -0
- nbxtensor/backend/launcher.py +2350 -0
- nbxtensor/backend/launcher_contract.py +429 -0
- nbxtensor/backend/metal_backend.py +661 -0
- nbxtensor/backend/metal_device.py +1274 -0
- nbxtensor/backend/process_memory.py +73 -0
- nbxtensor/backend/replay_graph.py +322 -0
- nbxtensor/backend/runtime.py +409 -0
- nbxtensor/backend/triton_ext_driver.py +735 -0
- nbxtensor/dtype/__init__.py +1 -0
- nbxtensor/dtype/convert.py +107 -0
- nbxtensor/dtype/dtypes.yml +70 -0
- nbxtensor/dtype/itemsize.py +166 -0
- nbxtensor/dtype/nbx_dtype.py +72 -0
- nbxtensor/dtype/operands.py +158 -0
- nbxtensor/dtype/outputs.py +64 -0
- nbxtensor/dtype/policy.py +155 -0
- nbxtensor/dtype/policy.yml +51 -0
- nbxtensor/dtype/promotion.py +112 -0
- nbxtensor/host.py +55 -0
- nbxtensor/io/__init__.py +1 -0
- nbxtensor/io/read_rate.py +197 -0
- nbxtensor/io/safetensors.py +314 -0
- nbxtensor/memory/__init__.py +9 -0
- nbxtensor/memory/allocator.py +1988 -0
- nbxtensor/memory/arena.py +75 -0
- nbxtensor/memory/device_memory.py +150 -0
- nbxtensor/memory/device_transfer.py +154 -0
- nbxtensor/memory/layout.py +43 -0
- nbxtensor/memory/memory_pool.py +191 -0
- nbxtensor/memory/metal.py +96 -0
- nbxtensor/memory/oom_advice.py +91 -0
- nbxtensor/memory/pointer_tables.py +323 -0
- nbxtensor/memory/pool.py +507 -0
- nbxtensor/memory/shadow.py +43 -0
- nbxtensor/memory/slab.py +273 -0
- nbxtensor/memory/trace_replay.py +122 -0
- nbxtensor/memory/traces/sana-video-2b-720p.16g.2026-11-02.tsv +13610 -0
- nbxtensor/memory/vmm.py +118 -0
- nbxtensor/ops/__init__.py +1 -0
- nbxtensor/ops/_autotune_policy.py +90 -0
- nbxtensor/ops/_common.py +32 -0
- nbxtensor/ops/_configs.py +1041 -0
- nbxtensor/ops/_cost.py +231 -0
- nbxtensor/ops/abs.py +17 -0
- nbxtensor/ops/adaptive_avg_pool2d.py +161 -0
- nbxtensor/ops/add.py +96 -0
- nbxtensor/ops/addcdiv.py +29 -0
- nbxtensor/ops/addcmul.py +29 -0
- nbxtensor/ops/addmv_op.py +64 -0
- nbxtensor/ops/addr.py +68 -0
- nbxtensor/ops/all_reduce.py +83 -0
- nbxtensor/ops/amax.py +40 -0
- nbxtensor/ops/any_reduce.py +83 -0
- nbxtensor/ops/arange_op.py +27 -0
- nbxtensor/ops/argmax.py +107 -0
- nbxtensor/ops/argmin.py +93 -0
- nbxtensor/ops/atan2.py +71 -0
- nbxtensor/ops/attention_wrappers.py +1648 -0
- nbxtensor/ops/autotune_bucket.py +137 -0
- nbxtensor/ops/autotune_cache.py +430 -0
- nbxtensor/ops/autotune_certified.py +1262 -0
- nbxtensor/ops/autotune_refusals.py +380 -0
- nbxtensor/ops/autotune_settings.py +58 -0
- nbxtensor/ops/avg_pool2d.py +73 -0
- nbxtensor/ops/baddbmm_op.py +132 -0
- nbxtensor/ops/batch_norm.py +163 -0
- nbxtensor/ops/binary_strided.py +196 -0
- nbxtensor/ops/bitwise_and.py +26 -0
- nbxtensor/ops/bitwise_left_shift.py +47 -0
- nbxtensor/ops/bitwise_not.py +24 -0
- nbxtensor/ops/bitwise_or.py +26 -0
- nbxtensor/ops/bitwise_right_shift.py +47 -0
- nbxtensor/ops/bucketize.py +37 -0
- nbxtensor/ops/cat_op.py +87 -0
- nbxtensor/ops/celu.py +20 -0
- nbxtensor/ops/clamp.py +24 -0
- nbxtensor/ops/clamp_min.py +22 -0
- nbxtensor/ops/conv2d.py +265 -0
- nbxtensor/ops/conv2d_m8n8k4.py +165 -0
- nbxtensor/ops/conv_depthwise2d.py +154 -0
- nbxtensor/ops/conv_transpose2d.py +148 -0
- nbxtensor/ops/conv_wrappers.py +1482 -0
- nbxtensor/ops/copy.py +18 -0
- nbxtensor/ops/copy_op.py +39 -0
- nbxtensor/ops/cos.py +17 -0
- nbxtensor/ops/count_nonzero.py +64 -0
- nbxtensor/ops/cross_entropy.py +67 -0
- nbxtensor/ops/cummax.py +109 -0
- nbxtensor/ops/cummin.py +105 -0
- nbxtensor/ops/cumsum.py +244 -0
- nbxtensor/ops/decode_attn_vec.py +162 -0
- nbxtensor/ops/depthwise_conv2d.py +132 -0
- nbxtensor/ops/dequant_gemv.py +190 -0
- nbxtensor/ops/dft.py +67 -0
- nbxtensor/ops/dispatch.py +1228 -0
- nbxtensor/ops/div.py +75 -0
- nbxtensor/ops/dot_op.py +67 -0
- nbxtensor/ops/dropout.py +23 -0
- nbxtensor/ops/dtype_convert.py +42 -0
- nbxtensor/ops/elementwise_launch.py +81 -0
- nbxtensor/ops/elementwise_wrappers.py +2315 -0
- nbxtensor/ops/elu.py +20 -0
- nbxtensor/ops/embedding.py +69 -0
- nbxtensor/ops/eq.py +32 -0
- nbxtensor/ops/erf.py +18 -0
- nbxtensor/ops/exp.py +17 -0
- nbxtensor/ops/exp2.py +18 -0
- nbxtensor/ops/fft_op.py +125 -0
- nbxtensor/ops/fill_op.py +20 -0
- nbxtensor/ops/flash_attention.py +307 -0
- nbxtensor/ops/flash_attention_m8n8k4.py +384 -0
- nbxtensor/ops/flash_decode.py +78 -0
- nbxtensor/ops/flip_op.py +60 -0
- nbxtensor/ops/floor.py +90 -0
- nbxtensor/ops/full_op.py +24 -0
- nbxtensor/ops/fused_moe.py +417 -0
- nbxtensor/ops/fused_moe_m8n8k4.py +99 -0
- nbxtensor/ops/fused_upsample_conv.py +413 -0
- nbxtensor/ops/gather_op.py +52 -0
- nbxtensor/ops/ge.py +32 -0
- nbxtensor/ops/gelu.py +31 -0
- nbxtensor/ops/gemv_vec.py +80 -0
- nbxtensor/ops/glu.py +43 -0
- nbxtensor/ops/grid_sampler.py +145 -0
- nbxtensor/ops/group_norm_tiled.py +67 -0
- nbxtensor/ops/groupnorm.py +123 -0
- nbxtensor/ops/gt.py +32 -0
- nbxtensor/ops/hardsigmoid.py +18 -0
- nbxtensor/ops/hardswish.py +19 -0
- nbxtensor/ops/im2col.py +57 -0
- nbxtensor/ops/index_add.py +95 -0
- nbxtensor/ops/index_put_op.py +92 -0
- nbxtensor/ops/index_select.py +121 -0
- nbxtensor/ops/index_wrappers.py +770 -0
- nbxtensor/ops/isfinite.py +20 -0
- nbxtensor/ops/isinf.py +20 -0
- nbxtensor/ops/isnan.py +18 -0
- nbxtensor/ops/launch_keys.py +1054 -0
- nbxtensor/ops/launch_observer.py +54 -0
- nbxtensor/ops/layernorm.py +71 -0
- nbxtensor/ops/le.py +35 -0
- nbxtensor/ops/leaky_relu.py +19 -0
- nbxtensor/ops/lerp.py +76 -0
- nbxtensor/ops/linalg_wrappers.py +1370 -0
- nbxtensor/ops/linspace_op.py +47 -0
- nbxtensor/ops/log.py +17 -0
- nbxtensor/ops/log_sigmoid.py +23 -0
- nbxtensor/ops/logical_and.py +26 -0
- nbxtensor/ops/logical_not.py +24 -0
- nbxtensor/ops/logical_or.py +26 -0
- nbxtensor/ops/logical_xor.py +37 -0
- nbxtensor/ops/loss_wrappers.py +282 -0
- nbxtensor/ops/lt.py +32 -0
- nbxtensor/ops/masked_fill.py +21 -0
- nbxtensor/ops/matmul.py +377 -0
- nbxtensor/ops/matmul_m8n8k4.py +235 -0
- nbxtensor/ops/max_pool2d.py +74 -0
- nbxtensor/ops/max_pool3d.py +93 -0
- nbxtensor/ops/max_reduce.py +91 -0
- nbxtensor/ops/maximum.py +18 -0
- nbxtensor/ops/mean.py +40 -0
- nbxtensor/ops/min_reduce.py +91 -0
- nbxtensor/ops/minimum.py +18 -0
- nbxtensor/ops/mish.py +22 -0
- nbxtensor/ops/mma_m8n8k4.py +152 -0
- nbxtensor/ops/moe_align.py +195 -0
- nbxtensor/ops/moe_decode_vec.py +374 -0
- nbxtensor/ops/moe_device_residency.py +141 -0
- nbxtensor/ops/moe_wrappers.py +345 -0
- nbxtensor/ops/mse_loss.py +79 -0
- nbxtensor/ops/mul.py +51 -0
- nbxtensor/ops/nan_to_num.py +23 -0
- nbxtensor/ops/ne.py +32 -0
- nbxtensor/ops/neg.py +17 -0
- nbxtensor/ops/nllloss.py +124 -0
- nbxtensor/ops/nonzero.py +33 -0
- nbxtensor/ops/nonzero_op.py +62 -0
- nbxtensor/ops/norm_wrappers.py +579 -0
- nbxtensor/ops/ones_op.py +20 -0
- nbxtensor/ops/oracles/__init__.py +6 -0
- nbxtensor/ops/oracles/conv2d_fp64.py +450 -0
- nbxtensor/ops/pad_op.py +159 -0
- nbxtensor/ops/paged_decode_attn.py +215 -0
- nbxtensor/ops/pixel_shuffle.py +144 -0
- nbxtensor/ops/pixel_unshuffle.py +72 -0
- nbxtensor/ops/pow.py +137 -0
- nbxtensor/ops/prod.py +81 -0
- nbxtensor/ops/rand_op.py +52 -0
- nbxtensor/ops/random_wrappers.py +366 -0
- nbxtensor/ops/reciprocal.py +17 -0
- nbxtensor/ops/reduction_wrappers.py +845 -0
- nbxtensor/ops/relu.py +18 -0
- nbxtensor/ops/remainder.py +46 -0
- nbxtensor/ops/repeat_interleave.py +48 -0
- nbxtensor/ops/repeat_op.py +132 -0
- nbxtensor/ops/residual_chain.py +374 -0
- nbxtensor/ops/rmsnorm.py +68 -0
- nbxtensor/ops/rope.py +142 -0
- nbxtensor/ops/rsqrt.py +17 -0
- nbxtensor/ops/scaled_softmax.py +96 -0
- nbxtensor/ops/scatter_op.py +139 -0
- nbxtensor/ops/screen_oracle.py +479 -0
- nbxtensor/ops/selu.py +22 -0
- nbxtensor/ops/shape_wrappers.py +1032 -0
- nbxtensor/ops/sigmoid.py +19 -0
- nbxtensor/ops/silu.py +27 -0
- nbxtensor/ops/sin.py +17 -0
- nbxtensor/ops/softmax.py +169 -0
- nbxtensor/ops/softplus.py +27 -0
- nbxtensor/ops/sort_op.py +304 -0
- nbxtensor/ops/spectral_wrappers.py +481 -0
- nbxtensor/ops/sqrt.py +17 -0
- nbxtensor/ops/stack_op.py +84 -0
- nbxtensor/ops/std.py +113 -0
- nbxtensor/ops/strided_copy.py +200 -0
- nbxtensor/ops/sub.py +35 -0
- nbxtensor/ops/sum.py +40 -0
- nbxtensor/ops/tan.py +19 -0
- nbxtensor/ops/tanh.py +21 -0
- nbxtensor/ops/threshold.py +19 -0
- nbxtensor/ops/tiling.yml +91 -0
- nbxtensor/ops/tiling_policy.py +43 -0
- nbxtensor/ops/tiling_sizes.py +370 -0
- nbxtensor/ops/topk.py +267 -0
- nbxtensor/ops/trace_op.py +64 -0
- nbxtensor/ops/tril.py +64 -0
- nbxtensor/ops/triu.py +62 -0
- nbxtensor/ops/unfold_op.py +37 -0
- nbxtensor/ops/unique_op.py +97 -0
- nbxtensor/ops/upsample_bilinear2d.py +106 -0
- nbxtensor/ops/upsample_nearest2d.py +52 -0
- nbxtensor/ops/upsample_nearest3d.py +61 -0
- nbxtensor/ops/var.py +136 -0
- nbxtensor/ops/vector_norm.py +216 -0
- nbxtensor/ops/weight_norm.py +104 -0
- nbxtensor/ops/where.py +39 -0
- nbxtensor/ops/wrappers.py +825 -0
- nbxtensor/ops/zeros_op.py +20 -0
- nbxtensor/quant/__init__.py +1 -0
- nbxtensor/quant/quantized_tensor.py +187 -0
- nbxtensor/random/__init__.py +1 -0
- nbxtensor/random/mt_randn.py +154 -0
- nbxtensor/random/rng_pin.py +59 -0
- nbxtensor/random/rng_stream.py +118 -0
- nbxtensor/random/seeded_draw.py +223 -0
- nbxtensor/shape/__init__.py +157 -0
- nbxtensor/tensor.py +1867 -0
- nbxtensor-0.0.1.dist-info/METADATA +379 -0
- nbxtensor-0.0.1.dist-info/RECORD +291 -0
- nbxtensor-0.0.1.dist-info/WHEEL +4 -0
- nbxtensor-0.0.1.dist-info/licenses/LICENSE +189 -0
nbxtensor/memory/vmm.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""The device's virtual memory management primitives (CUDA's driver API: cuMemAddressReserve, cuMemCreate, cuMemMap,
|
|
2
|
+
cuMemSetAccess, cuMemUnmap, cuMemRelease) — what an expandable range (`memory.expandable`) builds on: ONE virtual
|
|
3
|
+
address range per device, physical chunks mapped into it as it grows and unmapped where a free block covers them whole
|
|
4
|
+
(R16, the supervisor's GO 2026-11-02 01:30; the method of torch's `expandable_segments`, PR #96995).
|
|
5
|
+
|
|
6
|
+
Reached through ctypes on the driver library the backend table names (`driver_libs`); a backend without the API (HIP,
|
|
7
|
+
Metal) or a device without the attribute (`CU_DEVICE_ATTRIBUTE_VIRTUAL_MEMORY_MANAGEMENT_SUPPORTED`) answers
|
|
8
|
+
`supported() == False` and the pool keeps its driver segments. Every call returns the driver's status code; the caller
|
|
9
|
+
names a failure. Measured on V100 (registres/benchmarks/vmm_v100.md, 2026-11-02): the granularity is 2 MiB; a map of a
|
|
10
|
+
chunk (create + map + set access) costs what an ordinary allocation of the same size costs (~0.36 ms), an unmap ~0.1 ms.
|
|
11
|
+
|
|
12
|
+
Torch-free, numpy-free.
|
|
13
|
+
"""
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import ctypes
|
|
17
|
+
from typing import Optional, Tuple
|
|
18
|
+
|
|
19
|
+
#: cuMemAllocationProp.type: CU_MEM_ALLOCATION_TYPE_PINNED; .location.type: CU_MEM_LOCATION_TYPE_DEVICE
|
|
20
|
+
_ALLOC_PINNED, _LOC_DEVICE = 1, 1
|
|
21
|
+
#: CU_MEM_ACCESS_FLAGS_PROT_READWRITE
|
|
22
|
+
_PROT_RW = 3
|
|
23
|
+
#: CU_MEM_ALLOC_GRANULARITY_MINIMUM
|
|
24
|
+
_GRAN_MINIMUM = 0
|
|
25
|
+
#: CU_DEVICE_ATTRIBUTE_VIRTUAL_MEMORY_MANAGEMENT_SUPPORTED
|
|
26
|
+
_ATTR_VMM = 102
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class _Loc(ctypes.Structure):
|
|
30
|
+
_fields_ = [("type", ctypes.c_int), ("id", ctypes.c_int)]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class _AllocFlags(ctypes.Structure):
|
|
34
|
+
_fields_ = [("compressionType", ctypes.c_ubyte), ("gpuDirectRDMACapable", ctypes.c_ubyte),
|
|
35
|
+
("usage", ctypes.c_ushort), ("reserved", ctypes.c_ubyte * 4)]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class _Prop(ctypes.Structure):
|
|
39
|
+
_fields_ = [("type", ctypes.c_int), ("requestedHandleTypes", ctypes.c_int), ("location", _Loc),
|
|
40
|
+
("win32HandleMetaData", ctypes.c_void_p), ("allocFlags", _AllocFlags)]
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class _Access(ctypes.Structure):
|
|
44
|
+
_fields_ = [("location", _Loc), ("flags", ctypes.c_int)]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class Vmm:
|
|
48
|
+
"""One device's VMM calls. `lib`: the driver library (ctypes CDLL); `device`: the device ordinal the process sees."""
|
|
49
|
+
|
|
50
|
+
def __init__(self, lib, device: int) -> None:
|
|
51
|
+
self.lib = lib
|
|
52
|
+
self.device = int(device)
|
|
53
|
+
self._prop = _Prop()
|
|
54
|
+
self._prop.type = _ALLOC_PINNED
|
|
55
|
+
self._prop.location = _Loc(_LOC_DEVICE, self.device)
|
|
56
|
+
self._access = _Access(_Loc(_LOC_DEVICE, self.device), _PROT_RW)
|
|
57
|
+
|
|
58
|
+
@staticmethod
|
|
59
|
+
def load(libs) -> Optional[object]:
|
|
60
|
+
"""The first driver library of `libs` that loads, initialised; None when none does."""
|
|
61
|
+
for name in libs or ():
|
|
62
|
+
try:
|
|
63
|
+
lib = ctypes.CDLL(name)
|
|
64
|
+
except OSError:
|
|
65
|
+
continue
|
|
66
|
+
if lib.cuInit(0) == 0:
|
|
67
|
+
return lib
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
def supported(self) -> bool:
|
|
71
|
+
"""The device answers the VMM attribute with 1."""
|
|
72
|
+
dev, val = ctypes.c_int(), ctypes.c_int()
|
|
73
|
+
if self.lib.cuDeviceGet(ctypes.byref(dev), self.device) != 0:
|
|
74
|
+
return False
|
|
75
|
+
if self.lib.cuDeviceGetAttribute(ctypes.byref(val), _ATTR_VMM, dev) != 0:
|
|
76
|
+
return False
|
|
77
|
+
return val.value == 1
|
|
78
|
+
|
|
79
|
+
def granularity(self) -> Tuple[int, int]:
|
|
80
|
+
"""(rc, the minimum allocation granularity in bytes)."""
|
|
81
|
+
g = ctypes.c_size_t()
|
|
82
|
+
rc = self.lib.cuMemGetAllocationGranularity(ctypes.byref(g), ctypes.byref(self._prop), _GRAN_MINIMUM)
|
|
83
|
+
return rc, int(g.value)
|
|
84
|
+
|
|
85
|
+
def reserve(self, nbytes: int) -> Tuple[int, int]:
|
|
86
|
+
"""(rc, the base of a reserved virtual range of `nbytes`)."""
|
|
87
|
+
va = ctypes.c_uint64()
|
|
88
|
+
rc = self.lib.cuMemAddressReserve(ctypes.byref(va), ctypes.c_size_t(nbytes), ctypes.c_size_t(0),
|
|
89
|
+
ctypes.c_uint64(0), ctypes.c_ulonglong(0))
|
|
90
|
+
return rc, int(va.value)
|
|
91
|
+
|
|
92
|
+
def unreserve(self, va: int, nbytes: int) -> int:
|
|
93
|
+
return self.lib.cuMemAddressFree(ctypes.c_uint64(va), ctypes.c_size_t(nbytes))
|
|
94
|
+
|
|
95
|
+
def create(self, nbytes: int) -> Tuple[int, int]:
|
|
96
|
+
"""(rc, a physical allocation handle of `nbytes` on the device)."""
|
|
97
|
+
h = ctypes.c_ulonglong()
|
|
98
|
+
rc = self.lib.cuMemCreate(ctypes.byref(h), ctypes.c_size_t(nbytes), ctypes.byref(self._prop),
|
|
99
|
+
ctypes.c_ulonglong(0))
|
|
100
|
+
return rc, int(h.value)
|
|
101
|
+
|
|
102
|
+
def map(self, va: int, nbytes: int, handle: int) -> int:
|
|
103
|
+
"""Map `handle` at `va` and open it to the device; on a failed access grant the mapping is undone."""
|
|
104
|
+
rc = self.lib.cuMemMap(ctypes.c_uint64(va), ctypes.c_size_t(nbytes), ctypes.c_size_t(0),
|
|
105
|
+
ctypes.c_ulonglong(handle), ctypes.c_ulonglong(0))
|
|
106
|
+
if rc != 0:
|
|
107
|
+
return rc
|
|
108
|
+
rc = self.lib.cuMemSetAccess(ctypes.c_uint64(va), ctypes.c_size_t(nbytes), ctypes.byref(self._access),
|
|
109
|
+
ctypes.c_size_t(1))
|
|
110
|
+
if rc != 0:
|
|
111
|
+
self.lib.cuMemUnmap(ctypes.c_uint64(va), ctypes.c_size_t(nbytes))
|
|
112
|
+
return rc
|
|
113
|
+
|
|
114
|
+
def unmap(self, va: int, nbytes: int) -> int:
|
|
115
|
+
return self.lib.cuMemUnmap(ctypes.c_uint64(va), ctypes.c_size_t(nbytes))
|
|
116
|
+
|
|
117
|
+
def release(self, handle: int) -> int:
|
|
118
|
+
return self.lib.cuMemRelease(ctypes.c_ulonglong(handle))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Ops: the Triton kernels, one file per op (pure @triton.jit compute). No torch in this package."""
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""NBX_DISABLE_AUTOTUNE — diagnostic env var that forces all autotuned
|
|
2
|
+
matmul-class kernels to use a single fixed config.
|
|
3
|
+
|
|
4
|
+
Purpose (P-SANA-4KPX-RUNTIME 2026-05-07): isolate autotune as the
|
|
5
|
+
cause of shape-dependent numerical divergence at Sana 4Kpx scale.
|
|
6
|
+
When `NBX_DISABLE_AUTOTUNE=1`, the autotune `configs=[...]` list is
|
|
7
|
+
filtered down to a single `Config` known to be Volta-viable, so the
|
|
8
|
+
autotuner has no degrees of freedom and the same bit-pattern of
|
|
9
|
+
accumulation runs at every shape. If running with this flag yields a
|
|
10
|
+
coherent PNG that the autotune-enabled run does not, autotune is
|
|
11
|
+
confirmed as the cause.
|
|
12
|
+
|
|
13
|
+
This is **not for production** — autotune is required to reach
|
|
14
|
+
cuBLAS perf parity per CLAUDE.md autotune doctrine. Use only as a
|
|
15
|
+
diagnostic / temporary workaround until a buggy config is removed
|
|
16
|
+
from the search space or its kernel is fixed.
|
|
17
|
+
|
|
18
|
+
Universal across hardware (R23): the fixed config is `BLOCK_M=64,
|
|
19
|
+
BLOCK_N=64, BLOCK_K=32, num_warps=4, num_stages=2` for matmul-class
|
|
20
|
+
kernels — Volta-viable per CLAUDE.md autotune policy and within
|
|
21
|
+
sm_80+ SMEM headroom too.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
import os
|
|
25
|
+
|
|
26
|
+
NBX_DISABLE_AUTOTUNE = os.environ.get("NBX_DISABLE_AUTOTUNE", "0") == "1"
|
|
27
|
+
|
|
28
|
+
# Diagnostic env var (P-SANA-4KPX-RUNTIME 2026-05-08): forces all
|
|
29
|
+
# half-precision (fp16/bf16) inputs to mm/bmm/addmm to be upcast to
|
|
30
|
+
# fp32 BEFORE entering the matmul kernel, regardless of hardware
|
|
31
|
+
# capability or M size. Also forces output dtype to fp32 and
|
|
32
|
+
# IEEE_PRECISION=True. Used to isolate whether the residual Sana 4Kpx
|
|
33
|
+
# bug is caused by a dtype-intermediate path (cuDNN-vs-NBX
|
|
34
|
+
# accumulation precision difference) that the existing wrapper rules
|
|
35
|
+
# don't cover for bf16 inputs on Volta. NOT for production - costs
|
|
36
|
+
# 2x VRAM and disables HMMA. Once a definitive verdict is reached
|
|
37
|
+
# (Cas A: bug fixed -> isolate the specific dtype path that needs
|
|
38
|
+
# correction; Cas B: bug persists -> dtype intermediate eliminated as
|
|
39
|
+
# suspect, focus shifts to reduction order or layout/stride).
|
|
40
|
+
NBX_FORCE_FP32_ACCUM = os.environ.get("NBX_FORCE_FP32_ACCUM", "0") == "1"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def maybe_pin_single(configs, predicate):
|
|
44
|
+
"""If `NBX_DISABLE_AUTOTUNE=1`, return a single-element list with
|
|
45
|
+
the FIRST config matching `predicate`. Otherwise return `configs`
|
|
46
|
+
unchanged.
|
|
47
|
+
|
|
48
|
+
`predicate` is a callable `Config -> bool`. The first match in the
|
|
49
|
+
`configs` list is selected, so callers should prefer ordering with
|
|
50
|
+
the desired Volta-safe target near the top (or use a unique
|
|
51
|
+
predicate).
|
|
52
|
+
"""
|
|
53
|
+
if not NBX_DISABLE_AUTOTUNE:
|
|
54
|
+
return configs
|
|
55
|
+
for c in configs:
|
|
56
|
+
if predicate(c):
|
|
57
|
+
return [c]
|
|
58
|
+
# Fallback: keep a single arbitrary config if the predicate finds
|
|
59
|
+
# nothing (e.g. depthwise has different field names). Caller must
|
|
60
|
+
# adjust predicate per kernel.
|
|
61
|
+
return configs[:1]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def is_matmul_pinned(c):
|
|
65
|
+
"""Match the matmul/bmm/addmm Volta-safe target:
|
|
66
|
+
BLOCK_M=64, BLOCK_N=64, BLOCK_K=32, num_warps=4, num_stages=2.
|
|
67
|
+
"""
|
|
68
|
+
kw = c.kwargs
|
|
69
|
+
return (kw.get('BLOCK_M') == 64 and kw.get('BLOCK_N') == 64
|
|
70
|
+
and kw.get('BLOCK_K') == 32
|
|
71
|
+
and c.num_warps == 4 and c.num_stages == 2)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def is_conv2d_pinned(c):
|
|
75
|
+
"""Match conv2d Volta-safe target:
|
|
76
|
+
BLOCK_SIZE_BHW=64, BLOCK_SIZE_OUTF=64, BLOCK_SIZE_INF=32, warps=4, stages=2.
|
|
77
|
+
"""
|
|
78
|
+
kw = c.kwargs
|
|
79
|
+
return (kw.get('BLOCK_SIZE_BHW') == 64
|
|
80
|
+
and kw.get('BLOCK_SIZE_OUTF') == 64
|
|
81
|
+
and kw.get('BLOCK_SIZE_INF') == 32
|
|
82
|
+
and c.num_warps == 4 and c.num_stages == 2)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def is_depthwise_conv2d_pinned(c):
|
|
86
|
+
"""Match depthwise conv2d's pinned config — its fields are the 2-D tile's (BC channels x TH x TW): 2 x 8 x 64,
|
|
87
|
+
the best measured on SANA-Video's 11200- and 13440-channel 3x3 (V100-SXM2, 2026-11-03).
|
|
88
|
+
"""
|
|
89
|
+
kw = c.kwargs
|
|
90
|
+
return kw.get('BC') == 2 and kw.get('TH') == 8 and kw.get('TW') == 64
|
nbxtensor/ops/_common.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Shared activation element functions — pure @triton.jit, no pointers.
|
|
2
|
+
|
|
3
|
+
These operate on already-loaded values and compose naturally.
|
|
4
|
+
Ported from attorch (MIT license).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import triton
|
|
8
|
+
import triton.language as tl
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@triton.jit
|
|
12
|
+
def sigmoid(x):
|
|
13
|
+
"""Sigmoid: 1 / (1 + exp(-x))"""
|
|
14
|
+
return 1.0 / (1.0 + tl.exp(-x))
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@triton.jit
|
|
18
|
+
def tanh_fn(x):
|
|
19
|
+
"""Tanh via sigmoid: 2 * sigmoid(2x) - 1"""
|
|
20
|
+
return 2.0 * sigmoid(2.0 * x) - 1.0
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@triton.jit
|
|
24
|
+
def relu_fn(x):
|
|
25
|
+
"""ReLU: max(0, x)"""
|
|
26
|
+
return tl.maximum(0, x)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@triton.jit
|
|
30
|
+
def relu6_fn(x):
|
|
31
|
+
"""ReLU6: min(max(0, x), 6)"""
|
|
32
|
+
return tl.minimum(relu_fn(x), 6)
|