nbxtensor 0.0.3__tar.gz → 0.0.5__tar.gz
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-0.0.3 → nbxtensor-0.0.5}/CHANGELOG.md +40 -1
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/PKG-INFO +20 -12
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/README.md +17 -10
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/pyproject.toml +6 -2
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/__init__.py +1 -1
- nbxtensor-0.0.5/src/nbxtensor/__main__.py +39 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/cpu/blas.py +11 -0
- nbxtensor-0.0.5/src/nbxtensor/backend/install_metal.py +107 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/launcher.py +3 -2
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/level_zero.py +2 -2
- nbxtensor-0.0.5/src/nbxtensor/backend/libnames.py +26 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/metal_backend.py +25 -17
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/replay_graph.py +2 -1
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/runtime.py +9 -6
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/io/read_rate.py +14 -3
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/io/safetensors.py +35 -2
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/autotune_certified.py +18 -8
- nbxtensor-0.0.5/tests/test_a_setting_not_served_says_why.py +32 -0
- nbxtensor-0.0.5/tests/test_install_metal_fetches_only_what_it_names.py +117 -0
- nbxtensor-0.0.5/tests/test_it_installs_on_a_mac.py +23 -0
- nbxtensor-0.0.3/src/nbxtensor/__main__.py +0 -29
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/.github/PULL_REQUEST_TEMPLATE/certificate.md +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/CONTRIBUTING.md +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/LICENSE +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/THIRD_PARTY_NOTICES.md +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/assets/logo.png +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/__init__.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/capabilities.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/cpu/__init__.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/cpu/pool.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/cpu_backend.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/device_facts.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/device_files.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/device_names.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/amd/cdna.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/amd/cdna2.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/amd/cdna3.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/amd/cdna4.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/amd/rdna3.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/amd/rdna4.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m1.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m1_max.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m1_pro.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m1_ultra.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m2.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m2_max.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m2_pro.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m2_ultra.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m3.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m3_max.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m3_pro.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m3_ultra.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m4.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m4_max.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m4_pro.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m5.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m5_max.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m5_pro.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m5_ultra.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_m6.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/apple/apple_silicon.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/intel/bmg.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/intel/dg2.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/intel/lnl.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/intel/pvc.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/nvidia/ampere.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/nvidia/hopper.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/devices/nvidia/volta.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/faults.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/host_memory.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/install_help.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/install_steps.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/launcher_contract.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/level_zero_driver.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/metal_device.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/process_memory.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/backend/triton_ext_driver.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/dtype/__init__.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/dtype/convert.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/dtype/dtypes.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/dtype/itemsize.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/dtype/nbx_dtype.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/dtype/operands.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/dtype/outputs.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/dtype/policy.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/dtype/policy.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/dtype/promotion.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/host.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/io/__init__.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/__init__.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/allocator.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/arena.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/device_memory.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/device_transfer.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/layout.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/memory_pool.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/metal.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/oom_advice.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/pointer_tables.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/pool.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/shadow.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/slab.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/trace_replay.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/traces/sana-video-2b-720p.16g.2026-11-02.tsv +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/memory/vmm.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/__init__.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/_autotune_policy.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/_common.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/_configs.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/_cost.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/abs.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/adaptive_avg_pool2d.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/add.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/addcdiv.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/addcmul.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/addmv_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/addr.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/all_reduce.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/amax.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/any_reduce.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/arange_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/argmax.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/argmin.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/atan2.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/attention_wrappers.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/autotune_bucket.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/autotune_cache.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/autotune_refusals.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/autotune_settings.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/avg_pool2d.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/baddbmm_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/batch_norm.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/binary_strided.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/bitwise_and.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/bitwise_left_shift.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/bitwise_not.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/bitwise_or.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/bitwise_right_shift.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/bucketize.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/cat_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/celu.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/certified_index.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/clamp.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/clamp_min.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/conv2d.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/conv2d_m8n8k4.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/conv_depthwise2d.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/conv_transpose2d.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/conv_wrappers.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/copy.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/copy_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/cos.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/count_nonzero.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/cross_entropy.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/cummax.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/cummin.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/cumsum.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/decode_attn_vec.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/depthwise_conv2d.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/dequant_gemv.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/dft.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/dispatch.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/div.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/dot_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/dropout.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/dtype_convert.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/elementwise_launch.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/elementwise_wrappers.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/elu.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/embedding.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/eq.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/erf.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/exp.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/exp2.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/fft_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/fill_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/flash_attention.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/flash_attention_m8n8k4.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/flash_decode.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/flip_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/floor.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/full_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/fused_moe.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/fused_moe_m8n8k4.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/fused_upsample_conv.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/gather_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/ge.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/gelu.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/gemv_vec.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/glu.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/grid_sampler.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/group_norm_tiled.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/groupnorm.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/gt.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/hardsigmoid.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/hardswish.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/im2col.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/index_add.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/index_put_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/index_select.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/index_wrappers.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/isfinite.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/isinf.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/isnan.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/launch_keys.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/launch_observer.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/layernorm.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/le.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/leaky_relu.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/lerp.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/linalg_wrappers.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/linspace_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/log.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/log_sigmoid.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/logical_and.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/logical_not.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/logical_or.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/logical_xor.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/loss_wrappers.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/lt.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/masked_fill.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/matmul.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/matmul_m8n8k4.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/max_pool2d.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/max_pool3d.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/max_reduce.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/maximum.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/mean.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/min_reduce.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/minimum.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/mish.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/mma_m8n8k4.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/moe_align.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/moe_decode_vec.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/moe_device_residency.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/moe_wrappers.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/mse_loss.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/mul.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/nan_to_num.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/ne.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/neg.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/nllloss.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/nonzero.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/nonzero_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/norm_wrappers.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/ones_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/oracles/__init__.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/oracles/conv2d_fp64.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/pad_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/paged_decode_attn.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/pixel_shuffle.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/pixel_unshuffle.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/pow.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/prod.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/rand_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/random_wrappers.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/reciprocal.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/reduction_wrappers.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/relu.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/remainder.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/repeat_interleave.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/repeat_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/residual_chain.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/rmsnorm.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/rope.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/rsqrt.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/scaled_softmax.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/scatter_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/screen_oracle.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/selu.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/shape_wrappers.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/sigmoid.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/silu.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/sin.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/softmax.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/softplus.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/sort_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/spectral_wrappers.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/sqrt.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/stack_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/std.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/strided_copy.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/sub.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/sum.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/tan.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/tanh.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/threshold.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/tiling.yml +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/tiling_policy.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/tiling_sizes.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/topk.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/trace_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/tril.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/triu.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/unfold_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/unique_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/upsample_bilinear2d.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/upsample_nearest2d.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/upsample_nearest3d.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/var.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/vector_norm.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/weight_norm.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/where.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/wrappers.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/ops/zeros_op.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/quant/__init__.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/quant/quantized_tensor.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/random/__init__.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/random/mt_randn.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/random/rng_pin.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/random/rng_stream.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/random/seeded_draw.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/shape/__init__.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/src/nbxtensor/tensor.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_a_small_tensor_never_pins_a_large_block.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_a_sweep_refused_everywhere_says_so.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_a_triton_kernel_compiles_for_amd_and_launches_through_hip.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_allocator_interceptor.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_array_api_promotion.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_cpu_pool.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_device_facts.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_device_files.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_device_memory.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_dtype_convert.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_dtype_outputs.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_dtype_promotion.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_host.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_io_bf16_split.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_io_read_rate.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_nbx_dtype.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_no_environment_switch_changes_a_kernel.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_ops_cost.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_policy.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_readme.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_shape.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_the_backend_is_the_card_on_the_machine.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_the_compiler_key_is_prewarmed.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_the_hip_driver_keeps_the_launch_contract.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_the_launcher_refuses_a_backend_it_has_no_driver_for.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_the_level_zero_backend_keeps_its_contracts.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_the_malloc_trace_names_the_wrapper.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_the_metal_dispatch_facts_are_declared_or_refused.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_third_party_notices.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tests/test_version.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tools/device_key_census.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tools/device_key_trace.py +0 -0
- {nbxtensor-0.0.3 → nbxtensor-0.0.5}/tools/scatter_scan.py +0 -0
|
@@ -7,6 +7,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.0.5] - 2026-11-07
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **The library runs on Windows**: weights are read at their offset without `os.preadv` (Windows' `ReadFile` with an
|
|
14
|
+
OVERLAPPED offset), the BLAS's thread control is found beside numpy (`numpy.libs`) instead of through /proc, and the
|
|
15
|
+
GPU libraries are opened by their Windows names (nvcuda.dll, cudart64_12.dll from the runtime wheel's `bin`, nvml.dll,
|
|
16
|
+
amdhip64_6.dll, ze_loader.dll, OpenCL.dll). Written and tested with Windows simulated: the project has no Windows
|
|
17
|
+
machine yet.
|
|
18
|
+
- **`python -m nbxtensor doctor` on a Mac without Triton exits 1**: it named the fix and exited 0, so a script could
|
|
19
|
+
not tell that nothing could run yet.
|
|
20
|
+
- **The library imports on Windows**: its page size came from `os.sysconf`, which Windows does not have; and the code
|
|
21
|
+
generator's identity now reads a backend's files as `/` paths with its `.pyd` and `.dll` binaries, so the same code
|
|
22
|
+
has the same identity on every system.
|
|
23
|
+
- **A certified setting that is not served says why**: where the directory holds a key proven under another code
|
|
24
|
+
generator than the running one, the line named a memory class that matched ("certified for 18 GB, this card is
|
|
25
|
+
18 GB, not served"); it now names both generators and the re-proof command. A setting proven on another memory class
|
|
26
|
+
is still said as such.
|
|
27
|
+
|
|
28
|
+
## [0.0.4] - 2026-11-07
|
|
29
|
+
|
|
30
|
+
### Added
|
|
31
|
+
- **Triton for the Apple GPU in one command**: `python -m nbxtensor install-metal` installs the Metal wheels of the
|
|
32
|
+
project's fork NeuroBrix/triton-ext (Triton built with triton-ext, and imperatormk's AppleGPU backend as
|
|
33
|
+
`nbx-triton-apple`, triton-lang/triton-ext#126), each by the release URL and sha256 written in the library,
|
|
34
|
+
through pip with `--no-deps --require-hashes --no-index` — never an extra index nor a package name resolved on PyPI. The
|
|
35
|
+
wheels are for Python 3.12 and macOS 15 or later (release apple-v0.1.0+triton3.8.0); it refuses by name off an
|
|
36
|
+
Apple-silicon Mac, on another Python, or below the macOS the wheels are built for. `python -m nbxtensor doctor` on a Mac
|
|
37
|
+
without it says so and names the command; the Metal backend's refusal names it too. On a Mac, nbxtensor depends on
|
|
38
|
+
`pyobjc-framework-Metal`, through which it opens the Metal device; without it the run fell to a CPU profile and was
|
|
39
|
+
refused for triton-cpu, it is now refused by name with its install line.
|
|
40
|
+
|
|
41
|
+
### Fixed
|
|
42
|
+
- **nbxtensor installs on a Mac**: it depended on `triton` on every platform, and PyPI publishes no Triton for macOS, so
|
|
43
|
+
`pip install nbxtensor` — and with it the NeuroBrix engine, even its PyTorch engine on MPS — could not resolve on a
|
|
44
|
+
clean macOS environment. Triton is now a dependency where PyPI has it; on a Mac it is built from source with its Metal
|
|
45
|
+
backend (the README's install), and the library says by name what to build when it is absent.
|
|
46
|
+
|
|
10
47
|
## [0.0.3] - 2026-11-06
|
|
11
48
|
|
|
12
49
|
### Fixed
|
|
@@ -143,7 +180,9 @@ memory; the fix is in test).
|
|
|
143
180
|
- **`flash_decode_split_kernel` and its route**: armed only by an environment switch (`NBX_FLASH_DECODE`, with `NBX_FD_BLOCK_N` and `NBX_FD_SEG`) and measured slower than the vector decode kernels; `flash_decode.py` keeps the fixed-order reduce they share.
|
|
144
181
|
- **`conv1d_forward_kernel`**: launched by no route (a 1-D convolution runs through `conv2d`).
|
|
145
182
|
|
|
146
|
-
[Unreleased]: https://github.com/NeuroBrix/nbxtensor/compare/v0.0.
|
|
183
|
+
[Unreleased]: https://github.com/NeuroBrix/nbxtensor/compare/v0.0.5...HEAD
|
|
184
|
+
[0.0.5]: https://github.com/NeuroBrix/nbxtensor/compare/v0.0.4...v0.0.5
|
|
185
|
+
[0.0.4]: https://github.com/NeuroBrix/nbxtensor/compare/v0.0.3...v0.0.4
|
|
147
186
|
[0.0.3]: https://github.com/NeuroBrix/nbxtensor/compare/v0.0.2...v0.0.3
|
|
148
187
|
[0.0.2]: https://github.com/NeuroBrix/nbxtensor/compare/v0.0.1...v0.0.2
|
|
149
188
|
[0.0.1]: https://github.com/NeuroBrix/nbxtensor/releases/tag/v0.0.1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: nbxtensor
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.5
|
|
4
4
|
Summary: Run AI models without PyTorch: tensors, Triton kernels, planned memory and certified tuning, wherever Triton runs — NVIDIA, AMD, Intel and Apple GPUs.
|
|
5
5
|
Project-URL: Homepage, https://github.com/NeuroBrix/nbxtensor
|
|
6
6
|
Project-URL: Source, https://github.com/NeuroBrix/nbxtensor
|
|
@@ -12,8 +12,9 @@ License-File: LICENSE
|
|
|
12
12
|
Requires-Python: >=3.10
|
|
13
13
|
Requires-Dist: numpy
|
|
14
14
|
Requires-Dist: nvidia-cuda-runtime-cu12; platform_system == 'Linux'
|
|
15
|
+
Requires-Dist: pyobjc-framework-metal; platform_system == 'Darwin'
|
|
15
16
|
Requires-Dist: pyyaml
|
|
16
|
-
Requires-Dist: triton
|
|
17
|
+
Requires-Dist: triton; platform_system != 'Darwin'
|
|
17
18
|
Provides-Extra: test
|
|
18
19
|
Requires-Dist: pytest; extra == 'test'
|
|
19
20
|
Description-Content-Type: text/markdown
|
|
@@ -24,7 +25,7 @@ Description-Content-Type: text/markdown
|
|
|
24
25
|
|
|
25
26
|
Run AI models without PyTorch, on any GPU Triton supports: tensors, Triton kernels, planned memory and certified tuning.
|
|
26
27
|
|
|
27
|
-
Runs wherever Triton runs — NVIDIA, AMD, Intel and Apple Silicon GPUs. Inference first; training is not in this
|
|
28
|
+
Runs wherever Triton runs — NVIDIA, AMD, Intel and Apple Silicon GPUs, on Linux, Windows and macOS. Inference first; training is not in this
|
|
28
29
|
release. Found a bug on your hardware? [Open an issue](https://github.com/NeuroBrix/nbxtensor/issues) — we fix fast.
|
|
29
30
|
|
|
30
31
|
[](https://pypi.org/project/nbxtensor/)
|
|
@@ -137,7 +138,7 @@ What changed from one version to the next — added, changed, fixed, removed —
|
|
|
137
138
|
nbxtensor never needs torch: it is not a dependency, not even an optional one, and the library and its kernels run in
|
|
138
139
|
an environment where torch is not installed (proven on Metal, 2026-10-29: `tools/torch_free_proof.py` records every
|
|
139
140
|
attempt to import torch, caught ones included, and recorded none). Python 3.10 or later; its dependencies are numpy,
|
|
140
|
-
pyyaml and Triton.
|
|
141
|
+
pyyaml and Triton (on a Mac, `pyobjc-framework-Metal` and the Triton `install-metal` brings).
|
|
141
142
|
|
|
142
143
|
```
|
|
143
144
|
pip install nbxtensor
|
|
@@ -155,14 +156,21 @@ install commands when one is not.
|
|
|
155
156
|
|
|
156
157
|
**From the NeuroBrix repository** (contributors): `pip install -e nbxtensor`.
|
|
157
158
|
|
|
158
|
-
**macOS, Apple silicon (Metal).** PyPI publishes no Triton for macOS
|
|
159
|
-
|
|
159
|
+
**macOS, Apple silicon (Metal).** PyPI publishes no Triton for macOS. `install-metal` installs NeuroBrix's Triton
|
|
160
|
+
build for Apple GPUs, [NeuroBrix/triton-ext](https://github.com/NeuroBrix/triton-ext) (Triton built with
|
|
161
|
+
`TRITON_EXT_ENABLED=1` and the `nbx-triton-apple` backend; upstream:
|
|
162
|
+
[triton-lang/triton-ext#126](https://github.com/triton-lang/triton-ext/pull/126)); each wheel is checked against the
|
|
163
|
+
sha256 written in the library (Python 3.12, macOS 15 or later):
|
|
160
164
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
```
|
|
166
|
+
pip install nbxtensor
|
|
167
|
+
python -m nbxtensor install-metal
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Xcode's Metal toolchain is the other requirement (`xcrun metal` must find the real compiler, not Xcode's placeholder:
|
|
171
|
+
`TOOLCHAINS=Metal`); `python -m nbxtensor doctor` says what is missing. To build Triton and its Metal backend yourself
|
|
172
|
+
instead: Triton (github.com/triton-lang/triton) built with `TRITON_EXT_ENABLED=1`, then triton-ext's `backend/AppleGPU`
|
|
173
|
+
installed into the same environment.
|
|
166
174
|
|
|
167
175
|
`nbxtensor.dtype` and `nbxtensor.shape` need neither a device nor Triton.
|
|
168
176
|
|
|
@@ -492,7 +500,7 @@ with the tensor class (API.md §4).
|
|
|
492
500
|
|
|
493
501
|
## Versions
|
|
494
502
|
|
|
495
|
-
The first publication was **0.0.1**; this is **0.0.
|
|
503
|
+
The first publication was **0.0.1**; this is **0.0.5**. Each fix published after it increments the number (0.0.6,
|
|
496
504
|
…), with no alpha or beta label. The rewrite of the core in Rust will be **2.0.0**. `nbxtensor.__version__` is the
|
|
497
505
|
installed version.
|
|
498
506
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Run AI models without PyTorch, on any GPU Triton supports: tensors, Triton kernels, planned memory and certified tuning.
|
|
6
6
|
|
|
7
|
-
Runs wherever Triton runs — NVIDIA, AMD, Intel and Apple Silicon GPUs. Inference first; training is not in this
|
|
7
|
+
Runs wherever Triton runs — NVIDIA, AMD, Intel and Apple Silicon GPUs, on Linux, Windows and macOS. Inference first; training is not in this
|
|
8
8
|
release. Found a bug on your hardware? [Open an issue](https://github.com/NeuroBrix/nbxtensor/issues) — we fix fast.
|
|
9
9
|
|
|
10
10
|
[](https://pypi.org/project/nbxtensor/)
|
|
@@ -117,7 +117,7 @@ What changed from one version to the next — added, changed, fixed, removed —
|
|
|
117
117
|
nbxtensor never needs torch: it is not a dependency, not even an optional one, and the library and its kernels run in
|
|
118
118
|
an environment where torch is not installed (proven on Metal, 2026-10-29: `tools/torch_free_proof.py` records every
|
|
119
119
|
attempt to import torch, caught ones included, and recorded none). Python 3.10 or later; its dependencies are numpy,
|
|
120
|
-
pyyaml and Triton.
|
|
120
|
+
pyyaml and Triton (on a Mac, `pyobjc-framework-Metal` and the Triton `install-metal` brings).
|
|
121
121
|
|
|
122
122
|
```
|
|
123
123
|
pip install nbxtensor
|
|
@@ -135,14 +135,21 @@ install commands when one is not.
|
|
|
135
135
|
|
|
136
136
|
**From the NeuroBrix repository** (contributors): `pip install -e nbxtensor`.
|
|
137
137
|
|
|
138
|
-
**macOS, Apple silicon (Metal).** PyPI publishes no Triton for macOS
|
|
139
|
-
|
|
138
|
+
**macOS, Apple silicon (Metal).** PyPI publishes no Triton for macOS. `install-metal` installs NeuroBrix's Triton
|
|
139
|
+
build for Apple GPUs, [NeuroBrix/triton-ext](https://github.com/NeuroBrix/triton-ext) (Triton built with
|
|
140
|
+
`TRITON_EXT_ENABLED=1` and the `nbx-triton-apple` backend; upstream:
|
|
141
|
+
[triton-lang/triton-ext#126](https://github.com/triton-lang/triton-ext/pull/126)); each wheel is checked against the
|
|
142
|
+
sha256 written in the library (Python 3.12, macOS 15 or later):
|
|
140
143
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
```
|
|
145
|
+
pip install nbxtensor
|
|
146
|
+
python -m nbxtensor install-metal
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Xcode's Metal toolchain is the other requirement (`xcrun metal` must find the real compiler, not Xcode's placeholder:
|
|
150
|
+
`TOOLCHAINS=Metal`); `python -m nbxtensor doctor` says what is missing. To build Triton and its Metal backend yourself
|
|
151
|
+
instead: Triton (github.com/triton-lang/triton) built with `TRITON_EXT_ENABLED=1`, then triton-ext's `backend/AppleGPU`
|
|
152
|
+
installed into the same environment.
|
|
146
153
|
|
|
147
154
|
`nbxtensor.dtype` and `nbxtensor.shape` need neither a device nor Triton.
|
|
148
155
|
|
|
@@ -472,7 +479,7 @@ with the tensor class (API.md §4).
|
|
|
472
479
|
|
|
473
480
|
## Versions
|
|
474
481
|
|
|
475
|
-
The first publication was **0.0.1**; this is **0.0.
|
|
482
|
+
The first publication was **0.0.1**; this is **0.0.5**. Each fix published after it increments the number (0.0.6,
|
|
476
483
|
…), with no alpha or beta label. The rewrite of the core in Rust will be **2.0.0**. `nbxtensor.__version__` is the
|
|
477
484
|
installed version.
|
|
478
485
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "nbxtensor"
|
|
7
|
-
version = "0.0.
|
|
7
|
+
version = "0.0.5"
|
|
8
8
|
description = "Run AI models without PyTorch: tensors, Triton kernels, planned memory and certified tuning, wherever Triton runs — NVIDIA, AMD, Intel and Apple GPUs."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "Apache-2.0" }
|
|
@@ -16,7 +16,11 @@ authors = [{ name = "NeuroBrix" }]
|
|
|
16
16
|
# On Linux the CUDA runtime library its CUDA backend opens (libcudart.so.12), which the NVIDIA driver does not ship: a clean
|
|
17
17
|
# machine with only the driver found no GPU runtime and the engine read the card as CPU-only (the stable's install test,
|
|
18
18
|
# 2026-11-05). On a machine without an NVIDIA card it is a library nothing opens.
|
|
19
|
-
|
|
19
|
+
# Triton on every platform PyPI publishes it for; macOS has none (the Metal Triton is built from source, with triton-ext's
|
|
20
|
+
# AppleGPU backend — the README's install), so a plain "triton" made the library uninstallable on a Mac (2026-11-06).
|
|
21
|
+
# On a Mac the Metal device is opened through pyobjc's Metal framework; Triton for Metal comes from `install-metal`.
|
|
22
|
+
dependencies = ["numpy", "triton; platform_system != 'Darwin'", "pyyaml", "nvidia-cuda-runtime-cu12; platform_system == 'Linux'",
|
|
23
|
+
"pyobjc-framework-Metal; platform_system == 'Darwin'"]
|
|
20
24
|
|
|
21
25
|
[project.urls]
|
|
22
26
|
Homepage = "https://github.com/NeuroBrix/nbxtensor"
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""`python -m nbxtensor doctor`: which GPU backend this machine runs, and for every NVIDIA, AMD or Intel GPU on its PCI
|
|
2
|
+
bus whether the runtime library and the Triton backend it needs are installed — with the vendor's install steps when
|
|
3
|
+
one is missing (`backend.install_help`); on an Apple-silicon Mac, whether Triton for Metal is installed.
|
|
4
|
+
`python -m nbxtensor install-metal [--dry-run]`: install Triton for the Apple GPU from this version's release
|
|
5
|
+
(`backend.install_metal`)."""
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def doctor() -> int:
|
|
10
|
+
from nbxtensor.backend import install_help, runtime
|
|
11
|
+
from nbxtensor.backend.metal_backend import is_apple_silicon, triton_metal_available
|
|
12
|
+
if is_apple_silicon() and not triton_metal_available():
|
|
13
|
+
print("Apple GPU found; Triton for Metal not installed — run: python -m nbxtensor install-metal")
|
|
14
|
+
return 1 # nothing can run yet: a script reads it from the exit status
|
|
15
|
+
try:
|
|
16
|
+
backend = runtime.gpu_backend()
|
|
17
|
+
print(f"backend in force: {backend}" + (" (the Apple GPU, through Metal)" if backend == "metal" else ""))
|
|
18
|
+
except RuntimeError as exc:
|
|
19
|
+
backend = None
|
|
20
|
+
print(f"backend in force: none — {str(exc).splitlines()[0]}")
|
|
21
|
+
if backend != "metal" or install_help.pci_gpus(): # a Mac has no PCI GPU to report: nothing to install there
|
|
22
|
+
print(install_help.report())
|
|
23
|
+
return 0
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def main(argv=None) -> int:
|
|
27
|
+
argv = sys.argv[1:] if argv is None else argv
|
|
28
|
+
if argv[:1] == ["doctor"]:
|
|
29
|
+
return doctor()
|
|
30
|
+
if argv[:1] == ["install-metal"] and set(argv[1:]) <= {"--dry-run"}:
|
|
31
|
+
import nbxtensor
|
|
32
|
+
from nbxtensor.backend import install_metal
|
|
33
|
+
return install_metal.main(nbxtensor.__version__, dry_run="--dry-run" in argv[1:])
|
|
34
|
+
print("usage: python -m nbxtensor doctor | install-metal [--dry-run]", file=sys.stderr)
|
|
35
|
+
return 2
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
if __name__ == "__main__":
|
|
39
|
+
raise SystemExit(main())
|
|
@@ -20,6 +20,7 @@ from __future__ import annotations
|
|
|
20
20
|
import ctypes
|
|
21
21
|
import functools
|
|
22
22
|
import platform
|
|
23
|
+
import sys
|
|
23
24
|
from pathlib import Path
|
|
24
25
|
from typing import Optional, Tuple
|
|
25
26
|
|
|
@@ -33,6 +34,16 @@ _OPENBLAS_GET = ("scipy_openblas_get_num_threads64_", "scipy_openblas_get_num_th
|
|
|
33
34
|
|
|
34
35
|
|
|
35
36
|
def _loaded_openblas() -> Optional[str]:
|
|
37
|
+
if sys.platform == "win32":
|
|
38
|
+
# no /proc on Windows: numpy's wheel ships its OpenBLAS beside the package (`numpy.libs`, older wheels
|
|
39
|
+
# `numpy/.libs`), loaded with numpy; ctypes opening the same path returns the module already in the process
|
|
40
|
+
import numpy
|
|
41
|
+
root = Path(numpy.__file__).resolve().parent
|
|
42
|
+
for d in (root.parent / "numpy.libs", root / ".libs"):
|
|
43
|
+
hits = sorted(d.glob("*openblas*.dll")) if d.is_dir() else []
|
|
44
|
+
if hits:
|
|
45
|
+
return str(hits[0])
|
|
46
|
+
return None
|
|
36
47
|
maps = Path("/proc/self/maps")
|
|
37
48
|
if not maps.is_file():
|
|
38
49
|
return None
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
"""`python -m nbxtensor install-metal`: install Triton for the Apple GPU — the project's own wheels (Triton built with
|
|
2
|
+
TRITON_EXT_ENABLED=1, and triton-ext's AppleGPU backend as `nbx-triton-apple`), downloaded from the release of the
|
|
3
|
+
project's fork, github.com/NeuroBrix/triton-ext. The AppleGPU backend is imperatormk's (triton-lang/triton-ext#126).
|
|
4
|
+
|
|
5
|
+
PyPI publishes no Triton for macOS, so a Mac has no Triton after `pip install nbxtensor`. The wheels are fetched from
|
|
6
|
+
the URLs written below, each checked against the sha256 written beside it (`pip --require-hashes`), with `--no-deps`:
|
|
7
|
+
never through an extra index and never by a package name pip would look up on PyPI — anyone can publish a package
|
|
8
|
+
named "triton-apple-backend" there (dependency confusion). A machine other than an Apple-silicon Mac, or a Python the
|
|
9
|
+
table does not cover, is refused by name.
|
|
10
|
+
"""
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
import platform
|
|
15
|
+
import re
|
|
16
|
+
import subprocess
|
|
17
|
+
import sys
|
|
18
|
+
import tempfile
|
|
19
|
+
from typing import List, Tuple
|
|
20
|
+
|
|
21
|
+
#: the only place the wheels are fetched from: the releases of the project's fork of triton-ext
|
|
22
|
+
RELEASES = "https://github.com/NeuroBrix/triton-ext/releases/download/"
|
|
23
|
+
|
|
24
|
+
#: the Metal wheels per CPython tag: (URL of the release asset, sha256 of the file), Triton first; a tag absent here is
|
|
25
|
+
#: refused by name. The fork's release apple-v0.1.0+triton3.8.0 (2026-11-07): Triton 3.8.0 (git 4a15f415) built with
|
|
26
|
+
#: TRITON_EXT_ENABLED=1 and nbx-triton-apple 0.1.0, both macOS 15.0 arm64 (the prebuilt LLVM Triton links is minos 15.0);
|
|
27
|
+
#: sha256 read on the downloaded assets.
|
|
28
|
+
METAL_WHEELS: dict = {
|
|
29
|
+
"cp312": (
|
|
30
|
+
(RELEASES + "apple-v0.1.0%2Btriton3.8.0/triton-3.8.0%2Bgit4a15f415.nbx1-cp312-cp312-macosx_15_0_arm64.whl",
|
|
31
|
+
"b9084dc93ae7f1468062a03e713d49c9add9a1c9a609fae753a7b32a13b7a223"),
|
|
32
|
+
(RELEASES + "apple-v0.1.0%2Btriton3.8.0/nbx_triton_apple-0.1.0-cp312-cp312-macosx_15_0_arm64.whl",
|
|
33
|
+
"b9ed95c983b220b1fbf1300481b1e2f52a0435c10ee618ef7ccf60a132fe263c"),
|
|
34
|
+
),
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class InstallMetalRefused(RuntimeError):
|
|
39
|
+
"""This machine or this Python has no Metal wheels in this version's table."""
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _python_tag() -> str:
|
|
43
|
+
return f"cp{sys.version_info.major}{sys.version_info.minor}"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def wheels(version: str) -> List[Tuple[str, str]]:
|
|
47
|
+
"""[(url, sha256)] of the wheels this machine installs, or a named refusal."""
|
|
48
|
+
if not (platform.system() == "Darwin" and platform.machine() == "arm64"):
|
|
49
|
+
raise InstallMetalRefused(
|
|
50
|
+
f"install-metal installs Triton for the Apple GPU and runs on an Apple-silicon Mac only (this machine: "
|
|
51
|
+
f"{platform.system()} {platform.machine()}). Elsewhere Triton comes from PyPI with nbxtensor.")
|
|
52
|
+
tag = _python_tag()
|
|
53
|
+
if tag not in METAL_WHEELS:
|
|
54
|
+
covered = ", ".join(sorted(METAL_WHEELS)) or "none yet"
|
|
55
|
+
raise InstallMetalRefused(
|
|
56
|
+
f"nbxtensor {version} carries no Metal wheels for Python {sys.version_info.major}.{sys.version_info.minor} "
|
|
57
|
+
f"({tag}); covered: {covered}.")
|
|
58
|
+
entries = list(METAL_WHEELS[tag])
|
|
59
|
+
need = max(_min_macos(url) for url, _sha in entries)
|
|
60
|
+
have = _macos_version()
|
|
61
|
+
if have < need:
|
|
62
|
+
raise InstallMetalRefused(
|
|
63
|
+
f"macOS {'.'.join(map(str, need))} required for now: the Metal wheels of nbxtensor {version} are built for "
|
|
64
|
+
f"macOS {'.'.join(map(str, need))} and later (this Mac: macOS {'.'.join(map(str, have))}).")
|
|
65
|
+
return entries
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _min_macos(url: str) -> Tuple[int, int]:
|
|
69
|
+
"""The lowest macOS a wheel installs on, read from its platform tag (`macosx_15_0_arm64` -> (15, 0))."""
|
|
70
|
+
m = re.search(r"-macosx_(\d+)_(\d+)_arm64\.whl$", url)
|
|
71
|
+
if m is None:
|
|
72
|
+
raise InstallMetalRefused(f"not a macOS arm64 wheel: {url}")
|
|
73
|
+
return int(m.group(1)), int(m.group(2))
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _macos_version() -> Tuple[int, int]:
|
|
77
|
+
parts = [int(p) for p in (platform.mac_ver()[0] or "0").split(".")[:2]]
|
|
78
|
+
return (parts + [0])[0], (parts + [0])[1]
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def pip_command(requirements: str) -> List[str]:
|
|
82
|
+
"""pip on this interpreter, from a requirements file of URLs and hashes only: no index is read, nothing else."""
|
|
83
|
+
return [sys.executable, "-m", "pip", "install", "--no-deps", "--require-hashes", "--no-index", "-r", requirements]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def requirements_text(entries: List[Tuple[str, str]]) -> str:
|
|
87
|
+
return "".join(f"{url} --hash=sha256:{sha}\n" for url, sha in entries)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def main(version: str, dry_run: bool = False) -> int:
|
|
91
|
+
try:
|
|
92
|
+
entries = wheels(version)
|
|
93
|
+
except InstallMetalRefused as exc:
|
|
94
|
+
print(f"install-metal: {exc}", file=sys.stderr)
|
|
95
|
+
return 1
|
|
96
|
+
text = requirements_text(entries)
|
|
97
|
+
if dry_run:
|
|
98
|
+
print(text, end="")
|
|
99
|
+
print(" ".join(pip_command("<these lines>")))
|
|
100
|
+
return 0
|
|
101
|
+
fd, path = tempfile.mkstemp(prefix="nbxtensor-metal-", suffix=".txt")
|
|
102
|
+
try:
|
|
103
|
+
with os.fdopen(fd, "w") as f:
|
|
104
|
+
f.write(text)
|
|
105
|
+
return subprocess.call(pip_command(path))
|
|
106
|
+
finally:
|
|
107
|
+
os.unlink(path)
|
|
@@ -488,14 +488,15 @@ class CudaDriver(_ModuleDriver):
|
|
|
488
488
|
|
|
489
489
|
def __init__(self) -> None:
|
|
490
490
|
lib = None
|
|
491
|
-
|
|
491
|
+
from nbxtensor.backend.libnames import CUDA_DRIVER
|
|
492
|
+
for name in CUDA_DRIVER:
|
|
492
493
|
try:
|
|
493
494
|
lib = ctypes.CDLL(name)
|
|
494
495
|
break
|
|
495
496
|
except OSError:
|
|
496
497
|
continue
|
|
497
498
|
if lib is None:
|
|
498
|
-
raise RuntimeError("NeuroBrix launcher:
|
|
499
|
+
raise RuntimeError(f"NeuroBrix launcher: the CUDA driver library not found (tried {CUDA_DRIVER})")
|
|
499
500
|
self.lib = lib
|
|
500
501
|
self._check(lib.cuInit(0), "cuInit")
|
|
501
502
|
# ctypes infers the type of every argument at every call unless the signature is
|
|
@@ -27,7 +27,7 @@ import threading
|
|
|
27
27
|
from typing import Dict, Optional, Tuple
|
|
28
28
|
|
|
29
29
|
#: the Level Zero loader (`libze1` on Ubuntu), tried in order
|
|
30
|
-
|
|
30
|
+
from nbxtensor.backend.libnames import LEVEL_ZERO as LIBS # noqa: E402
|
|
31
31
|
|
|
32
32
|
# ZE_STRUCTURE_TYPE_* (ze.py)
|
|
33
33
|
_ST_DRIVER_PROPERTIES, _ST_DEVICE_COMPUTE, _ST_QUEUE_GROUP, _ST_DEVICE_MEMORY = 0x1, 0x4, 0x6, 0x7
|
|
@@ -558,7 +558,7 @@ def runtime() -> LevelZeroRuntime:
|
|
|
558
558
|
|
|
559
559
|
|
|
560
560
|
#: the OpenCL ICD loader (`ocl-icd-libopencl1`; Intel's runtime registers itself in it with intel-opencl-icd)
|
|
561
|
-
|
|
561
|
+
from nbxtensor.backend.libnames import OPENCL as OPENCL_LIBS # noqa: E402
|
|
562
562
|
_CL_DEVICE_TYPE_GPU, _CL_DEVICE_VENDOR_ID, _CL_DEVICE_EXTENSIONS, _CL_DEVICE_ID_INTEL = 4, 0x1001, 0x1030, 0x4251
|
|
563
563
|
|
|
564
564
|
#: target facts Intel's compiler reads (intel/backend/compiler.py `parse_target`) -> the OpenCL extension that states
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""The vendor libraries the backends open through ctypes, named as each system names them: a shared object on Linux
|
|
2
|
+
(`libcuda.so.1`), a DLL on Windows (`nvcuda.dll`). Read by the backend tables (`backend.runtime`), the launch driver
|
|
3
|
+
(`backend.launcher`), the graph replay (`backend.replay_graph`), the expandable pool (`memory.vmm`) and Level Zero
|
|
4
|
+
(`backend.level_zero`). Windows' names are the vendors' (NVIDIA: nvcuda.dll in System32 with the driver, cudart64_12.dll
|
|
5
|
+
in the CUDA runtime wheel's `bin`, nvml.dll; AMD HIP SDK: amdhip64_6.dll; Intel: ze_loader.dll, OpenCL.dll).
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
|
|
11
|
+
WINDOWS = sys.platform == "win32"
|
|
12
|
+
|
|
13
|
+
#: the CUDA runtime, after the one the environment's wheel carries (`runtime._environment_runtime_libs`)
|
|
14
|
+
CUDA_RUNTIME = ["cudart64_12.dll", "cudart64_110.dll"] if WINDOWS else ["libcudart.so", "libcudart.so.12", "libcudart.so.11.0"]
|
|
15
|
+
#: the CUDA runtime file inside the nvidia-cuda-runtime wheel, and the wheel's directory that holds it
|
|
16
|
+
CUDA_RUNTIME_IN_WHEEL = ("bin", "cudart64_12.dll") if WINDOWS else ("lib", "libcudart.so.12")
|
|
17
|
+
#: the CUDA driver API
|
|
18
|
+
CUDA_DRIVER = ["nvcuda.dll"] if WINDOWS else ["libcuda.so.1", "libcuda.so"]
|
|
19
|
+
#: NVIDIA's management library
|
|
20
|
+
NVML = ["nvml.dll"] if WINDOWS else ["libnvidia-ml.so.1", "libnvidia-ml.so"]
|
|
21
|
+
#: the HIP runtime
|
|
22
|
+
HIP_RUNTIME = ["amdhip64_6.dll", "amdhip64.dll"] if WINDOWS else ["libamdhip64.so", "libamdhip64.so.5"]
|
|
23
|
+
#: the Level Zero loader
|
|
24
|
+
LEVEL_ZERO = ["ze_loader.dll"] if WINDOWS else ["libze_loader.so.1", "libze_loader.so"]
|
|
25
|
+
#: the OpenCL ICD loader
|
|
26
|
+
OPENCL = ["OpenCL.dll"] if WINDOWS else ["libOpenCL.so.1", "libOpenCL.so"]
|
|
@@ -139,6 +139,16 @@ class TritonMetalShaderCompilerMissingError(TritonMetalNotInstalledError):
|
|
|
139
139
|
"""
|
|
140
140
|
|
|
141
141
|
|
|
142
|
+
class TritonMetalBindingMissingError(TritonMetalNotInstalledError):
|
|
143
|
+
"""Raised when Triton for Metal is installed but pyobjc's Metal binding, through which the device is opened, is
|
|
144
|
+
not: the device cannot be opened, and the run would otherwise fall to a CPU profile."""
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def metal_binding_available() -> bool:
|
|
148
|
+
"""pyobjc's Metal binding, through which the device is opened, is installed (asked without importing it)."""
|
|
149
|
+
return importlib.util.find_spec("Metal") is not None
|
|
150
|
+
|
|
151
|
+
|
|
142
152
|
def is_apple_silicon() -> bool:
|
|
143
153
|
"""True on an Apple-Silicon Mac."""
|
|
144
154
|
return platform.system() == "Darwin" and platform.machine() == "arm64"
|
|
@@ -573,27 +583,25 @@ def ensure_triton_metal_or_raise() -> None:
|
|
|
573
583
|
|
|
574
584
|
if not triton_metal_available():
|
|
575
585
|
raise TritonMetalNotInstalledError(
|
|
576
|
-
"The --triton engine needs
|
|
577
|
-
"none is installed
|
|
578
|
-
"
|
|
579
|
-
"
|
|
580
|
-
"exists:\n"
|
|
581
|
-
" pip install triton-msl (MIT; needs Triton 3.7+ built "
|
|
582
|
-
"with TRITON_EXT_ENABLED=1)\n"
|
|
586
|
+
"The --triton engine needs Triton for the Apple GPU (Triton with "
|
|
587
|
+
"triton-ext's AppleGPU backend), and none is installed. PyPI publishes "
|
|
588
|
+
"no Triton for macOS; nbxtensor's release carries it:\n"
|
|
589
|
+
" python -m nbxtensor install-metal\n"
|
|
583
590
|
"\n"
|
|
584
|
-
"
|
|
585
|
-
"
|
|
586
|
-
"supply-chain surface you did not consent to, and it fails "
|
|
587
|
-
"confusingly on\n"
|
|
588
|
-
"air-gapped machines.\n"
|
|
591
|
+
"A run does not install it for you: a download at run time is a "
|
|
592
|
+
"supply-chain surface you did not consent to.\n"
|
|
589
593
|
"\n"
|
|
590
|
-
"
|
|
591
|
-
"
|
|
592
|
-
"on Apple GPUs through PyTorch MPS with no extra install.\n"
|
|
593
|
-
"\n"
|
|
594
|
-
"Status and known gaps: docs/internal/metal_adoption_plan_2026_09_03.md"
|
|
594
|
+
"Alternative: the PyTorch engine (--compiled) runs on the Apple GPU "
|
|
595
|
+
"through MPS (pip install torch \"neurobrix[pytorch]\")."
|
|
595
596
|
)
|
|
596
597
|
|
|
598
|
+
if not metal_binding_available():
|
|
599
|
+
# the device is opened through pyobjc's Metal binding: without it the run found no device and fell to a CPU
|
|
600
|
+
# profile, refused there for triton-cpu with not a word about Metal (the Mac's clean venv, 2026-11-07 00:51)
|
|
601
|
+
raise TritonMetalBindingMissingError(
|
|
602
|
+
"The --triton engine opens the Apple GPU through pyobjc's Metal binding, and it is not installed:\n"
|
|
603
|
+
" pip install pyobjc-framework-Metal")
|
|
604
|
+
|
|
597
605
|
if not metal_shader_compiler_available():
|
|
598
606
|
raise TritonMetalShaderCompilerMissingError(
|
|
599
607
|
"A Triton Metal backend is installed, but Apple's offline shader "
|
|
@@ -39,23 +39,26 @@ def _environment_runtime_libs(package: str, names) -> list:
|
|
|
39
39
|
return []
|
|
40
40
|
import os
|
|
41
41
|
root = list(spec.submodule_search_locations)[0]
|
|
42
|
+
from nbxtensor.backend.libnames import CUDA_RUNTIME_IN_WHEEL, WINDOWS
|
|
42
43
|
out = []
|
|
43
44
|
for n in names:
|
|
44
|
-
cand = os.path.join(root,
|
|
45
|
+
cand = os.path.join(root, CUDA_RUNTIME_IN_WHEEL[0], n)
|
|
45
46
|
if os.path.exists(cand):
|
|
46
47
|
out.append(cand)
|
|
48
|
+
if WINDOWS: # the DLL's own directory searched for what it loads
|
|
49
|
+
os.add_dll_directory(os.path.dirname(cand))
|
|
47
50
|
return out
|
|
48
51
|
|
|
49
52
|
|
|
50
53
|
# Runtime API mapping per backend
|
|
54
|
+
from nbxtensor.backend import libnames as _LIB # noqa: E402 the libraries as this system names them
|
|
51
55
|
_GPU_BACKENDS = {
|
|
52
56
|
"cuda": {
|
|
53
|
-
"rt_libs": _environment_runtime_libs("nvidia.cuda_runtime", [
|
|
54
|
-
+ ["libcudart.so", "libcudart.so.12", "libcudart.so.11.0"],
|
|
57
|
+
"rt_libs": _environment_runtime_libs("nvidia.cuda_runtime", [_LIB.CUDA_RUNTIME_IN_WHEEL[1]]) + _LIB.CUDA_RUNTIME,
|
|
55
58
|
# the driver API's library: the virtual memory primitives of the expandable pool (`memory.vmm`, R16)
|
|
56
|
-
"driver_libs":
|
|
59
|
+
"driver_libs": _LIB.CUDA_DRIVER,
|
|
57
60
|
# the management library: what the driver attributes to THIS process on a device (`backend.process_memory`)
|
|
58
|
-
"management_libs":
|
|
61
|
+
"management_libs": _LIB.NVML,
|
|
59
62
|
"pci_bus_id": "cudaDeviceGetPCIBusId",
|
|
60
63
|
"malloc": "cudaMalloc", "free": "cudaFree",
|
|
61
64
|
"memcpy": "cudaMemcpy", "memset": "cudaMemset",
|
|
@@ -100,7 +103,7 @@ _GPU_BACKENDS = {
|
|
|
100
103
|
"device_enable_peer_access": "cudaDeviceEnablePeerAccess",
|
|
101
104
|
},
|
|
102
105
|
"hip": {
|
|
103
|
-
"rt_libs":
|
|
106
|
+
"rt_libs": _LIB.HIP_RUNTIME,
|
|
104
107
|
# the same three facts as cuda's, declared ABSENT: the expandable pool speaks the CUDA driver's VMM calls only
|
|
105
108
|
# (`memory.vmm`; HIP's hipMemCreate family is not wired), so a HIP device keeps its driver segments; and no
|
|
106
109
|
# per-process accounting is read on ROCm (`backend.process_memory` answers None, the runtime's growth is not
|
|
@@ -11,7 +11,8 @@ import time
|
|
|
11
11
|
from concurrent.futures import ThreadPoolExecutor
|
|
12
12
|
from typing import Dict, List, Optional, Sequence
|
|
13
13
|
|
|
14
|
-
__all__ = ["PIECE", "WITNESS_BYTES", "START_BYTES", "mount_of", "pieces", "trial", "choose", "measure", "workers_for"
|
|
14
|
+
__all__ = ["PIECE", "WITNESS_BYTES", "START_BYTES", "mount_of", "pieces", "trial", "choose", "measure", "workers_for",
|
|
15
|
+
"can_bypass_the_cache"]
|
|
15
16
|
|
|
16
17
|
PIECE = 16 << 20 # the loaders' read piece
|
|
17
18
|
|
|
@@ -63,14 +64,21 @@ def pieces(files, max_bytes: int):
|
|
|
63
64
|
return out, total
|
|
64
65
|
|
|
65
66
|
|
|
67
|
+
def can_bypass_the_cache() -> bool:
|
|
68
|
+
"""Whether this system lets a measure read past its page cache (macOS F_NOCACHE + msync, Linux posix_fadvise);
|
|
69
|
+
Windows offers neither through Python, and a rate read from the cache is not the storage's."""
|
|
70
|
+
return sys.platform == "darwin" or hasattr(os, "posix_fadvise")
|
|
71
|
+
|
|
72
|
+
|
|
66
73
|
def trial(pieces, workers: int) -> float:
|
|
67
74
|
"""Bytes per second reading `pieces` with `workers` threads, the cache bypassed."""
|
|
75
|
+
from nbxtensor.io.safetensors import _read_at
|
|
68
76
|
for path in {p for p, _, _ in pieces}:
|
|
69
77
|
_evict(path, os.path.getsize(path))
|
|
70
78
|
fds = {}
|
|
71
79
|
for path, _, _ in pieces:
|
|
72
80
|
if path not in fds:
|
|
73
|
-
fd = os.open(path, os.O_RDONLY)
|
|
81
|
+
fd = os.open(path, os.O_RDONLY | getattr(os, "O_BINARY", 0))
|
|
74
82
|
_no_cache(fd)
|
|
75
83
|
fds[path] = fd
|
|
76
84
|
bufs = [bytearray(PIECE) for _ in range(workers)]
|
|
@@ -80,7 +88,7 @@ def trial(pieces, workers: int) -> float:
|
|
|
80
88
|
buf = memoryview(bufs[i % workers])[:n]
|
|
81
89
|
got = 0
|
|
82
90
|
while got < n:
|
|
83
|
-
got +=
|
|
91
|
+
got += _read_at(fds[path], buf[got:], off + got)
|
|
84
92
|
return n
|
|
85
93
|
|
|
86
94
|
t = time.perf_counter()
|
|
@@ -146,6 +154,9 @@ def workers_for(directory, witness_dir=None, max_workers: Optional[int] = None,
|
|
|
146
154
|
up to everything the files hold. When no size gives a stable measure, refused by name: never a silent None, never
|
|
147
155
|
a default."""
|
|
148
156
|
from pathlib import Path
|
|
157
|
+
if not can_bypass_the_cache():
|
|
158
|
+
raise RuntimeError(f"ZERO FALLBACK: no uncached read-rate measure on this system ({sys.platform}: no way to "
|
|
159
|
+
f"read past the page cache) — no worker count is assumed")
|
|
149
160
|
root = Path(directory)
|
|
150
161
|
max_workers = max_workers or os.cpu_count() or 1
|
|
151
162
|
files = [str(p) for p in sorted(root.glob(pattern), key=lambda p: -p.stat().st_size)[:4]]
|