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.
Files changed (291) hide show
  1. nbxtensor/THIRD_PARTY_NOTICES.md +287 -0
  2. nbxtensor/__init__.py +17 -0
  3. nbxtensor/backend/__init__.py +1 -0
  4. nbxtensor/backend/capabilities.py +207 -0
  5. nbxtensor/backend/cpu/__init__.py +1 -0
  6. nbxtensor/backend/cpu/blas.py +102 -0
  7. nbxtensor/backend/cpu/pool.py +204 -0
  8. nbxtensor/backend/cpu_backend.py +162 -0
  9. nbxtensor/backend/device_facts.py +105 -0
  10. nbxtensor/backend/device_files.py +129 -0
  11. nbxtensor/backend/device_names.py +18 -0
  12. nbxtensor/backend/devices/amd/cdna.yml +228 -0
  13. nbxtensor/backend/devices/amd/cdna2.yml +228 -0
  14. nbxtensor/backend/devices/amd/cdna3.yml +227 -0
  15. nbxtensor/backend/devices/apple/apple_m1.yml +266 -0
  16. nbxtensor/backend/devices/apple/apple_m1_max.yml +266 -0
  17. nbxtensor/backend/devices/apple/apple_m1_pro.yml +266 -0
  18. nbxtensor/backend/devices/apple/apple_m1_ultra.yml +266 -0
  19. nbxtensor/backend/devices/apple/apple_m2.yml +266 -0
  20. nbxtensor/backend/devices/apple/apple_m2_max.yml +266 -0
  21. nbxtensor/backend/devices/apple/apple_m2_pro.yml +266 -0
  22. nbxtensor/backend/devices/apple/apple_m2_ultra.yml +266 -0
  23. nbxtensor/backend/devices/apple/apple_m3.yml +266 -0
  24. nbxtensor/backend/devices/apple/apple_m3_max.yml +266 -0
  25. nbxtensor/backend/devices/apple/apple_m3_pro.yml +266 -0
  26. nbxtensor/backend/devices/apple/apple_m3_ultra.yml +266 -0
  27. nbxtensor/backend/devices/apple/apple_m4.yml +266 -0
  28. nbxtensor/backend/devices/apple/apple_m4_max.yml +266 -0
  29. nbxtensor/backend/devices/apple/apple_m4_pro.yml +308 -0
  30. nbxtensor/backend/devices/apple/apple_m5.yml +269 -0
  31. nbxtensor/backend/devices/apple/apple_m5_max.yml +269 -0
  32. nbxtensor/backend/devices/apple/apple_m5_pro.yml +269 -0
  33. nbxtensor/backend/devices/apple/apple_m5_ultra.yml +269 -0
  34. nbxtensor/backend/devices/apple/apple_m6.yml +269 -0
  35. nbxtensor/backend/devices/apple/apple_silicon.yml +263 -0
  36. nbxtensor/backend/devices/nvidia/ampere.yml +214 -0
  37. nbxtensor/backend/devices/nvidia/hopper.yml +213 -0
  38. nbxtensor/backend/devices/nvidia/volta.yml +411 -0
  39. nbxtensor/backend/faults.py +151 -0
  40. nbxtensor/backend/host_memory.py +185 -0
  41. nbxtensor/backend/launcher.py +2350 -0
  42. nbxtensor/backend/launcher_contract.py +429 -0
  43. nbxtensor/backend/metal_backend.py +661 -0
  44. nbxtensor/backend/metal_device.py +1274 -0
  45. nbxtensor/backend/process_memory.py +73 -0
  46. nbxtensor/backend/replay_graph.py +322 -0
  47. nbxtensor/backend/runtime.py +409 -0
  48. nbxtensor/backend/triton_ext_driver.py +735 -0
  49. nbxtensor/dtype/__init__.py +1 -0
  50. nbxtensor/dtype/convert.py +107 -0
  51. nbxtensor/dtype/dtypes.yml +70 -0
  52. nbxtensor/dtype/itemsize.py +166 -0
  53. nbxtensor/dtype/nbx_dtype.py +72 -0
  54. nbxtensor/dtype/operands.py +158 -0
  55. nbxtensor/dtype/outputs.py +64 -0
  56. nbxtensor/dtype/policy.py +155 -0
  57. nbxtensor/dtype/policy.yml +51 -0
  58. nbxtensor/dtype/promotion.py +112 -0
  59. nbxtensor/host.py +55 -0
  60. nbxtensor/io/__init__.py +1 -0
  61. nbxtensor/io/read_rate.py +197 -0
  62. nbxtensor/io/safetensors.py +314 -0
  63. nbxtensor/memory/__init__.py +9 -0
  64. nbxtensor/memory/allocator.py +1988 -0
  65. nbxtensor/memory/arena.py +75 -0
  66. nbxtensor/memory/device_memory.py +150 -0
  67. nbxtensor/memory/device_transfer.py +154 -0
  68. nbxtensor/memory/layout.py +43 -0
  69. nbxtensor/memory/memory_pool.py +191 -0
  70. nbxtensor/memory/metal.py +96 -0
  71. nbxtensor/memory/oom_advice.py +91 -0
  72. nbxtensor/memory/pointer_tables.py +323 -0
  73. nbxtensor/memory/pool.py +507 -0
  74. nbxtensor/memory/shadow.py +43 -0
  75. nbxtensor/memory/slab.py +273 -0
  76. nbxtensor/memory/trace_replay.py +122 -0
  77. nbxtensor/memory/traces/sana-video-2b-720p.16g.2026-11-02.tsv +13610 -0
  78. nbxtensor/memory/vmm.py +118 -0
  79. nbxtensor/ops/__init__.py +1 -0
  80. nbxtensor/ops/_autotune_policy.py +90 -0
  81. nbxtensor/ops/_common.py +32 -0
  82. nbxtensor/ops/_configs.py +1041 -0
  83. nbxtensor/ops/_cost.py +231 -0
  84. nbxtensor/ops/abs.py +17 -0
  85. nbxtensor/ops/adaptive_avg_pool2d.py +161 -0
  86. nbxtensor/ops/add.py +96 -0
  87. nbxtensor/ops/addcdiv.py +29 -0
  88. nbxtensor/ops/addcmul.py +29 -0
  89. nbxtensor/ops/addmv_op.py +64 -0
  90. nbxtensor/ops/addr.py +68 -0
  91. nbxtensor/ops/all_reduce.py +83 -0
  92. nbxtensor/ops/amax.py +40 -0
  93. nbxtensor/ops/any_reduce.py +83 -0
  94. nbxtensor/ops/arange_op.py +27 -0
  95. nbxtensor/ops/argmax.py +107 -0
  96. nbxtensor/ops/argmin.py +93 -0
  97. nbxtensor/ops/atan2.py +71 -0
  98. nbxtensor/ops/attention_wrappers.py +1648 -0
  99. nbxtensor/ops/autotune_bucket.py +137 -0
  100. nbxtensor/ops/autotune_cache.py +430 -0
  101. nbxtensor/ops/autotune_certified.py +1262 -0
  102. nbxtensor/ops/autotune_refusals.py +380 -0
  103. nbxtensor/ops/autotune_settings.py +58 -0
  104. nbxtensor/ops/avg_pool2d.py +73 -0
  105. nbxtensor/ops/baddbmm_op.py +132 -0
  106. nbxtensor/ops/batch_norm.py +163 -0
  107. nbxtensor/ops/binary_strided.py +196 -0
  108. nbxtensor/ops/bitwise_and.py +26 -0
  109. nbxtensor/ops/bitwise_left_shift.py +47 -0
  110. nbxtensor/ops/bitwise_not.py +24 -0
  111. nbxtensor/ops/bitwise_or.py +26 -0
  112. nbxtensor/ops/bitwise_right_shift.py +47 -0
  113. nbxtensor/ops/bucketize.py +37 -0
  114. nbxtensor/ops/cat_op.py +87 -0
  115. nbxtensor/ops/celu.py +20 -0
  116. nbxtensor/ops/clamp.py +24 -0
  117. nbxtensor/ops/clamp_min.py +22 -0
  118. nbxtensor/ops/conv2d.py +265 -0
  119. nbxtensor/ops/conv2d_m8n8k4.py +165 -0
  120. nbxtensor/ops/conv_depthwise2d.py +154 -0
  121. nbxtensor/ops/conv_transpose2d.py +148 -0
  122. nbxtensor/ops/conv_wrappers.py +1482 -0
  123. nbxtensor/ops/copy.py +18 -0
  124. nbxtensor/ops/copy_op.py +39 -0
  125. nbxtensor/ops/cos.py +17 -0
  126. nbxtensor/ops/count_nonzero.py +64 -0
  127. nbxtensor/ops/cross_entropy.py +67 -0
  128. nbxtensor/ops/cummax.py +109 -0
  129. nbxtensor/ops/cummin.py +105 -0
  130. nbxtensor/ops/cumsum.py +244 -0
  131. nbxtensor/ops/decode_attn_vec.py +162 -0
  132. nbxtensor/ops/depthwise_conv2d.py +132 -0
  133. nbxtensor/ops/dequant_gemv.py +190 -0
  134. nbxtensor/ops/dft.py +67 -0
  135. nbxtensor/ops/dispatch.py +1228 -0
  136. nbxtensor/ops/div.py +75 -0
  137. nbxtensor/ops/dot_op.py +67 -0
  138. nbxtensor/ops/dropout.py +23 -0
  139. nbxtensor/ops/dtype_convert.py +42 -0
  140. nbxtensor/ops/elementwise_launch.py +81 -0
  141. nbxtensor/ops/elementwise_wrappers.py +2315 -0
  142. nbxtensor/ops/elu.py +20 -0
  143. nbxtensor/ops/embedding.py +69 -0
  144. nbxtensor/ops/eq.py +32 -0
  145. nbxtensor/ops/erf.py +18 -0
  146. nbxtensor/ops/exp.py +17 -0
  147. nbxtensor/ops/exp2.py +18 -0
  148. nbxtensor/ops/fft_op.py +125 -0
  149. nbxtensor/ops/fill_op.py +20 -0
  150. nbxtensor/ops/flash_attention.py +307 -0
  151. nbxtensor/ops/flash_attention_m8n8k4.py +384 -0
  152. nbxtensor/ops/flash_decode.py +78 -0
  153. nbxtensor/ops/flip_op.py +60 -0
  154. nbxtensor/ops/floor.py +90 -0
  155. nbxtensor/ops/full_op.py +24 -0
  156. nbxtensor/ops/fused_moe.py +417 -0
  157. nbxtensor/ops/fused_moe_m8n8k4.py +99 -0
  158. nbxtensor/ops/fused_upsample_conv.py +413 -0
  159. nbxtensor/ops/gather_op.py +52 -0
  160. nbxtensor/ops/ge.py +32 -0
  161. nbxtensor/ops/gelu.py +31 -0
  162. nbxtensor/ops/gemv_vec.py +80 -0
  163. nbxtensor/ops/glu.py +43 -0
  164. nbxtensor/ops/grid_sampler.py +145 -0
  165. nbxtensor/ops/group_norm_tiled.py +67 -0
  166. nbxtensor/ops/groupnorm.py +123 -0
  167. nbxtensor/ops/gt.py +32 -0
  168. nbxtensor/ops/hardsigmoid.py +18 -0
  169. nbxtensor/ops/hardswish.py +19 -0
  170. nbxtensor/ops/im2col.py +57 -0
  171. nbxtensor/ops/index_add.py +95 -0
  172. nbxtensor/ops/index_put_op.py +92 -0
  173. nbxtensor/ops/index_select.py +121 -0
  174. nbxtensor/ops/index_wrappers.py +770 -0
  175. nbxtensor/ops/isfinite.py +20 -0
  176. nbxtensor/ops/isinf.py +20 -0
  177. nbxtensor/ops/isnan.py +18 -0
  178. nbxtensor/ops/launch_keys.py +1054 -0
  179. nbxtensor/ops/launch_observer.py +54 -0
  180. nbxtensor/ops/layernorm.py +71 -0
  181. nbxtensor/ops/le.py +35 -0
  182. nbxtensor/ops/leaky_relu.py +19 -0
  183. nbxtensor/ops/lerp.py +76 -0
  184. nbxtensor/ops/linalg_wrappers.py +1370 -0
  185. nbxtensor/ops/linspace_op.py +47 -0
  186. nbxtensor/ops/log.py +17 -0
  187. nbxtensor/ops/log_sigmoid.py +23 -0
  188. nbxtensor/ops/logical_and.py +26 -0
  189. nbxtensor/ops/logical_not.py +24 -0
  190. nbxtensor/ops/logical_or.py +26 -0
  191. nbxtensor/ops/logical_xor.py +37 -0
  192. nbxtensor/ops/loss_wrappers.py +282 -0
  193. nbxtensor/ops/lt.py +32 -0
  194. nbxtensor/ops/masked_fill.py +21 -0
  195. nbxtensor/ops/matmul.py +377 -0
  196. nbxtensor/ops/matmul_m8n8k4.py +235 -0
  197. nbxtensor/ops/max_pool2d.py +74 -0
  198. nbxtensor/ops/max_pool3d.py +93 -0
  199. nbxtensor/ops/max_reduce.py +91 -0
  200. nbxtensor/ops/maximum.py +18 -0
  201. nbxtensor/ops/mean.py +40 -0
  202. nbxtensor/ops/min_reduce.py +91 -0
  203. nbxtensor/ops/minimum.py +18 -0
  204. nbxtensor/ops/mish.py +22 -0
  205. nbxtensor/ops/mma_m8n8k4.py +152 -0
  206. nbxtensor/ops/moe_align.py +195 -0
  207. nbxtensor/ops/moe_decode_vec.py +374 -0
  208. nbxtensor/ops/moe_device_residency.py +141 -0
  209. nbxtensor/ops/moe_wrappers.py +345 -0
  210. nbxtensor/ops/mse_loss.py +79 -0
  211. nbxtensor/ops/mul.py +51 -0
  212. nbxtensor/ops/nan_to_num.py +23 -0
  213. nbxtensor/ops/ne.py +32 -0
  214. nbxtensor/ops/neg.py +17 -0
  215. nbxtensor/ops/nllloss.py +124 -0
  216. nbxtensor/ops/nonzero.py +33 -0
  217. nbxtensor/ops/nonzero_op.py +62 -0
  218. nbxtensor/ops/norm_wrappers.py +579 -0
  219. nbxtensor/ops/ones_op.py +20 -0
  220. nbxtensor/ops/oracles/__init__.py +6 -0
  221. nbxtensor/ops/oracles/conv2d_fp64.py +450 -0
  222. nbxtensor/ops/pad_op.py +159 -0
  223. nbxtensor/ops/paged_decode_attn.py +215 -0
  224. nbxtensor/ops/pixel_shuffle.py +144 -0
  225. nbxtensor/ops/pixel_unshuffle.py +72 -0
  226. nbxtensor/ops/pow.py +137 -0
  227. nbxtensor/ops/prod.py +81 -0
  228. nbxtensor/ops/rand_op.py +52 -0
  229. nbxtensor/ops/random_wrappers.py +366 -0
  230. nbxtensor/ops/reciprocal.py +17 -0
  231. nbxtensor/ops/reduction_wrappers.py +845 -0
  232. nbxtensor/ops/relu.py +18 -0
  233. nbxtensor/ops/remainder.py +46 -0
  234. nbxtensor/ops/repeat_interleave.py +48 -0
  235. nbxtensor/ops/repeat_op.py +132 -0
  236. nbxtensor/ops/residual_chain.py +374 -0
  237. nbxtensor/ops/rmsnorm.py +68 -0
  238. nbxtensor/ops/rope.py +142 -0
  239. nbxtensor/ops/rsqrt.py +17 -0
  240. nbxtensor/ops/scaled_softmax.py +96 -0
  241. nbxtensor/ops/scatter_op.py +139 -0
  242. nbxtensor/ops/screen_oracle.py +479 -0
  243. nbxtensor/ops/selu.py +22 -0
  244. nbxtensor/ops/shape_wrappers.py +1032 -0
  245. nbxtensor/ops/sigmoid.py +19 -0
  246. nbxtensor/ops/silu.py +27 -0
  247. nbxtensor/ops/sin.py +17 -0
  248. nbxtensor/ops/softmax.py +169 -0
  249. nbxtensor/ops/softplus.py +27 -0
  250. nbxtensor/ops/sort_op.py +304 -0
  251. nbxtensor/ops/spectral_wrappers.py +481 -0
  252. nbxtensor/ops/sqrt.py +17 -0
  253. nbxtensor/ops/stack_op.py +84 -0
  254. nbxtensor/ops/std.py +113 -0
  255. nbxtensor/ops/strided_copy.py +200 -0
  256. nbxtensor/ops/sub.py +35 -0
  257. nbxtensor/ops/sum.py +40 -0
  258. nbxtensor/ops/tan.py +19 -0
  259. nbxtensor/ops/tanh.py +21 -0
  260. nbxtensor/ops/threshold.py +19 -0
  261. nbxtensor/ops/tiling.yml +91 -0
  262. nbxtensor/ops/tiling_policy.py +43 -0
  263. nbxtensor/ops/tiling_sizes.py +370 -0
  264. nbxtensor/ops/topk.py +267 -0
  265. nbxtensor/ops/trace_op.py +64 -0
  266. nbxtensor/ops/tril.py +64 -0
  267. nbxtensor/ops/triu.py +62 -0
  268. nbxtensor/ops/unfold_op.py +37 -0
  269. nbxtensor/ops/unique_op.py +97 -0
  270. nbxtensor/ops/upsample_bilinear2d.py +106 -0
  271. nbxtensor/ops/upsample_nearest2d.py +52 -0
  272. nbxtensor/ops/upsample_nearest3d.py +61 -0
  273. nbxtensor/ops/var.py +136 -0
  274. nbxtensor/ops/vector_norm.py +216 -0
  275. nbxtensor/ops/weight_norm.py +104 -0
  276. nbxtensor/ops/where.py +39 -0
  277. nbxtensor/ops/wrappers.py +825 -0
  278. nbxtensor/ops/zeros_op.py +20 -0
  279. nbxtensor/quant/__init__.py +1 -0
  280. nbxtensor/quant/quantized_tensor.py +187 -0
  281. nbxtensor/random/__init__.py +1 -0
  282. nbxtensor/random/mt_randn.py +154 -0
  283. nbxtensor/random/rng_pin.py +59 -0
  284. nbxtensor/random/rng_stream.py +118 -0
  285. nbxtensor/random/seeded_draw.py +223 -0
  286. nbxtensor/shape/__init__.py +157 -0
  287. nbxtensor/tensor.py +1867 -0
  288. nbxtensor-0.0.1.dist-info/METADATA +379 -0
  289. nbxtensor-0.0.1.dist-info/RECORD +291 -0
  290. nbxtensor-0.0.1.dist-info/WHEEL +4 -0
  291. nbxtensor-0.0.1.dist-info/licenses/LICENSE +189 -0
@@ -0,0 +1,263 @@
1
+ # The library's half of apple/apple_silicon.yml: the keys nbxtensor reads (docs/nbxtensor/device_keys.txt),
2
+ # moved with their sources by tools/split_vendor_files.py. NeuroBrix's half stays in
3
+ # src/neurobrix/config/vendors/apple/apple_silicon.yml; the engine reads the two merged.
4
+
5
+ architecture: apple_silicon
6
+ compute_capability: "apple9" # M3/M4 family; M1 = apple7, M2 = apple8
7
+
8
+ # What the Triton target actually reports, which is NOT the family above.
9
+ # MEASURED 2026-09-05 on an M4 Pro: the Metal backend builds its arch string
10
+ # from the Metal DEVICE NAME, lowercased and hyphenated
11
+ # (`kernels/metal_device.py::MetalRuntime.arch_name`), so it says
12
+ # "apple-m4-pro" where this file says "apple9". Matching on the family alone,
13
+ # the smem budget below resolved to NOTHING on a real Mac and the 32 KB
14
+ # filter silently did not apply — all 17 Volta tiles were offered, including
15
+ # the 72 KB one that cannot run here.
16
+ #
17
+ # These are prefixes, matched against the reported target. "apple-m" covers
18
+ # the whole M-series, which is exactly the scope this file claims in its
19
+ # header (M1..M4, GPU family 7/8/9). A chip outside it matches nothing and
20
+ # gets no filtering, which is the same zero-fallback answer as before.
21
+ compute_capability_matches:
22
+ - "apple-m"
23
+
24
+ block_sizes:
25
+ default: 1024
26
+
27
+ bmm:
28
+ block_m: 32
29
+ block_n: 32
30
+ block_k: 32
31
+ num_warps: 4
32
+
33
+ conv2d:
34
+ block_h: 16
35
+ block_w: 16
36
+ num_warps: 4
37
+
38
+ reduction: 1024
39
+
40
+ # Row-wise reductions over a dim (min / max / prod / all / any) and argmin.
41
+ #
42
+ # MEASURED 2026-09-07: `min` and `max` over a dim return a VALUE AND ITS
43
+ # INDEX, so their reduce carries a pair, and the Metal lowering stages such
44
+ # a reduce one element per thread — the tile must fit num_warps * 32. The
45
+ # adopted 8 x 1024 is 8192 against a 128-thread group.
46
+ #
47
+ # 8 x 128 with 32 warps is 1024 elements over 1024 threads, and is correct
48
+ # for max, min and argmin at N = 511, 1024, 1025 and 3077 against numpy in
49
+ # float64 (the row group is what matters here: at 8 rows the lowering used
50
+ # to collapse every row onto the first, which is fixed upstream and is why
51
+ # this entry can carry more than one row at all).
52
+ reduction_2d:
53
+ block_m: 8
54
+ block_n: 128
55
+ num_warps: 32
56
+
57
+ argmin:
58
+ block_m: 8
59
+ tile_n: 128
60
+ num_warps: 32
61
+
62
+ # Row-wise argmax — greedy sampling reads the argmax of a 32000-wide
63
+ # vocabulary row every token.
64
+ #
65
+ # MEASURED 2026-09-07: argmax is a MULTI-VALUE reduce (a value and its
66
+ # index travel together), and the Metal lowering has no multipass form for
67
+ # a tuple — it says so and refuses — so the tile must fit the threadgroup,
68
+ # which is num_warps * 32. The 4096 cap every architecture used refused
69
+ # against the default 4 warps (128 threads). 1024 over 32 warps is the
70
+ # largest that fits; the index it returns is exact at every tile measured
71
+ # (128/4, 256/8, 512/16, 1024/32 all give the same index on a 32000-wide
72
+ # row), so this is throughput, not correctness.
73
+ argmax:
74
+ tile_n: 1024
75
+ num_warps: 32
76
+
77
+ # M=1 dequant-GEMV occupancy rule — see nvidia/volta.yml for the rationale
78
+ # (the wrapper halves BLOCK_N until the grid reaches min_programs).
79
+ # 2 waves x 40 GPU cores (M3/M4 Max class); validation_status: analytical.
80
+ # Key absent or 0 -> no adaptation.
81
+ dequant_gemv:
82
+ min_programs: 80
83
+
84
+ # sdpa_thresholds RETIRED (roadmap C3, 2026-10-22): the tl.dot flash's tile is certified per key by autotune
85
+ # certify (`launch_keys.flash_tiles_certified`), not read from a hand table.
86
+
87
+ memory:
88
+ # 32 KB of threadgroup memory per threadgroup (Apple GPU family 7+).
89
+ # The single most binding difference from every NVIDIA profile here.
90
+ # MEASURED 2026-09-05 on an M4 Pro: `MTLDevice.maxThreadgroupMemoryLength()`
91
+ # returns exactly 32768, so the documented figure holds on real hardware.
92
+ max_shared_memory_per_block: 32768
93
+ max_registers_per_block: 32768
94
+ # Apple GPUs schedule in 32-wide SIMD groups. Named `warp_size` because one
95
+ # hardware concept has ONE key across every profile — AMD's 64-wide
96
+ # wavefronts are declared under the same name.
97
+ warp_size: 32
98
+
99
+ # SDPA deterministic-routing budget. 0 = NOT APPLICABLE: the
100
+ # non-determinism this routes around is a Volta-SIMT MMA issue and does
101
+ # not transfer to Apple's simdgroup path. Left 0 until shown otherwise on
102
+ # real hardware.
103
+ sdpa_math_max_scores_bytes: 0
104
+ sdpa_math_min_chunk_rows: 128
105
+ # Allocator pool: fraction of device memory the free-list may keep parked.
106
+ # Apple Silicon is UNIFIED memory — the "device" budget is system RAM
107
+ # shared with everything else on the machine, so parking is far less
108
+ # polite here than on a discrete card. Halved accordingly.
109
+ alloc_pool_parked_cap_fraction: 0.25
110
+ precision:
111
+ # Whether each engine branch's OWN kernels compute float64 / complex128 elements, read with
112
+ # supports_fp64 (both must hold) -- a CAPABILITY: `compiled` is ATen's, which carries both wherever
113
+ # the device does; `triton` is the NeuroBrix Triton kernels' (cuda/hip lower double; Metal's
114
+ # lowering narrows it in silence, measured 2026-09-28 on the Sana 4K positional embedding). Read
115
+ # by the DtypeEngine (`config.device_supports_fp64`) and by the Triton wrappers' binding
116
+ # (`triton.dtype.triton_has_fp64` -> `nbx_tensor.set_backend_has_fp64`).
117
+ kernels_carry_fp64:
118
+ compiled: true
119
+ triton: false
120
+ # Attention operands that disagree in dtype (an fp16 GEMM stored fp32 feeding V) all take the
121
+ # narrowest of the three, the compiled engine's alignment: the half attention stays on the matrix
122
+ # unit (V100, 2026-10-08: 1.16 s/op aligned narrowest vs 22.0 s/op on the scalar flash aligned widest).
123
+ attention_operands: narrowest
124
+ # Software-pipelining budget — see nvidia/volta.yml for the schema.
125
+ #
126
+ # validation_status: conservative_pending_first_light. cp.async is a PTX
127
+ # instruction with no Apple equivalent, and the Metal backend stages through
128
+ # threadgroup memory by a different mechanism. Neither Volta's measured
129
+ # fault nor Ampere's clearance transfers, so the budget stays at 2 until an
130
+ # Apple GPU measures it: clamping can only cost throughput.
131
+ pipelining:
132
+ max_num_stages: 2
133
+
134
+ # How work reaches the device.
135
+ #
136
+ # A launch used to commit its command buffer and block on
137
+ # `waitUntilCompleted()` before returning, so every kernel cost a host round
138
+ # trip. Measured 2026-09-07 on TinyLlama decode: 598 us per launch across
139
+ # 10,695 launches, 1,337 of them in a single decode step — 799 ms of an
140
+ # 857 ms step. Metal executes one queue's buffers in commit order, so the
141
+ # wait was never what made the engine correct; it only made every host read
142
+ # of device memory safe by accident. The waits moved to the host accesses
143
+ # themselves and the launch path commits without blocking.
144
+ #
145
+ # `max_command_buffers_in_flight` is what a queue may hold committed and not
146
+ # yet awaited. Metal's own ceiling is 64 per queue and it BLOCKS inside
147
+ # `commandBuffer()` at that point — a stall with nobody's name on it. 32
148
+ # keeps the backpressure ours and visible, at half the ceiling; it is a
149
+ # starting point measured on an M4 Pro, not a hardware constant.
150
+ dispatch:
151
+ max_command_buffers_in_flight: 32
152
+ # Dispatches one command buffer carries before the stream commits it. A
153
+ # NeuroBrix stream is one command buffer with one serialised compute
154
+ # encoder; this bounds how long the host waits for a result and how much
155
+ # work a single failure takes down with it. It is not a correctness knob —
156
+ # the encoder's own barriers keep the order at any value. A decode step of
157
+ # TinyLlama encodes ~1,350 dispatches, so 512 puts it in three buffers
158
+ # where one per launch put it in 1,505.
159
+ max_dispatches_per_command_buffer: 512
160
+
161
+ # Autotune correctness screen. The engine runs every candidate config once and
162
+ # compares its result against a reference config's before timing any of them,
163
+ # because an autotuner that ranks on speed alone selects whichever WRONG
164
+ # kernel is fastest — a kernel that writes half its output does half the
165
+ # stores and wins. Measured on Apple 2026-09-07: fp16 mm [64,32]@[32,64] chose
166
+ # a config that left half the columns zero.
167
+ #
168
+ # These are the tolerances that separate "a different but valid summation
169
+ # order" from "a different answer". Two configs with different block sizes
170
+ # reduce in a different order, so their results differ in the last bits; a
171
+ # config that drops output differs by the scale of the output itself. The
172
+ # gap between those two is several orders of magnitude, and these sit in it.
173
+ #
174
+ # Relative to the reference's own magnitude: max|a - b| / max|b|. Integer
175
+ # and boolean results are compared BIT-IDENTICALLY and ignore this table —
176
+ # there is no valid reordering that changes an integer.
177
+ autotune_screen_rtol:
178
+ float16: 2.0e-2
179
+ bfloat16: 4.0e-2
180
+ float32: 1.0e-4
181
+ float64: 1.0e-8
182
+ int64: 0.0 # an integer result (the MoE alignment's routing tables) is met exactly
183
+
184
+ # Above this many bytes of buffer, the autotune correctness screen does not
185
+ # run. Screening copies every argument out and back once per candidate, so a
186
+ # very large tensor turns a tuning step into hundreds of megabytes of traffic
187
+ # — and on unified memory that pressure is the machine's, not a card's.
188
+ # MEASURED 2026-09-07: unbounded screening of a 151936-wide softmax perturbed
189
+ # six unrelated tests in the same process. A skipped screen is announced, not
190
+ # silent.
191
+ autotune_screen_max_bytes: 33554432
192
+
193
+ autotune:
194
+ buckets:
195
+ # elements — an element-wise launch's element count (`kernels/ops/elementwise_launch.py`), NEVER the `default`
196
+ # dimension ladder (`autotune_bucket.ladder_for` refuses it). NOT measured on this architecture (no such device on
197
+ # either machine): the four classes measured on V100-SXM2 2026-10-23 (nvidia/volta.yml, launch-bound under 65 536
198
+ # elements, bandwidth classes above) and confirmed on apple_m4_pro 2026-10-24 — the measurement on this
199
+ # architecture is owed (docs/reference/owed-proofs.md, "element-wise ladder per architecture").
200
+ elements:
201
+ - {up_to: 65536, step: 65536}
202
+ - {up_to: 1048576, step: 1048576}
203
+ - {up_to: 16777216, step: 16777216}
204
+ - {up_to: null, step: 68719476736}
205
+ default:
206
+ - {up_to: 64, step: 1}
207
+ - {up_to: 256, step: 16}
208
+ - {up_to: 1024, step: 32}
209
+ - {up_to: 8192, step: 128}
210
+ # Above 8 192 a QUARTER-OCTAVE, not a 512-step. The 512 tail was decided by a sweep
211
+ # that ran to about 4 096 and never met a request-scale dimension: a vocoder's batched
212
+ # GEMM keys on the WAVEFORM and reaches 1 963 520, which a 512-step cuts into some four
213
+ # thousand buckets — 1 400 of one model's 1 522 distinct M values sat above 8 192.
214
+ # Measured 2026-09-22 on both classes, two shapes (the vocoder's B=1,N=1,K=9 and a
215
+ # GEMM at N=K=512), each octave bucket carrying three or four measured values with its
216
+ # TOP as representative: 0.0 % median loss, 0.2 % max at ONE octave bucket. The rows
217
+ # below are finer than the octave that was measured, so they cost no more than it did.
218
+ # The first three octaves above the knee keep a NARROW step. Measured directly on the
219
+ # rows as shipped (the upscalers' N=360, K=180; three sizes inside each bucket with
220
+ # its TOP among them, 2026-09-22): a quarter-octave there cost 0.0 % median but
221
+ # **5.2 %** at the 10 240 bucket and 1.2 % at 16 384 — the loss lives just above the
222
+ # knee, where a quarter of an OCTAVE is still a quarter of the VALUE. Beyond 65 536
223
+ # the same sweep measured 0.0 % median and at most 0.6 %, so the quarter-octave stands.
224
+ # The convolution-width ladder below keeps its quarter-octave: its own sweep measured
225
+ # 0.0 % median AND max there, on both classes and two channel counts.
226
+ - {up_to: 16384, step: 512}
227
+ - {up_to: 32768, step: 1024}
228
+ - {up_to: 65536, step: 2048}
229
+ - {up_to: 131072, step: 16384}
230
+ - {up_to: 262144, step: 32768}
231
+ - {up_to: 524288, step: 65536}
232
+ - {up_to: 1048576, step: 131072}
233
+ - {up_to: 2097152, step: 262144}
234
+ - {up_to: null, step: 524288}
235
+ # The width of a ONE-ROW convolution (a 1-D convolution over a sequence: a vocoder's
236
+ # samples, a mel spectrogram's frames) is the request's length, unbounded by any
237
+ # resolution — chatterbox's vocoder reaches 444 721 samples for 18 s of speech. Above the
238
+ # GEMM ladder it steps by a quarter-octave (≤ 25 % of the value), so a census meets every
239
+ # class of a speech length in ~100 runs instead of ~1 000; the loss of that step is owed a
240
+ # measurement on both classes (bucket_loss.py) before the ladder is called final.
241
+ W:
242
+ - {up_to: 64, step: 1}
243
+ - {up_to: 256, step: 16}
244
+ - {up_to: 1024, step: 32}
245
+ - {up_to: 8192, step: 128}
246
+ - {up_to: 16384, step: 2048}
247
+ - {up_to: 32768, step: 4096}
248
+ - {up_to: 65536, step: 8192}
249
+ - {up_to: 131072, step: 16384}
250
+ - {up_to: 262144, step: 32768}
251
+ - {up_to: 524288, step: 65536}
252
+ - {up_to: null, step: 131072}
253
+
254
+ # The flash kernel at a power-of-two head dim >= 128 is NOT measured on this architecture: the zero-pad
255
+ # detour stays (launch_keys.flash_headdim_detour). Declared, never left absent: true only where the
256
+ # correctness oracle was run with the detour off on this arch and stack (Volta, Triton 3.8, 2026-10-03).
257
+ flash:
258
+ pow2_head_dim_correct: false
259
+
260
+ # Convolution weight storage order (launch_keys.conv_weight_layout): KCRS, the container's own,
261
+ # until this arch measures KRSC (the M4 Pro measured +46-63 % on its 3x3 keys, 2026-10-07).
262
+ conv:
263
+ weight_layout: KCRS
@@ -0,0 +1,214 @@
1
+ # The library's half of nvidia/ampere.yml: the keys nbxtensor reads (docs/nbxtensor/device_keys.txt),
2
+ # moved with their sources by tools/split_vendor_files.py. NeuroBrix's half stays in
3
+ # src/neurobrix/config/vendors/nvidia/ampere.yml; the engine reads the two merged.
4
+
5
+ architecture: ampere
6
+ compute_capability: "8.0"
7
+
8
+ block_sizes:
9
+ # Default block size for simple kernels
10
+ default: 1024
11
+
12
+ # Batched Matrix Multiply configuration
13
+ bmm:
14
+ block_m: 64
15
+ block_n: 64
16
+ block_k: 32
17
+ num_warps: 4
18
+
19
+ # Convolution configuration
20
+ conv2d:
21
+ block_h: 16
22
+ block_w: 16
23
+ num_warps: 4
24
+
25
+ # Generic reduction block size
26
+ reduction: 1024
27
+
28
+ # M=1 dequant-GEMV occupancy rule — see nvidia/volta.yml for the
29
+ # full rationale (pinned parity BLOCK_N under-fills small-N grids;
30
+ # the wrapper halves BLOCK_N until the grid reaches min_programs).
31
+ # 216 = 2 waves x 108 SMs (A100); validation_status: analytical. Key absent or 0 -> no adaptation.
32
+ dequant_gemv:
33
+ min_programs: 216
34
+
35
+ # Scaled Dot-Product Attention block size thresholds.
36
+ # Schema documented in volta.yml. Decode entries first.
37
+ # Ampere values not yet empirically calibrated against per-LLM
38
+ # golden text; values mirror legacy structure with decode/prefill
39
+ # split. Run benches and update if needed.
40
+ sdpa_thresholds:
41
+ # Decode path (seqlen_q ≤ 16)
42
+ - seqlen_q_le: 16
43
+ head_dim_ge: 256
44
+ block_m: 16
45
+ block_n: 32
46
+ num_warps: 4
47
+ - seqlen_q_le: 16
48
+ block_m: 16
49
+ block_n: 64
50
+ num_warps: 4
51
+ # Prefill path (seqlen_q > 16)
52
+ - head_dim_ge: 256
53
+ block_m: 32
54
+ block_n: 32
55
+ num_warps: 4
56
+ - head_dim_ge: 128
57
+ block_m: 64
58
+ block_n: 64
59
+ num_warps: 4
60
+ - head_dim_lt: 128
61
+ block_m: 128
62
+ block_n: 64
63
+ num_warps: 4
64
+
65
+ memory:
66
+ max_shared_memory_per_block: 167936 # 164 KB (A100 SXM4/PCIe)
67
+ max_registers_per_block: 65536
68
+ # NVIDIA CUDA C++ Programming Guide, Technical Specifications per Compute Capability: "Maximum number of 32-bit
69
+ # registers per thread: 255" (7.x, 8.x, 9.x). Bounds a program's elements per thread (the row programs' prune).
70
+ max_registers_per_thread: 255
71
+ warp_size: 32
72
+ # SDPA deterministic-routing budget (R10 schema parity with
73
+ # volta.yml). 0 = DISABLED BY DESIGN: the flash-attention Triton
74
+ # non-determinism is a Volta-SIMT issue (pre-Ampere MMA path);
75
+ # Ampere has proper async tensor-core MMA and the flash kernel is
76
+ # deterministic here. Routing to the slower _math_attention
77
+ # fallback on Ampere would be a pure perf regression with zero
78
+ # determinism benefit, so the runtime never takes it when this is
79
+ # 0 (scores_bytes <= 0 is always False). The key's VALUE, not its
80
+ # presence, is the gate. hand_curated_from_docs.
81
+ sdpa_math_max_scores_bytes: 0
82
+ # Row block (alignment and floor) of the chunked deterministic
83
+ # math prefill; the chunk-halving retry on a refused allocation
84
+ # never goes below it.
85
+ sdpa_math_min_chunk_rows: 128
86
+ # Allocator pool: bytes the free-list may keep PARKED per device as a
87
+ # fraction of that device's memory (2026-09-02, pool default-on gate).
88
+ # Beyond it the largest parked blocks go back to the driver, bounding
89
+ # the pool's contribution to the driver watermark (measured +3.4 GB on
90
+ # the xlong int4 row unbounded). 0 = unbounded.
91
+ alloc_pool_parked_cap_fraction: 0.50
92
+ precision:
93
+ # Attention operands that disagree in dtype (an fp16 GEMM stored fp32 feeding V) all take the
94
+ # narrowest of the three, the compiled engine's alignment: the half attention stays on the matrix
95
+ # unit (V100, 2026-10-08: 1.16 s/op aligned narrowest vs 22.0 s/op on the scalar flash aligned widest).
96
+ attention_operands: narrowest
97
+ # Whether each engine branch's OWN kernels compute float64 / complex128 elements, read with
98
+ # supports_fp64 (both must hold) -- a CAPABILITY: `compiled` is ATen's, which carries both wherever
99
+ # the device does; `triton` is the NeuroBrix Triton kernels' (cuda/hip lower double; Metal's
100
+ # lowering narrows it in silence, measured 2026-09-28 on the Sana 4K positional embedding). Read
101
+ # by the DtypeEngine (`config.device_supports_fp64`) and by the Triton wrappers' binding
102
+ # (`triton.dtype.triton_has_fp64` -> `nbx_tensor.set_backend_has_fp64`).
103
+ kernels_carry_fp64:
104
+ compiled: true
105
+ triton: true
106
+ # Software-pipelining budget — see volta.yml for the schema. Ampere
107
+ # (sm_80) has cp.async, so the cap is set above anything the config
108
+ # space emits (our widest autotune space tops out at 5) and never binds.
109
+ pipelining:
110
+ max_num_stages: 8
111
+
112
+ # Autotune correctness screen. The engine runs every candidate config once and
113
+ # compares its result against a reference config's before timing any of them,
114
+ # because an autotuner that ranks on speed alone selects whichever WRONG
115
+ # kernel is fastest — a kernel that writes half its output does half the
116
+ # stores and wins. Measured on Apple 2026-09-07: fp16 mm [64,32]@[32,64] chose
117
+ # a config that left half the columns zero.
118
+ #
119
+ # These are the tolerances that separate "a different but valid summation
120
+ # order" from "a different answer". Two configs with different block sizes
121
+ # reduce in a different order, so their results differ in the last bits; a
122
+ # config that drops output differs by the scale of the output itself. The
123
+ # gap between those two is several orders of magnitude, and these sit in it.
124
+ #
125
+ # Relative to the reference's own magnitude: max|a - b| / max|b|. Integer
126
+ # and boolean results are compared BIT-IDENTICALLY and ignore this table —
127
+ # there is no valid reordering that changes an integer.
128
+ autotune_screen_rtol:
129
+ float16: 2.0e-2
130
+ bfloat16: 4.0e-2
131
+ float32: 1.0e-4
132
+ float64: 1.0e-8
133
+ int64: 0.0 # an integer result (the MoE alignment's routing tables) is met exactly
134
+
135
+ # Above this many bytes of buffer, the autotune correctness screen does not
136
+ # run. Screening copies every argument out and back once per candidate, so a
137
+ # very large tensor turns a tuning step into hundreds of megabytes of traffic
138
+ # — and on unified memory that pressure is the machine's, not a card's.
139
+ # MEASURED 2026-09-07: unbounded screening of a 151936-wide softmax perturbed
140
+ # six unrelated tests in the same process. A skipped screen is announced, not
141
+ # silent.
142
+ autotune_screen_max_bytes: 33554432
143
+
144
+ autotune:
145
+ buckets:
146
+ # elements — an element-wise launch's element count (`kernels/ops/elementwise_launch.py`), NEVER the `default`
147
+ # dimension ladder (`autotune_bucket.ladder_for` refuses it). NOT measured on this architecture (no such device on
148
+ # either machine): the four classes measured on V100-SXM2 2026-10-23 (nvidia/volta.yml, launch-bound under 65 536
149
+ # elements, bandwidth classes above) and confirmed on apple_m4_pro 2026-10-24 — the measurement on this
150
+ # architecture is owed (docs/reference/owed-proofs.md, "element-wise ladder per architecture").
151
+ elements:
152
+ - {up_to: 65536, step: 65536}
153
+ - {up_to: 1048576, step: 1048576}
154
+ - {up_to: 16777216, step: 16777216}
155
+ - {up_to: null, step: 68719476736}
156
+ default:
157
+ - {up_to: 64, step: 1}
158
+ - {up_to: 256, step: 16}
159
+ - {up_to: 1024, step: 32}
160
+ - {up_to: 8192, step: 128}
161
+ # Above 8 192 a QUARTER-OCTAVE, not a 512-step. The 512 tail was decided by a sweep
162
+ # that ran to about 4 096 and never met a request-scale dimension: a vocoder's batched
163
+ # GEMM keys on the WAVEFORM and reaches 1 963 520, which a 512-step cuts into some four
164
+ # thousand buckets — 1 400 of one model's 1 522 distinct M values sat above 8 192.
165
+ # Measured 2026-09-22 on both classes, two shapes (the vocoder's B=1,N=1,K=9 and a
166
+ # GEMM at N=K=512), each octave bucket carrying three or four measured values with its
167
+ # TOP as representative: 0.0 % median loss, 0.2 % max at ONE octave bucket. The rows
168
+ # below are finer than the octave that was measured, so they cost no more than it did.
169
+ # The first three octaves above the knee keep a NARROW step. Measured directly on the
170
+ # rows as shipped (the upscalers' N=360, K=180; three sizes inside each bucket with
171
+ # its TOP among them, 2026-09-22): a quarter-octave there cost 0.0 % median but
172
+ # **5.2 %** at the 10 240 bucket and 1.2 % at 16 384 — the loss lives just above the
173
+ # knee, where a quarter of an OCTAVE is still a quarter of the VALUE. Beyond 65 536
174
+ # the same sweep measured 0.0 % median and at most 0.6 %, so the quarter-octave stands.
175
+ # The convolution-width ladder below keeps its quarter-octave: its own sweep measured
176
+ # 0.0 % median AND max there, on both classes and two channel counts.
177
+ - {up_to: 16384, step: 512}
178
+ - {up_to: 32768, step: 1024}
179
+ - {up_to: 65536, step: 2048}
180
+ - {up_to: 131072, step: 16384}
181
+ - {up_to: 262144, step: 32768}
182
+ - {up_to: 524288, step: 65536}
183
+ - {up_to: 1048576, step: 131072}
184
+ - {up_to: 2097152, step: 262144}
185
+ - {up_to: null, step: 524288}
186
+ # The width of a ONE-ROW convolution (a 1-D convolution over a sequence: a vocoder's
187
+ # samples, a mel spectrogram's frames) is the request's length, unbounded by any
188
+ # resolution — chatterbox's vocoder reaches 444 721 samples for 18 s of speech. Above the
189
+ # GEMM ladder it steps by a quarter-octave (≤ 25 % of the value), so a census meets every
190
+ # class of a speech length in ~100 runs instead of ~1 000; the loss of that step is owed a
191
+ # measurement on both classes (bucket_loss.py) before the ladder is called final.
192
+ W:
193
+ - {up_to: 64, step: 1}
194
+ - {up_to: 256, step: 16}
195
+ - {up_to: 1024, step: 32}
196
+ - {up_to: 8192, step: 128}
197
+ - {up_to: 16384, step: 2048}
198
+ - {up_to: 32768, step: 4096}
199
+ - {up_to: 65536, step: 8192}
200
+ - {up_to: 131072, step: 16384}
201
+ - {up_to: 262144, step: 32768}
202
+ - {up_to: 524288, step: 65536}
203
+ - {up_to: null, step: 131072}
204
+
205
+ # The flash kernel at a power-of-two head dim >= 128 is NOT measured on this architecture: the zero-pad
206
+ # detour stays (launch_keys.flash_headdim_detour). Declared, never left absent: true only where the
207
+ # correctness oracle was run with the detour off on this arch and stack (Volta, Triton 3.8, 2026-10-03).
208
+ flash:
209
+ pow2_head_dim_correct: false
210
+
211
+ # Convolution weight storage order (launch_keys.conv_weight_layout): KCRS, the container's own,
212
+ # until this arch measures KRSC (the M4 Pro measured +46-63 % on its 3x3 keys, 2026-10-07).
213
+ conv:
214
+ weight_layout: KCRS