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,308 @@
1
+ # The library's half of apple/apple_m4_pro.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_m4_pro.yml; the engine reads the two merged.
4
+
5
+ architecture: apple_silicon
6
+ # provenance: measured 2026-09-10 — the backend builds this string
7
+ # from the device name (`driver.py`), verified on Apple M4 Pro.
8
+ compute_capability: "apple-m4-pro"
9
+ # What the Triton target actually reports, which is NOT the family above.
10
+ # MEASURED 2026-09-05 on an M4 Pro: the Metal backend builds its arch string
11
+ # from the Metal DEVICE NAME, lowercased and hyphenated
12
+ # (`kernels/metal_device.py::MetalRuntime.arch_name`), so it says
13
+ # "apple-m4-pro" where this file says "apple9". Matching on the family alone,
14
+ # the smem budget below resolved to NOTHING on a real Mac and the 32 KB
15
+ # filter silently did not apply — all 17 Volta tiles were offered, including
16
+ # the 72 KB one that cannot run here.
17
+ #
18
+ # These are prefixes, matched against the reported target. "apple-m" covers
19
+ # the whole M-series, which is exactly the scope this file claims in its
20
+ # header (M1..M4, GPU family 7/8/9). A chip outside it matches nothing and
21
+ # gets no filtering, which is the same zero-fallback answer as before.
22
+ compute_capability_matches:
23
+ # This file claims ONE variant. The family profile keeps the
24
+ # broad "apple-m" prefix and serves anything unknown.
25
+ - "apple-m4-pro"
26
+
27
+ block_sizes:
28
+ default: 1024
29
+
30
+ bmm:
31
+ block_m: 32
32
+ block_n: 32
33
+ block_k: 32
34
+ num_warps: 4
35
+
36
+ conv2d:
37
+ block_h: 16
38
+ block_w: 16
39
+ num_warps: 4
40
+
41
+ reduction: 1024
42
+
43
+ # Row-wise reductions over a dim (min / max / prod / all / any) and argmin.
44
+ #
45
+ # MEASURED 2026-09-07: `min` and `max` over a dim return a VALUE AND ITS
46
+ # INDEX, so their reduce carries a pair, and the Metal lowering stages such
47
+ # a reduce one element per thread — the tile must fit num_warps * 32. The
48
+ # adopted 8 x 1024 is 8192 against a 128-thread group.
49
+ #
50
+ # 8 x 128 with 32 warps is 1024 elements over 1024 threads, and is correct
51
+ # for max, min and argmin at N = 511, 1024, 1025 and 3077 against numpy in
52
+ # float64 (the row group is what matters here: at 8 rows the lowering used
53
+ # to collapse every row onto the first, which is fixed upstream and is why
54
+ # this entry can carry more than one row at all).
55
+ reduction_2d:
56
+ block_m: 8
57
+ block_n: 128
58
+ num_warps: 32
59
+
60
+ argmin:
61
+ block_m: 8
62
+ tile_n: 128
63
+ num_warps: 32
64
+
65
+ # Row-wise argmax — greedy sampling reads the argmax of a 32000-wide
66
+ # vocabulary row every token.
67
+ #
68
+ # MEASURED 2026-09-07: argmax is a MULTI-VALUE reduce (a value and its
69
+ # index travel together), and the Metal lowering has no multipass form for
70
+ # a tuple — it says so and refuses — so the tile must fit the threadgroup,
71
+ # which is num_warps * 32. The 4096 cap every architecture used refused
72
+ # against the default 4 warps (128 threads). 1024 over 32 warps is the
73
+ # largest that fits; the index it returns is exact at every tile measured
74
+ # (128/4, 256/8, 512/16, 1024/32 all give the same index on a 32000-wide
75
+ # row), so this is throughput, not correctness.
76
+ argmax:
77
+ tile_n: 1024
78
+ num_warps: 32
79
+
80
+ # M=1 dequant-GEMV occupancy rule — see nvidia/volta.yml for the rationale
81
+ # (the wrapper halves BLOCK_N until the grid reaches min_programs).
82
+ # 2 waves x 40 GPU cores (M3/M4 Max class); validation_status: analytical.
83
+ # Key absent or 0 -> no adaptation.
84
+ dequant_gemv:
85
+ min_programs: 80
86
+
87
+ # sdpa_thresholds RETIRED (roadmap C3, 2026-10-22): the tl.dot flash's tile is certified per key by autotune
88
+ # certify (`launch_keys.flash_tiles_certified`), not read from a hand table.
89
+
90
+ memory:
91
+ # 32 KB of threadgroup memory per threadgroup (Apple GPU family 7+).
92
+ # The single most binding difference from every NVIDIA profile here.
93
+ # MEASURED 2026-09-05 on an M4 Pro: `MTLDevice.maxThreadgroupMemoryLength()`
94
+ # returns exactly 32768, so the documented figure holds on real hardware.
95
+ max_shared_memory_per_block: 32768
96
+ max_registers_per_block: 32768
97
+ # Apple GPUs schedule in 32-wide SIMD groups. Named `warp_size` because one
98
+ # hardware concept has ONE key across every profile — AMD's 64-wide
99
+ # wavefronts are declared under the same name.
100
+ warp_size: 32
101
+
102
+ # SDPA deterministic-routing budget. 0 = NOT APPLICABLE: the
103
+ # non-determinism this routes around is a Volta-SIMT MMA issue and does
104
+ # not transfer to Apple's simdgroup path. Left 0 until shown otherwise on
105
+ # real hardware.
106
+ sdpa_math_max_scores_bytes: 0
107
+ sdpa_math_min_chunk_rows: 128
108
+ # Allocator pool: fraction of device memory the free-list may keep parked.
109
+ # Apple Silicon is UNIFIED memory — the "device" budget is system RAM
110
+ # shared with everything else on the machine, so parking is far less
111
+ # polite here than on a discrete card. Halved accordingly.
112
+ alloc_pool_parked_cap_fraction: 0.25
113
+ precision:
114
+ # Whether each engine branch's OWN kernels compute float64 / complex128 elements, read with
115
+ # supports_fp64 (both must hold) -- a CAPABILITY: `compiled` is ATen's, which carries both wherever
116
+ # the device does; `triton` is the NeuroBrix Triton kernels' (cuda/hip lower double; Metal's
117
+ # lowering narrows it in silence, measured 2026-09-28 on the Sana 4K positional embedding). Read
118
+ # by the DtypeEngine (`config.device_supports_fp64`) and by the Triton wrappers' binding
119
+ # (`triton.dtype.triton_has_fp64` -> `nbx_tensor.set_backend_has_fp64`).
120
+ kernels_carry_fp64:
121
+ compiled: true
122
+ triton: false
123
+ # Attention operands that disagree in dtype (an fp16 GEMM stored fp32 feeding V) all take the
124
+ # narrowest of the three, the compiled engine's alignment: the half attention stays on the matrix
125
+ # unit (V100, 2026-10-08: 1.16 s/op aligned narrowest vs 22.0 s/op on the scalar flash aligned widest).
126
+ attention_operands: narrowest
127
+ # Software-pipelining budget — see nvidia/volta.yml for the schema.
128
+ #
129
+ # validation_status: conservative_pending_first_light. cp.async is a PTX
130
+ # instruction with no Apple equivalent, and the Metal backend stages through
131
+ # threadgroup memory by a different mechanism. Neither Volta's measured
132
+ # fault nor Ampere's clearance transfers, so the budget stays at 2 until an
133
+ # Apple GPU measures it: clamping can only cost throughput.
134
+ pipelining:
135
+ max_num_stages: 2
136
+
137
+ # How work reaches the device.
138
+ #
139
+ # A launch used to commit its command buffer and block on
140
+ # `waitUntilCompleted()` before returning, so every kernel cost a host round
141
+ # trip. Measured 2026-09-07 on TinyLlama decode: 598 us per launch across
142
+ # 10,695 launches, 1,337 of them in a single decode step — 799 ms of an
143
+ # 857 ms step. Metal executes one queue's buffers in commit order, so the
144
+ # wait was never what made the engine correct; it only made every host read
145
+ # of device memory safe by accident. The waits moved to the host accesses
146
+ # themselves and the launch path commits without blocking.
147
+ #
148
+ # `max_command_buffers_in_flight` is what a queue may hold committed and not
149
+ # yet awaited. Metal's own ceiling is 64 per queue and it BLOCKS inside
150
+ # `commandBuffer()` at that point — a stall with nobody's name on it. 32
151
+ # keeps the backpressure ours and visible, at half the ceiling; it is a
152
+ # starting point measured on an M4 Pro, not a hardware constant.
153
+ dispatch:
154
+ max_command_buffers_in_flight: 32
155
+ # Dispatches one command buffer carries before the stream commits it. A
156
+ # NeuroBrix stream is one command buffer with one serialised compute
157
+ # encoder; this bounds how long the host waits for a result and how much
158
+ # work a single failure takes down with it. It is not a correctness knob —
159
+ # the encoder's own barriers keep the order at any value. A decode step of
160
+ # TinyLlama encodes ~1,350 dispatches, so 512 puts it in three buffers
161
+ # where one per launch put it in 1,505.
162
+ max_dispatches_per_command_buffer: 512
163
+
164
+ autotune:
165
+ buckets:
166
+ # elements — an element-wise launch's element count (`kernels/ops/elementwise_launch.py`), NEVER the `default`
167
+ # dimension ladder (`autotune_bucket.ladder_for` refuses it). MEASURED on THIS chip 2026-10-24 (apple_m4_pro, the
168
+ # Mac's campaign ew_ladder_2026_10_24: the shared copy's 15 configs, fp32, 49 counts 4 096..268 435 456): volta's
169
+ # four rows hold — at >= 2 ms each class's config, certified at its floor, is within 4.0 % max / 1.6 % median of
170
+ # each count's best, inside the chip's noise bands; below 2 ms every config times at the launch.
171
+ elements:
172
+ - {up_to: 65536, step: 65536}
173
+ - {up_to: 1048576, step: 1048576}
174
+ - {up_to: 16777216, step: 16777216}
175
+ - {up_to: null, step: 68719476736}
176
+ default:
177
+ - {up_to: 64, step: 1}
178
+ - {up_to: 256, step: 16}
179
+ - {up_to: 1024, step: 32}
180
+ - {up_to: 8192, step: 128}
181
+ # Above 8 192 a QUARTER-OCTAVE, not a 512-step. The 512 tail was decided by a sweep
182
+ # that ran to about 4 096 and never met a request-scale dimension: a vocoder's batched
183
+ # GEMM keys on the WAVEFORM and reaches 1 963 520, which a 512-step cuts into some four
184
+ # thousand buckets — 1 400 of one model's 1 522 distinct M values sat above 8 192.
185
+ # Measured 2026-09-22 on both classes, two shapes (the vocoder's B=1,N=1,K=9 and a
186
+ # GEMM at N=K=512), each octave bucket carrying three or four measured values with its
187
+ # TOP as representative: 0.0 % median loss, 0.2 % max at ONE octave bucket. The rows
188
+ # below are finer than the octave that was measured, so they cost no more than it did.
189
+ # The first three octaves above the knee keep a NARROW step. Measured directly on the
190
+ # rows as shipped (the upscalers' N=360, K=180; three sizes inside each bucket with
191
+ # its TOP among them, 2026-09-22): a quarter-octave there cost 0.0 % median but
192
+ # **5.2 %** at the 10 240 bucket and 1.2 % at 16 384 — the loss lives just above the
193
+ # knee, where a quarter of an OCTAVE is still a quarter of the VALUE. Beyond 65 536
194
+ # the same sweep measured 0.0 % median and at most 0.6 %, so the quarter-octave stands.
195
+ # The convolution-width ladder below keeps its quarter-octave: its own sweep measured
196
+ # 0.0 % median AND max there, on both classes and two channel counts.
197
+ - {up_to: 16384, step: 512}
198
+ - {up_to: 32768, step: 1024}
199
+ - {up_to: 65536, step: 2048}
200
+ - {up_to: 131072, step: 16384}
201
+ - {up_to: 262144, step: 32768}
202
+ - {up_to: 524288, step: 65536}
203
+ - {up_to: 1048576, step: 131072}
204
+ - {up_to: 2097152, step: 262144}
205
+ - {up_to: null, step: 524288}
206
+ # The width of a ONE-ROW convolution (a 1-D convolution over a sequence: a vocoder's
207
+ # samples, a mel spectrogram's frames) is the request's length, unbounded by any
208
+ # resolution — chatterbox's vocoder reaches 444 721 samples for 18 s of speech. Above the
209
+ # GEMM ladder it steps by a quarter-octave (≤ 25 % of the value), so a census meets every
210
+ # class of a speech length in ~100 runs instead of ~1 000; the loss of that step is owed a
211
+ # measurement on both classes (bucket_loss.py) before the ladder is called final.
212
+ W:
213
+ - {up_to: 64, step: 1}
214
+ - {up_to: 256, step: 16}
215
+ - {up_to: 1024, step: 32}
216
+ - {up_to: 8192, step: 128}
217
+ - {up_to: 16384, step: 2048}
218
+ - {up_to: 32768, step: 4096}
219
+ - {up_to: 65536, step: 8192}
220
+ - {up_to: 131072, step: 16384}
221
+ - {up_to: 262144, step: 32768}
222
+ - {up_to: 524288, step: 65536}
223
+ - {up_to: null, step: 131072}
224
+
225
+ autotune_screen_rtol:
226
+ float16: 2.0e-2
227
+ bfloat16: 4.0e-2
228
+ float32: 1.0e-4
229
+ float64: 1.0e-8
230
+ int64: 0.0 # an integer result (the MoE alignment's routing tables) is met exactly
231
+
232
+ # Above this many bytes of buffer, the autotune correctness screen does not
233
+ # run. Screening copies every argument out and back once per candidate, so a
234
+ # very large tensor turns a tuning step into hundreds of megabytes of traffic
235
+ # — and on unified memory that pressure is the machine's, not a card's.
236
+ # MEASURED 2026-09-07: unbounded screening of a 151936-wide softmax perturbed
237
+ # six unrelated tests in the same process. A skipped screen is announced, not
238
+ # silent.
239
+ #
240
+ # RAISED 2026-09-14 (M4 Pro, this file only): the upscaler catalogue's
241
+ # convolutions carry 73–145 MB of arguments (swin2SR 180→180 @ 448², e.g.),
242
+ # all above the 32 MB the other Apple profiles keep — so every upscaler conv
243
+ # was seated UNSCREENED, a silent-wrong-in-waiting on a public path, WHILE the
244
+ # conv fp64 oracle (oracles/conv2d_fp64.py) was already wired into the screen
245
+ # provider. The screen's cost at this size is bounded and paid once per
246
+ # uncertified key; serving a never-verified conv is unbounded risk on every
247
+ # inference. `bench_would_swap` remains the real OOM guard (it checks actual
248
+ # available memory per key), so this ceiling cannot force a swap — it only
249
+ # stops the screen from refusing to run on a conv it can well afford.
250
+ # WHICH Metal backend this machine runs. The engine targets Triton; this is a
251
+ # SELECTION, not a branch — `triton/metal_backend.py` is the only module that
252
+ # names an implementation, and it READS this line (it does not infer from what
253
+ # happens to be installed; that bug was fixed 2026-09-17).
254
+ #
255
+ # `triton_ext` is triton-lang/triton-ext's AppleGPU backend (C++ MLIR -> MSL),
256
+ # and it is the only selectable one. The bledden triton-msl fork was ARCHIVED on
257
+ # 2026-09-17: it stays in this repository's history and in the atelier clones as
258
+ # reference and inspiration, and a profile that still names it is refused BY
259
+ # NAME rather than silently swapped, so a measurement can always name what
260
+ # produced it.
261
+ #
262
+ # A venv without `triton_apple_backend` now REFUSES here rather than running.
263
+ # That is correct and it is visible: measured 2026-09-17, the engine's own venv
264
+ # carries Triton 3.7.0 and the fork, while triton-ext needs the 3.8.0 built from
265
+ # source that lives in the triton-ext venv. Making one environment that a user
266
+ # can install and get a working Triton path from is its own piece of work, and
267
+ # until it lands `--triton` runs from the engine venv say exactly why they stop.
268
+ # metal_backend: triton_ext` ... and it is NOT
269
+ # installed (no module 'triton_apple_backend')"
270
+ # — which is correct, and is what makes this a packaging job rather than a
271
+ # one-line profile edit.
272
+ metal_backend: triton_ext
273
+ # Measured 2026-09-16, swin2SR-classical-sr-x2-64 on this machine: its addmm
274
+ # carries 289144080 bytes of operands (M=200704 N=180 K=180), just past 256 MiB,
275
+ # so the screen stood down on the model's heaviest keys —
276
+ # [AUTOTUNE_UNSCREENED] ... over the profile's screening budget 268435456.
277
+ # The configuration seated here is the FASTEST AMONG 10 CANDIDATES THAT
278
+ # NOTHING VERIFIED
279
+ # An unscreened seat is exactly the hole the fp64 oracle exists to close, and a
280
+ # budget that stops just below the real workload closes nothing. 1 GiB covers
281
+ # swin2SR's keys with room; the oracle's fp64 reference roughly doubles the
282
+ # operand bytes, which this machine has (12.2 GB free when measured).
283
+ autotune_screen_max_bytes: 1073741824
284
+
285
+ # The flash kernel at a power-of-two head dim >= 128, MEASURED on this chip and stack (triton-ext adbf6e84,
286
+ # Triton 3.8, 2026-10-08 00:05): the 33-case attention correctness oracle
287
+ # (tests/unit/kernels/test_numeric_correctness_oracle.py) passes with NBX_D128_DETOUR=0, routed to the flash
288
+ # kernel on the device; through the wrapper, bf16 against float64, D 128 at 2048-4608 tokens is 4.3-5.2e-03
289
+ # with the detour off and 3.2-3.9e-03 with it on. The detour sent D 128 to the math path at 0.62-0.68 TFLOP/s;
290
+ # the flash kernel runs it at 2.65-3.17 (D 256: 0.94 -> 1.39).
291
+ # Every head dim, MEASURED 2026-10-23 04:5x on this chip and stack (triton-ext b06cbb0d + i64, Triton 3.8): the 33-case
292
+ # attention correctness oracle passes with this flag on (non-power-of-two dims 96, 127, 129, 160, 192, 255 then take the
293
+ # flash in its power-of-two head-dim block, the extra columns masked to zero); at Allegro's head dim (96, bf16, 2 x 24
294
+ # heads, 2048 tokens) the flash runs in 24.5 ms against 120.5 ms on the math route it took (4.9x), float64 error 5.7e-4
295
+ # vs 4.6e-4, outputs 2e-3 apart (bf16). Above the 2 GiB scores bound the route was already the flash (4096 and 8192
296
+ # tokens: identical outputs and times).
297
+ flash:
298
+ pow2_head_dim_correct: true
299
+ any_head_dim_correct: true
300
+
301
+ # Convolution weight storage order (launch_keys.conv_weight_layout). KRSC: the loader writes every
302
+ # 3x3-class conv weight channels-innermost, once, and the conv kernel reads it in place.
303
+ # MEASURED 2026-10-07 on this chip (served adbf6e84, census 3x3 shapes, the certified configs):
304
+ # +46-63 % on every 3x3 key (1024 ch at 256^2: 3.31 -> 5.38 TFLOP/s; 64->256 VAE convs 2.25 ->
305
+ # 3.31); 1x1 is the same memory either way.
306
+ conv:
307
+ weight_layout: KRSC
308
+
@@ -0,0 +1,269 @@
1
+ # The library's half of apple/apple_m5.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_m5.yml; the engine reads the two merged.
4
+
5
+ architecture: apple_silicon
6
+ # provenance: measured 2026-09-10 — the backend builds this string
7
+ # from the device name (`driver.py`), verified on Apple M4 Pro.
8
+ compute_capability: "apple-m5"
9
+ # gpu_family: not stated. This project does not know which
10
+ # Apple GPU family M5 reports, and will not guess one.
11
+
12
+ # What the Triton target actually reports, which is NOT the family above.
13
+ # MEASURED 2026-09-05 on an M4 Pro: the Metal backend builds its arch string
14
+ # from the Metal DEVICE NAME, lowercased and hyphenated
15
+ # (`kernels/metal_device.py::MetalRuntime.arch_name`), so it says
16
+ # "apple-m4-pro" where this file says "apple9". Matching on the family alone,
17
+ # the smem budget below resolved to NOTHING on a real Mac and the 32 KB
18
+ # filter silently did not apply — all 17 Volta tiles were offered, including
19
+ # the 72 KB one that cannot run here.
20
+ #
21
+ # These are prefixes, matched against the reported target. "apple-m" covers
22
+ # the whole M-series, which is exactly the scope this file claims in its
23
+ # header (M1..M4, GPU family 7/8/9). A chip outside it matches nothing and
24
+ # gets no filtering, which is the same zero-fallback answer as before.
25
+ compute_capability_matches:
26
+ # This file claims ONE variant. The family profile keeps the
27
+ # broad "apple-m" prefix and serves anything unknown.
28
+ - "apple-m5"
29
+
30
+ block_sizes:
31
+ default: 1024
32
+
33
+ bmm:
34
+ block_m: 32
35
+ block_n: 32
36
+ block_k: 32
37
+ num_warps: 4
38
+
39
+ conv2d:
40
+ block_h: 16
41
+ block_w: 16
42
+ num_warps: 4
43
+
44
+ reduction: 1024
45
+
46
+ # Row-wise reductions over a dim (min / max / prod / all / any) and argmin.
47
+ #
48
+ # MEASURED 2026-09-07: `min` and `max` over a dim return a VALUE AND ITS
49
+ # INDEX, so their reduce carries a pair, and the Metal lowering stages such
50
+ # a reduce one element per thread — the tile must fit num_warps * 32. The
51
+ # adopted 8 x 1024 is 8192 against a 128-thread group.
52
+ #
53
+ # 8 x 128 with 32 warps is 1024 elements over 1024 threads, and is correct
54
+ # for max, min and argmin at N = 511, 1024, 1025 and 3077 against numpy in
55
+ # float64 (the row group is what matters here: at 8 rows the lowering used
56
+ # to collapse every row onto the first, which is fixed upstream and is why
57
+ # this entry can carry more than one row at all).
58
+ reduction_2d:
59
+ block_m: 8
60
+ block_n: 128
61
+ num_warps: 32
62
+
63
+ argmin:
64
+ block_m: 8
65
+ tile_n: 128
66
+ num_warps: 32
67
+
68
+ # Row-wise argmax — greedy sampling reads the argmax of a 32000-wide
69
+ # vocabulary row every token.
70
+ #
71
+ # MEASURED 2026-09-07: argmax is a MULTI-VALUE reduce (a value and its
72
+ # index travel together), and the Metal lowering has no multipass form for
73
+ # a tuple — it says so and refuses — so the tile must fit the threadgroup,
74
+ # which is num_warps * 32. The 4096 cap every architecture used refused
75
+ # against the default 4 warps (128 threads). 1024 over 32 warps is the
76
+ # largest that fits; the index it returns is exact at every tile measured
77
+ # (128/4, 256/8, 512/16, 1024/32 all give the same index on a 32000-wide
78
+ # row), so this is throughput, not correctness.
79
+ argmax:
80
+ tile_n: 1024
81
+ num_warps: 32
82
+
83
+ # M=1 dequant-GEMV occupancy rule — see nvidia/volta.yml for the rationale
84
+ # (the wrapper halves BLOCK_N until the grid reaches min_programs).
85
+ # 2 waves x 40 GPU cores (M3/M4 Max class); validation_status: analytical.
86
+ # Key absent or 0 -> no adaptation.
87
+ dequant_gemv:
88
+ min_programs: 80
89
+
90
+ # sdpa_thresholds RETIRED (roadmap C3, 2026-10-22): the tl.dot flash's tile is certified per key by autotune
91
+ # certify (`launch_keys.flash_tiles_certified`), not read from a hand table.
92
+
93
+ memory:
94
+ # 32 KB of threadgroup memory per threadgroup (Apple GPU family 7+).
95
+ # The single most binding difference from every NVIDIA profile here.
96
+ # MEASURED 2026-09-05 on an M4 Pro: `MTLDevice.maxThreadgroupMemoryLength()`
97
+ # returns exactly 32768, so the documented figure holds on real hardware.
98
+ max_shared_memory_per_block: 32768
99
+ max_registers_per_block: 32768
100
+ # Apple GPUs schedule in 32-wide SIMD groups. Named `warp_size` because one
101
+ # hardware concept has ONE key across every profile — AMD's 64-wide
102
+ # wavefronts are declared under the same name.
103
+ warp_size: 32
104
+
105
+ # SDPA deterministic-routing budget. 0 = NOT APPLICABLE: the
106
+ # non-determinism this routes around is a Volta-SIMT MMA issue and does
107
+ # not transfer to Apple's simdgroup path. Left 0 until shown otherwise on
108
+ # real hardware.
109
+ sdpa_math_max_scores_bytes: 0
110
+ sdpa_math_min_chunk_rows: 128
111
+ # Allocator pool: fraction of device memory the free-list may keep parked.
112
+ # Apple Silicon is UNIFIED memory — the "device" budget is system RAM
113
+ # shared with everything else on the machine, so parking is far less
114
+ # polite here than on a discrete card. Halved accordingly.
115
+ alloc_pool_parked_cap_fraction: 0.25
116
+ precision:
117
+ # Whether each engine branch's OWN kernels compute float64 / complex128 elements, read with
118
+ # supports_fp64 (both must hold) -- a CAPABILITY: `compiled` is ATen's, which carries both wherever
119
+ # the device does; `triton` is the NeuroBrix Triton kernels' (cuda/hip lower double; Metal's
120
+ # lowering narrows it in silence, measured 2026-09-28 on the Sana 4K positional embedding). Read
121
+ # by the DtypeEngine (`config.device_supports_fp64`) and by the Triton wrappers' binding
122
+ # (`triton.dtype.triton_has_fp64` -> `nbx_tensor.set_backend_has_fp64`).
123
+ kernels_carry_fp64:
124
+ compiled: true
125
+ triton: false
126
+ # Attention operands that disagree in dtype (an fp16 GEMM stored fp32 feeding V) all take the
127
+ # narrowest of the three, the compiled engine's alignment: the half attention stays on the matrix
128
+ # unit (V100, 2026-10-08: 1.16 s/op aligned narrowest vs 22.0 s/op on the scalar flash aligned widest).
129
+ attention_operands: narrowest
130
+ # Software-pipelining budget — see nvidia/volta.yml for the schema.
131
+ #
132
+ # validation_status: conservative_pending_first_light. cp.async is a PTX
133
+ # instruction with no Apple equivalent, and the Metal backend stages through
134
+ # threadgroup memory by a different mechanism. Neither Volta's measured
135
+ # fault nor Ampere's clearance transfers, so the budget stays at 2 until an
136
+ # Apple GPU measures it: clamping can only cost throughput.
137
+ pipelining:
138
+ max_num_stages: 2
139
+
140
+ # How work reaches the device.
141
+ #
142
+ # A launch used to commit its command buffer and block on
143
+ # `waitUntilCompleted()` before returning, so every kernel cost a host round
144
+ # trip. Measured 2026-09-07 on TinyLlama decode: 598 us per launch across
145
+ # 10,695 launches, 1,337 of them in a single decode step — 799 ms of an
146
+ # 857 ms step. Metal executes one queue's buffers in commit order, so the
147
+ # wait was never what made the engine correct; it only made every host read
148
+ # of device memory safe by accident. The waits moved to the host accesses
149
+ # themselves and the launch path commits without blocking.
150
+ #
151
+ # `max_command_buffers_in_flight` is what a queue may hold committed and not
152
+ # yet awaited. Metal's own ceiling is 64 per queue and it BLOCKS inside
153
+ # `commandBuffer()` at that point — a stall with nobody's name on it. 32
154
+ # keeps the backpressure ours and visible, at half the ceiling; it is a
155
+ # starting point measured on an M4 Pro, not a hardware constant.
156
+ dispatch:
157
+ max_command_buffers_in_flight: 32
158
+ # Dispatches one command buffer carries before the stream commits it. A
159
+ # NeuroBrix stream is one command buffer with one serialised compute
160
+ # encoder; this bounds how long the host waits for a result and how much
161
+ # work a single failure takes down with it. It is not a correctness knob —
162
+ # the encoder's own barriers keep the order at any value. A decode step of
163
+ # TinyLlama encodes ~1,350 dispatches, so 512 puts it in three buffers
164
+ # where one per launch put it in 1,505.
165
+ max_dispatches_per_command_buffer: 512
166
+
167
+ # Autotune correctness screen. The engine runs every candidate config once and
168
+ # compares its result against a reference config's before timing any of them,
169
+ # because an autotuner that ranks on speed alone selects whichever WRONG
170
+ # kernel is fastest — a kernel that writes half its output does half the
171
+ # stores and wins. Measured on Apple 2026-09-07: fp16 mm [64,32]@[32,64] chose
172
+ # a config that left half the columns zero.
173
+ #
174
+ # These are the tolerances that separate "a different but valid summation
175
+ # order" from "a different answer". Two configs with different block sizes
176
+ # reduce in a different order, so their results differ in the last bits; a
177
+ # config that drops output differs by the scale of the output itself. The
178
+ # gap between those two is several orders of magnitude, and these sit in it.
179
+ #
180
+ # Relative to the reference's own magnitude: max|a - b| / max|b|. Integer
181
+ # and boolean results are compared BIT-IDENTICALLY and ignore this table —
182
+ # there is no valid reordering that changes an integer.
183
+ autotune_screen_rtol:
184
+ float16: 2.0e-2
185
+ bfloat16: 4.0e-2
186
+ float32: 1.0e-4
187
+ float64: 1.0e-8
188
+ int64: 0.0 # an integer result (the MoE alignment's routing tables) is met exactly
189
+
190
+ # Above this many bytes of buffer, the autotune correctness screen does not
191
+ # run. Screening copies every argument out and back once per candidate, so a
192
+ # very large tensor turns a tuning step into hundreds of megabytes of traffic
193
+ # — and on unified memory that pressure is the machine's, not a card's.
194
+ # MEASURED 2026-09-07: unbounded screening of a 151936-wide softmax perturbed
195
+ # six unrelated tests in the same process. A skipped screen is announced, not
196
+ # silent.
197
+ autotune_screen_max_bytes: 33554432
198
+
199
+ autotune:
200
+ buckets:
201
+ # elements — an element-wise launch's element count (`kernels/ops/elementwise_launch.py`), NEVER the `default`
202
+ # dimension ladder (`autotune_bucket.ladder_for` refuses it). NOT measured on this architecture (no such device on
203
+ # either machine): the four classes measured on V100-SXM2 2026-10-23 (nvidia/volta.yml, launch-bound under 65 536
204
+ # elements, bandwidth classes above) and confirmed on apple_m4_pro 2026-10-24 — the measurement on this
205
+ # architecture is owed (docs/reference/owed-proofs.md, "element-wise ladder per architecture").
206
+ elements:
207
+ - {up_to: 65536, step: 65536}
208
+ - {up_to: 1048576, step: 1048576}
209
+ - {up_to: 16777216, step: 16777216}
210
+ - {up_to: null, step: 68719476736}
211
+ default:
212
+ - {up_to: 64, step: 1}
213
+ - {up_to: 256, step: 16}
214
+ - {up_to: 1024, step: 32}
215
+ - {up_to: 8192, step: 128}
216
+ # Above 8 192 a QUARTER-OCTAVE, not a 512-step. The 512 tail was decided by a sweep
217
+ # that ran to about 4 096 and never met a request-scale dimension: a vocoder's batched
218
+ # GEMM keys on the WAVEFORM and reaches 1 963 520, which a 512-step cuts into some four
219
+ # thousand buckets — 1 400 of one model's 1 522 distinct M values sat above 8 192.
220
+ # Measured 2026-09-22 on both classes, two shapes (the vocoder's B=1,N=1,K=9 and a
221
+ # GEMM at N=K=512), each octave bucket carrying three or four measured values with its
222
+ # TOP as representative: 0.0 % median loss, 0.2 % max at ONE octave bucket. The rows
223
+ # below are finer than the octave that was measured, so they cost no more than it did.
224
+ # The first three octaves above the knee keep a NARROW step. Measured directly on the
225
+ # rows as shipped (the upscalers' N=360, K=180; three sizes inside each bucket with
226
+ # its TOP among them, 2026-09-22): a quarter-octave there cost 0.0 % median but
227
+ # **5.2 %** at the 10 240 bucket and 1.2 % at 16 384 — the loss lives just above the
228
+ # knee, where a quarter of an OCTAVE is still a quarter of the VALUE. Beyond 65 536
229
+ # the same sweep measured 0.0 % median and at most 0.6 %, so the quarter-octave stands.
230
+ # The convolution-width ladder below keeps its quarter-octave: its own sweep measured
231
+ # 0.0 % median AND max there, on both classes and two channel counts.
232
+ - {up_to: 16384, step: 512}
233
+ - {up_to: 32768, step: 1024}
234
+ - {up_to: 65536, step: 2048}
235
+ - {up_to: 131072, step: 16384}
236
+ - {up_to: 262144, step: 32768}
237
+ - {up_to: 524288, step: 65536}
238
+ - {up_to: 1048576, step: 131072}
239
+ - {up_to: 2097152, step: 262144}
240
+ - {up_to: null, step: 524288}
241
+ # The width of a ONE-ROW convolution (a 1-D convolution over a sequence: a vocoder's
242
+ # samples, a mel spectrogram's frames) is the request's length, unbounded by any
243
+ # resolution — chatterbox's vocoder reaches 444 721 samples for 18 s of speech. Above the
244
+ # GEMM ladder it steps by a quarter-octave (≤ 25 % of the value), so a census meets every
245
+ # class of a speech length in ~100 runs instead of ~1 000; the loss of that step is owed a
246
+ # measurement on both classes (bucket_loss.py) before the ladder is called final.
247
+ W:
248
+ - {up_to: 64, step: 1}
249
+ - {up_to: 256, step: 16}
250
+ - {up_to: 1024, step: 32}
251
+ - {up_to: 8192, step: 128}
252
+ - {up_to: 16384, step: 2048}
253
+ - {up_to: 32768, step: 4096}
254
+ - {up_to: 65536, step: 8192}
255
+ - {up_to: 131072, step: 16384}
256
+ - {up_to: 262144, step: 32768}
257
+ - {up_to: 524288, step: 65536}
258
+ - {up_to: null, step: 131072}
259
+
260
+ # The flash kernel at a power-of-two head dim >= 128 is NOT measured on this architecture: the zero-pad
261
+ # detour stays (launch_keys.flash_headdim_detour). Declared, never left absent: true only where the
262
+ # correctness oracle was run with the detour off on this arch and stack (Volta, Triton 3.8, 2026-10-03).
263
+ flash:
264
+ pow2_head_dim_correct: false
265
+
266
+ # Convolution weight storage order (launch_keys.conv_weight_layout): KCRS, the container's own,
267
+ # until this arch measures KRSC (the M4 Pro measured +46-63 % on its 3x3 keys, 2026-10-07).
268
+ conv:
269
+ weight_layout: KCRS