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
|
@@ -0,0 +1,479 @@
|
|
|
1
|
+
"""The fp64 oracle the autotune screen consults, computed from the LIVE args.
|
|
2
|
+
|
|
3
|
+
The screen's consensus asks the candidates whether they agree with each other.
|
|
4
|
+
That question has one blind spot, and it is not academic: when the defect is in
|
|
5
|
+
the BACKEND'S EMISSION rather than in the choice of tile, every candidate is
|
|
6
|
+
wrong in the same way, the vote is unanimous, and the screen seats a wrong
|
|
7
|
+
configuration in silence.
|
|
8
|
+
|
|
9
|
+
Measured 2026-09-11 on four `addmm` shapes the catalogue demands: the emitted
|
|
10
|
+
MSL declared the float scalars `alpha`/`beta` as `int`, so the bit pattern of
|
|
11
|
+
`1.0f` multiplied the accumulator — wrong by a factor of 1065353216. Eight
|
|
12
|
+
runs, four shapes, two arms: the bare vote SEATED a configuration every time;
|
|
13
|
+
the same screen with this oracle REFUSED every time.
|
|
14
|
+
|
|
15
|
+
## Where the cost is paid, and why it is affordable
|
|
16
|
+
|
|
17
|
+
A CERTIFIED entry is served without a sweep, without a screen and without an
|
|
18
|
+
oracle — zero cost. Only an UNCERTIFIED key sweeps, and only then is the screen
|
|
19
|
+
run and the oracle computed, once for the key and not once per candidate.
|
|
20
|
+
|
|
21
|
+
**The cost is therefore paid exactly where the risk lives, and never
|
|
22
|
+
elsewhere** — and the certified directory gains a second reason to exist that
|
|
23
|
+
was not visible before: it does not only remove the sweep, it removes the
|
|
24
|
+
oracle's cost with it.
|
|
25
|
+
|
|
26
|
+
## What this covers, and what it says when it does not
|
|
27
|
+
|
|
28
|
+
An oracle exists for the kernels whose mathematics can be recomputed in float64
|
|
29
|
+
on the host from the live operands. For anything else this returns None, and
|
|
30
|
+
the screen falls back to the consensus — LOUDLY, once per process, naming the
|
|
31
|
+
key, because a screen running without an oracle is exactly the situation the
|
|
32
|
+
`addmm` measurement showed to be dangerous.
|
|
33
|
+
"""
|
|
34
|
+
from __future__ import annotations
|
|
35
|
+
|
|
36
|
+
from typing import Any, Dict, List, Optional
|
|
37
|
+
|
|
38
|
+
import numpy as np
|
|
39
|
+
|
|
40
|
+
#: Keys already announced as running without an oracle. Once per process: a
|
|
41
|
+
#: warning repeated per launch is a warning nobody reads.
|
|
42
|
+
_ANNOUNCED: set = set()
|
|
43
|
+
|
|
44
|
+
_NP = {"fp16": np.float16, "float16": np.float16,
|
|
45
|
+
"fp32": np.float32, "float32": np.float32,
|
|
46
|
+
"fp64": np.float64, "float64": np.float64}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _to_f64(t) -> Optional[np.ndarray]:
|
|
50
|
+
"""A live operand as float64, or None when it cannot be read here."""
|
|
51
|
+
try:
|
|
52
|
+
from nbxtensor.dtype.nbx_dtype import NBXDtype
|
|
53
|
+
# ONE path to host memory, for every dtype. The bf16 case used to read
|
|
54
|
+
# the device pointer directly with `ctypes.string_at`, which crosses NO
|
|
55
|
+
# BARRIER -- so a buffer a kernel had just written was read before the
|
|
56
|
+
# write landed. Measured 2026-09-12 on a kernel-written buffer: 4093 of
|
|
57
|
+
# 4096 elements differed from the copy path, and agreed after an
|
|
58
|
+
# explicit synchronisation.
|
|
59
|
+
#
|
|
60
|
+
# That produced the symptom it is easiest to misread: every candidate
|
|
61
|
+
# compared against the same stale bytes, so the fp64 oracle contradicted
|
|
62
|
+
# all ten and the screen refused the whole space. A reference read at
|
|
63
|
+
# the wrong moment contradicts every correct answer exactly as loudly
|
|
64
|
+
# as a wrong one. Eighteen recorded refusals rested on it.
|
|
65
|
+
#
|
|
66
|
+
# The defect had the shape of a PATH, not of a dtype: bf16 was merely
|
|
67
|
+
# the only traffic on it. So the raw path is gone rather than repaired,
|
|
68
|
+
# and a dtype routed here later cannot inherit it. Removing it also
|
|
69
|
+
# removes the second failure mode `string_at` carries -- it hands its
|
|
70
|
+
# size to `PyBytes_FromStringAndSize` as a C int, so any buffer of
|
|
71
|
+
# 2 GiB or more returns "Negative size", confirmed live on this machine.
|
|
72
|
+
host = t.to_cpu() if getattr(t, "_device", "cpu") != "cpu" else t
|
|
73
|
+
if getattr(t, "_dtype", None) == NBXDtype.bfloat16:
|
|
74
|
+
# numpy has no bf16; the bits are the top half of an fp32 and
|
|
75
|
+
# travel in a uint16 container.
|
|
76
|
+
bits = np.asarray(host.numpy()).view(np.uint16).astype(np.uint32)
|
|
77
|
+
return ((bits << np.uint32(16)).view(np.float32)
|
|
78
|
+
.reshape(tuple(t.shape)).astype(np.float64))
|
|
79
|
+
return np.asarray(host.numpy(), dtype=np.float64)
|
|
80
|
+
except Exception: # noqa: BLE001
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _mm(named: Dict[str, Any], rows: Optional[tuple] = None) -> Optional[np.ndarray]:
|
|
85
|
+
"""The fp64 reference for `mm`/`addmm`, optionally on a ROW WINDOW only.
|
|
86
|
+
|
|
87
|
+
`rows=(r0, r1)` computes `a[r0:r1] @ b` instead of the whole product. That is the rack's
|
|
88
|
+
row-windowed oracle technique (autotune_certify.RowWindowedOracle), brought to the screen
|
|
89
|
+
so a shape over the screening budget is verified on named windows instead of not at all.
|
|
90
|
+
A whole fp64 reference for a 4 194 304 x 540 output is 18 GB; three row windows of it are
|
|
91
|
+
a few megabytes, and the per-element comparison is identical on them."""
|
|
92
|
+
a_live = named.get("a_ptr")
|
|
93
|
+
if rows is not None:
|
|
94
|
+
# The rows are cut WHERE THE OPERAND LIVES, before it crosses. Cut after the read,
|
|
95
|
+
# the whole operand came to the host and was cast whole to float64 once per window
|
|
96
|
+
# (measured 2026-09-28: 4 096 MiB on the host for 64 rows of a 1 048 576 x 256 fp32
|
|
97
|
+
# operand; the certifier's footprint spiked by 3.7 GB per matmul key), so the window
|
|
98
|
+
# saved nothing where it was meant to. A device slice is a view whose strides no flat
|
|
99
|
+
# reader follows; it is made contiguous on the device first (`_materialise`'s rule).
|
|
100
|
+
r0, r1 = rows
|
|
101
|
+
if getattr(a_live, "_device", "cpu") != "cpu" and hasattr(a_live, "__getitem__"):
|
|
102
|
+
piece = a_live[r0:r1]
|
|
103
|
+
contiguous = getattr(piece, "contiguous", None)
|
|
104
|
+
a_live = contiguous() if callable(contiguous) else piece
|
|
105
|
+
a, b = _to_f64(a_live), _to_f64(named.get("b_ptr"))
|
|
106
|
+
if a is None or b is None:
|
|
107
|
+
return None
|
|
108
|
+
if rows is not None and a.shape[0] != (r1 - r0):
|
|
109
|
+
a = a[r0:r1] # a host operand: cut after the read
|
|
110
|
+
out = a @ b
|
|
111
|
+
bias = named.get("bias_ptr")
|
|
112
|
+
if bias is not None:
|
|
113
|
+
bv = _to_f64(bias)
|
|
114
|
+
if bv is None:
|
|
115
|
+
return None
|
|
116
|
+
alpha = float(named.get("alpha", 1.0) or 1.0)
|
|
117
|
+
beta = float(named.get("beta", 1.0) or 1.0)
|
|
118
|
+
if bv.ndim == 2 and rows is not None and bv.shape[0] != out.shape[0]:
|
|
119
|
+
bv = bv[r0:r1] # a per-row bias follows the window
|
|
120
|
+
out = alpha * out + beta * (bv[None, :] if bv.ndim == 1 else bv)
|
|
121
|
+
return out
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _baddbmm(named: Dict[str, Any]) -> Optional[np.ndarray]:
|
|
125
|
+
a, b = _to_f64(named.get("A_ptr")), _to_f64(named.get("B_ptr"))
|
|
126
|
+
if a is None or b is None:
|
|
127
|
+
return None
|
|
128
|
+
out = a @ b
|
|
129
|
+
alpha = float(named.get("alpha", 1.0) or 1.0)
|
|
130
|
+
beta = float(named.get("beta", 1.0) or 1.0)
|
|
131
|
+
out = alpha * out
|
|
132
|
+
if named.get("HAS_BIAS") and named.get("bias_ptr") is not None:
|
|
133
|
+
bv = _to_f64(named["bias_ptr"])
|
|
134
|
+
if bv is None:
|
|
135
|
+
return None
|
|
136
|
+
out = out + beta * bv
|
|
137
|
+
return out
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
#: kernel short name -> (reference for its OUTPUT from live args, output arg).
|
|
141
|
+
#: A kernel absent from here has no oracle and the screen says so out loud.
|
|
142
|
+
#:
|
|
143
|
+
#: The OUTPUT ARGUMENT NAME is not decoration. The first version of this
|
|
144
|
+
#: provider matched the output buffer by BYTE LENGTH, and for a matmul at
|
|
145
|
+
#: (19, 2048, 2048) the operand `a` and the output `c` are both 19x2048 fp32 —
|
|
146
|
+
#: the same 155648 bytes. The oracle was therefore placed on `a`, an INPUT, so
|
|
147
|
+
#: every candidate "disagreed" with it and the screen refused all ten
|
|
148
|
+
#: candidates of a shape whose certified deviation is 1.7e-06.
|
|
149
|
+
#:
|
|
150
|
+
#: An oracle that refuses correct configurations is worse than no oracle: it
|
|
151
|
+
#: turns a silent wrong into a loud stop on healthy work, and it would have
|
|
152
|
+
#: been believed because a refusal reads as vigilance. Matched by ADDRESS now.
|
|
153
|
+
ORACLES = {
|
|
154
|
+
"matmul_kernel": (_mm, "c_ptr"),
|
|
155
|
+
"addmm_kernel": (_mm, "c_ptr"),
|
|
156
|
+
"baddbmm_kernel": (_baddbmm, "out_ptr"),}
|
|
157
|
+
|
|
158
|
+
# The convolution family — the 11.5 % the table above did not cover (owed-proofs
|
|
159
|
+
# item 3: 822 of 7 158 keys on this rack). Its reference lives in its own module
|
|
160
|
+
# with its own tests against torch at 1e-12; until 2026-09-13 that module's
|
|
161
|
+
# table was never joined to THIS one, so the live screen kept announcing "no
|
|
162
|
+
# oracle for this kernel" on every conv key while the docstring next door said
|
|
163
|
+
# the family was covered. Register entry 46.
|
|
164
|
+
from nbxtensor.ops.oracles import conv2d_fp64 as _conv # noqa: E402
|
|
165
|
+
|
|
166
|
+
ORACLES.update({
|
|
167
|
+
name: ((lambda named, _fn=fn: _fn(named, _to_f64)), out_name)
|
|
168
|
+
for name, (fn, out_name) in _conv.ORACLES.items()
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
#: Kernels whose oracle can be computed on a ROW WINDOW of the output — the output read as
|
|
173
|
+
#: `[prod(leading dims), last dim]`, which for the matrix kernels is the matrix and for the
|
|
174
|
+
#: convolution family is `[N*Cout*Ho, Wo]`. The convolution rows map to input rows through the
|
|
175
|
+
#: receptive field (`conv2d_fp64.receptive_slab`, the certifier's arithmetic since 2026-09-07);
|
|
176
|
+
#: until 2026-09-26 the family was absent here and an over-budget conv key fell to windowed
|
|
177
|
+
#: CONSENSUS or to no screen at all, while an under-budget one read its WHOLE input in float64
|
|
178
|
+
#: (a 128-channel 2048x1024 input: 2.1 GB, the Mac's 27.5 GB footprint). A kernel absent from
|
|
179
|
+
#: this set falls back to windowed consensus, announced, rather than to nothing.
|
|
180
|
+
ROW_WINDOWABLE = {"matmul_kernel", "addmm_kernel"} | set(_conv.ROW_ORACLES)
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _slab_reader(tensor, shape):
|
|
184
|
+
"""Read `[n0:n1, :, u0:u1, v0:v1]` of a contiguous NCHW device tensor to the host in float64
|
|
185
|
+
— ONLY that slab crosses, cut where the tensor lives. `shape` is the `[N, C, H, W]` the
|
|
186
|
+
kernel's named extents declare; the live argument may be flat."""
|
|
187
|
+
def slab(n0, n1, u0, u1, v0, v1):
|
|
188
|
+
view = tensor.view(*shape) if tuple(tensor.shape) != tuple(shape) else tensor
|
|
189
|
+
piece = view[n0:n1, :, u0:u1, v0:v1].contiguous()
|
|
190
|
+
return _to_f64(piece)
|
|
191
|
+
return slab
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def oracle_row_bytes(tuner, meta) -> Optional[int]:
|
|
195
|
+
"""What one flat output row costs THIS kernel's float64 reference on the host, or None for
|
|
196
|
+
a kernel the row table does not window (the default: the row's own elements in float64).
|
|
197
|
+
Raises `ValueError` for a kernel the table windows whose cost cannot be formed — the
|
|
198
|
+
launcher then seats the key unscreened and says why, rather than sizing the window to the
|
|
199
|
+
output row."""
|
|
200
|
+
name = getattr(getattr(tuner, "base_fn", None), "__name__", "") or ""
|
|
201
|
+
named = {**dict(getattr(tuner, "nargs", None) or {}), **dict(meta or {})}
|
|
202
|
+
return _conv.oracle_row_bytes(name, named)
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def fp64_footprint(buffers) -> int:
|
|
206
|
+
"""The host bytes a FULL reference would hold for these device buffers: every element in
|
|
207
|
+
float64, whatever it is on the device. The screening budget is a rule about cost, and the
|
|
208
|
+
oracle's cost is this number, not the buffers' device bytes — a 537 MB bf16 input is 2.1 GB
|
|
209
|
+
of float64 before the first tap is computed. The element size comes from `NBXDtype`, the
|
|
210
|
+
one authority (`_writable_buffers` records `dtype.name`, the enum's own name); a name the
|
|
211
|
+
enum does not know is a refusal, never a guess."""
|
|
212
|
+
from nbxtensor.dtype.nbx_dtype import NBXDtype, dtype_size, parse_dtype
|
|
213
|
+
total = 0
|
|
214
|
+
for _addr, nbytes, dtype in buffers:
|
|
215
|
+
# `_writable_buffers` records `value.dtype.name`, and `NBXTensor.dtype` is the TRITON
|
|
216
|
+
# dtype (`fp16`, `bf16`, `fp32`, ...) — the engine's own parser knows those spellings
|
|
217
|
+
# beside the enum's; anything neither knows is refused, never guessed.
|
|
218
|
+
name = str(dtype)
|
|
219
|
+
try:
|
|
220
|
+
nbx = NBXDtype[name] if name in NBXDtype.__members__ else parse_dtype(name)
|
|
221
|
+
except (KeyError, ValueError):
|
|
222
|
+
raise ValueError(f"the screen cannot size a buffer of dtype {dtype!r}: not an NBXDtype") from None
|
|
223
|
+
total += int(nbytes) * 8 // dtype_size(nbx)
|
|
224
|
+
return total
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
def windowed_reference(tuner, meta, rows) -> Optional[np.ndarray]:
|
|
228
|
+
"""The fp64 reference for flat `rows` of the output, or None if this kernel cannot be windowed.
|
|
229
|
+
|
|
230
|
+
Returns the ARRAY, not bytes: the launcher slices the candidates' own bytes to the same
|
|
231
|
+
rows and compares, so both sides are the same rows of the same tensor. A refusal by a
|
|
232
|
+
row oracle is recorded through `set_last_refusal`, so the launcher's seat line can say
|
|
233
|
+
"the oracle refused, and why" instead of "no oracle covers this kernel"."""
|
|
234
|
+
name = getattr(getattr(tuner, "base_fn", None), "__name__", "") or ""
|
|
235
|
+
if name not in ROW_WINDOWABLE:
|
|
236
|
+
return None
|
|
237
|
+
named = {**dict(getattr(tuner, "nargs", None) or {}), **dict(meta or {})}
|
|
238
|
+
if not named:
|
|
239
|
+
return None
|
|
240
|
+
entry = _conv.ROW_ORACLES.get(name)
|
|
241
|
+
if entry is None:
|
|
242
|
+
try:
|
|
243
|
+
return _mm(named, rows=rows)
|
|
244
|
+
except Exception: # noqa: BLE001
|
|
245
|
+
return None
|
|
246
|
+
try:
|
|
247
|
+
x, w = named.get(entry.input_name), named.get(entry.weight_name)
|
|
248
|
+
if x is None or w is None:
|
|
249
|
+
raise ValueError(f"its arguments {entry.input_name!r}/{entry.weight_name!r} are not among the live arguments")
|
|
250
|
+
weight = _to_f64(w)
|
|
251
|
+
if weight is None:
|
|
252
|
+
raise ValueError("its weight could not be read here")
|
|
253
|
+
return entry.rows(named, _slab_reader(x, entry.input_shape(named)), weight, rows)
|
|
254
|
+
except (KeyError, TypeError, ValueError) as exc:
|
|
255
|
+
set_last_refusal(f"{name}: the row-windowed oracle refused — {exc}")
|
|
256
|
+
return None
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _span_bytes(logical, tensor, nbytes: int) -> Optional[bytes]:
|
|
260
|
+
"""`logical` (the tensor's elements in row-major order) laid out as the `nbytes` span the screen snapshots from
|
|
261
|
+
the tensor's `data_ptr()`, or None when they cannot be the same buffer.
|
|
262
|
+
|
|
263
|
+
The screen compares a candidate's effect on the PHYSICAL span of every buffer (`_writable_buffers` keeps a dense
|
|
264
|
+
permutation, a conv input read NHWC as NCHW, and a stride-0 broadcast). A reference in logical order is that span
|
|
265
|
+
only for a contiguous tensor: for a permuted fp32 conv input it is the same elements in another order, every
|
|
266
|
+
candidate "changed" the input, and the screen refused the whole space of a correct kernel (2026-10-29)."""
|
|
267
|
+
stride = getattr(tensor, "stride", None)
|
|
268
|
+
item = logical.dtype.itemsize
|
|
269
|
+
if (not callable(stride) or getattr(tensor, "is_contiguous", lambda: True)()
|
|
270
|
+
or logical.ndim == 0):
|
|
271
|
+
return logical.tobytes() if logical.nbytes == nbytes else None
|
|
272
|
+
if nbytes % item:
|
|
273
|
+
return None
|
|
274
|
+
steps = tuple(int(s) for s in stride())
|
|
275
|
+
if any(s < 0 for s in steps):
|
|
276
|
+
return None
|
|
277
|
+
reach = sum((int(n) - 1) * s for n, s in zip(logical.shape, steps)) + 1 if logical.size else 0
|
|
278
|
+
if reach * item != nbytes:
|
|
279
|
+
return None
|
|
280
|
+
span = np.zeros(reach, dtype=logical.dtype)
|
|
281
|
+
np.lib.stride_tricks.as_strided(span, shape=logical.shape, strides=tuple(s * item for s in steps))[...] = logical
|
|
282
|
+
return span.tobytes()
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
def provider(tuner, key, buffers, meta=None) -> Optional[List[bytes]]:
|
|
286
|
+
"""The correct contents of every screened buffer, or None.
|
|
287
|
+
|
|
288
|
+
The screen snapshots EVERY writable buffer, not just the output — four of
|
|
289
|
+
them for `addmm` (`a`, `b`, `bias`, `c`). The correct content of an INPUT
|
|
290
|
+
after the kernel is its content unchanged; only the output has an oracle.
|
|
291
|
+
Returning the oracle for all of them compares an input to an output.
|
|
292
|
+
"""
|
|
293
|
+
|
|
294
|
+
name = getattr(getattr(tuner, "base_fn", None), "__name__", "") or ""
|
|
295
|
+
entry = ORACLES.get(name)
|
|
296
|
+
if entry is None:
|
|
297
|
+
announce_no_oracle(name or str(tuner), key)
|
|
298
|
+
return None
|
|
299
|
+
fn, out_name = entry
|
|
300
|
+
# Positional arguments from the autotuner, constexpr arguments from the
|
|
301
|
+
# launch kwargs: an oracle that needs `kernel_height` finds it only here.
|
|
302
|
+
named = {**dict(getattr(tuner, "nargs", None) or {}), **dict(meta or {})}
|
|
303
|
+
if not named:
|
|
304
|
+
return None
|
|
305
|
+
out_tensor = named.get(out_name)
|
|
306
|
+
out_addr = int(out_tensor.data_ptr()) if out_tensor is not None else None
|
|
307
|
+
if out_addr is None:
|
|
308
|
+
announce_no_oracle(name, key,
|
|
309
|
+
why=f"its output argument {out_name!r} is not among "
|
|
310
|
+
f"the live arguments")
|
|
311
|
+
return None
|
|
312
|
+
try:
|
|
313
|
+
import time as _time
|
|
314
|
+
_t0 = _time.perf_counter()
|
|
315
|
+
reference = fn(named)
|
|
316
|
+
# The oracle's own CPU wall time is the one number measured for this
|
|
317
|
+
# key BEFORE any candidate runs, so it is the bootstrap base for the
|
|
318
|
+
# first candidate's time budget: a GPU configuration slower than the
|
|
319
|
+
# single-threaded float64 CPU computation of the same mathematics is
|
|
320
|
+
# not a configuration, whatever else it is.
|
|
321
|
+
record_oracle_ms(key, (_time.perf_counter() - _t0) * 1e3)
|
|
322
|
+
except Exception: # noqa: BLE001
|
|
323
|
+
reference = None
|
|
324
|
+
if reference is None:
|
|
325
|
+
announce_no_oracle(name, key, why="its operands could not be read here")
|
|
326
|
+
return None
|
|
327
|
+
|
|
328
|
+
# A reference built from non-finite operands vouches for nothing. NaN
|
|
329
|
+
# compares unequal to everything including itself, so every candidate
|
|
330
|
+
# "disagrees" and the screen either refuses the whole space or — worse, when
|
|
331
|
+
# the deviation is computed on bf16 bits — lets a wrong configuration
|
|
332
|
+
# through wearing a `screened: true` stamp. Measured on swin2SR (M4 Pro,
|
|
333
|
+
# 2026-09-17): a conv whose input carried 63181 NaN and 356 Inf produced
|
|
334
|
+
# "the fp64 oracle contradicts EVERY candidate (18 of 18)".
|
|
335
|
+
#
|
|
336
|
+
# Refusing here routes the key through `_seat_unscreened`, which records it
|
|
337
|
+
# `screened: false` with this reason and keeps it out of the certified
|
|
338
|
+
# directory. The engine still runs; it just stops claiming the run was
|
|
339
|
+
# validated.
|
|
340
|
+
bad = int(np.count_nonzero(~np.isfinite(reference)))
|
|
341
|
+
if bad:
|
|
342
|
+
set_last_refusal(
|
|
343
|
+
f"the fp64 reference is not finite ({bad} of {reference.size} "
|
|
344
|
+
f"elements NaN or Inf), so it cannot adjudicate any candidate — "
|
|
345
|
+
f"the operands read for this key were themselves not finite")
|
|
346
|
+
announce_no_oracle(name, key, why=last_refusal())
|
|
347
|
+
return None
|
|
348
|
+
|
|
349
|
+
# Every live tensor by its address, so an INPUT is read through the copy
|
|
350
|
+
# path like everything else. The line this replaces read the device
|
|
351
|
+
# pointer with `ctypes.string_at` and justified it as "an input,
|
|
352
|
+
# unchanged" -- an assumption this repository's own measurement destroyed
|
|
353
|
+
# the same day: the bf16 operand of eighteen refusals was the BIAS, an
|
|
354
|
+
# input produced by a conversion kernel earlier in the graph. An input can
|
|
355
|
+
# be exactly as stale as an output, and "unchanged" says nothing about
|
|
356
|
+
# WHEN it was written.
|
|
357
|
+
#
|
|
358
|
+
# The size failure mode does not even need that argument: `string_at`
|
|
359
|
+
# hands its length to `PyBytes_FromStringAndSize` as a C int, so any
|
|
360
|
+
# buffer of 2 GiB or more returns "Negative size" whoever wrote it --
|
|
361
|
+
# confirmed live here at 2 GiB + 1 -- and a matmul input passes 2 GiB
|
|
362
|
+
# without difficulty on the shapes that matter.
|
|
363
|
+
by_addr = {}
|
|
364
|
+
for _v in named.values():
|
|
365
|
+
try:
|
|
366
|
+
by_addr[int(_v.data_ptr())] = _v
|
|
367
|
+
except Exception: # noqa: BLE001
|
|
368
|
+
continue
|
|
369
|
+
|
|
370
|
+
out: List[bytes] = []
|
|
371
|
+
for addr, nbytes, dtype_name in buffers:
|
|
372
|
+
if int(addr) == out_addr: # the output, BY ADDRESS
|
|
373
|
+
if dtype_name in ("bf16", "bfloat16"):
|
|
374
|
+
# bfloat16 is not a numpy dtype, so `_NP.get` fell through to
|
|
375
|
+
# fp32 -- and the reference then measured 4 bytes/element while
|
|
376
|
+
# the bf16 output buffer is 2, so `want.nbytes` was exactly
|
|
377
|
+
# double and the oracle was DISCARDED on every bf16 output.
|
|
378
|
+
# Measured 2026-09-14: conv2d at (1,180,448,448) bf16 --
|
|
379
|
+
# reference 144506880 vs buffer 72253440 -- so the whole conv
|
|
380
|
+
# family (and any bf16-output kernel) sat on the bare vote while
|
|
381
|
+
# the fp64 oracle was wired and computing. The output holds the
|
|
382
|
+
# top 16 bits of fp32; round the reference to bf16 the same way
|
|
383
|
+
# (`f32_to_bf16_bits`, round-to-nearest-even) so it compares in
|
|
384
|
+
# the buffer's own width. `_deviation` decodes bf16 bytes, so
|
|
385
|
+
# the tolerance comparison is unchanged. A dtype fix, not a
|
|
386
|
+
# backend one.
|
|
387
|
+
from nbxtensor.dtype.convert import f32_to_bf16_bits
|
|
388
|
+
want = np.ascontiguousarray(
|
|
389
|
+
f32_to_bf16_bits(np.ascontiguousarray(reference, dtype=np.float32)))
|
|
390
|
+
else:
|
|
391
|
+
want = np.ascontiguousarray(
|
|
392
|
+
reference.astype(_NP.get(dtype_name, np.float32)))
|
|
393
|
+
if want.size == int(np.prod(getattr(out_tensor, "shape", (want.size,)))):
|
|
394
|
+
want = want.reshape(tuple(out_tensor.shape))
|
|
395
|
+
raw = _span_bytes(want, out_tensor, int(nbytes))
|
|
396
|
+
if raw is None:
|
|
397
|
+
announce_no_oracle(
|
|
398
|
+
name, key,
|
|
399
|
+
why=f"the reference is {want.nbytes} bytes and the output "
|
|
400
|
+
f"buffer is {nbytes}")
|
|
401
|
+
return None
|
|
402
|
+
out.append(raw)
|
|
403
|
+
else:
|
|
404
|
+
# An input, unchanged -- read through the tensor's own copy to the
|
|
405
|
+
# host, which crosses the barrier a raw pointer read does not.
|
|
406
|
+
src = by_addr.get(int(addr))
|
|
407
|
+
if src is None:
|
|
408
|
+
announce_no_oracle(
|
|
409
|
+
name, key,
|
|
410
|
+
why=f"an input buffer at {addr:#x} is not among the live "
|
|
411
|
+
f"arguments, so it can only be read by raw pointer, "
|
|
412
|
+
f"which crosses no barrier and caps at 2 GiB")
|
|
413
|
+
return None
|
|
414
|
+
host = src.to_cpu() if getattr(src, "_device", "cpu") != "cpu" else src
|
|
415
|
+
logical = np.ascontiguousarray(host.numpy())
|
|
416
|
+
raw = _span_bytes(logical, src, int(nbytes))
|
|
417
|
+
if raw is None:
|
|
418
|
+
announce_no_oracle(
|
|
419
|
+
name, key,
|
|
420
|
+
why=f"the input at {addr:#x} copies to {logical.nbytes} bytes "
|
|
421
|
+
f"and the buffer is {nbytes}")
|
|
422
|
+
return None
|
|
423
|
+
out.append(raw)
|
|
424
|
+
return out
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
#: Oracle CPU wall time by key text, for the sweep's time budget. In-process,
|
|
428
|
+
#: like `_SCREEN_CACHE`: the budget protects a sweep that runs in this very
|
|
429
|
+
#: process, so persisting these would only let a stale machine state speak.
|
|
430
|
+
_ORACLE_MS: dict = {}
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
#: Why the oracle last declined, so the record can say it instead of "no
|
|
434
|
+
#: reference". Set immediately before returning None; read by the launcher when
|
|
435
|
+
#: it stamps the key unscreened.
|
|
436
|
+
_LAST_REFUSAL: Optional[str] = None
|
|
437
|
+
|
|
438
|
+
|
|
439
|
+
def set_last_refusal(why: str) -> None:
|
|
440
|
+
global _LAST_REFUSAL
|
|
441
|
+
_LAST_REFUSAL = why
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def last_refusal() -> Optional[str]:
|
|
445
|
+
return _LAST_REFUSAL
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
def record_oracle_ms(key, ms: float) -> None:
|
|
449
|
+
_ORACLE_MS[str(key)] = float(ms)
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def oracle_ms_of(key):
|
|
453
|
+
"""The oracle's measured CPU time for this key, or None if it never ran."""
|
|
454
|
+
return _ORACLE_MS.get(str(key))
|
|
455
|
+
|
|
456
|
+
|
|
457
|
+
def announce_no_oracle(kernel_name: str, key, why: str = "no oracle is registered "
|
|
458
|
+
"for this kernel") -> None:
|
|
459
|
+
"""Say, once per process, that a screen ran on a consensus alone.
|
|
460
|
+
|
|
461
|
+
A mechanism that is complete and switched off is the most expensive form of
|
|
462
|
+
a vacuous guard: it costs the price of writing it and returns nothing. The
|
|
463
|
+
only thing worse is one that is silent about being off.
|
|
464
|
+
"""
|
|
465
|
+
token = (kernel_name, str(key))
|
|
466
|
+
if token in _ANNOUNCED:
|
|
467
|
+
return
|
|
468
|
+
_ANNOUNCED.add(token)
|
|
469
|
+
print(f"[AUTOTUNE_ORACLE] {kernel_name}: screening at key {key} on the "
|
|
470
|
+
f"CONSENSUS ALONE — {why}. A consensus cannot see a defect that is "
|
|
471
|
+
f"in the backend's emission, because every candidate then shares it "
|
|
472
|
+
f"and the vote is unanimous (measured: addmm wrong by 1e9 with a "
|
|
473
|
+
f"unanimous vote, 2026-09-11).", flush=True)
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
def install() -> None:
|
|
477
|
+
"""Make the screen consult this oracle."""
|
|
478
|
+
from nbxtensor.backend import launcher as L
|
|
479
|
+
L.set_screen_oracle(provider)
|
nbxtensor/ops/selu.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""SELU — pure @triton.jit kernel."""
|
|
2
|
+
|
|
3
|
+
import triton
|
|
4
|
+
import triton.language as tl
|
|
5
|
+
|
|
6
|
+
@triton.jit
|
|
7
|
+
def selu_forward_kernel(
|
|
8
|
+
input_ptr, output_ptr,
|
|
9
|
+
n_elements,
|
|
10
|
+
BLOCK_SIZE: tl.constexpr,
|
|
11
|
+
):
|
|
12
|
+
pid = tl.program_id(0).to(tl.int64)
|
|
13
|
+
offset = pid.to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE) # 64-bit from the program id: the product itself wraps past 2^31 elements (register 58)
|
|
14
|
+
mask = offset < n_elements
|
|
15
|
+
|
|
16
|
+
scale = 1.0507009873554804934193349852946
|
|
17
|
+
alpha = 1.6732632423543772848170429916717
|
|
18
|
+
|
|
19
|
+
x = tl.load(input_ptr + offset, mask=mask)
|
|
20
|
+
x_fp32 = x.to(tl.float32)
|
|
21
|
+
out = scale * (tl.maximum(0, x_fp32) + tl.minimum(0, alpha * (tl.exp(x_fp32) - 1.0)))
|
|
22
|
+
tl.store(output_ptr + offset, out, mask=mask)
|