Kernels:
Trusted publisher
Uploaded using `kernel-builder`.
Browse files- README.md +1 -0
- build/torch-cuda/__init__.py +3 -0
- build/torch-cuda/_ops.py +1 -1
- build/torch-cuda/autotune_config.py +70 -0
- build/torch-cuda/bayesian_autotuner.py +138 -93
- build/torch-cuda/compat.py +12 -0
- build/torch-cuda/embedding.py +306 -0
- build/torch-cuda/metadata.json +11 -9
- build/torch-cuda/metadata.json.sigstore +1 -1
- build/torch-cuda/pruners.py +1 -1
- build/torch-cuda/quant.py +7 -9
- build/torch-cuda/symbols.json +68 -14
README.md
CHANGED
|
@@ -23,6 +23,7 @@ matmul_2d(...)
|
|
| 23 |
- `matmul_grouped`
|
| 24 |
- `moe_fused_batched`
|
| 25 |
- `moe_fused_grouped`
|
|
|
|
| 26 |
- `backward`
|
| 27 |
- `get_supported_act_fns`
|
| 28 |
- `get_supported_norms`
|
|
|
|
| 23 |
- `matmul_grouped`
|
| 24 |
- `moe_fused_batched`
|
| 25 |
- `moe_fused_grouped`
|
| 26 |
+
- `embedding_lookup`
|
| 27 |
- `backward`
|
| 28 |
- `get_supported_act_fns`
|
| 29 |
- `get_supported_norms`
|
build/torch-cuda/__init__.py
CHANGED
|
@@ -17,6 +17,7 @@ from .matmul import matmul_2d
|
|
| 17 |
from .batched import matmul_batched
|
| 18 |
from .grouped import matmul_grouped
|
| 19 |
from .moe import moe_fused_batched, moe_fused_grouped
|
|
|
|
| 20 |
from . import backward
|
| 21 |
from .formats import get_supported_act_fns
|
| 22 |
from .norm import get_supported_norms, rms_norm_rows
|
|
@@ -32,6 +33,8 @@ __all__ = [
|
|
| 32 |
# the fused MoE forwards over them
|
| 33 |
"moe_fused_batched",
|
| 34 |
"moe_fused_grouped",
|
|
|
|
|
|
|
| 35 |
# importing it registers the dgrad formulas on the ops, so a forward call differentiates
|
| 36 |
"backward",
|
| 37 |
"get_supported_act_fns",
|
|
|
|
| 17 |
from .batched import matmul_batched
|
| 18 |
from .grouped import matmul_grouped
|
| 19 |
from .moe import moe_fused_batched, moe_fused_grouped
|
| 20 |
+
from .embedding import embedding_lookup
|
| 21 |
from . import backward
|
| 22 |
from .formats import get_supported_act_fns
|
| 23 |
from .norm import get_supported_norms, rms_norm_rows
|
|
|
|
| 33 |
# the fused MoE forwards over them
|
| 34 |
"moe_fused_batched",
|
| 35 |
"moe_fused_grouped",
|
| 36 |
+
# selected-row embedding lookup
|
| 37 |
+
"embedding_lookup",
|
| 38 |
# importing it registers the dgrad formulas on the ops, so a forward call differentiates
|
| 39 |
"backward",
|
| 40 |
"get_supported_act_fns",
|
build/torch-cuda/_ops.py
CHANGED
|
@@ -25,7 +25,7 @@ def get_backend() -> str:
|
|
| 25 |
|
| 26 |
def _find_ops_name() -> str:
|
| 27 |
kernel_name = "finegrained_kernels"
|
| 28 |
-
unique_id = "
|
| 29 |
backend = get_backend()
|
| 30 |
return f"_{kernel_name}_{backend}_{unique_id}"
|
| 31 |
|
|
|
|
| 25 |
|
| 26 |
def _find_ops_name() -> str:
|
| 27 |
kernel_name = "finegrained_kernels"
|
| 28 |
+
unique_id = "ec5cc90"
|
| 29 |
backend = get_backend()
|
| 30 |
return f"_{kernel_name}_{backend}_{unique_id}"
|
| 31 |
|
build/torch-cuda/autotune_config.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2026 The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""``FINEGRAINED_AUTOTUNE_CONFIG``: the one runtime control over every tuned kernel.
|
| 16 |
+
|
| 17 |
+
Its value is a mode name (``fast``), inline JSON, or a path to a JSON file. JSON keys are the
|
| 18 |
+
tuner's own options; ``"mode"`` there applies a preset whose keys explicit ones override.
|
| 19 |
+
|
| 20 |
+
The tuner reads this when each kernel is decorated, i.e. when the package is imported.
|
| 21 |
+
"""
|
| 22 |
+
|
| 23 |
+
import json
|
| 24 |
+
import os
|
| 25 |
+
from pathlib import Path
|
| 26 |
+
|
| 27 |
+
ENV_VAR = "FINEGRAINED_AUTOTUNE_CONFIG"
|
| 28 |
+
|
| 29 |
+
# Tuner kwargs by name, plus the debugging outputs (``key_log_path``, ``call_count_path``,
|
| 30 |
+
# ``tracebacks``) and the cross-rank tune lock wait.
|
| 31 |
+
KEYS = {
|
| 32 |
+
"n_trials": int, "strict": bool, "runoff": bool, "basin_probes": bool,
|
| 33 |
+
"max_refine_iters": int, "log_path": str,
|
| 34 |
+
"key_log_path": str, "call_count_path": str, "tracebacks": bool, "lock_timeout": float,
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
MODES = {
|
| 38 |
+
# one measured config, no search phases: correctness runs, not performance
|
| 39 |
+
"fast": {"n_trials": 1, "runoff": False, "basin_probes": False, "max_refine_iters": 0},
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
def _read(value: str) -> dict:
|
| 44 |
+
"""The raw config, a mode name kept as ``{"mode": ...}`` so explicit keys compose with it."""
|
| 45 |
+
if not value:
|
| 46 |
+
return {}
|
| 47 |
+
if value.lstrip().startswith("{"):
|
| 48 |
+
return json.loads(value)
|
| 49 |
+
if os.path.isfile(value):
|
| 50 |
+
return json.loads(Path(value).read_text())
|
| 51 |
+
return {"mode": value}
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
def load_autotune_config() -> dict:
|
| 55 |
+
"""Validated overrides from the environment: the mode's preset, then explicit keys."""
|
| 56 |
+
config = _read(os.environ.get(ENV_VAR, ""))
|
| 57 |
+
mode = config.pop("mode", None)
|
| 58 |
+
if mode is not None:
|
| 59 |
+
if mode not in MODES:
|
| 60 |
+
raise ValueError(
|
| 61 |
+
f"{ENV_VAR} mode {mode!r} is not one of {sorted(MODES)} (or a JSON object / JSON file path)"
|
| 62 |
+
)
|
| 63 |
+
config = {**MODES[mode], **config}
|
| 64 |
+
unknown = set(config) - set(KEYS)
|
| 65 |
+
if unknown:
|
| 66 |
+
raise ValueError(
|
| 67 |
+
f"{ENV_VAR} has unknown keys {sorted(unknown)}; expected a subset of {sorted(KEYS)} or \"mode\""
|
| 68 |
+
)
|
| 69 |
+
return {key: KEYS[key](value) for key, value in config.items()}
|
| 70 |
+
|
build/torch-cuda/bayesian_autotuner.py
CHANGED
|
@@ -37,6 +37,7 @@ import random
|
|
| 37 |
import time
|
| 38 |
from collections import defaultdict
|
| 39 |
from contextlib import contextmanager
|
|
|
|
| 40 |
|
| 41 |
import torch
|
| 42 |
|
|
@@ -53,19 +54,24 @@ from triton.runtime.autotuner import (
|
|
| 53 |
triton_key,
|
| 54 |
)
|
| 55 |
|
|
|
|
|
|
|
| 56 |
logger = logging.getLogger(__name__)
|
| 57 |
|
| 58 |
-
#
|
| 59 |
-
|
|
|
|
|
|
|
|
|
|
| 60 |
# Discriminates cudagraph REPLAY (host code runs only at capture) from per-token
|
| 61 |
# re-execution — the decode-gap forensics tool.
|
| 62 |
_CALL_COUNTS = None
|
| 63 |
-
if
|
| 64 |
import atexit
|
| 65 |
|
| 66 |
_CALL_COUNTS = {}
|
| 67 |
|
| 68 |
-
def _dump_call_counts(path=
|
| 69 |
with open(path, "w") as f:
|
| 70 |
json.dump(_CALL_COUNTS, f, indent=1, sort_keys=True)
|
| 71 |
|
|
@@ -84,48 +90,58 @@ class BayesianAutotuner(Autotuner):
|
|
| 84 |
max_failures: int | None = None,
|
| 85 |
n_startup_trials: int = 12,
|
| 86 |
gamma: float = 0.25,
|
| 87 |
-
|
|
|
|
| 88 |
max_refine_iters: int = 5,
|
| 89 |
log_path: str | None = None,
|
| 90 |
path_anchor_axes: tuple[str, ...] = (),
|
|
|
|
| 91 |
finite_check_args: tuple[str, ...] = (),
|
| 92 |
**kwargs,
|
| 93 |
):
|
| 94 |
super().__init__(*args, **kwargs)
|
| 95 |
self.fn_name = getattr(self.fn, "__name__", str(self.fn))
|
| 96 |
-
|
| 97 |
-
#
|
| 98 |
-
#
|
| 99 |
-
|
|
|
|
| 100 |
# A tune aborts once this many configs have failed to compile/run without the measured
|
| 101 |
# budget being met. Defaults to n_trials: a grid that cannot land its measurements without
|
| 102 |
# that many rejects has a pruner gap, and the fix is to fence the dead region rather than
|
| 103 |
# to tolerate the compiles. Its own axis so a kernel can raise it deliberately.
|
| 104 |
-
# an explicit argument wins over the
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
env_max_failures = os.environ.get("FINEGRAINED_AUTOTUNE_MAX_FAILURES")
|
| 108 |
-
max_failures = env_max_failures if env_max_failures is not None else self.n_trials
|
| 109 |
self.max_failures = int(max_failures)
|
| 110 |
self.n_startup_trials = n_startup_trials
|
| 111 |
# top fraction of measured configs the TPE treats as "good"
|
| 112 |
self.gamma = gamma
|
| 113 |
-
self.
|
| 114 |
-
self.
|
|
|
|
| 115 |
# Branch axes (by kwarg name) that relocate the TILE optimum — the caller's
|
| 116 |
# declaration, since it is configuration knowledge (the tuner never hardcodes
|
| 117 |
# axis names). Each distinct value combination of these axes gets one guaranteed
|
| 118 |
# max-tile anchor; empty = median anchors only.
|
| 119 |
self.path_anchor_axes = tuple(path_anchor_axes)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
# Output arg NAMES (a declaration — the tuner never hardcodes kernel details) whose
|
| 121 |
# values are checked for NaN/inf after each config's bench: a config that writes
|
| 122 |
# non-finite output scores inf and can never be crowned. The tuner times, it never
|
| 123 |
# validates — this veto closes the NaN half of the "wrong-answer configs win
|
| 124 |
# tunes" class at negligible cost (one isfinite pass per benched config).
|
| 125 |
self.finite_check_args = tuple(finite_check_args)
|
| 126 |
-
# JSONL log of every benched (key, config, ms) — set here or via
|
| 127 |
-
#
|
| 128 |
-
self.log_path = log_path or
|
|
|
|
|
|
|
| 129 |
# steady-state launch support: key extraction without dict builds (eager decode
|
| 130 |
# is host-bound; the cache-hit path of run() is on the per-token critical path)
|
| 131 |
self._arg_position = {name: i for i, name in enumerate(self.arg_names)}
|
|
@@ -195,7 +211,7 @@ class BayesianAutotuner(Autotuner):
|
|
| 195 |
if root is not e:
|
| 196 |
msg += f" || root: {type(root).__name__}: {str(root)[-300:]}"
|
| 197 |
err = f"{type(e).__name__}: {msg}"
|
| 198 |
-
if
|
| 199 |
logger.warning(
|
| 200 |
"[autotune] %s failed on %s:\n%s",
|
| 201 |
self.fn_name,
|
|
@@ -460,9 +476,22 @@ class BayesianAutotuner(Autotuner):
|
|
| 460 |
self.nargs = None
|
| 461 |
return ret
|
| 462 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 463 |
def _bayesian_search(self, configs: List[Config], args, kwargs, key) -> Config:
|
| 464 |
timings: Dict[int, float] = {}
|
| 465 |
-
sigs =
|
| 466 |
|
| 467 |
def bench_idx(idx: int) -> float:
|
| 468 |
if idx in timings:
|
|
@@ -489,8 +518,8 @@ class BayesianAutotuner(Autotuner):
|
|
| 489 |
# per-dimension model can write off a whole axis it never saw succeed (two dsv4 tunes
|
| 490 |
# shipped 25-60% slow winners because their random seeds only sampled a basin's dead
|
| 491 |
# configs), and coordinate descent can't recover a winner two coupled flips away.
|
| 492 |
-
n_startup =
|
| 493 |
-
anchors = self._basin_anchor_indices(configs)
|
| 494 |
order = list(range(len(configs)))
|
| 495 |
random.Random(0).shuffle(order)
|
| 496 |
warm_idx = self._warm_start_index(configs, key)
|
|
@@ -574,22 +603,21 @@ class BayesianAutotuner(Autotuner):
|
|
| 574 |
|
| 575 |
# Coordinate-descent refinement: try single-dim perturbations around
|
| 576 |
# the current best until no neighbor improves.
|
| 577 |
-
|
| 578 |
-
|
| 579 |
-
|
| 580 |
-
|
| 581 |
-
|
| 582 |
-
|
| 583 |
-
|
| 584 |
-
|
| 585 |
-
|
| 586 |
-
|
| 587 |
-
|
| 588 |
-
|
| 589 |
-
|
| 590 |
-
|
| 591 |
-
|
| 592 |
-
break
|
| 593 |
|
| 594 |
# Crown RUNOFF: the search's single-shot timings carry enough noise to flip crowns
|
| 595 |
# between same-code tune rolls (gpt-oss prefill grouped rolled 1727-2150us on identical
|
|
@@ -597,21 +625,24 @@ class BayesianAutotuner(Autotuner):
|
|
| 597 |
# the top candidates back-to-back — same warmed process, adjacent in time, so they see
|
| 598 |
# the same clocks — and crown the winner of THAT comparison. Costs ~3 extra benches.
|
| 599 |
finite = sorted((t, i) for i, t in timings.items() if t != float("inf"))
|
| 600 |
-
|
| 601 |
-
|
|
|
|
|
|
|
| 602 |
timings.pop(i, None)
|
| 603 |
bench_idx(i) # memoizing closure: re-benches and re-records the popped entry
|
| 604 |
|
| 605 |
self.configs_timings = {configs[i]: t for i, t in timings.items()}
|
| 606 |
-
|
|
|
|
| 607 |
if timings[best] == float("inf"):
|
| 608 |
# crowning an arbitrary broken config would persist it as `best` on disk and
|
| 609 |
# every later healthy process would replay it without re-tuning — the exact
|
| 610 |
# sticky-contaminated-context scenario inf-forgiveness exists to survive
|
| 611 |
self._report_bench_failures()
|
| 612 |
raise RuntimeError(
|
| 613 |
-
f"[bayesian-autotune] {self.fn_name}: every
|
| 614 |
-
"
|
| 615 |
"be trap-contaminated (retry in a fresh process) or the grid is broken "
|
| 616 |
"for this launch (see the failure report above)."
|
| 617 |
)
|
|
@@ -639,12 +670,8 @@ class BayesianAutotuner(Autotuner):
|
|
| 639 |
pass
|
| 640 |
|
| 641 |
def _basin_anchor_indices(self, configs: List[Config]) -> List[int]:
|
| 642 |
-
"""
|
| 643 |
-
|
| 644 |
-
minimal corner (min BK x 2 warps) can be latency-bound pathological (a 131µs anchor in
|
| 645 |
-
a basin whose peak is 41µs re-poisons the axis it was meant to protect). Coordinate
|
| 646 |
-
descent climbs BN/BK/warps/stages from wherever the TPE lands within the basin.
|
| 647 |
-
Returns [] when the grid has no such axes (single basin)."""
|
| 648 |
# Basin axes are DERIVED, not declared: a config kwarg with string or boolean
|
| 649 |
# values is a branch axis (different code path — compute mode, operand swap,
|
| 650 |
# warp specialization), which partitions the grid into disjoint performance
|
|
@@ -670,41 +697,46 @@ class BayesianAutotuner(Autotuner):
|
|
| 670 |
if len(groups) <= 1:
|
| 671 |
return []
|
| 672 |
|
| 673 |
-
def tile_order(i):
|
| 674 |
-
return (
|
| 675 |
-
configs[i].kwargs.get("BLOCK_SIZE_N", 0),
|
| 676 |
-
configs[i].kwargs.get("BLOCK_SIZE_K", 0),
|
| 677 |
-
configs[i].num_warps,
|
| 678 |
-
configs[i].num_stages,
|
| 679 |
-
)
|
| 680 |
-
|
| 681 |
-
# Median anchor per basin, PLUS one max-tile anchor per declared PATH-axis combo
|
| 682 |
-
# (``path_anchor_axes``). The median alone left the big-tile end unsampled: TPE
|
| 683 |
-
# densities lock onto the first-timed mid-tile region and coordinate descent cannot
|
| 684 |
-
# cross DIAGONAL ridges — dsv4 mxfp8 prefill gate_up's BN=128/BK=256 winner (840us)
|
| 685 |
-
# needs BN and warps to move together, so descent from the BN=64 crown rejects the
|
| 686 |
-
# lone BN step and n_trials 100/200/400 all missed it; one guaranteed big-tile
|
| 687 |
-
# sample fixed it (crown 958 -> 880 at the default budget). The max anchor rides
|
| 688 |
-
# the declared COARSE grouping, NOT the full branch-axis cross: per-basin max
|
| 689 |
-
# anchors on the weight-only grouped grid (32 basins: modes x WS x PS x 2 memory
|
| 690 |
-
# modes each way) put 64 forced trials into a 100-trial budget and starved the
|
| 691 |
-
# search — gpt-oss prefill regressed 3463 -> 4099us on a quiet box before this was
|
| 692 |
-
# scoped. Which axes qualify is the KERNEL's declaration (configuration knowledge);
|
| 693 |
-
# axes absent from this grid are ignored.
|
| 694 |
anchors = []
|
| 695 |
coarse_seen = set()
|
| 696 |
coarse_axes = [k for k in self.path_anchor_axes if k in basin_axes]
|
| 697 |
for basin, idxs in groups.items():
|
| 698 |
-
|
| 699 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 700 |
if not self.path_anchor_axes:
|
| 701 |
-
continue
|
| 702 |
-
# declared axes absent from THIS grid still coarse-group to () — one global
|
| 703 |
-
# max-tile anchor, the big-tile guarantee without per-basin anchor spam
|
| 704 |
coarse = tuple(basin[basin_axes.index(k)] for k in coarse_axes)
|
| 705 |
-
if coarse not in coarse_seen
|
| 706 |
coarse_seen.add(coarse)
|
| 707 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 708 |
return anchors
|
| 709 |
|
| 710 |
def _warm_start_index(self, configs: List[Config], key=None):
|
|
@@ -729,8 +761,8 @@ class BayesianAutotuner(Autotuner):
|
|
| 729 |
"""Persist the tuned best config to Triton's on-disk cache so a later run (or process)
|
| 730 |
skips the whole minutes-long search+compile — most of which is Triton codegen, not
|
| 731 |
benching. Keyed exactly like Triton's own autotune cache (triton version + backend +
|
| 732 |
-
kernel source
|
| 733 |
-
changing re-tunes.
|
| 734 |
|
| 735 |
Unlike Triton's stock version we do NOT bail when configs carry a ``pre_hook`` (ours
|
| 736 |
always do): we persist each config's ``all_kwargs()`` — serializable and pre_hook-free —
|
|
@@ -750,19 +782,22 @@ class BayesianAutotuner(Autotuner):
|
|
| 750 |
triton_key(),
|
| 751 |
make_backend(driver.active.get_current_target()).hash(),
|
| 752 |
fn.cache_key,
|
|
|
|
| 753 |
str(sorted(env_vars.items())),
|
| 754 |
# Key NAMES and the search budget are determinants too: tuning_key holds
|
| 755 |
# values only (renaming a key or swapping two same-typed keys would collide),
|
| 756 |
-
# and
|
| 757 |
# without n_trials a 3-trial exploratory winner gets replayed at 100 trials.
|
| 758 |
str(self.keys),
|
| 759 |
-
f"n_trials={self.n_trials},n_startup_trials={self.n_startup_trials},gamma={self.gamma}
|
|
|
|
|
|
|
| 760 |
str(tuning_key),
|
| 761 |
] + [str(c) for c in configs] # str(Config) is pre_hook-free and process-stable
|
| 762 |
cache_key = hashlib.sha256("-".join(cache_key).encode("utf-8")).hexdigest()
|
| 763 |
cache = get_cache_manager(cache_key)
|
| 764 |
file_name = f"{fn.__name__[:150]}.bayes_autotune.json"
|
| 765 |
-
keylog =
|
| 766 |
if keylog:
|
| 767 |
with open(keylog, "a") as f:
|
| 768 |
f.write(json.dumps({
|
|
@@ -840,7 +875,7 @@ def _tuning_lock(cache, file_name: str):
|
|
| 840 |
Held while a key is tuned and its crown published, so concurrent TP/EP ranks converge on the
|
| 841 |
same config instead of each crowning its own (see ``check_disk_cache``). Advisory ``flock`` on
|
| 842 |
a sidecar file next to the crown; entirely best-effort — no cache dir, no ``fcntl``, or a lock
|
| 843 |
-
that cannot be taken within ``
|
| 844 |
is doing a real tune) all fall through to tuning locally. Losing the lock costs redundant work,
|
| 845 |
never correctness."""
|
| 846 |
lock_file = None
|
|
@@ -850,9 +885,7 @@ def _tuning_lock(cache, file_name: str):
|
|
| 850 |
cache_dir = getattr(cache, "cache_dir", None)
|
| 851 |
if cache_dir:
|
| 852 |
os.makedirs(cache_dir, exist_ok=True)
|
| 853 |
-
deadline = time.time() +
|
| 854 |
-
os.environ.get("FINEGRAINED_TUNE_LOCK_TIMEOUT") or 1800
|
| 855 |
-
)
|
| 856 |
lock_file = open(os.path.join(cache_dir, f"{file_name}.lock"), "w")
|
| 857 |
while True:
|
| 858 |
try:
|
|
@@ -892,10 +925,12 @@ def bayesian_autotune(
|
|
| 892 |
max_failures: int | None = None,
|
| 893 |
n_startup_trials: int = 12,
|
| 894 |
gamma: float = 0.25,
|
| 895 |
-
|
|
|
|
| 896 |
max_refine_iters: int = 5,
|
| 897 |
log_path: str | None = None,
|
| 898 |
path_anchor_axes: tuple[str, ...] = (),
|
|
|
|
| 899 |
finite_check_args: tuple[str, ...] = (),
|
| 900 |
cache_results: bool = True,
|
| 901 |
reset_to_zero=None,
|
|
@@ -905,19 +940,27 @@ def bayesian_autotune(
|
|
| 905 |
"""Decorator mirroring ``@triton.autotune``. Extra kwargs:
|
| 906 |
n_trials: successfully measured configs per key (TPE budget; configs
|
| 907 |
that fail to compile/run are skipped without consuming it)
|
|
|
|
| 908 |
n_startup_trials: random seed configs before the TPE model kicks in
|
| 909 |
gamma: top fraction of measured configs treated as "good"
|
| 910 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 911 |
path_anchor_axes: branch axes (kwarg names) whose values relocate the tile
|
| 912 |
optimum — one guaranteed max-tile anchor per value combo
|
| 913 |
(see _basin_anchor_indices); the kernel declares them, the
|
| 914 |
tuner stays independent of configuration details
|
|
|
|
|
|
|
| 915 |
max_failures: abort the tune once this many configs fail to compile/run before
|
| 916 |
-
the measured budget is met (default n_trials;
|
| 917 |
-
|
| 918 |
grid spins: failures don't consume the trial budget, so the search
|
| 919 |
keeps picking and each pick costs an O(configs) rescan.
|
| 920 |
-
log_path: JSONL of benched configs (or
|
| 921 |
cache_results: persist the tuned best config to disk (on by default) so later
|
| 922 |
runs skip the search+compile — see BayesianAutotuner.check_disk_cache"""
|
| 923 |
|
|
@@ -933,10 +976,12 @@ def bayesian_autotune(
|
|
| 933 |
max_failures=max_failures,
|
| 934 |
n_startup_trials=n_startup_trials,
|
| 935 |
gamma=gamma,
|
| 936 |
-
|
|
|
|
| 937 |
max_refine_iters=max_refine_iters,
|
| 938 |
log_path=log_path,
|
| 939 |
path_anchor_axes=path_anchor_axes,
|
|
|
|
| 940 |
finite_check_args=finite_check_args,
|
| 941 |
cache_results=cache_results,
|
| 942 |
**kwargs,
|
|
|
|
| 37 |
import time
|
| 38 |
from collections import defaultdict
|
| 39 |
from contextlib import contextmanager
|
| 40 |
+
from pathlib import Path
|
| 41 |
|
| 42 |
import torch
|
| 43 |
|
|
|
|
| 54 |
triton_key,
|
| 55 |
)
|
| 56 |
|
| 57 |
+
from .autotune_config import load_autotune_config
|
| 58 |
+
|
| 59 |
logger = logging.getLogger(__name__)
|
| 60 |
|
| 61 |
+
# Include the tuner implementation alongside Triton's kernel-source hash.
|
| 62 |
+
_TUNER_SOURCE_HASH = hashlib.sha256(Path(__file__).read_bytes()).hexdigest()
|
| 63 |
+
|
| 64 |
+
# Host-execution counter (``call_count_path`` in FINEGRAINED_AUTOTUNE_CONFIG): every
|
| 65 |
+
# BayesianAutotuner.run() call increments its kernel's tally, dumped to that path at exit.
|
| 66 |
# Discriminates cudagraph REPLAY (host code runs only at capture) from per-token
|
| 67 |
# re-execution — the decode-gap forensics tool.
|
| 68 |
_CALL_COUNTS = None
|
| 69 |
+
if load_autotune_config().get("call_count_path"):
|
| 70 |
import atexit
|
| 71 |
|
| 72 |
_CALL_COUNTS = {}
|
| 73 |
|
| 74 |
+
def _dump_call_counts(path=load_autotune_config()["call_count_path"]):
|
| 75 |
with open(path, "w") as f:
|
| 76 |
json.dump(_CALL_COUNTS, f, indent=1, sort_keys=True)
|
| 77 |
|
|
|
|
| 90 |
max_failures: int | None = None,
|
| 91 |
n_startup_trials: int = 12,
|
| 92 |
gamma: float = 0.25,
|
| 93 |
+
runoff: bool = True,
|
| 94 |
+
basin_probes: bool = True,
|
| 95 |
max_refine_iters: int = 5,
|
| 96 |
log_path: str | None = None,
|
| 97 |
path_anchor_axes: tuple[str, ...] = (),
|
| 98 |
+
coupled_axes: tuple[tuple[str, ...], ...] = (),
|
| 99 |
finite_check_args: tuple[str, ...] = (),
|
| 100 |
**kwargs,
|
| 101 |
):
|
| 102 |
super().__init__(*args, **kwargs)
|
| 103 |
self.fn_name = getattr(self.fn, "__name__", str(self.fn))
|
| 104 |
+
overrides = load_autotune_config()
|
| 105 |
+
# Bayesian trial budget — the per-decorator default, overridable via ``n_trials`` in
|
| 106 |
+
# FINEGRAINED_AUTOTUNE_CONFIG (quick sweeps / exhaustive runs without touching the
|
| 107 |
+
# decorators; set it >= grid size to fall back to stock exhaustive bench-all).
|
| 108 |
+
self.n_trials = overrides.get("n_trials", n_trials)
|
| 109 |
# A tune aborts once this many configs have failed to compile/run without the measured
|
| 110 |
# budget being met. Defaults to n_trials: a grid that cannot land its measurements without
|
| 111 |
# that many rejects has a pruner gap, and the fix is to fence the dead region rather than
|
| 112 |
# to tolerate the compiles. Its own axis so a kernel can raise it deliberately.
|
| 113 |
+
# an explicit argument wins over the config override, which wins over the default
|
| 114 |
+
if max_failures is None: # ``strict`` aborts on the first failure
|
| 115 |
+
max_failures = 0 if overrides.get("strict") else self.n_trials
|
|
|
|
|
|
|
| 116 |
self.max_failures = int(max_failures)
|
| 117 |
self.n_startup_trials = n_startup_trials
|
| 118 |
# top fraction of measured configs the TPE treats as "good"
|
| 119 |
self.gamma = gamma
|
| 120 |
+
self.runoff = overrides.get("runoff", runoff)
|
| 121 |
+
self.basin_probes = overrides.get("basin_probes", basin_probes)
|
| 122 |
+
self.max_refine_iters = overrides.get("max_refine_iters", max_refine_iters)
|
| 123 |
# Branch axes (by kwarg name) that relocate the TILE optimum — the caller's
|
| 124 |
# declaration, since it is configuration knowledge (the tuner never hardcodes
|
| 125 |
# axis names). Each distinct value combination of these axes gets one guaranteed
|
| 126 |
# max-tile anchor; empty = median anchors only.
|
| 127 |
self.path_anchor_axes = tuple(path_anchor_axes)
|
| 128 |
+
# Joint choices share one TPE density and one coordinate-refinement step.
|
| 129 |
+
self.coupled_axes = tuple(tuple(group) for group in coupled_axes)
|
| 130 |
+
coupled_names = [name for group in self.coupled_axes for name in group]
|
| 131 |
+
if any(len(group) < 2 for group in self.coupled_axes) or len(set(coupled_names)) != len(coupled_names):
|
| 132 |
+
raise ValueError("coupled_axes must contain disjoint groups of at least two configuration fields")
|
| 133 |
+
self._coupled_names = frozenset(coupled_names)
|
| 134 |
# Output arg NAMES (a declaration — the tuner never hardcodes kernel details) whose
|
| 135 |
# values are checked for NaN/inf after each config's bench: a config that writes
|
| 136 |
# non-finite output scores inf and can never be crowned. The tuner times, it never
|
| 137 |
# validates — this veto closes the NaN half of the "wrong-answer configs win
|
| 138 |
# tunes" class at negligible cost (one isfinite pass per benched config).
|
| 139 |
self.finite_check_args = tuple(finite_check_args)
|
| 140 |
+
# JSONL log of every benched (key, config, ms) — set here or via ``log_path`` in
|
| 141 |
+
# FINEGRAINED_AUTOTUNE_CONFIG. Analyse offline to prune bad configs.
|
| 142 |
+
self.log_path = log_path or overrides.get("log_path")
|
| 143 |
+
self.key_log_path = overrides.get("key_log_path")
|
| 144 |
+
self.tracebacks = overrides.get("tracebacks", False)
|
| 145 |
# steady-state launch support: key extraction without dict builds (eager decode
|
| 146 |
# is host-bound; the cache-hit path of run() is on the per-token critical path)
|
| 147 |
self._arg_position = {name: i for i, name in enumerate(self.arg_names)}
|
|
|
|
| 211 |
if root is not e:
|
| 212 |
msg += f" || root: {type(root).__name__}: {str(root)[-300:]}"
|
| 213 |
err = f"{type(e).__name__}: {msg}"
|
| 214 |
+
if self.tracebacks:
|
| 215 |
logger.warning(
|
| 216 |
"[autotune] %s failed on %s:\n%s",
|
| 217 |
self.fn_name,
|
|
|
|
| 476 |
self.nargs = None
|
| 477 |
return ret
|
| 478 |
|
| 479 |
+
def _search_signatures(self, configs: List[Config]):
|
| 480 |
+
signatures = []
|
| 481 |
+
for config in configs:
|
| 482 |
+
values = config.all_kwargs()
|
| 483 |
+
signature = {(name,): value for name, value in values.items() if name not in self._coupled_names}
|
| 484 |
+
for group in self.coupled_axes:
|
| 485 |
+
try:
|
| 486 |
+
signature[group] = tuple(values[name] for name in group)
|
| 487 |
+
except KeyError as exc:
|
| 488 |
+
raise ValueError(f"Unknown coupled_axes configuration field: {exc.args[0]}") from exc
|
| 489 |
+
signatures.append(tuple(sorted(signature.items())))
|
| 490 |
+
return signatures
|
| 491 |
+
|
| 492 |
def _bayesian_search(self, configs: List[Config], args, kwargs, key) -> Config:
|
| 493 |
timings: Dict[int, float] = {}
|
| 494 |
+
sigs = self._search_signatures(configs)
|
| 495 |
|
| 496 |
def bench_idx(idx: int) -> float:
|
| 497 |
if idx in timings:
|
|
|
|
| 518 |
# per-dimension model can write off a whole axis it never saw succeed (two dsv4 tunes
|
| 519 |
# shipped 25-60% slow winners because their random seeds only sampled a basin's dead
|
| 520 |
# configs), and coordinate descent can't recover a winner two coupled flips away.
|
| 521 |
+
n_startup = min(self.n_trials, max(2, self.n_startup_trials))
|
| 522 |
+
anchors = self._basin_anchor_indices(configs) if self.basin_probes else []
|
| 523 |
order = list(range(len(configs)))
|
| 524 |
random.Random(0).shuffle(order)
|
| 525 |
warm_idx = self._warm_start_index(configs, key)
|
|
|
|
| 603 |
|
| 604 |
# Coordinate-descent refinement: try single-dim perturbations around
|
| 605 |
# the current best until no neighbor improves.
|
| 606 |
+
for _ in range(self.max_refine_iters):
|
| 607 |
+
best_idx = min(timings, key=timings.get)
|
| 608 |
+
best_sig = sigs[best_idx]
|
| 609 |
+
best_ms = timings[best_idx]
|
| 610 |
+
improved = False
|
| 611 |
+
for i, s in enumerate(sigs):
|
| 612 |
+
if i in timings:
|
| 613 |
+
continue
|
| 614 |
+
diff = sum(1 for (_, a), (_, b) in zip(best_sig, s) if a != b)
|
| 615 |
+
if diff != 1:
|
| 616 |
+
continue
|
| 617 |
+
if bench_idx(i) < best_ms:
|
| 618 |
+
improved = True
|
| 619 |
+
if not improved:
|
| 620 |
+
break
|
|
|
|
| 621 |
|
| 622 |
# Crown RUNOFF: the search's single-shot timings carry enough noise to flip crowns
|
| 623 |
# between same-code tune rolls (gpt-oss prefill grouped rolled 1727-2150us on identical
|
|
|
|
| 625 |
# the top candidates back-to-back — same warmed process, adjacent in time, so they see
|
| 626 |
# the same clocks — and crown the winner of THAT comparison. Costs ~3 extra benches.
|
| 627 |
finite = sorted((t, i) for i, t in timings.items() if t != float("inf"))
|
| 628 |
+
finalists = list(timings)
|
| 629 |
+
if self.runoff and len(finite) > 1:
|
| 630 |
+
finalists = [i for _, i in finite[:3]]
|
| 631 |
+
for i in finalists:
|
| 632 |
timings.pop(i, None)
|
| 633 |
bench_idx(i) # memoizing closure: re-benches and re-records the popped entry
|
| 634 |
|
| 635 |
self.configs_timings = {configs[i]: t for i, t in timings.items()}
|
| 636 |
+
# Other candidates still carry search-time samples, not comparable runoff measurements.
|
| 637 |
+
best = min(finalists, key=timings.get)
|
| 638 |
if timings[best] == float("inf"):
|
| 639 |
# crowning an arbitrary broken config would persist it as `best` on disk and
|
| 640 |
# every later healthy process would replay it without re-tuning — the exact
|
| 641 |
# sticky-contaminated-context scenario inf-forgiveness exists to survive
|
| 642 |
self._report_bench_failures()
|
| 643 |
raise RuntimeError(
|
| 644 |
+
f"[bayesian-autotune] {self.fn_name}: every final candidate failed "
|
| 645 |
+
"— nothing correct to crown or persist; the context may "
|
| 646 |
"be trap-contaminated (retry in a fresh process) or the grid is broken "
|
| 647 |
"for this launch (see the failure report above)."
|
| 648 |
)
|
|
|
|
| 670 |
pass
|
| 671 |
|
| 672 |
def _basin_anchor_indices(self, configs: List[Config]) -> List[int]:
|
| 673 |
+
"""Interior representatives of categorical basins, plus a wide output tile
|
| 674 |
+
per declared compute path. All anchors come from the pruned grid."""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 675 |
# Basin axes are DERIVED, not declared: a config kwarg with string or boolean
|
| 676 |
# values is a branch axis (different code path — compute mode, operand swap,
|
| 677 |
# warp specialization), which partitions the grid into disjoint performance
|
|
|
|
| 697 |
if len(groups) <= 1:
|
| 698 |
return []
|
| 699 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 700 |
anchors = []
|
| 701 |
coarse_seen = set()
|
| 702 |
coarse_axes = [k for k in self.path_anchor_axes if k in basin_axes]
|
| 703 |
for basin, idxs in groups.items():
|
| 704 |
+
# Choose the middle of every ordinal axis together. Lexicographic sorting
|
| 705 |
+
# ignores M and can put the "median" at extreme K/warps/stages. Each axis is
|
| 706 |
+
# scored by its value's rank normalized to [0, 1], so axes with many values
|
| 707 |
+
# do not outweigh axes with few; the anchor is the config closest to 0.5 on
|
| 708 |
+
# all of them (smallest squared distance), i.e. the basin's interior.
|
| 709 |
+
values = [configs[i].all_kwargs() for i in idxs]
|
| 710 |
+
axes = {
|
| 711 |
+
k: sorted({v[k] for v in values})
|
| 712 |
+
for k, value in values[0].items()
|
| 713 |
+
if isinstance(value, (int, float)) and not isinstance(value, bool)
|
| 714 |
+
}
|
| 715 |
+
|
| 716 |
+
def distance(i):
|
| 717 |
+
args = configs[i].all_kwargs()
|
| 718 |
+
return sum(
|
| 719 |
+
(options.index(args[k]) / max(1, len(options) - 1) - 0.5) ** 2
|
| 720 |
+
for k, options in axes.items()
|
| 721 |
+
)
|
| 722 |
+
|
| 723 |
+
anchors.append(min(idxs, key=distance))
|
| 724 |
if not self.path_anchor_axes:
|
| 725 |
+
continue
|
|
|
|
|
|
|
| 726 |
coarse = tuple(basin[basin_axes.index(k)] for k in coarse_axes)
|
| 727 |
+
if coarse not in coarse_seen:
|
| 728 |
coarse_seen.add(coarse)
|
| 729 |
+
# The existing wide-tile anchor protects coupled output-tile ridges,
|
| 730 |
+
# with interior contraction/warps/stages rather than their largest corner.
|
| 731 |
+
|
| 732 |
+
def wide_order(i):
|
| 733 |
+
# largest output tile first; interior on the other axes breaks ties
|
| 734 |
+
kwargs = configs[i].kwargs
|
| 735 |
+
return -kwargs.get("BLOCK_SIZE_M", 1) * kwargs.get("BLOCK_SIZE_N", 1), distance(i)
|
| 736 |
+
|
| 737 |
+
wide = min(idxs, key=wide_order)
|
| 738 |
+
if wide != anchors[-1]:
|
| 739 |
+
anchors.append(wide)
|
| 740 |
return anchors
|
| 741 |
|
| 742 |
def _warm_start_index(self, configs: List[Config], key=None):
|
|
|
|
| 761 |
"""Persist the tuned best config to Triton's on-disk cache so a later run (or process)
|
| 762 |
skips the whole minutes-long search+compile — most of which is Triton codegen, not
|
| 763 |
benching. Keyed exactly like Triton's own autotune cache (triton version + backend +
|
| 764 |
+
kernel/tuner source hashes + invalidating env + key + the full config grid), so any
|
| 765 |
+
of those changing re-tunes.
|
| 766 |
|
| 767 |
Unlike Triton's stock version we do NOT bail when configs carry a ``pre_hook`` (ours
|
| 768 |
always do): we persist each config's ``all_kwargs()`` — serializable and pre_hook-free —
|
|
|
|
| 782 |
triton_key(),
|
| 783 |
make_backend(driver.active.get_current_target()).hash(),
|
| 784 |
fn.cache_key,
|
| 785 |
+
_TUNER_SOURCE_HASH,
|
| 786 |
str(sorted(env_vars.items())),
|
| 787 |
# Key NAMES and the search budget are determinants too: tuning_key holds
|
| 788 |
# values only (renaming a key or swapping two same-typed keys would collide),
|
| 789 |
+
# and the n_trials override is not in Triton's invalidating-env list —
|
| 790 |
# without n_trials a 3-trial exploratory winner gets replayed at 100 trials.
|
| 791 |
str(self.keys),
|
| 792 |
+
f"n_trials={self.n_trials},n_startup_trials={self.n_startup_trials},gamma={self.gamma},"
|
| 793 |
+
f"runoff={self.runoff},basin_probes={self.basin_probes},max_refine_iters={self.max_refine_iters},"
|
| 794 |
+
f"coupled_axes={self.coupled_axes}",
|
| 795 |
str(tuning_key),
|
| 796 |
] + [str(c) for c in configs] # str(Config) is pre_hook-free and process-stable
|
| 797 |
cache_key = hashlib.sha256("-".join(cache_key).encode("utf-8")).hexdigest()
|
| 798 |
cache = get_cache_manager(cache_key)
|
| 799 |
file_name = f"{fn.__name__[:150]}.bayes_autotune.json"
|
| 800 |
+
keylog = self.key_log_path
|
| 801 |
if keylog:
|
| 802 |
with open(keylog, "a") as f:
|
| 803 |
f.write(json.dumps({
|
|
|
|
| 875 |
Held while a key is tuned and its crown published, so concurrent TP/EP ranks converge on the
|
| 876 |
same config instead of each crowning its own (see ``check_disk_cache``). Advisory ``flock`` on
|
| 877 |
a sidecar file next to the crown; entirely best-effort — no cache dir, no ``fcntl``, or a lock
|
| 878 |
+
that cannot be taken within ``lock_timeout`` seconds (FINEGRAINED_AUTOTUNE_CONFIG; default 30 min, since the holder
|
| 879 |
is doing a real tune) all fall through to tuning locally. Losing the lock costs redundant work,
|
| 880 |
never correctness."""
|
| 881 |
lock_file = None
|
|
|
|
| 885 |
cache_dir = getattr(cache, "cache_dir", None)
|
| 886 |
if cache_dir:
|
| 887 |
os.makedirs(cache_dir, exist_ok=True)
|
| 888 |
+
deadline = time.time() + load_autotune_config().get("lock_timeout", 1800.0)
|
|
|
|
|
|
|
| 889 |
lock_file = open(os.path.join(cache_dir, f"{file_name}.lock"), "w")
|
| 890 |
while True:
|
| 891 |
try:
|
|
|
|
| 925 |
max_failures: int | None = None,
|
| 926 |
n_startup_trials: int = 12,
|
| 927 |
gamma: float = 0.25,
|
| 928 |
+
runoff: bool = True,
|
| 929 |
+
basin_probes: bool = True,
|
| 930 |
max_refine_iters: int = 5,
|
| 931 |
log_path: str | None = None,
|
| 932 |
path_anchor_axes: tuple[str, ...] = (),
|
| 933 |
+
coupled_axes: tuple[tuple[str, ...], ...] = (),
|
| 934 |
finite_check_args: tuple[str, ...] = (),
|
| 935 |
cache_results: bool = True,
|
| 936 |
reset_to_zero=None,
|
|
|
|
| 940 |
"""Decorator mirroring ``@triton.autotune``. Extra kwargs:
|
| 941 |
n_trials: successfully measured configs per key (TPE budget; configs
|
| 942 |
that fail to compile/run are skipped without consuming it)
|
| 943 |
+
(runtime override: ``n_trials`` in FINEGRAINED_AUTOTUNE_CONFIG)
|
| 944 |
n_startup_trials: random seed configs before the TPE model kicks in
|
| 945 |
gamma: top fraction of measured configs treated as "good"
|
| 946 |
+
runoff: remeasure the top candidates before choosing the winner
|
| 947 |
+
(runtime override: ``runoff``)
|
| 948 |
+
basin_probes: measure categorical basin anchors before the TPE
|
| 949 |
+
(runtime override: ``basin_probes``)
|
| 950 |
+
max_refine_iters: coordinate-descent iterations after the TPE (0 disables)
|
| 951 |
+
(runtime override: ``max_refine_iters``)
|
| 952 |
path_anchor_axes: branch axes (kwarg names) whose values relocate the tile
|
| 953 |
optimum — one guaranteed max-tile anchor per value combo
|
| 954 |
(see _basin_anchor_indices); the kernel declares them, the
|
| 955 |
tuner stays independent of configuration details
|
| 956 |
+
coupled_axes: groups of config fields treated as joint choices by TPE and
|
| 957 |
+
refinement, including Config fields such as num_stages
|
| 958 |
max_failures: abort the tune once this many configs fail to compile/run before
|
| 959 |
+
the measured budget is met (default n_trials; runtime override
|
| 960 |
+
``strict`` in FINEGRAINED_AUTOTUNE_CONFIG sets 0). Without it a broadly broken
|
| 961 |
grid spins: failures don't consume the trial budget, so the search
|
| 962 |
keeps picking and each pick costs an O(configs) rescan.
|
| 963 |
+
log_path: JSONL of benched configs (or ``log_path`` in FINEGRAINED_AUTOTUNE_CONFIG)
|
| 964 |
cache_results: persist the tuned best config to disk (on by default) so later
|
| 965 |
runs skip the search+compile — see BayesianAutotuner.check_disk_cache"""
|
| 966 |
|
|
|
|
| 976 |
max_failures=max_failures,
|
| 977 |
n_startup_trials=n_startup_trials,
|
| 978 |
gamma=gamma,
|
| 979 |
+
runoff=runoff,
|
| 980 |
+
basin_probes=basin_probes,
|
| 981 |
max_refine_iters=max_refine_iters,
|
| 982 |
log_path=log_path,
|
| 983 |
path_anchor_axes=path_anchor_axes,
|
| 984 |
+
coupled_axes=coupled_axes,
|
| 985 |
finite_check_args=finite_check_args,
|
| 986 |
cache_results=cache_results,
|
| 987 |
**kwargs,
|
build/torch-cuda/compat.py
CHANGED
|
@@ -502,6 +502,18 @@ def is_sm10x() -> bool:
|
|
| 502 |
return torch.cuda.is_available() and torch.cuda.get_device_capability()[0] == 10
|
| 503 |
|
| 504 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 505 |
@functools.cache
|
| 506 |
def is_sm90() -> bool:
|
| 507 |
"""Whether the CURRENT device is Hopper (sm_90) — the target the measured NVIDIA-backend
|
|
|
|
| 502 |
return torch.cuda.is_available() and torch.cuda.get_device_capability()[0] == 10
|
| 503 |
|
| 504 |
|
| 505 |
+
@functools.cache
|
| 506 |
+
def is_blackwell() -> bool:
|
| 507 |
+
"""Whether the CURRENT device is any Blackwell family: sm_10x (datacenter), sm_11x
|
| 508 |
+
(Jetson Thor) or sm_12x (consumer). Wider than ``is_sm10x``: these share the FP4
|
| 509 |
+
conversion instructions but not TMEM scaled-MMA."""
|
| 510 |
+
return (
|
| 511 |
+
torch.cuda.is_available()
|
| 512 |
+
and torch.version.hip is None
|
| 513 |
+
and torch.cuda.get_device_capability()[0] in (10, 11, 12)
|
| 514 |
+
)
|
| 515 |
+
|
| 516 |
+
|
| 517 |
@functools.cache
|
| 518 |
def is_sm90() -> bool:
|
| 519 |
"""Whether the CURRENT device is Hopper (sm_90) — the target the measured NVIDIA-backend
|
build/torch-cuda/embedding.py
ADDED
|
@@ -0,0 +1,306 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2026 The HuggingFace Inc. team. All rights reserved.
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""Selected-row lookup for floating-point and integer quantized embedding tables."""
|
| 16 |
+
|
| 17 |
+
import torch
|
| 18 |
+
import triton
|
| 19 |
+
import triton.language as tl
|
| 20 |
+
|
| 21 |
+
from .compat import (
|
| 22 |
+
FP8_DTYPE,
|
| 23 |
+
MX_SCALE_GROUP_K,
|
| 24 |
+
NVFP4_SCALE_GROUP_K,
|
| 25 |
+
add_op_namespace_prefix,
|
| 26 |
+
compile_time_only_triton_op,
|
| 27 |
+
compile_time_only_triton_wrap,
|
| 28 |
+
device_context,
|
| 29 |
+
)
|
| 30 |
+
from .formats import ue8m0_as_uint8
|
| 31 |
+
from .loading.scales import decode_group_scale
|
| 32 |
+
from .quant import e2m1_cols_to_f32
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
@triton.jit
|
| 36 |
+
def _decode_weight(value, row, FORMAT: tl.constexpr):
|
| 37 |
+
"""Stored weight elements to fp32, before scaling. FP4 unpacks two columns per byte;
|
| 38 |
+
INT4 takes the looked-up row's nibble (even rows low, odd rows high)."""
|
| 39 |
+
if FORMAT == "nvfp4" or FORMAT == "mxfp4":
|
| 40 |
+
value = e2m1_cols_to_f32(value.to(tl.uint8))
|
| 41 |
+
elif FORMAT == "int4":
|
| 42 |
+
nibble = (value.to(tl.uint8).to(tl.int32) >> ((row % 2) * 4)) & 15
|
| 43 |
+
value = ((nibble ^ 8) - 8).to(tl.float32)
|
| 44 |
+
else:
|
| 45 |
+
value = value.to(tl.float32)
|
| 46 |
+
return value
|
| 47 |
+
|
| 48 |
+
|
| 49 |
+
@triton.jit
|
| 50 |
+
def _load_scale(
|
| 51 |
+
S,
|
| 52 |
+
program,
|
| 53 |
+
row,
|
| 54 |
+
col,
|
| 55 |
+
valid,
|
| 56 |
+
row_valid,
|
| 57 |
+
D: tl.constexpr,
|
| 58 |
+
S_ROW: tl.constexpr,
|
| 59 |
+
S_COL: tl.constexpr,
|
| 60 |
+
SCALE_BLOCK_ROW: tl.constexpr,
|
| 61 |
+
SCALE_BLOCK_COL: tl.constexpr,
|
| 62 |
+
FORMAT: tl.constexpr,
|
| 63 |
+
BLOCK: tl.constexpr,
|
| 64 |
+
PACKING: tl.constexpr,
|
| 65 |
+
):
|
| 66 |
+
"""Decoded fp32 scale for each of the tile's ``BLOCK`` output values."""
|
| 67 |
+
if (
|
| 68 |
+
D % BLOCK == 0
|
| 69 |
+
and S_COL != 0
|
| 70 |
+
and BLOCK % SCALE_BLOCK_COL == 0
|
| 71 |
+
and FORMAT != "mxfp8"
|
| 72 |
+
):
|
| 73 |
+
# Load one scale per group; MXFP8 favors its existing flat byte loads.
|
| 74 |
+
groups = (program % (D // BLOCK)) * (BLOCK // SCALE_BLOCK_COL)
|
| 75 |
+
groups += tl.arange(0, BLOCK // SCALE_BLOCK_COL)
|
| 76 |
+
scale = tl.load(
|
| 77 |
+
S + (row // SCALE_BLOCK_ROW) * S_ROW + groups * S_COL,
|
| 78 |
+
row_valid,
|
| 79 |
+
other=0.0,
|
| 80 |
+
)
|
| 81 |
+
scale = decode_group_scale(scale).to(tl.float32)
|
| 82 |
+
scale = tl.broadcast_to(
|
| 83 |
+
scale[:, None], (BLOCK // SCALE_BLOCK_COL, SCALE_BLOCK_COL)
|
| 84 |
+
).reshape((BLOCK,))
|
| 85 |
+
else:
|
| 86 |
+
scale_offsets = (row // SCALE_BLOCK_ROW) * S_ROW
|
| 87 |
+
if S_COL != 0:
|
| 88 |
+
scale_offsets += (col * PACKING // SCALE_BLOCK_COL) * S_COL
|
| 89 |
+
scale = tl.load(
|
| 90 |
+
S + scale_offsets,
|
| 91 |
+
row_valid if S_COL == 0 else valid,
|
| 92 |
+
other=0.0,
|
| 93 |
+
)
|
| 94 |
+
scale = decode_group_scale(scale).to(tl.float32)
|
| 95 |
+
if PACKING == 2:
|
| 96 |
+
scale = tl.broadcast_to(scale, (BLOCK // PACKING,))
|
| 97 |
+
scale = tl.interleave(scale, scale)
|
| 98 |
+
return scale
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
@triton.jit
|
| 102 |
+
def _embedding_kernel(
|
| 103 |
+
W,
|
| 104 |
+
Ids,
|
| 105 |
+
S,
|
| 106 |
+
G,
|
| 107 |
+
Out,
|
| 108 |
+
N: tl.constexpr,
|
| 109 |
+
D: tl.constexpr,
|
| 110 |
+
V: tl.constexpr,
|
| 111 |
+
W_ROW: tl.constexpr,
|
| 112 |
+
W_COL: tl.constexpr,
|
| 113 |
+
S_ROW: tl.constexpr,
|
| 114 |
+
S_COL: tl.constexpr,
|
| 115 |
+
SCALE_BLOCK_ROW: tl.constexpr,
|
| 116 |
+
SCALE_BLOCK_COL: tl.constexpr,
|
| 117 |
+
FORMAT: tl.constexpr,
|
| 118 |
+
BLOCK: tl.constexpr,
|
| 119 |
+
):
|
| 120 |
+
# FP4 packs adjacent columns; INT4 packs adjacent vocabulary rows.
|
| 121 |
+
packing: tl.constexpr = 2 if (FORMAT == "nvfp4" or FORMAT == "mxfp4") else 1
|
| 122 |
+
program = tl.program_id(0).to(tl.int64)
|
| 123 |
+
offsets = program * (BLOCK // packing) + tl.arange(0, BLOCK // packing)
|
| 124 |
+
valid = offsets < N * (D // packing)
|
| 125 |
+
# Tiles contained in one row share its index and per-row scale across all lanes.
|
| 126 |
+
if D % BLOCK == 0:
|
| 127 |
+
indices = program // (D // BLOCK)
|
| 128 |
+
else:
|
| 129 |
+
indices = offsets // (D // packing)
|
| 130 |
+
valid_rows = indices < N
|
| 131 |
+
row = tl.load(Ids + indices, valid_rows, other=0).to(tl.int64)
|
| 132 |
+
in_bounds = (row >= 0) & (row < V)
|
| 133 |
+
tl.device_assert(in_bounds | ~valid_rows, "embedding index out of range")
|
| 134 |
+
valid = valid & in_bounds
|
| 135 |
+
col = offsets % (D // packing)
|
| 136 |
+
weight_row = row // 2 if FORMAT == "int4" else row
|
| 137 |
+
value = tl.load(W + weight_row * W_ROW + col * W_COL, valid, other=0.0)
|
| 138 |
+
value = _decode_weight(value, row, FORMAT)
|
| 139 |
+
scale = _load_scale(
|
| 140 |
+
S, program, row, col, valid, valid_rows & in_bounds, D, S_ROW, S_COL,
|
| 141 |
+
SCALE_BLOCK_ROW, SCALE_BLOCK_COL, FORMAT, BLOCK, packing,
|
| 142 |
+
)
|
| 143 |
+
value = value * scale
|
| 144 |
+
if FORMAT == "nvfp4":
|
| 145 |
+
value = value * tl.load(G).to(tl.float32)
|
| 146 |
+
output_offsets = program * BLOCK + tl.arange(0, BLOCK)
|
| 147 |
+
tl.store(Out + output_offsets, value, output_offsets < N * D)
|
| 148 |
+
|
| 149 |
+
|
| 150 |
+
def _check_inputs(weight, indices, scale, global_scale, output_dtype, weight_format, block_size):
|
| 151 |
+
"""Validate an ``embedding_lookup`` call and resolve its format, its scale (UE8M0 viewed
|
| 152 |
+
as bytes), the ``(width, vocab, scale strides, scale blocks)`` kernel layout and the
|
| 153 |
+
output dtype. See ``embedding_lookup`` for the accepted layouts."""
|
| 154 |
+
if weight_format is None:
|
| 155 |
+
if global_scale is not None:
|
| 156 |
+
weight_format = "nvfp4"
|
| 157 |
+
else:
|
| 158 |
+
weight_format = "int8" if weight.dtype == torch.int8 else "fp8"
|
| 159 |
+
if weight_format not in ("fp8", "nvfp4", "mxfp8", "mxfp4", "int8", "int4"):
|
| 160 |
+
raise ValueError(f"Unsupported embedding weight format: {weight_format}.")
|
| 161 |
+
if weight.ndim != 2 or indices.dtype not in (torch.int32, torch.int64):
|
| 162 |
+
raise ValueError("Expected a 2D embedding table and int32/int64 indices.")
|
| 163 |
+
if weight.device != indices.device or weight.device != scale.device:
|
| 164 |
+
raise ValueError("Embedding table, indices, and scales must share a device.")
|
| 165 |
+
packed_columns = weight_format in ("nvfp4", "mxfp4")
|
| 166 |
+
width = weight.shape[1] * (2 if packed_columns else 1)
|
| 167 |
+
vocab = weight.shape[0] * (2 if weight_format == "int4" else 1)
|
| 168 |
+
if width == 0:
|
| 169 |
+
raise ValueError("Embedding width must be positive.")
|
| 170 |
+
float_dtypes = (torch.float16, torch.bfloat16, torch.float32)
|
| 171 |
+
scale_row = scale_col = 0
|
| 172 |
+
row_block = col_block = 1
|
| 173 |
+
if weight_format in ("fp8", "int8"):
|
| 174 |
+
expected_dtype = FP8_DTYPE if weight_format == "fp8" else torch.int8
|
| 175 |
+
if weight.dtype != expected_dtype or scale.dtype not in float_dtypes:
|
| 176 |
+
raise ValueError(
|
| 177 |
+
f"{weight_format.upper()} requires {expected_dtype} weights and floating scales."
|
| 178 |
+
)
|
| 179 |
+
if scale.numel() == 1 and weight_format == "fp8":
|
| 180 |
+
pass
|
| 181 |
+
elif scale.shape in ((vocab,), (vocab, 1)):
|
| 182 |
+
scale_row = scale.stride(0)
|
| 183 |
+
elif (
|
| 184 |
+
weight_format == "fp8"
|
| 185 |
+
and block_size > 0
|
| 186 |
+
and scale.shape
|
| 187 |
+
== (triton.cdiv(vocab, block_size), triton.cdiv(width, block_size))
|
| 188 |
+
):
|
| 189 |
+
row_block = col_block = block_size
|
| 190 |
+
scale_row, scale_col = scale.stride()
|
| 191 |
+
else:
|
| 192 |
+
raise ValueError(
|
| 193 |
+
"FP8 scales must be scalar, per-row, or a block grid; INT8 scales must be per-row."
|
| 194 |
+
)
|
| 195 |
+
else:
|
| 196 |
+
if weight_format == "mxfp8":
|
| 197 |
+
if weight.dtype != FP8_DTYPE:
|
| 198 |
+
raise ValueError("MXFP8 requires E4M3 weights.")
|
| 199 |
+
elif weight.dtype not in (torch.int8, torch.uint8):
|
| 200 |
+
raise ValueError("FP4 and INT4 weights must be packed int8/uint8 bytes.")
|
| 201 |
+
if weight_format == "nvfp4":
|
| 202 |
+
col_block = NVFP4_SCALE_GROUP_K
|
| 203 |
+
scale_dtypes = (FP8_DTYPE,)
|
| 204 |
+
elif weight_format in ("mxfp8", "mxfp4"):
|
| 205 |
+
col_block = MX_SCALE_GROUP_K
|
| 206 |
+
scale = ue8m0_as_uint8(scale)
|
| 207 |
+
scale_dtypes = (torch.uint8,)
|
| 208 |
+
else:
|
| 209 |
+
if scale.ndim != 2 or scale.shape[1] == 0 or width % scale.shape[1]:
|
| 210 |
+
raise ValueError(
|
| 211 |
+
"INT4 scales must be a per-row grid of equal column groups."
|
| 212 |
+
)
|
| 213 |
+
col_block = width // scale.shape[1]
|
| 214 |
+
scale_dtypes = float_dtypes
|
| 215 |
+
if (
|
| 216 |
+
width % col_block
|
| 217 |
+
or scale.shape != (vocab, width // col_block)
|
| 218 |
+
or scale.dtype not in scale_dtypes
|
| 219 |
+
):
|
| 220 |
+
raise ValueError(
|
| 221 |
+
f"{weight_format.upper()} requires a ({vocab}, {width // col_block}) scale grid with dtype in {scale_dtypes}."
|
| 222 |
+
)
|
| 223 |
+
scale_row, scale_col = scale.stride()
|
| 224 |
+
if weight_format == "nvfp4":
|
| 225 |
+
if (
|
| 226 |
+
global_scale is None
|
| 227 |
+
or global_scale.dtype != torch.float32
|
| 228 |
+
or global_scale.numel() != 1
|
| 229 |
+
or global_scale.device != weight.device
|
| 230 |
+
):
|
| 231 |
+
raise ValueError(
|
| 232 |
+
"NVFP4 requires one FP32 global multiplier on the table's device."
|
| 233 |
+
)
|
| 234 |
+
elif global_scale is not None:
|
| 235 |
+
raise ValueError("Only NVFP4 embeddings use a global multiplier.")
|
| 236 |
+
dtype = output_dtype or (
|
| 237 |
+
torch.bfloat16 if weight_format in ("nvfp4", "mxfp8", "mxfp4") else scale.dtype
|
| 238 |
+
)
|
| 239 |
+
if dtype not in float_dtypes:
|
| 240 |
+
raise ValueError("Embedding output must be float16, bfloat16, or float32.")
|
| 241 |
+
return weight_format, scale, (width, vocab, scale_row, scale_col, row_block, col_block), dtype
|
| 242 |
+
|
| 243 |
+
|
| 244 |
+
@compile_time_only_triton_op(add_op_namespace_prefix("embedding_lookup"))
|
| 245 |
+
def embedding_lookup(
|
| 246 |
+
weight: torch.Tensor,
|
| 247 |
+
indices: torch.Tensor,
|
| 248 |
+
scale: torch.Tensor,
|
| 249 |
+
global_scale: torch.Tensor | None = None,
|
| 250 |
+
output_dtype: torch.dtype | None = None,
|
| 251 |
+
*,
|
| 252 |
+
weight_format: str | None = None,
|
| 253 |
+
block_size: int = 128,
|
| 254 |
+
) -> torch.Tensor:
|
| 255 |
+
"""Gather and dequantize selected rows without expanding the embedding table.
|
| 256 |
+
|
| 257 |
+
``weight_format`` selects ``fp8``, ``nvfp4``, ``mxfp8``, ``mxfp4``, ``int8``, or ``int4``.
|
| 258 |
+
By default, a global scale selects NVFP4, signed int8 weights select INT8, and otherwise
|
| 259 |
+
FP8 is used. FP8 accepts scalar, per-row, or square block scales (``block_size``).
|
| 260 |
+
NVFP4 uses E4M3 group-16 scales and one FP32 multiplier; MX formats use UE8M0 group-32
|
| 261 |
+
scales. FP4 packs adjacent columns, low nibble first. INT8 uses per-row scales; INT4
|
| 262 |
+
packs adjacent vocabulary rows and uses per-row column groups inferred from its scale
|
| 263 |
+
grid. Integer values are signed, symmetric, and have no zero point.
|
| 264 |
+
|
| 265 |
+
Outputs default to the floating scale dtype, or bf16 for NVFP4/MX. Table/grid strides
|
| 266 |
+
may describe TP slices. Indices follow ``torch.nn.functional.embedding``: negative and
|
| 267 |
+
out-of-range values fail; padding indices look up their stored row. Empty, repeated,
|
| 268 |
+
and noncontiguous indices work.
|
| 269 |
+
"""
|
| 270 |
+
weight_format, scale, layout, dtype = _check_inputs(
|
| 271 |
+
weight, indices, scale, global_scale, output_dtype, weight_format, block_size
|
| 272 |
+
)
|
| 273 |
+
width, vocab, scale_row, scale_col, row_block, col_block = layout
|
| 274 |
+
out = torch.empty((*indices.shape, width), dtype=dtype, device=weight.device)
|
| 275 |
+
rows, numel = indices.numel(), out.numel()
|
| 276 |
+
if rows == 0:
|
| 277 |
+
return out
|
| 278 |
+
# Keep small lookups parallel; larger tiles amortize scheduling for bulk lookups.
|
| 279 |
+
block = 256
|
| 280 |
+
if numel >= 256 * 1024:
|
| 281 |
+
block = 1024
|
| 282 |
+
if numel >= 4 * 1024 * 1024:
|
| 283 |
+
block = 4096
|
| 284 |
+
with device_context(weight.device):
|
| 285 |
+
compile_time_only_triton_wrap(_embedding_kernel)[(triton.cdiv(numel, block),)](
|
| 286 |
+
weight,
|
| 287 |
+
indices.reshape(-1),
|
| 288 |
+
scale,
|
| 289 |
+
global_scale,
|
| 290 |
+
out,
|
| 291 |
+
rows,
|
| 292 |
+
width,
|
| 293 |
+
vocab,
|
| 294 |
+
weight.stride(0),
|
| 295 |
+
weight.stride(1),
|
| 296 |
+
scale_row,
|
| 297 |
+
scale_col,
|
| 298 |
+
row_block,
|
| 299 |
+
col_block,
|
| 300 |
+
weight_format,
|
| 301 |
+
block,
|
| 302 |
+
num_warps=4,
|
| 303 |
+
enable_fp_fusion=False,
|
| 304 |
+
debug=True,
|
| 305 |
+
)
|
| 306 |
+
return out
|
build/torch-cuda/metadata.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
{
|
| 2 |
"name": "finegrained-kernels",
|
| 3 |
-
"id": "
|
| 4 |
"version": 0,
|
| 5 |
"kernels-minver": "0.14.0",
|
| 6 |
"license": "Apache-2.0",
|
|
@@ -12,13 +12,15 @@
|
|
| 12 |
"digest": {
|
| 13 |
"algorithm": "sha256",
|
| 14 |
"files": {
|
| 15 |
-
"__init__.py": "
|
| 16 |
-
"_ops.py": "
|
|
|
|
| 17 |
"backward.py": "K1S6KD3J/12SthXiqBcmNO9kUikctQpccsbxsO8lpRg=",
|
| 18 |
"batched.py": "U4zfmMlnQjr4j+kiIxzzohKmIXG0rtQX38c3i+aBgT8=",
|
| 19 |
-
"bayesian_autotuner.py": "
|
| 20 |
-
"compat.py": "
|
| 21 |
"descriptors.py": "4acRMazGPFlbydNt1Hbo8RpAqb3fOtnOQBv5yb4onqw=",
|
|
|
|
| 22 |
"epilogue.py": "vIeMt0EqWgpvadDw5r38/5TVRMMzIMthfXGHPa3lTeY=",
|
| 23 |
"formats.py": "rtzJgKnIK1PV/sqNnPGO67Ve6czzx1ldyIhs9HhydSk=",
|
| 24 |
"grouped.py": "jv+qffb9l+MRDbo9UdA1yV15o8QcgNvE6ZYzCpPrpYM=",
|
|
@@ -29,11 +31,11 @@
|
|
| 29 |
"mma.py": "gLkCU5QjhQVMacixNR24Yi07aNelQyN+I0pJOuRxE4E=",
|
| 30 |
"moe.py": "4n/TzWy0kRXAL9qGY/aChbdSdCpahVVmMUKCfd6/zF0=",
|
| 31 |
"norm.py": "VvE6GUE0Oztf7PDcviLCcB4fhnXt7/zgdE+aApv6DBM=",
|
| 32 |
-
"pruners.py": "
|
| 33 |
-
"quant.py": "
|
| 34 |
"scheduling.py": "cxwoL5NTJxARVxLStDsNalm/jqbkCObm8uyLRFL/yYc=",
|
| 35 |
"swizzle.py": "ueIJ9FsO8QZhVt3nMFlA+8b+U9/ZHabHFlhufsONV04=",
|
| 36 |
-
"symbols.json": "
|
| 37 |
}
|
| 38 |
},
|
| 39 |
"provenance": {
|
|
@@ -43,7 +45,7 @@
|
|
| 43 |
"dirty": false
|
| 44 |
},
|
| 45 |
"kernel": {
|
| 46 |
-
"commit": "
|
| 47 |
"dirty": false
|
| 48 |
}
|
| 49 |
}
|
|
|
|
| 1 |
{
|
| 2 |
"name": "finegrained-kernels",
|
| 3 |
+
"id": "_finegrained_kernels_cuda_ec5cc90",
|
| 4 |
"version": 0,
|
| 5 |
"kernels-minver": "0.14.0",
|
| 6 |
"license": "Apache-2.0",
|
|
|
|
| 12 |
"digest": {
|
| 13 |
"algorithm": "sha256",
|
| 14 |
"files": {
|
| 15 |
+
"__init__.py": "xFRwaLTont8ZLTxS5ajuiDqM9gWwXAU4xap2prqdhrY=",
|
| 16 |
+
"_ops.py": "DwdUBjZmrNFv1HEdJDNcSfPqBc4da6D3M8v2dUzUA3g=",
|
| 17 |
+
"autotune_config.py": "d5fb2Vqss0fgC9TZbarrmQIInL1n1L7rHz6o3Gqv6cI=",
|
| 18 |
"backward.py": "K1S6KD3J/12SthXiqBcmNO9kUikctQpccsbxsO8lpRg=",
|
| 19 |
"batched.py": "U4zfmMlnQjr4j+kiIxzzohKmIXG0rtQX38c3i+aBgT8=",
|
| 20 |
+
"bayesian_autotuner.py": "NDRUQrhk+bEEvrOkIilWJPfqdKpcsd4E4QQ9AHzylKI=",
|
| 21 |
+
"compat.py": "K3RCq1ETi80duzv3zSldIwrL5e46vZAWtLxLlg1LXvM=",
|
| 22 |
"descriptors.py": "4acRMazGPFlbydNt1Hbo8RpAqb3fOtnOQBv5yb4onqw=",
|
| 23 |
+
"embedding.py": "k7jiz2vtEJuYKo+w6TuS/4WO1D4Bv96O5DMFjEpYUGo=",
|
| 24 |
"epilogue.py": "vIeMt0EqWgpvadDw5r38/5TVRMMzIMthfXGHPa3lTeY=",
|
| 25 |
"formats.py": "rtzJgKnIK1PV/sqNnPGO67Ve6czzx1ldyIhs9HhydSk=",
|
| 26 |
"grouped.py": "jv+qffb9l+MRDbo9UdA1yV15o8QcgNvE6ZYzCpPrpYM=",
|
|
|
|
| 31 |
"mma.py": "gLkCU5QjhQVMacixNR24Yi07aNelQyN+I0pJOuRxE4E=",
|
| 32 |
"moe.py": "4n/TzWy0kRXAL9qGY/aChbdSdCpahVVmMUKCfd6/zF0=",
|
| 33 |
"norm.py": "VvE6GUE0Oztf7PDcviLCcB4fhnXt7/zgdE+aApv6DBM=",
|
| 34 |
+
"pruners.py": "5kZlpQiAvhdy8tiD8+tsy3YLDwYpHGY/aKAsxIVkTRw=",
|
| 35 |
+
"quant.py": "1fNRvb63DAOcFNLfKw3cSwMqSwLua4smI+xvhlsUk3k=",
|
| 36 |
"scheduling.py": "cxwoL5NTJxARVxLStDsNalm/jqbkCObm8uyLRFL/yYc=",
|
| 37 |
"swizzle.py": "ueIJ9FsO8QZhVt3nMFlA+8b+U9/ZHabHFlhufsONV04=",
|
| 38 |
+
"symbols.json": "sVGkXI22bMHsNCUTsKl1Hj70D7j8D+/KhJ2CS1JhIPA="
|
| 39 |
}
|
| 40 |
},
|
| 41 |
"provenance": {
|
|
|
|
| 45 |
"dirty": false
|
| 46 |
},
|
| 47 |
"kernel": {
|
| 48 |
+
"commit": "ec5cc90e1657566c66c62b5021435edbcfa348c3",
|
| 49 |
"dirty": false
|
| 50 |
}
|
| 51 |
}
|
build/torch-cuda/metadata.json.sigstore
CHANGED
|
@@ -1 +1 @@
|
|
| 1 |
-
{"mediaType":"application/vnd.dev.sigstore.bundle.v0.3+json","verificationMaterial":{"certificate":{"rawBytes":"MIIHKjCCBrGgAwIBAgIUYjRfDt64EwMm2w5mvJf2snFI03gwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjYxMDIwMDc0NTA4WhcNMjYxMDIwMDc1NTA4WjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEVosgukER4CXhkkdfSXj6fQjeiWig2uOUbciDoDxHWLHj/LYrEK37NIX0hVju279Sg0dyPpiIctPzCStUj3ecUaOCBdAwggXMMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSMEGDAWgBTf0+nPViQRlvmo2OkoVaLGLhhkPzBrBgNVHREBAf8EYTBfhl1odHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkvLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQueWFtbEByZWZzL2hlYWRzL21haW4wOQYKKwYBBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50LmNvbTAfBgorBgEEAYO/MAECBBF3b3JrZmxvd19kaXNwYXRjaDA2BgorBgEEAYO/MAEDBCg0M2YxNTgxMGIzYWNhYWQxZDE3ZjY3NzQ1ZjA2NzY4OTZiNmZjZjBkMBMGCisGAQQBg78wAQQEBUJ1aWxkMCsGCisGAQQBg78wAQUEHWh1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5MB0GCisGAQQBg78wAQYED3JlZnMvaGVhZHMvbWFpbjA7BgorBgEEAYO/MAEIBC0MK2h0dHBzOi8vdG9rZW4uYWN0aW9ucy5naXRodWJ1c2VyY29udGVudC5jb20wbQYKKwYBBAGDvzABCQRfDF1odHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkvLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQueWFtbEByZWZzL2hlYWRzL21haW4wOAYKKwYBBAGDvzABCgQqDCg0M2YxNTgxMGIzYWNhYWQxZDE3ZjY3NzQ1ZjA2NzY4OTZiNmZjZjBkMBsGCisGAQQBg78wAQsEDQwLc2VsZi1ob3N0ZWQwQAYKKwYBBAGDvzABDAQyDDBodHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkwOAYKKwYBBAGDvzABDQQqDCg0M2YxNTgxMGIzYWNhYWQxZDE3ZjY3NzQ1ZjA2NzY4OTZiNmZjZjBkMB8GCisGAQQBg78wAQ4EEQwPcmVmcy9oZWFkcy9tYWluMBoGCisGAQQBg78wAQ8EDAwKMTA3MTQ3NTUyOTAuBgorBgEEAYO/MAEQBCAMHmh0dHBzOi8vZ2l0aHViLmNvbS9odWdnaW5nZmFjZTAYBgorBgEEAYO/MAERBAoMCDI1NzIwNzQzMG0GCisGAQQBg78wARIEXwxdaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5Ly5naXRodWIvd29ya2Zsb3dzL2J1aWxkLnlhbWxAcmVmcy9oZWFkcy9tYWluMDgGCisGAQQBg78wARMEKgwoNDNmMTU4MTBiM2FjYWFkMWQxN2Y2Nzc0NWYwNjc2ODk2YjZmY2YwZDAhBgorBgEEAYO/MAEUBBMMEXdvcmtmbG93X2Rpc3BhdGNoMGQGCisGAQQBg78wARUEVgxUaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5L2FjdGlvbnMvcnVucy8zOTM4Nzk5OTk0Ny9hdHRlbXB0cy8xMBYGCisGAQQBg78wARYECAwGcHVibGljMEYGCisGAQQBg78wARgEOAw2cmVwbzpodWdnaW5nZmFjZS9rZXJuZWxzLWNvbW11bml0eTpyZWY6cmVmcy9oZWFkcy9tYWluMIGJBgorBgEEAdZ5AgQCBHsEeQB3AHUA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGhWEVw1gAABAMARjBEAiBQIWsZSWB9SJnGRw0TAla0o5FB0zYAm05drx5ceF8hZwIgcJXjQg1k+AOW7IQ8jSl/xqcqBqMtOZZ4ZDUyAW74/3EwCgYIKoZIzj0EAwMDZwAwZAIwQUUPe2Wu9HMn7udhGmysCY3wmjvsq5XAq26BaF2dsHqb654f7eVjlzgv69NyN+INAjBS+0uAAoIQtkuKGmdxafnxXTlaVHKjkgGeHzCOM9vQ2d1M5Pe6SMCzIJX6Be0kZv8="},"tlogEntries":[{"logIndex":"3333276781","logId":{"keyId":"wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="},"kindVersion":{"kind":"hashedrekord","version":"0.0.1"},"integratedTime":"1792482308","inclusionPromise":{"signedEntryTimestamp":"MEQCIBFaOIQqgtBjrkEZL6N9d+ec1YTSMPhobCkwlT0b0kSCAiA1RnJFqAyg2V4NirN3+K9sq3AlLM6Fr7y0yLF5WUaPJg=="},"inclusionProof":{"logIndex":"3211372519","rootHash":"AAuNOep3f6B6LEiLxEJLdf3MrE+3zqg7zm9NZq+xwfg=","treeSize":"3211372521","hashes":["kSi6E1FLwjGxB6aGLjryVwfihvJqSpRS8HNrf320SFM=","KpdKzAVftSQYDDBeFgeUVygXUujlCunLuEufgAMcTCs=","HsnVOmvwSYcTBx5ev7Cwx82EDIzB4cL99kQg3bhkmk8=","ZO4WKHe6e+kjduSIqG+P39aU3jpzqV5WS46QbUt/1lM=","DSCf6YnSfwKGZbSQHikozOUYjJVNknivnUg1PC0RRns=","OMrFmT5b3Baa5tQ18hoVjZoPhI3C49iB09L+Byp3z2o=","/2z6rGxIRvEQCFmmSVuv3acTBVHwi852tRBHlC4/vSE=","aHvYjdQ34DQYMV9K0YMPPiIHQk74oGCBXn6ekwMGA3U=","pPbxA70P/0HkEiYY2jZB61Bpv0868ThbYHS5oemCUxo=","eKD1kuBv/uuXm3Q+ddDIoOM07eGyxtScSe41MjUUwEA=","35bnJ5pQ9Q/ajuvM0i7P6+YcssTBPuuptjhAKxuEmfo=","OcDrZ0RIsie8PY2uv3Av6cECp65xfWyxKOKcM1/c3sc=","zj28xnvSQbA7lgK1R588ZHvZYy6Gy03wZvsJNVfxG9o=","2ljWFy3+P4yeeVU2ALgF4M45of0N5Rv4W1Z/jm/9n5w=","3aUq4N47Z1/AszcODIxRgusLXNRFZAnHFg6Vur7t22o=","PwdgHXfl6JMsozFa2gp9OjWOM8+7eYRrqPJa9FEI6k4=","HovTPBWzoErvUg1u5sIi3x1ZonZ7yJekVsBrmpomCIA=","G+nk7mgE5h6dUmv2UY7NDJrY3WvrZY31raaO1AETt+o=","qlTWNDzERnTBQVcHHXXVPjiUP0SsikGxfcxVlgqVFDo=","gg9GNApNke3+zNhl4tsWtmIycCFrOMCB3lys6XuSQNQ=","NlOclldmKPA1tMKIskqHAwuQDYHp31YwpK+OOMrMccc=","qxzHanAzz57SDdmJe0B7bJK72NTIBbwEMGBBKvDOROw=","xH/DCseLHr9eKoYT8qsORZK7zVdEGYWHuVtsVrD95wY="],"checkpoint":{"envelope":"rekor.sigstore.dev - 1193050959916656506\n3211372521\nAAuNOep3f6B6LEiLxEJLdf3MrE+3zqg7zm9NZq+xwfg=\n\n— rekor.sigstore.dev wNI9ajBGAiEAiHqnOXsqc9SUah3w9DEbIpUb2csqmTT7SpdakR2wOmYCIQDAikNdot3q0+e2IXLza+Diw4Tn08v5eti/aHYhGvKzTg==\n"}},"canonicalizedBody":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJlMTE4OGEyZmEzYWM5NGJkYTFmMzEzMDQ1NDU2YzFhYmNmZTcwNmM1ZDU4YmMwN2RjZjA5Yjg3NmZlZjM0N2UwIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJUUNscUdyeDRIRTRNdG1Uc24rZFZWTVEyWUEweTRjUGpLT0xBY1E3emlENGNnSWdBOEt4YU5qYTV5RlZkcXoxRG5qM0tpbE8yZDg3WHdpWmU2NExMd3B3c2FFPSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVaExha05EUW5KSFowRjNTVUpCWjBsVldXcFNaa1IwTmpSRmQwMXRNbmMxYlhaS1pqSnpia1pKTURObmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFFU1hkTlJHTXdUbFJCTkZkb1kwNU5hbGw0VFVSSmQwMUVZekZPVkVFMFYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZXYjNObmRXdEZValJEV0docmEyUm1VMWhxTm1aUmFtVnBWMmxuTW5WUFZXSmphVVFLYjBSNFNGZE1TR292VEZseVJVc3pOMDVKV0RCb1ZtcDFNamM1VTJjd1pIbFFjR2xKWTNSUWVrTlRkRlZxTTJWalZXRlBRMEprUVhkbloxaE5UVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFuSkNaMDVXU0ZKRlFrRm1PRVZaVkVKbWFHd3hiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmhTRlp1V2pKc2RWb3lXbWhaTWxWMllUSldlV0p0Vm5OamVURnFZakl4ZEdSWE5YQmtTR3QyVEcxa2NHUkhhREZaYVRrellqTktjZ3BhYlhoMlpETk5kbGx1Vm5CaVIxRjFaVmRHZEdKRlFubGFWMXA2VERKb2JGbFhVbnBNTWpGb1lWYzBkMDlSV1V0TGQxbENRa0ZIUkhaNlFVSkJVVkZ5Q21GSVVqQmpTRTAyVEhrNU1HSXlkR3hpYVRWb1dUTlNjR0l5TlhwTWJXUndaRWRvTVZsdVZucGFXRXBxWWpJMU1GcFhOVEJNYlU1MllsUkJaa0puYjNJS1FtZEZSVUZaVHk5TlFVVkRRa0pHTTJJelNuSmFiWGgyWkRFNWEyRllUbmRaV0ZKcVlVUkJNa0puYjNKQ1owVkZRVmxQTDAxQlJVUkNRMmN3VFRKWmVBcE9WR2Q0VFVkSmVsbFhUbWhaVjFGNFdrUkZNMXBxV1ROT2VsRXhXbXBCTWs1NldUUlBWRnBwVG0xYWFscHFRbXROUWsxSFEybHpSMEZSVVVKbk56aDNDa0ZSVVVWQ1ZVb3hZVmQ0YTAxRGMwZERhWE5IUVZGUlFtYzNPSGRCVVZWRlNGZG9NVm95WkhCaWJXUnRXVmRPYkV3eWRHeGpiVFZzWWtoTmRGa3lPWFFLWWxoV2RXRllValZOUWpCSFEybHpSMEZSVVVKbk56aDNRVkZaUlVRelNteGFiazEyWVVkV2FGcElUWFppVjBad1ltcEJOMEpuYjNKQ1owVkZRVmxQTHdwTlFVVkpRa013VFVzeWFEQmtTRUo2VDJrNGRtUkhPWEphVnpSMVdWZE9NR0ZYT1hWamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcUNtSXlNSGRpVVZsTFMzZFpRa0pCUjBSMmVrRkNRMUZTWmtSR01XOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaFNGWnVXakpzZFZveVdtZ0tXVEpWZG1FeVZubGliVlp6WTNreGFtSXlNWFJrVnpWd1pFaHJka3h0WkhCa1IyZ3hXV2s1TTJJelNuSmFiWGgyWkROTmRsbHVWbkJpUjFGMVpWZEdkQXBpUlVKNVdsZGFla3d5YUd4WlYxSjZUREl4YUdGWE5IZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1EyZFJjVVJEWnpCTk1sbDRUbFJuZUUxSFNYcFpWMDVvQ2xsWFVYaGFSRVV6V21wWk0wNTZVVEZhYWtFeVRucFpORTlVV21sT2JWcHFXbXBDYTAxQ2MwZERhWE5IUVZGUlFtYzNPSGRCVVhORlJGRjNUR015Vm5NS1dta3hiMkl6VGpCYVYxRjNVVUZaUzB0M1dVSkNRVWRFZG5wQlFrUkJVWGxFUkVKdlpFaFNkMk42YjNaTU1tUndaRWRvTVZscE5XcGlNakIyWVVoV2JncGFNbXgxV2pKYWFGa3lWWFpoTWxaNVltMVdjMk41TVdwaU1qRjBaRmMxY0dSSWEzZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JGRlJjVVJEWnpCTk1sbDRDazVVWjNoTlIwbDZXVmRPYUZsWFVYaGFSRVV6V21wWk0wNTZVVEZhYWtFeVRucFpORTlVV21sT2JWcHFXbXBDYTAxQ09FZERhWE5IUVZGUlFtYzNPSGNLUVZFMFJVVlJkMUJqYlZadFkzazViMXBYUm10amVUbDBXVmRzZFUxQ2IwZERhWE5IUVZGUlFtYzNPSGRCVVRoRlJFRjNTMDFVUVROTlZGRXpUbFJWZVFwUFZFRjFRbWR2Y2tKblJVVkJXVTh2VFVGRlVVSkRRVTFJYldnd1pFaENlazlwT0haYU1td3dZVWhXYVV4dFRuWmlVemx2WkZka2JtRlhOVzVhYlVacUNscFVRVmxDWjI5eVFtZEZSVUZaVHk5TlFVVlNRa0Z2VFVORVNURk9la2wzVG5wUmVrMUhNRWREYVhOSFFWRlJRbWMzT0hkQlVrbEZXSGQ0WkdGSVVqQUtZMGhOTmt4NU9XNWhXRkp2WkZkSmRWa3lPWFJNTW1neFdqSmtjR0p0WkcxWlYwNXNUREowYkdOdE5XeGlTRTEwV1RJNWRHSllWblZoV0ZJMVRIazFiZ3BoV0ZKdlpGZEpkbVF5T1hsaE1scHpZak5rZWt3eVNqRmhWM2hyVEc1c2FHSlhlRUZqYlZadFkzazViMXBYUm10amVUbDBXVmRzZFUxRVowZERhWE5IQ2tGUlVVSm5OemgzUVZKTlJVdG5kMjlPUkU1dFRWUlZORTFVUW1sTk1rWnFXVmRHYTAxWFVYaE9NbGt5VG5wak1FNVhXWGRPYW1NeVQwUnJNbGxxV20wS1dUSlpkMXBFUVdoQ1oyOXlRbWRGUlVGWlR5OU5RVVZWUWtKTlRVVllaSFpqYlhSdFlrYzVNMWd5VW5Cak0wSm9aRWRPYjAxSFVVZERhWE5IUVZGUlFncG5OemgzUVZKVlJWWm5lRlZoU0ZJd1kwaE5Oa3g1T1c1aFdGSnZaRmRKZFZreU9YUk1NbWd4V2pKa2NHSnRaRzFaVjA1c1RESjBiR050Tld4aVNFMTBDbGt5T1hSaVdGWjFZVmhTTlV3eVJtcGtSMngyWW01TmRtTnVWblZqZVRoNlQxUk5ORTU2YXpWUFZHc3dUbms1YUdSSVVteGlXRUl3WTNrNGVFMUNXVWNLUTJselIwRlJVVUpuTnpoM1FWSlpSVU5CZDBkalNGWnBZa2RzYWsxRldVZERhWE5IUVZGUlFtYzNPSGRCVW1kRlQwRjNNbU50Vm5kaWVuQnZaRmRrYmdwaFZ6VnVXbTFHYWxwVE9YSmFXRXAxV2xkNGVreFhUblppVnpFeFltMXNNR1ZVY0hsYVYxazJZMjFXYldONU9XOWFWMFpyWTNrNWRGbFhiSFZOU1VkS0NrSm5iM0pDWjBWRlFXUmFOVUZuVVVOQ1NITkZaVkZDTTBGSVZVRXpWREIzWVhOaVNFVlVTbXBIVWpSamJWZGpNMEZ4U2t0WWNtcGxVRXN6TDJnMGNIa0taME00Y0Rkdk5FRkJRVWRvVjBWV2R6Rm5RVUZDUVUxQlVtcENSVUZwUWxGSlYzTmFVMWRDT1ZOS2JrZFNkekJVUVd4aE1HODFSa0l3ZWxsQmJUQTFaQXB5ZURWalpVWTRhRnAzU1dkalNsaHFVV2N4YXl0QlQxYzNTVkU0YWxOc0wzaHhZM0ZDY1UxMFQxcGFORnBFVlhsQlZ6YzBMek5GZDBObldVbExiMXBKQ25wcU1FVkJkMDFFV25kQmQxcEJTWGRSVlZWUVpUSlhkVGxJVFc0M2RXUm9SMjE1YzBOWk0zZHRhblp6Y1RWWVFYRXlOa0poUmpKa2MwaHhZalkxTkdZS04yVldhbXg2WjNZMk9VNTVUaXRKVGtGcVFsTXJNSFZCUVc5SlVYUnJkVXRIYldSNFlXWnVlRmhVYkdGV1NFdHFhMmRIWlVoNlEwOU5PWFpSTW1ReFRRbzFVR1UyVTAxRGVrbEtXRFpDWlRCclduWTRQUW90TFMwdExVVk9SQ0JEUlZKVVNVWkpRMEZVUlMwdExTMHRDZz09In19fX0="}],"timestampVerificationData":{"rfc3161Timestamps":[{"signedTimestamp":"MIICyjADAgEAMIICwQYJKoZIhvcNAQcCoIICsjCCAq4CAQMxDTALBglghkgBZQMEAgEwgbgGCyqGSIb3DQEJEAEEoIGoBIGlMIGiAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQgY3k0z/Mt7jMBEhOjvjf2G4CnoToAJ6VFGWkxAh1uoOYCFQCJXH8pBrNsoDup37wFNKA026PnoBgPMjAyNjEwMjAwNzQ1MDhaMAMCAQGgMqQwMC4xFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEVMBMGA1UEAxMMc2lnc3RvcmUtdHNhoAAxggHbMIIB1wIBATBRMDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQCFDoTVC8MkGHuvMFDL8uKjosqI4sMMAsGCWCGSAFlAwQCAaCB/DAaBgkqhkiG9w0BCQMxDQYLKoZIhvcNAQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTI2MTAyMDA3NDUwOFowLwYJKoZIhvcNAQkEMSIEIF71Fa9Y2eBvEIVLLboLwnryQ7XILn3/JFn/+1wF+4ddMIGOBgsqhkiG9w0BCRACLzF/MH0wezB5BCCF+Se8B6tiysO0Q1bBDvyBssaIP9p6uebYcNnROs0FtzBVMD2kOzA5MRUwEwYDVQQKEwxzaWdzdG9yZS5kZXYxIDAeBgNVBAMTF3NpZ3N0b3JlLXRzYS1zZWxmc2lnbmVkAhQ6E1QvDJBh7rzBQy/Lio6LKiOLDDAKBggqhkjOPQQDAgRnMGUCMQDjXGEzJIPO0LhMOvGESo6oPJAF8cA/W/LS4FxKIXt2lA+oMCsX4UlFfHVmyUHEi8MCMGGJHGkEaw0eWLT2aTvt7BArmK0TWJXsTkbdnXPHHieoVQ6XUIfg+a76JBGvPIZN0w=="}]}},"messageSignature":{"messageDigest":{"algorithm":"SHA2_256","digest":"4RiKL6OslL2h8xMEVFbBq8/nBsXVi8B9zwm4dv7zR+A="},"signature":"MEUCIQClqGrx4HE4MtmTsn+dVVMQ2YA0y4cPjKOLAcQ7ziD4cgIgA8KxaNja5yFVdqz1Dnj3KilO2d87XwiZe64LLwpwsaE="}}
|
|
|
|
| 1 |
+
{"mediaType":"application/vnd.dev.sigstore.bundle.v0.3+json", "verificationMaterial":{"certificate":{"rawBytes":"MIIHKzCCBrGgAwIBAgIUP/mmZM1RBNZy+2BaxIPboKaANfUwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjYxMDIwMDk1MzU0WhcNMjYxMDIwMTAwMzU0WjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcYog7arHY0Y9LB1dbz4EMiisjAeogYrVaM/azAT620TxPmQwSkpj3gM5WuntjYLVKH7v6Y/ZJKbtEH3Iyz0eQqOCBdAwggXMMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAfBgNVHSMEGDAWgBTf0+nPViQRlvmo2OkoVaLGLhhkPzBrBgNVHREBAf8EYTBfhl1odHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkvLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQueWFtbEByZWZzL2hlYWRzL21haW4wOQYKKwYBBAGDvzABAQQraHR0cHM6Ly90b2tlbi5hY3Rpb25zLmdpdGh1YnVzZXJjb250ZW50LmNvbTAfBgorBgEEAYO/MAECBBF3b3JrZmxvd19kaXNwYXRjaDA2BgorBgEEAYO/MAEDBChlYzVjYzkwZTE2NTc1NjZjNjZjNjJiNTAyMTQzNWVkYmNmYTM0OGMzMBMGCisGAQQBg78wAQQEBUJ1aWxkMCsGCisGAQQBg78wAQUEHWh1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5MB0GCisGAQQBg78wAQYED3JlZnMvaGVhZHMvbWFpbjA7BgorBgEEAYO/MAEIBC0MK2h0dHBzOi8vdG9rZW4uYWN0aW9ucy5naXRodWJ1c2VyY29udGVudC5jb20wbQYKKwYBBAGDvzABCQRfDF1odHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkvLmdpdGh1Yi93b3JrZmxvd3MvYnVpbGQueWFtbEByZWZzL2hlYWRzL21haW4wOAYKKwYBBAGDvzABCgQqDChlYzVjYzkwZTE2NTc1NjZjNjZjNjJiNTAyMTQzNWVkYmNmYTM0OGMzMBsGCisGAQQBg78wAQsEDQwLc2VsZi1ob3N0ZWQwQAYKKwYBBAGDvzABDAQyDDBodHRwczovL2dpdGh1Yi5jb20vaHVnZ2luZ2ZhY2Uva2VybmVscy1jb21tdW5pdHkwOAYKKwYBBAGDvzABDQQqDChlYzVjYzkwZTE2NTc1NjZjNjZjNjJiNTAyMTQzNWVkYmNmYTM0OGMzMB8GCisGAQQBg78wAQ4EEQwPcmVmcy9oZWFkcy9tYWluMBoGCisGAQQBg78wAQ8EDAwKMTA3MTQ3NTUyOTAuBgorBgEEAYO/MAEQBCAMHmh0dHBzOi8vZ2l0aHViLmNvbS9odWdnaW5nZmFjZTAYBgorBgEEAYO/MAERBAoMCDI1NzIwNzQzMG0GCisGAQQBg78wARIEXwxdaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5Ly5naXRodWIvd29ya2Zsb3dzL2J1aWxkLnlhbWxAcmVmcy9oZWFkcy9tYWluMDgGCisGAQQBg78wARMEKgwoZWM1Y2M5MGUxNjU3NTY2YzY2YzYyYjUwMjE0MzVlZGJjZmEzNDhjMzAhBgorBgEEAYO/MAEUBBMMEXdvcmtmbG93X2Rpc3BhdGNoMGQGCisGAQQBg78wARUEVgxUaHR0cHM6Ly9naXRodWIuY29tL2h1Z2dpbmdmYWNlL2tlcm5lbHMtY29tbXVuaXR5L2FjdGlvbnMvcnVucy8zOTQwMzQ1ODE5OS9hdHRlbXB0cy8xMBYGCisGAQQBg78wARYECAwGcHVibGljMEYGCisGAQQBg78wARgEOAw2cmVwbzpodWdnaW5nZmFjZS9rZXJuZWxzLWNvbW11bml0eTpyZWY6cmVmcy9oZWFkcy9tYWluMIGJBgorBgEEAdZ5AgQCBHsEeQB3AHUA3T0wasbHETJjGR4cmWc3AqJKXrjePK3/h4pygC8p7o4AAAGhWLtUgAAABAMARjBEAiAe/acaJEWfp83gcFkDKvoFLXrzTxjWugLIDNpSFeLusgIgI6Pe4FEqWllfViiFTAQVVYJoN4GbF+Zqar2IqNRKXywwCgYIKoZIzj0EAwMDaAAwZQIwTGwKwrp9v3bnF+jcmcxJDQlNH+G/X094ztAojPb9XMoglDopWFLG5CCHJwTVDBcxAjEAwAHPN6qnPDCH1MsFN1mUa25cXwEcCnBKYfOKJuuV4GuJ48l7lBLHt/XgHMSKAp0o"}, "tlogEntries":[{"logIndex":"3335086358", "logId":{"keyId":"wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="}, "kindVersion":{"kind":"hashedrekord", "version":"0.0.1"}, "integratedTime":"1792490034", "inclusionPromise":{"signedEntryTimestamp":"MEQCIDh5l4rIduFEIESVLdxB7yNjOmzLB6wHWBP+dLlyoALjAiBlffoVN9/Y6hMJ3jh8k9Tx78uilgTkTl+MFakp/tnDEw=="}, "inclusionProof":{"logIndex":"3213182096", "rootHash":"ETOUthJxn7Z36oDbegdN4ukdMMDtHTet6l/TBkV1Hww=", "treeSize":"3213182167", "hashes":["N4zOdeYV9bT+mL8n5/1CGmSuA2VV+UhN9MDbMneloJw=", "mj7NwwalWVWDX0Kh+to0lJbH1rGZDbNf4HcF9eItBVM=", "fwnSmRcMGxhsozTLY4LcxDpo08kcNy/vEPBGeeBSFbk=", "Cj68CvJffFHJ7/61leQDCepCbXGoBCS1YUvSGi3bm/Q=", "lfASF7qNkK6GWuggPpPvvjXCM94C8NJa0Wot/arlKXc=", "Yt7IuEE3A6hytfQiIcf8HBbHvrwdyXrEKDoszquugMM=", "Wtj/zv8pbDRBXP70LrlX25kih3b6H7UquUi/a+h1UG0=", "MgGbTQdHMx9a+WZnHvQoG7hXqexepfCSgGbCVHQdTME=", "5VvnPwgJg7mEz2CpXW/bEuCEagORQRlWh9Ndtihxwi0=", "PHxQAH8g/7NVsymUZ0Te3puxjBd3DEJNVas6rZCulgs=", "rYA6lUjt9opyITSlS0ZGyFtQo1JeGpc94KBmcxBHawE=", "Zz0ghh+5MBl4Vee4jXWbIrdb3i68SxmtMzhdMeM0hOg=", "6Rb7uOgk2v5YKcFSbAPOpLlWAIN1ciDPdlp4J/CUu5k=", "HovTPBWzoErvUg1u5sIi3x1ZonZ7yJekVsBrmpomCIA=", "G+nk7mgE5h6dUmv2UY7NDJrY3WvrZY31raaO1AETt+o=", "qlTWNDzERnTBQVcHHXXVPjiUP0SsikGxfcxVlgqVFDo=", "gg9GNApNke3+zNhl4tsWtmIycCFrOMCB3lys6XuSQNQ=", "NlOclldmKPA1tMKIskqHAwuQDYHp31YwpK+OOMrMccc=", "qxzHanAzz57SDdmJe0B7bJK72NTIBbwEMGBBKvDOROw=", "xH/DCseLHr9eKoYT8qsORZK7zVdEGYWHuVtsVrD95wY="], "checkpoint":{"envelope":"rekor.sigstore.dev - 1193050959916656506\n3213182167\nETOUthJxn7Z36oDbegdN4ukdMMDtHTet6l/TBkV1Hww=\n\n— rekor.sigstore.dev wNI9ajBGAiEA136ugN4DB8HrrSrQe1IkuD6gcEvjcYgnISn5rjXpld4CIQC11ZBPQ1jo/Uz+0/lcjMNx+Lkg4q0KC5vUVkoOyQojQA==\n"}}, "canonicalizedBody":"eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJhNDA1MWRmMTQ5MDNiM2Y4OTZmMzg3NWQyOTlmNTU4OTU5YjZmZWVjNzc5YmQwOWJjM2M5YWUxYjUxNmZhNjhjIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FVUNJUUQ4RVVFMEhWUHRzdGlVdDRFR0pnVG5ocitmUU9uRTg4SnpMYmVQN1M3MmV3SWdIZ0xaUy9lZFRDM1dMTmsrazdHQUtyUTJxeVdHZk1od3NVaXVQd2tEQVQ0PSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVaExla05EUW5KSFowRjNTVUpCWjBsVlVDOXRiVnBOTVZKQ1RscDVLekpDWVhoSlVHSnZTMkZCVG1aVmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFplRTFFU1hkTlJHc3hUWHBWTUZkb1kwNU5hbGw0VFVSSmQwMVVRWGROZWxVd1YycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZqV1c5bk4yRnlTRmt3V1RsTVFqRmtZbm8wUlUxcGFYTnFRV1Z2WjFseVZtRk5MMkVLZWtGVU5qSXdWSGhRYlZGM1UydHdhak5uVFRWWGRXNTBhbGxNVmt0SU4zWTJXUzlhU2t0aWRFVklNMGw1ZWpCbFVYRlBRMEprUVhkbloxaE5UVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXWkNaMDVXU0ZOTlJVZEVRVmRuUWxSbUNqQXJibEJXYVZGU2JIWnRiekpQYTI5V1lVeEhUR2hvYTFCNlFuSkNaMDVXU0ZKRlFrRm1PRVZaVkVKbWFHd3hiMlJJVW5kamVtOTJUREprY0dSSGFERUtXV2sxYW1JeU1IWmhTRlp1V2pKc2RWb3lXbWhaTWxWMllUSldlV0p0Vm5OamVURnFZakl4ZEdSWE5YQmtTR3QyVEcxa2NHUkhhREZaYVRrellqTktjZ3BhYlhoMlpETk5kbGx1Vm5CaVIxRjFaVmRHZEdKRlFubGFWMXA2VERKb2JGbFhVbnBNTWpGb1lWYzBkMDlSV1V0TGQxbENRa0ZIUkhaNlFVSkJVVkZ5Q21GSVVqQmpTRTAyVEhrNU1HSXlkR3hpYVRWb1dUTlNjR0l5TlhwTWJXUndaRWRvTVZsdVZucGFXRXBxWWpJMU1GcFhOVEJNYlU1MllsUkJaa0puYjNJS1FtZEZSVUZaVHk5TlFVVkRRa0pHTTJJelNuSmFiWGgyWkRFNWEyRllUbmRaV0ZKcVlVUkJNa0puYjNKQ1owVkZRVmxQTDAxQlJVUkNRMmhzV1hwV2FncFplbXQzV2xSRk1rNVVZekZPYWxwcVRtcGFhazVxU21sT1ZFRjVUVlJSZWs1WFZtdFpiVTV0V1ZSTk1FOUhUWHBOUWsxSFEybHpSMEZSVVVKbk56aDNDa0ZSVVVWQ1ZVb3hZVmQ0YTAxRGMwZERhWE5IUVZGUlFtYzNPSGRCVVZWRlNGZG9NVm95WkhCaWJXUnRXVmRPYkV3eWRHeGpiVFZzWWtoTmRGa3lPWFFLWWxoV2RXRllValZOUWpCSFEybHpSMEZSVVVKbk56aDNRVkZaUlVRelNteGFiazEyWVVkV2FGcElUWFppVjBad1ltcEJOMEpuYjNKQ1owVkZRVmxQTHdwTlFVVkpRa013VFVzeWFEQmtTRUo2VDJrNGRtUkhPWEphVnpSMVdWZE9NR0ZYT1hWamVUVnVZVmhTYjJSWFNqRmpNbFo1V1RJNWRXUkhWblZrUXpWcUNtSXlNSGRpVVZsTFMzZFpRa0pCUjBSMmVrRkNRMUZTWmtSR01XOWtTRkozWTNwdmRrd3laSEJrUjJneFdXazFhbUl5TUhaaFNGWnVXakpzZFZveVdtZ0tXVEpWZG1FeVZubGliVlp6WTNreGFtSXlNWFJrVnpWd1pFaHJka3h0WkhCa1IyZ3hXV2s1TTJJelNuSmFiWGgyWkROTmRsbHVWbkJpUjFGMVpWZEdkQXBpUlVKNVdsZGFla3d5YUd4WlYxSjZUREl4YUdGWE5IZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1EyZFJjVVJEYUd4WmVsWnFXWHByZDFwVVJUSk9WR014Q2s1cVdtcE9hbHBxVG1wS2FVNVVRWGxOVkZGNlRsZFdhMWx0VG0xWlZFMHdUMGROZWsxQ2MwZERhWE5IUVZGUlFtYzNPSGRCVVhORlJGRjNUR015Vm5NS1dta3hiMkl6VGpCYVYxRjNVVUZaUzB0M1dVSkNRVWRFZG5wQlFrUkJVWGxFUkVKdlpFaFNkMk42YjNaTU1tUndaRWRvTVZscE5XcGlNakIyWVVoV2JncGFNbXgxV2pKYWFGa3lWWFpoTWxaNVltMVdjMk41TVdwaU1qRjBaRmMxY0dSSWEzZFBRVmxMUzNkWlFrSkJSMFIyZWtGQ1JGRlJjVVJEYUd4WmVsWnFDbGw2YTNkYVZFVXlUbFJqTVU1cVdtcE9hbHBxVG1wS2FVNVVRWGxOVkZGNlRsZFdhMWx0VG0xWlZFMHdUMGROZWsxQ09FZERhWE5IUVZGUlFtYzNPSGNLUVZFMFJVVlJkMUJqYlZadFkzazViMXBYUm10amVUbDBXVmRzZFUxQ2IwZERhWE5IUVZGUlFtYzNPSGRCVVRoRlJFRjNTMDFVUVROTlZGRXpUbFJWZVFwUFZFRjFRbWR2Y2tKblJVVkJXVTh2VFVGRlVVSkRRVTFJYldnd1pFaENlazlwT0haYU1td3dZVWhXYVV4dFRuWmlVemx2WkZka2JtRlhOVzVhYlVacUNscFVRVmxDWjI5eVFtZEZSVUZaVHk5TlFVVlNRa0Z2VFVORVNURk9la2wzVG5wUmVrMUhNRWREYVhOSFFWRlJRbWMzT0hkQlVrbEZXSGQ0WkdGSVVqQUtZMGhOTmt4NU9XNWhXRkp2WkZkSmRWa3lPWFJNTW1neFdqSmtjR0p0WkcxWlYwNXNUREowYkdOdE5XeGlTRTEwV1RJNWRHSllWblZoV0ZJMVRIazFiZ3BoV0ZKdlpGZEpkbVF5T1hsaE1scHpZak5rZWt3eVNqRmhWM2hyVEc1c2FHSlhlRUZqYlZadFkzazViMXBYUm10amVUbDBXVmRzZFUxRVowZERhWE5IQ2tGUlVVSm5OemgzUVZKTlJVdG5kMjlhVjAweFdUSk5OVTFIVlhoT2FsVXpUbFJaTWxsNldUSlplbGw1V1dwVmQwMXFSVEJOZWxac1drZEthbHB0UlhvS1RrUm9hazE2UVdoQ1oyOXlRbWRGUlVGWlR5OU5RVVZWUWtKTlRVVllaSFpqYlhSdFlrYzVNMWd5VW5Cak0wSm9aRWRPYjAxSFVVZERhWE5IUVZGUlFncG5OemgzUVZKVlJWWm5lRlZoU0ZJd1kwaE5Oa3g1T1c1aFdGSnZaRmRKZFZreU9YUk1NbWd4V2pKa2NHSnRaRzFaVjA1c1RESjBiR050Tld4aVNFMTBDbGt5T1hSaVdGWjFZVmhTTlV3eVJtcGtSMngyWW01TmRtTnVWblZqZVRoNlQxUlJkMDE2VVRGUFJFVTFUMU01YUdSSVVteGlXRUl3WTNrNGVFMUNXVWNLUTJselIwRlJVVUpuTnpoM1FWSlpSVU5CZDBkalNGWnBZa2RzYWsxRldVZERhWE5IUVZGUlFtYzNPSGRCVW1kRlQwRjNNbU50Vm5kaWVuQnZaRmRrYmdwaFZ6VnVXbTFHYWxwVE9YSmFXRXAxV2xkNGVreFhUblppVnpFeFltMXNNR1ZVY0hsYVYxazJZMjFXYldONU9XOWFWMFpyWTNrNWRGbFhiSFZOU1VkS0NrSm5iM0pDWjBWRlFXUmFOVUZuVVVOQ1NITkZaVkZDTTBGSVZVRXpWREIzWVhOaVNFVlVTbXBIVWpSamJWZGpNMEZ4U2t0WWNtcGxVRXN6TDJnMGNIa0taME00Y0Rkdk5FRkJRVWRvVjB4MFZXZEJRVUZDUVUxQlVtcENSVUZwUVdVdllXTmhTa1ZYWm5BNE0yZGpSbXRFUzNadlJreFljbnBVZUdwWGRXZE1TUXBFVG5CVFJtVk1kWE5uU1dkSk5sQmxORVpGY1Zkc2JHWldhV2xHVkVGUlZsWlpTbTlPTkVkaVJpdGFjV0Z5TWtseFRsSkxXSGwzZDBObldVbExiMXBKQ25wcU1FVkJkMDFFWVVGQmQxcFJTWGRVUjNkTGQzSndPWFl6WW01R0sycGpiV040U2tSUmJFNUlLMGN2V0RBNU5IcDBRVzlxVUdJNVdFMXZaMnhFYjNBS1YwWk1SelZEUTBoS2QxUldSRUpqZUVGcVJVRjNRVWhRVGpaeGJsQkVRMGd4VFhOR1RqRnRWV0V5TldOWWQwVmpRMjVDUzFsbVQwdEtkWFZXTkVkMVNnbzBPR3czYkVKTVNIUXZXR2RJVFZOTFFYQXdid290TFMwdExVVk9SQ0JEUlZKVVNVWkpRMEZVUlMwdExTMHRDZz09In19fX0="}], "timestampVerificationData":{"rfc3161Timestamps":[{"signedTimestamp":"MIICyTADAgEAMIICwAYJKoZIhvcNAQcCoIICsTCCAq0CAQMxDTALBglghkgBZQMEAgEwgbcGCyqGSIb3DQEJEAEEoIGnBIGkMIGhAgEBBgkrBgEEAYO/MAIwMTANBglghkgBZQMEAgEFAAQgfFMO/p/NSekrYglMmlihkzviE2/TMjI7I9gvE+jPVZwCFHtSTryVjqRDdM+RmwtYaQ+zgsgnGA8yMDI2MTAyMDA5NTM1NFowAwIBAaAypDAwLjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MRUwEwYDVQQDEwxzaWdzdG9yZS10c2GgADGCAdswggHXAgEBMFEwOTEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MSAwHgYDVQQDExdzaWdzdG9yZS10c2Etc2VsZnNpZ25lZAIUOhNULwyQYe68wUMvy4qOiyojiwwwCwYJYIZIAWUDBAIBoIH8MBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRABBDAcBgkqhkiG9w0BCQUxDxcNMjYxMDIwMDk1MzU0WjAvBgkqhkiG9w0BCQQxIgQg3f6Q/nF2OKTQsvL152ZutBpL80L7gdl0XBjdZCcouJ8wgY4GCyqGSIb3DQEJEAIvMX8wfTB7MHkEIIX5J7wHq2LKw7RDVsEO/IGyxog/2nq55thw2dE6zQW3MFUwPaQ7MDkxFTATBgNVBAoTDHNpZ3N0b3JlLmRldjEgMB4GA1UEAxMXc2lnc3RvcmUtdHNhLXNlbGZzaWduZWQCFDoTVC8MkGHuvMFDL8uKjosqI4sMMAoGCCqGSM49BAMCBGcwZQIxAKnEXDu2NvqZyacw0ZGY4AbtlHSBesVRge3qaPnSC2bWDBInFL34StY/aRcVjYTU0AIwZZOS9rSnZ5Y96uJwvpNIowj14zfaPu6vOZLCfkwkTorS0cyiyGuRF8lzjClRukKm"}]}}, "messageSignature":{"messageDigest":{"algorithm":"SHA2_256", "digest":"pAUd8UkDs/iW84ddKZ9ViVm2/ux3m9Cbw8muG1Fvpow="}, "signature":"MEUCIQD8EUE0HVPtstiUt4EGJgTnhr+fQOnE88JzLbeP7S72ewIgHgLZS/edTC3WLNk+k7GAKrQ2qyWGfMhwsUiuPwkDAT4="}}
|
build/torch-cuda/pruners.py
CHANGED
|
@@ -253,7 +253,7 @@ def gated_pointer_weight_warp_spec_pruner():
|
|
| 253 |
sub-128 M tile — plain pointer/pointer at BM=128 and w4/w8 compiles and is often the winner.
|
| 254 |
|
| 255 |
Region measured by tuning the GPT-OSS W4A16 problem (N=K=2880) with a fresh Triton cache and
|
| 256 |
-
``
|
| 257 |
predicate names, and it drops none of the 117 that compiled. Every failure sat in the GATE
|
| 258 |
shape — the ungated shape's 63 WS configs all compiled. Unfenced these are wasted compiles per
|
| 259 |
new shape (the tuner memoizes them only after paying once). The ``BM < 128`` clause rests on a
|
|
|
|
| 253 |
sub-128 M tile — plain pointer/pointer at BM=128 and w4/w8 compiles and is often the winner.
|
| 254 |
|
| 255 |
Region measured by tuning the GPT-OSS W4A16 problem (N=K=2880) with a fresh Triton cache and
|
| 256 |
+
an autotune ``log_path``: of 129 WS configs, the 12 that failed are exactly the ones this
|
| 257 |
predicate names, and it drops none of the 117 that compiled. Every failure sat in the GATE
|
| 258 |
shape — the ungated shape's 63 WS configs all compiled. Unfenced these are wasted compiles per
|
| 259 |
new shape (the tuner memoizes them only after paying once). The ``BM < 128`` clause rests on a
|
build/torch-cuda/quant.py
CHANGED
|
@@ -19,7 +19,7 @@ from triton.language.extra.cuda import gdc_launch_dependents, gdc_wait
|
|
| 19 |
|
| 20 |
from .bayesian_autotuner import bayesian_autotune
|
| 21 |
from .formats import global_scale_stride, is_per_expert_global
|
| 22 |
-
from .compat import FP8_DTYPE, MX_SCALE_GROUP_K, NVFP4_SCALE_GROUP_K, compile_time_only_triton_wrap, device_context,
|
| 23 |
from .swizzle import swizzle_store_block
|
| 24 |
from .scheduling import build_tile_layout, resolve_tile_inline
|
| 25 |
|
|
@@ -61,16 +61,14 @@ def fp8_act_quant_inline(
|
|
| 61 |
return a_fp8, a_scale
|
| 62 |
|
| 63 |
|
| 64 |
-
#
|
| 65 |
-
|
| 66 |
-
# everywhere else. ``is_sm10x`` is driverless-safe, so no import-time guard is needed.
|
| 67 |
-
_E2M1_HW_CVT = tl.constexpr(is_sm10x())
|
| 68 |
|
| 69 |
|
| 70 |
@triton.jit
|
| 71 |
def _quant_e2m1_packed(v, BLOCK_SIZE_M: tl.constexpr, BLOCK_SIZE_K: tl.constexpr):
|
| 72 |
"""Pack signed, pre-scaled values on the E2M1 grid to ``(M, K//2)`` uint8 (first value
|
| 73 |
-
of each pair in the low nibble). On
|
| 74 |
``cvt.rn.satfinite.e2m1x2.f32`` (two f32 → one packed byte, first operand → HIGH nibble)
|
| 75 |
does it in one instruction; elsewhere a ``>=``-threshold bucketize builds the code. The
|
| 76 |
two agree except at exact E2M1 midpoints (0.25, 0.75, …), where the hardware rounds to
|
|
@@ -187,7 +185,7 @@ def _e2m1_code_to_bf16_bits(code):
|
|
| 187 |
@triton.jit
|
| 188 |
def _e2m1_pair_to_f16(packed):
|
| 189 |
"""One packed E2M1 byte -> the two fp16 values it holds, as a uint32 (low half = low nibble),
|
| 190 |
-
through the
|
| 191 |
integer ops. Every E2M1 magnitude is exact in fp16, so this is a value-identical decode, and
|
| 192 |
the direction of the unpack is irrelevant to the cost — the arithmetic is the whole bill
|
| 193 |
(measured on the gpt-oss W4A16 decode weight stream: 39.6us bit-twiddle, either axis, vs
|
|
@@ -210,7 +208,7 @@ def e2m1_to_bf16(b_packed):
|
|
| 210 |
interleave along K with a SINGLE 3D axis-swap (``join`` -> ``[R, C, 2]`` -> swap last two ->
|
| 211 |
reshape) instead of the three 2D transposes ``e2m1_to_e4m3`` needs — the weight-only unpack hot path
|
| 212 |
(fp4 weight upcast in-loop, the caller widening to the activation dtype). K order low-nibble-first, matching
|
| 213 |
-
``e2m1_to_e4m3``: ``[byte0_lo, byte0_hi, byte1_lo, ...]``. On
|
| 214 |
the hardware CVT (``_e2m1_pair_to_f16``, fp16 being exact for the grid); elsewhere the integer
|
| 215 |
bit-build. Only the taken arm compiles."""
|
| 216 |
if _E2M1_HW_CVT:
|
|
@@ -288,7 +286,7 @@ def e2m1_cols_to_f32(packed):
|
|
| 288 |
def e2m1_cols_to_e4m3(packed):
|
| 289 |
"""Column-unpack packed E2M1 (two nibbles per byte along the last dim, low nibble
|
| 290 |
first) to E4M3: ``(..., C) uint8 -> (..., 2C)`` — the column-axis counterpart of the
|
| 291 |
-
row-doubling ``e2m1_to_e4m3``; lossless (every E2M1 value is exact in E4M3).
|
| 292 |
decodes through the CVT unit (``_e2m1_pair_to_e4m3``), elsewhere the integer bit-build;
|
| 293 |
either way the bytes are bitcast once. Only the taken arm compiles."""
|
| 294 |
if _E2M1_HW_CVT:
|
|
|
|
| 19 |
|
| 20 |
from .bayesian_autotuner import bayesian_autotune
|
| 21 |
from .formats import global_scale_stride, is_per_expert_global
|
| 22 |
+
from .compat import FP8_DTYPE, MX_SCALE_GROUP_K, NVFP4_SCALE_GROUP_K, compile_time_only_triton_wrap, device_context, is_blackwell, pdl_launch_kwargs
|
| 23 |
from .swizzle import swizzle_store_block
|
| 24 |
from .scheduling import build_tile_layout, resolve_tile_inline
|
| 25 |
|
|
|
|
| 61 |
return a_fp8, a_scale
|
| 62 |
|
| 63 |
|
| 64 |
+
# Hardware FP4 conversions exist on every Blackwell family, independently of TMEM MMA.
|
| 65 |
+
_E2M1_HW_CVT = tl.constexpr(is_blackwell())
|
|
|
|
|
|
|
| 66 |
|
| 67 |
|
| 68 |
@triton.jit
|
| 69 |
def _quant_e2m1_packed(v, BLOCK_SIZE_M: tl.constexpr, BLOCK_SIZE_K: tl.constexpr):
|
| 70 |
"""Pack signed, pre-scaled values on the E2M1 grid to ``(M, K//2)`` uint8 (first value
|
| 71 |
+
of each pair in the low nibble). On Blackwell the hardware convert
|
| 72 |
``cvt.rn.satfinite.e2m1x2.f32`` (two f32 → one packed byte, first operand → HIGH nibble)
|
| 73 |
does it in one instruction; elsewhere a ``>=``-threshold bucketize builds the code. The
|
| 74 |
two agree except at exact E2M1 midpoints (0.25, 0.75, …), where the hardware rounds to
|
|
|
|
| 185 |
@triton.jit
|
| 186 |
def _e2m1_pair_to_f16(packed):
|
| 187 |
"""One packed E2M1 byte -> the two fp16 values it holds, as a uint32 (low half = low nibble),
|
| 188 |
+
through the Blackwell CVT unit: ONE instruction per pair against the bit-twiddle form's ~10
|
| 189 |
integer ops. Every E2M1 magnitude is exact in fp16, so this is a value-identical decode, and
|
| 190 |
the direction of the unpack is irrelevant to the cost — the arithmetic is the whole bill
|
| 191 |
(measured on the gpt-oss W4A16 decode weight stream: 39.6us bit-twiddle, either axis, vs
|
|
|
|
| 208 |
interleave along K with a SINGLE 3D axis-swap (``join`` -> ``[R, C, 2]`` -> swap last two ->
|
| 209 |
reshape) instead of the three 2D transposes ``e2m1_to_e4m3`` needs — the weight-only unpack hot path
|
| 210 |
(fp4 weight upcast in-loop, the caller widening to the activation dtype). K order low-nibble-first, matching
|
| 211 |
+
``e2m1_to_e4m3``: ``[byte0_lo, byte0_hi, byte1_lo, ...]``. On Blackwell the codes decode through
|
| 212 |
the hardware CVT (``_e2m1_pair_to_f16``, fp16 being exact for the grid); elsewhere the integer
|
| 213 |
bit-build. Only the taken arm compiles."""
|
| 214 |
if _E2M1_HW_CVT:
|
|
|
|
| 286 |
def e2m1_cols_to_e4m3(packed):
|
| 287 |
"""Column-unpack packed E2M1 (two nibbles per byte along the last dim, low nibble
|
| 288 |
first) to E4M3: ``(..., C) uint8 -> (..., 2C)`` — the column-axis counterpart of the
|
| 289 |
+
row-doubling ``e2m1_to_e4m3``; lossless (every E2M1 value is exact in E4M3). Blackwell
|
| 290 |
decodes through the CVT unit (``_e2m1_pair_to_e4m3``), elsewhere the integer bit-build;
|
| 291 |
either way the bytes are bitcast once. Only the taken arm compiles."""
|
| 292 |
if _E2M1_HW_CVT:
|
build/torch-cuda/symbols.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
| 1 |
{
|
| 2 |
"schema_version": 1,
|
| 3 |
-
"module": "
|
| 4 |
"functions": [
|
| 5 |
{
|
| 6 |
"name": "matmul_2d",
|
| 7 |
"qualname": "matmul_2d",
|
| 8 |
-
"module": "
|
| 9 |
"kind": "function",
|
| 10 |
"doc": "Dense (2D) quantized matmul dispatcher (W8A8 FP8, W4A8/W4A4 FP4) — the single-GEMM sibling of\n``matmul_grouped``/``matmul_batched``, taking the same ``As``/``Bs`` scale spec,\n``activation_format`` / gate|up fusion kwargs, and inferred quant block (no ``block_size`` argument — it\nfalls out of the weight-scale shape, so the data can't disagree with a parameter).\n\n``As`` is the activation block-scale spec, same as the routed ops: ``None`` → the op quantizes raw\n``A`` dynamically; a per-tensor scalar → static (calibrated) FP8 activation scale; block scales →\npre-quantized ``A``. ``Bs`` is the weight block scale. ``a_global_scale``/``b_global_scale`` are the\ntwo-level NVFP4 per-tensor second-level scales (calibrated ``input_scale`` ``g_a`` and\n``weight_scale_2`` ``g_b``) — provided, never computed; the op folds ``g_a·g_b`` onto the\naccumulator (``a_global_scale`` rides raw ``A`` or a pre-quantized ``As`` alike).\n``output_global_scale`` (NVFP4 requant only) is the NEXT proj's provided ``input_scale``:\nthe fused requant normalizes the GLU intermediate by it, returning ``(C, Cs)`` the down-proj\nconsumes as ``As=Cs, a_global_scale=output_global_scale``.\n\n``activation_format`` is the activations' quantization: ``None`` (default) = the weights' own\nformat, ``\"bf16\"`` = weight-only (no activation quant), or an explicit ``\"fp8\"`` / ``\"mxfp8\"`` /\n``\"mxfp4\"`` / ``\"nvfp4\"`` (``\"mxfp8\"`` on MXFP4 weights = the W4A8 chain; ``check_activation_format``\nhas the per-family matrix). ``gate=True`` reads ``B`` as the ``(2N, K)`` gate|up stack and fuses\nthe ``act_fn`` GLU (``swiglu_alpha``/``swiglu_limit`` its clamped variant), returning the\n``[..., N]`` intermediate; ``quantize_output=True`` (MX weights only) stores that intermediate in\n``activation_format`` and returns ``(C, Cs)`` for the next op.\n\nRoutes by weight dtype + inferred block: ``Bs`` None → full-precision; MX/NVFP4 (int8/E4M3 weights\nwith UE8M0 group-32 or E4M3 group-16 ``Bs``) → ``mx_dynamic_matmul``; tensor-wide FP8 (scalar\n``Bs``) → ``w8a8_tensor_dynamic_fp8_matmul``; block FP8 → the static variant when ``As`` is a\nper-tensor scalar, else dynamic.",
|
| 11 |
"signature": {
|
|
@@ -113,7 +113,7 @@
|
|
| 113 |
{
|
| 114 |
"name": "matmul_batched",
|
| 115 |
"qualname": "matmul_batched",
|
| 116 |
-
"module": "
|
| 117 |
"kind": "function",
|
| 118 |
"doc": "Batched matmul dispatcher (W8A8 FP8, W4A8/W4A4 FP4, or full-precision). Routes one\nprogram per routed row (``expert_ids`` gives its expert).\n\n``As`` marks ``A`` as already quantized (framework-precomputed scales, or a requantized\nintermediate handed to the down projection); a per-tensor scalar ``As`` is instead the static\n(calibrated) activation scale for block-scale FP8 weights — the op quantizes raw ``A`` against\nit; ``None`` = raw ``A``, quantized dynamically by the op in ``activation_format`` (``None`` =\nthe weights' own format — fp8/E4M3 offline for bd/tensor, inline for MX; ``\"bf16\"`` = weight-only;\n``\"mxfp4\"`` = packed E2M1 activations). ``Bs`` ``None`` = unquantized BF16/FP16 weights.\n``quantize_output`` requantizes the output into ``activation_format`` — the return is then\n``(C, Cs)``. ``gate``/``act_fn``/``swiglu_alpha``/``swiglu_limit`` fuse the gate|up GLU into the\nepilogue. ``As``/``Bs`` are each a bare block-scale tensor; the two-level NVFP4\nsecond-level scales ride the separate ``a_global_scale``/``b_global_scale`` (fp32 per-tensor,\nweights per-expert ``(E,)``; from ``nvfp4_quantize_two_level``), and the op folds ``g_a · g_b``\nonto the accumulator. The activation global ``g_a`` is CALIBRATED (the checkpoint's\n``input_scale``): ``a_global_scale=g_a`` with a raw ``A`` has the op quantize ``A / g_a`` per\nblock, and rides a pre-quantized ``As`` the same way. Under an NVFP4 requant the\nfused requant normalizes the GLU intermediate by the PROVIDED ``output_global_scale`` (the next\nproj's calibrated ``input_scale``) before the block quant and returns ``[C, Cs]``; the down\nconsumes it as ``As=Cs, a_global_scale=output_global_scale``. ``gather_idx``/``scatter_idx`` (each None or a ``(S,)`` map)\naddress the source row of ``A`` / destination row of ``C`` per program — None means row\n``s``; the gather lets the gate_up read unexpanded activations (source row\n``s // num_top_k``) with no copy.\n\nRoutes by what the weight tensors themselves say (there is no ``block_size``\nparameter — the quantization block is derived from the scale shape,\n``weight_block_size``):\n- ``Bs`` None → ``full_precision_matmul_batched`` (plain dot, no scales anywhere).\n- MX weights — ``int8`` (packed E2M1) or ``float8_e4m3fn`` (E4M3) with UE8M0\n group-32 ``Bs`` → ``mx_dynamic_matmul_batched``.\n- one scale per expert (``Bs`` ``(E,)``/``(E, 1, 1)``) →\n ``w8a8_tensor_dynamic_fp8_matmul_batched``.\n- block scales (``Bs`` ``(E, N/bn, K/bk)``) → ``w8a8_block_dynamic_fp8_matmul_batched``.",
|
| 119 |
"signature": {
|
|
@@ -239,7 +239,7 @@
|
|
| 239 |
{
|
| 240 |
"name": "matmul_grouped",
|
| 241 |
"qualname": "matmul_grouped",
|
| 242 |
-
"module": "
|
| 243 |
"kind": "function",
|
| 244 |
"doc": "Grouped matmul dispatcher (W8A8 FP8, W4A8/W4A4 FP4, or full-precision).\n``expert_start`` is the ``(E+1,)`` tiling schedule from one ``compute_grouped_scheduling``\npass, shared by every grouped GEMM of the layer (the expert sort is virtual — nothing is\nphysically permuted).\n\n``As`` marks ``A`` as already quantized (framework-precomputed scales, or a requantized\nintermediate handed to the down projection); a per-tensor scalar ``As`` is instead the static\n(calibrated) activation scale for block-scale FP8 weights — the op quantizes raw ``A`` against\nit; ``None`` = raw ``A``, quantized dynamically by the op in ``activation_format`` (``None`` =\nthe weights' own format — fp8/E4M3, or the fp4 chains; ``\"bf16\"`` = weight-only; ``\"mxfp4\"`` =\npacked E2M1 activations). ``Bs`` ``None`` = unquantized BF16/FP16 weights.\n``quantize_output`` requantizes the output into ``activation_format`` — the return is then\n``(C, Cs)``. ``gate``/``act_fn``/``swiglu_alpha``/``swiglu_limit`` fuse the gate|up GLU into the\nepilogue.\n``As``/``Bs`` are each a bare block-scale tensor; the two-level NVFP4 second-level scales ride\nthe separate ``a_global_scale``/``b_global_scale`` (fp32 per-tensor, weights per-expert ``(E,)``;\nfrom ``nvfp4_quantize_two_level``), and the op folds ``g_a · g_b`` onto the accumulator. The\nactivation global ``g_a`` is CALIBRATED (the checkpoint's ``input_scale``): ``a_global_scale=g_a``\nwith a raw ``A`` has the op quantize ``A / g_a`` per block, and rides a pre-quantized ``As`` the\nsame way. Under an NVFP4 requant the fused requant normalizes the GLU intermediate by the\nPROVIDED ``output_global_scale`` (the next proj's calibrated ``input_scale``) before the block\nquant and returns ``[C, Cs]``; the down consumes it as ``As=Cs, a_global_scale=output_global_scale``.\nRow order is carried by the standalone maps: ``gather_idx`` gathers ``A`` (``None`` ->\nalready expert-ordered), ``scatter_idx`` scatters the output. The fused MoE chain is one\nscheduling pass: gate_up with ``scatter_idx=None`` + ``gate=True`` + ``quantize_output=True``,\nthen down with ``gather_idx=None`` and the\nintermediate's scales as ``As``. EP-sentinel routes sit past ``expert_start[-1]``, which\nno tile reaches.\n\nRoutes by what the weight tensors themselves say (there is no ``block_size``\nparameter — the quantization block is derived from the scale shape,\n``weight_block_size``):\n- ``Bs`` None → ``full_precision_matmul_grouped`` (plain dot, no scales anywhere).\n- MX weights — ``int8`` (packed E2M1) or ``float8_e4m3fn`` (E4M3) with UE8M0\n group-32 ``Bs`` → ``mx_dynamic_matmul_grouped``.\n- one scale per expert (``Bs`` ``(E,)``/``(E, 1, 1)``) →\n ``w8a8_tensor_dynamic_fp8_matmul_grouped``.\n- block scales (``Bs`` ``(E, N/bn, K/bk)``) → ``w8a8_block_dynamic_fp8_matmul_grouped``.",
|
| 245 |
"signature": {
|
|
@@ -365,7 +365,7 @@
|
|
| 365 |
{
|
| 366 |
"name": "moe_fused_batched",
|
| 367 |
"qualname": "moe_fused_batched",
|
| 368 |
-
"module": "
|
| 369 |
"kind": "function",
|
| 370 |
"doc": "Fused batched MoE (decode): gate_up + SiLU + requant epilogue → per-row quantized\nintermediate → batched down → routing-weighted top-k reduce. Returns\n``(num_tokens, hidden_dim)``. The base ops dispatch on the weight dtypes / scale\nlayout (block-dynamic FP8, MXFP8/MXFP4, NVFP4 — decode runs the software/swap arms\nbelow the native mxf4nvf4 M=128 staging); ``activation_format`` names the activation\nquantization for the whole block — activations and the fused intermediate requant\ncarry it (``\"mxfp4\"`` runs the all-fp4 W4A4 chain, ``\"bf16\"`` is weight-only); ``None``\nfollows the weight format, and the ops validate the pairing. The\n``*_proj_input_global_scale`` pair is the NVFP4 activation second level (a checkpoint's\ncalibrated per-projection ``input_scale``): the gate_up quantizes hidden against its own,\nrequants the intermediate against the down's, and the down consumes that as its activation\nglobal. ``None`` is dynamic quant everywhere else. ``simulate_unfused`` (testing) rounds each\nstep through the activation dtype so the output matches the unfused reference to\nreduce order. ``act_fn`` is a\n``get_supported_act_fns()`` name (fused into the gate_up epilogue where the forward fuses) or any\ncallable applied on the host to the raw gate_up output; ``gate=False`` runs an ungated\nprojection. Scales are affine or pre-swizzled (``SWIZZLE_32_4_4``, self-describing 5-D)\n— the swizzled layout is for the dot_scaled arm; weight-only chains take affine.",
|
| 371 |
"signature": {
|
|
@@ -521,7 +521,7 @@
|
|
| 521 |
{
|
| 522 |
"name": "moe_fused_grouped",
|
| 523 |
"qualname": "moe_fused_grouped",
|
| 524 |
-
"module": "
|
| 525 |
"kind": "function",
|
| 526 |
"doc": "Fused grouped MoE (prefill): gather gate_up + SiLU + requant epilogue → quantized\nexpert-ordered intermediate → grouped down → routing-weighted top-k reduce. Returns\n``(num_tokens, hidden_dim)``. The base ops dispatch on the weight dtypes / scale\nlayout (block-dynamic FP8, MXFP8/MXFP4, NVFP4); ``activation_format`` names the activation\nquantization for the whole block — activations and the fused intermediate requant\ncarry it (``\"mxfp4\"``/``\"nvfp4\"`` run all-fp4 W4A4 chains, ``\"bf16\"`` is weight-only);\n``None`` follows the weight format, and the ops validate the pairing. The\n``*_proj_input_global_scale`` pair is the NVFP4 activation second level (a checkpoint's\ncalibrated per-projection ``input_scale``): the gate_up quantizes hidden against its own,\nrequants the intermediate against the down's, and the down consumes that as its activation\nglobal. ``None`` is dynamic quant everywhere else. ``simulate_unfused`` (testing) rounds each step through\nthe activation dtype so the output matches the unfused reference to reduce order. ``act_fn`` is a\n``get_supported_act_fns()`` name (fused into the gate_up epilogue where the forward fuses) or any\ncallable applied on the host to the raw gate_up output; ``gate=False`` runs an ungated\nprojection. Scales are affine or pre-swizzled (``SWIZZLE_32_4_4``, self-describing 5-D)\n— the swizzled layout is for the dot_scaled arm; weight-only chains take affine.",
|
| 527 |
"signature": {
|
|
@@ -674,10 +674,64 @@
|
|
| 674 |
"return_annotation": "torch.Tensor"
|
| 675 |
}
|
| 676 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 677 |
{
|
| 678 |
"name": "get_supported_act_fns",
|
| 679 |
"qualname": "get_supported_act_fns",
|
| 680 |
-
"module": "
|
| 681 |
"kind": "function",
|
| 682 |
"doc": "The activation names the gate|up epilogue fuses in-kernel; any other activation is applied\non the host by the MoE forwards (``act_fn`` as a callable).",
|
| 683 |
"signature": {
|
|
@@ -688,7 +742,7 @@
|
|
| 688 |
{
|
| 689 |
"name": "get_supported_norms",
|
| 690 |
"qualname": "get_supported_norms",
|
| 691 |
-
"module": "
|
| 692 |
"kind": "function",
|
| 693 |
"doc": "The norm names the kernels fuse (``post_expert_norm``), each ``x * factor * rsqrt(mean +\neps)`` over the row: ``\"rms_norm\"`` scales the normalized row by ``weight``,\n``\"centered_rms_norm\"`` by ``1 + weight`` (the zero-centered parameterization), and\n``\"input_scaled_rms_norm\"`` scales by ``1 + weight`` BEFORE normalizing, so the mean square\nis taken on the scaled row. Anything else stays a host callable.",
|
| 694 |
"signature": {
|
|
@@ -699,7 +753,7 @@
|
|
| 699 |
{
|
| 700 |
"name": "rms_norm_rows",
|
| 701 |
"qualname": "rms_norm_rows",
|
| 702 |
-
"module": "
|
| 703 |
"kind": "function",
|
| 704 |
"doc": "RMS-normalize ``(S, H)`` rows in one launch, in the ``get_supported_norms()`` form named by\n``norm`` (fp32 accumulate, input dtype out). The MoE chain folds this into\n``weighted_reduce`` instead; this is the standalone form.",
|
| 705 |
"signature": {
|
|
@@ -735,7 +789,7 @@
|
|
| 735 |
{
|
| 736 |
"name": "swizzle_mx_scales",
|
| 737 |
"qualname": "swizzle_mx_scales",
|
| 738 |
-
"module": "
|
| 739 |
"kind": "function",
|
| 740 |
"doc": "Reorder a block-scale tensor into the ``SWIZZLE_32_4_4`` layout the Blackwell tcgen05\nscaled-MMA consumes, one triton launch per matrix (``_swizzle_scales_kernel`` — no torch\npermute/transpose copies). The scale values are unchanged — this only rearranges them from\nplain row-major into the swizzled order the tensor core reads directly (the same layout\ncuBLAS/CUTLASS require for MXFP8/NVFP4 ``scaled_mm``). Plain row-major forces a gather that\ncaps the scaled dot below the fp8/fp4 peak; the swizzle removes it. Apply to weight scales\nonce at model load; the ops accept the result directly.\n\n``scale`` is the per-block scale grid — UE8M0 (``float8_e8m0fnu``, group-32 MXFP8/MXFP4) or\nE4M3 (``float8_e4m3fn``, group-16 NVFP4); the reorder is dtype-agnostic (moves bytes):\n\n- 2D ``(rows, K // group)``: one matrix (a dense weight's scale).\n- 3D ``(E, rows, K // group)``: an expert stack, each expert swizzled independently so its\n blocks stay ``ceil(rows/128)``-aligned (the reader indexes expert ``e`` at\n ``e * ceil(rows/128)``; byte-identical to a flat swizzle when ``rows % 128 == 0``).\n\n``gather_idx`` (2D only): a 1-D ``(padded_rows,)`` index mapping each output (sorted) row to\nits source row in ``scale`` (``-1`` = padding → zero row), folded into the kernel's load — the\nrouted/expert-sorted, per-tile-padded layout a grouped GEMM reads affine per BM=128 tile.\n``padded_rows`` must be a multiple of 128.\n\n``rows``/``cols`` are zero-padded to (128, 4) multiples; returns the 5D\n``(G, row_blocks, ceil(cols/4), 2, 256)`` artifact the ops read — ``G`` the expert count (1 for\na matrix), so an expert stack shards/gathers on its leading dim. Bit-identical to CUTLASS's\npacker (verified).",
|
| 741 |
"signature": {
|
|
@@ -759,7 +813,7 @@
|
|
| 759 |
{
|
| 760 |
"name": "unswizzle_mx_scales",
|
| 761 |
"qualname": "unswizzle_mx_scales",
|
| 762 |
-
"module": "
|
| 763 |
"kind": "function",
|
| 764 |
"doc": "Inverse of ``swizzle_mx_scales``: a SWIZZLE_32_4_4 artifact back to the plain row-major\n``(rows, cols)`` grid — or ``(num_experts, rows, cols)`` for an expert stack — with the\n(128, 4) padding trimmed. Pure reshape/permute on the byte view (no kernel); it runs at\nsave/dequantize time, never on a forward, so the torch-level cost is irrelevant.\n\n``rows``/``cols`` are the LOGICAL dims of ONE matrix (for a gate|up slab, the full ``2N``);\nboth are trimmed back out of the (128, 4) padding. ``num_experts`` selects the stacked\n``(E, rows, cols)`` result and must match the artifact's leading dim.",
|
| 765 |
"signature": {
|
|
@@ -795,7 +849,7 @@
|
|
| 795 |
{
|
| 796 |
"name": "mxfp8_act_quant",
|
| 797 |
"qualname": "mxfp8_act_quant",
|
| 798 |
-
"module": "
|
| 799 |
"kind": "function",
|
| 800 |
"doc": "Quantize ``(T, K)`` activations to MX once (E4M3 values + UE8M0 group-32 uint8 scales)\ninstead of inline per weight-tile — the fused gate_up re-ran the inline quant per N-tile\n(16x redundant amax/convert ALU + 2x act bytes), which held it at ~380 TFLOPS while the\npre-quantized down kernel ran at ~1080. One pass costs ~50µs at 8k tokens. Bit-exact with\nthe inline form (same group boundaries). ``swizzled=True`` emits the scale directly in\nSWIZZLE_32_4_4 for the tcgen05 fast path (same dense grid, per-element store).",
|
| 801 |
"signature": {
|
|
@@ -819,7 +873,7 @@
|
|
| 819 |
{
|
| 820 |
"name": "mxfp4_act_quant",
|
| 821 |
"qualname": "mxfp4_act_quant",
|
| 822 |
-
"module": "
|
| 823 |
"kind": "function",
|
| 824 |
"doc": "Quantize ``(T, K)`` activations to MXFP4 in one kernel pass: packed-E2M1 values\n(``(T, K//2)`` int8, two codes per byte, first value in the low nibble) + UE8M0\ngroup-32 uint8 scales (``(T, K//32)``, amax/6 ceil'd to a power of two). Bit-identical\nto the fused epilogues' inline form (shared ``mx_act_quant_inline`` arm). Feeds the\nW4A4 arm of the MX matmul ops; quantizing activations to fp4 at runtime is an\naccuracy call the caller owns — the ops never do it implicitly. ``swizzled=True`` emits the\nscale directly in SWIZZLE_32_4_4 for the tcgen05 fast path.",
|
| 825 |
"signature": {
|
|
@@ -843,7 +897,7 @@
|
|
| 843 |
{
|
| 844 |
"name": "nvfp4_act_quant",
|
| 845 |
"qualname": "nvfp4_act_quant",
|
| 846 |
-
"module": "
|
| 847 |
"kind": "function",
|
| 848 |
"doc": "Quantize ``(T, K)`` activations to NVFP4 in one kernel pass: packed-E2M1 values\n(``(T, K//2)`` int8) + E4M3 group-16 block scales (``(T, K//16)`` — ``amax/6`` rounded to\nE4M3, NOT a power of two; values divide by the DECODED scale before the E2M1 grid,\nthe standard two-step). ``global_scale`` is the CALIBRATED per-tensor second level\n(fp32, the checkpoint's ``input_scale``): values are normalized by it before\nthe block quant, so block scales stay in e4m3 range regardless of the activation's\ndynamic range — the canonical two-level format. The GEMM folds ``g_a·g_b`` back onto\nthe accumulator (pass ``As=scales`` with ``a_global_scale=global_scale``). Per-expert globals\nneed each row's expert, which ``expert_index`` gives where the caller already holds that map\n(the batched op's ``expert_ids``, sentinels and all) — it is read only when the globals are\nper expert, and ``mx_act_quant_grouped`` needs none at all, its tiles carrying an expert.\n``None`` = single-level (``g_a = 1``). ``swizzled=True`` emits the scale directly in\nSWIZZLE_32_4_4 for the tcgen05 fast path.",
|
| 849 |
"signature": {
|
|
|
|
| 1 |
{
|
| 2 |
"schema_version": 1,
|
| 3 |
+
"module": "_finegrained_kernels_cuda_ec5cc90",
|
| 4 |
"functions": [
|
| 5 |
{
|
| 6 |
"name": "matmul_2d",
|
| 7 |
"qualname": "matmul_2d",
|
| 8 |
+
"module": "_finegrained_kernels_cuda_ec5cc90.matmul",
|
| 9 |
"kind": "function",
|
| 10 |
"doc": "Dense (2D) quantized matmul dispatcher (W8A8 FP8, W4A8/W4A4 FP4) — the single-GEMM sibling of\n``matmul_grouped``/``matmul_batched``, taking the same ``As``/``Bs`` scale spec,\n``activation_format`` / gate|up fusion kwargs, and inferred quant block (no ``block_size`` argument — it\nfalls out of the weight-scale shape, so the data can't disagree with a parameter).\n\n``As`` is the activation block-scale spec, same as the routed ops: ``None`` → the op quantizes raw\n``A`` dynamically; a per-tensor scalar → static (calibrated) FP8 activation scale; block scales →\npre-quantized ``A``. ``Bs`` is the weight block scale. ``a_global_scale``/``b_global_scale`` are the\ntwo-level NVFP4 per-tensor second-level scales (calibrated ``input_scale`` ``g_a`` and\n``weight_scale_2`` ``g_b``) — provided, never computed; the op folds ``g_a·g_b`` onto the\naccumulator (``a_global_scale`` rides raw ``A`` or a pre-quantized ``As`` alike).\n``output_global_scale`` (NVFP4 requant only) is the NEXT proj's provided ``input_scale``:\nthe fused requant normalizes the GLU intermediate by it, returning ``(C, Cs)`` the down-proj\nconsumes as ``As=Cs, a_global_scale=output_global_scale``.\n\n``activation_format`` is the activations' quantization: ``None`` (default) = the weights' own\nformat, ``\"bf16\"`` = weight-only (no activation quant), or an explicit ``\"fp8\"`` / ``\"mxfp8\"`` /\n``\"mxfp4\"`` / ``\"nvfp4\"`` (``\"mxfp8\"`` on MXFP4 weights = the W4A8 chain; ``check_activation_format``\nhas the per-family matrix). ``gate=True`` reads ``B`` as the ``(2N, K)`` gate|up stack and fuses\nthe ``act_fn`` GLU (``swiglu_alpha``/``swiglu_limit`` its clamped variant), returning the\n``[..., N]`` intermediate; ``quantize_output=True`` (MX weights only) stores that intermediate in\n``activation_format`` and returns ``(C, Cs)`` for the next op.\n\nRoutes by weight dtype + inferred block: ``Bs`` None → full-precision; MX/NVFP4 (int8/E4M3 weights\nwith UE8M0 group-32 or E4M3 group-16 ``Bs``) → ``mx_dynamic_matmul``; tensor-wide FP8 (scalar\n``Bs``) → ``w8a8_tensor_dynamic_fp8_matmul``; block FP8 → the static variant when ``As`` is a\nper-tensor scalar, else dynamic.",
|
| 11 |
"signature": {
|
|
|
|
| 113 |
{
|
| 114 |
"name": "matmul_batched",
|
| 115 |
"qualname": "matmul_batched",
|
| 116 |
+
"module": "_finegrained_kernels_cuda_ec5cc90.batched",
|
| 117 |
"kind": "function",
|
| 118 |
"doc": "Batched matmul dispatcher (W8A8 FP8, W4A8/W4A4 FP4, or full-precision). Routes one\nprogram per routed row (``expert_ids`` gives its expert).\n\n``As`` marks ``A`` as already quantized (framework-precomputed scales, or a requantized\nintermediate handed to the down projection); a per-tensor scalar ``As`` is instead the static\n(calibrated) activation scale for block-scale FP8 weights — the op quantizes raw ``A`` against\nit; ``None`` = raw ``A``, quantized dynamically by the op in ``activation_format`` (``None`` =\nthe weights' own format — fp8/E4M3 offline for bd/tensor, inline for MX; ``\"bf16\"`` = weight-only;\n``\"mxfp4\"`` = packed E2M1 activations). ``Bs`` ``None`` = unquantized BF16/FP16 weights.\n``quantize_output`` requantizes the output into ``activation_format`` — the return is then\n``(C, Cs)``. ``gate``/``act_fn``/``swiglu_alpha``/``swiglu_limit`` fuse the gate|up GLU into the\nepilogue. ``As``/``Bs`` are each a bare block-scale tensor; the two-level NVFP4\nsecond-level scales ride the separate ``a_global_scale``/``b_global_scale`` (fp32 per-tensor,\nweights per-expert ``(E,)``; from ``nvfp4_quantize_two_level``), and the op folds ``g_a · g_b``\nonto the accumulator. The activation global ``g_a`` is CALIBRATED (the checkpoint's\n``input_scale``): ``a_global_scale=g_a`` with a raw ``A`` has the op quantize ``A / g_a`` per\nblock, and rides a pre-quantized ``As`` the same way. Under an NVFP4 requant the\nfused requant normalizes the GLU intermediate by the PROVIDED ``output_global_scale`` (the next\nproj's calibrated ``input_scale``) before the block quant and returns ``[C, Cs]``; the down\nconsumes it as ``As=Cs, a_global_scale=output_global_scale``. ``gather_idx``/``scatter_idx`` (each None or a ``(S,)`` map)\naddress the source row of ``A`` / destination row of ``C`` per program — None means row\n``s``; the gather lets the gate_up read unexpanded activations (source row\n``s // num_top_k``) with no copy.\n\nRoutes by what the weight tensors themselves say (there is no ``block_size``\nparameter — the quantization block is derived from the scale shape,\n``weight_block_size``):\n- ``Bs`` None → ``full_precision_matmul_batched`` (plain dot, no scales anywhere).\n- MX weights — ``int8`` (packed E2M1) or ``float8_e4m3fn`` (E4M3) with UE8M0\n group-32 ``Bs`` → ``mx_dynamic_matmul_batched``.\n- one scale per expert (``Bs`` ``(E,)``/``(E, 1, 1)``) →\n ``w8a8_tensor_dynamic_fp8_matmul_batched``.\n- block scales (``Bs`` ``(E, N/bn, K/bk)``) → ``w8a8_block_dynamic_fp8_matmul_batched``.",
|
| 119 |
"signature": {
|
|
|
|
| 239 |
{
|
| 240 |
"name": "matmul_grouped",
|
| 241 |
"qualname": "matmul_grouped",
|
| 242 |
+
"module": "_finegrained_kernels_cuda_ec5cc90.grouped",
|
| 243 |
"kind": "function",
|
| 244 |
"doc": "Grouped matmul dispatcher (W8A8 FP8, W4A8/W4A4 FP4, or full-precision).\n``expert_start`` is the ``(E+1,)`` tiling schedule from one ``compute_grouped_scheduling``\npass, shared by every grouped GEMM of the layer (the expert sort is virtual — nothing is\nphysically permuted).\n\n``As`` marks ``A`` as already quantized (framework-precomputed scales, or a requantized\nintermediate handed to the down projection); a per-tensor scalar ``As`` is instead the static\n(calibrated) activation scale for block-scale FP8 weights — the op quantizes raw ``A`` against\nit; ``None`` = raw ``A``, quantized dynamically by the op in ``activation_format`` (``None`` =\nthe weights' own format — fp8/E4M3, or the fp4 chains; ``\"bf16\"`` = weight-only; ``\"mxfp4\"`` =\npacked E2M1 activations). ``Bs`` ``None`` = unquantized BF16/FP16 weights.\n``quantize_output`` requantizes the output into ``activation_format`` — the return is then\n``(C, Cs)``. ``gate``/``act_fn``/``swiglu_alpha``/``swiglu_limit`` fuse the gate|up GLU into the\nepilogue.\n``As``/``Bs`` are each a bare block-scale tensor; the two-level NVFP4 second-level scales ride\nthe separate ``a_global_scale``/``b_global_scale`` (fp32 per-tensor, weights per-expert ``(E,)``;\nfrom ``nvfp4_quantize_two_level``), and the op folds ``g_a · g_b`` onto the accumulator. The\nactivation global ``g_a`` is CALIBRATED (the checkpoint's ``input_scale``): ``a_global_scale=g_a``\nwith a raw ``A`` has the op quantize ``A / g_a`` per block, and rides a pre-quantized ``As`` the\nsame way. Under an NVFP4 requant the fused requant normalizes the GLU intermediate by the\nPROVIDED ``output_global_scale`` (the next proj's calibrated ``input_scale``) before the block\nquant and returns ``[C, Cs]``; the down consumes it as ``As=Cs, a_global_scale=output_global_scale``.\nRow order is carried by the standalone maps: ``gather_idx`` gathers ``A`` (``None`` ->\nalready expert-ordered), ``scatter_idx`` scatters the output. The fused MoE chain is one\nscheduling pass: gate_up with ``scatter_idx=None`` + ``gate=True`` + ``quantize_output=True``,\nthen down with ``gather_idx=None`` and the\nintermediate's scales as ``As``. EP-sentinel routes sit past ``expert_start[-1]``, which\nno tile reaches.\n\nRoutes by what the weight tensors themselves say (there is no ``block_size``\nparameter — the quantization block is derived from the scale shape,\n``weight_block_size``):\n- ``Bs`` None → ``full_precision_matmul_grouped`` (plain dot, no scales anywhere).\n- MX weights — ``int8`` (packed E2M1) or ``float8_e4m3fn`` (E4M3) with UE8M0\n group-32 ``Bs`` → ``mx_dynamic_matmul_grouped``.\n- one scale per expert (``Bs`` ``(E,)``/``(E, 1, 1)``) →\n ``w8a8_tensor_dynamic_fp8_matmul_grouped``.\n- block scales (``Bs`` ``(E, N/bn, K/bk)``) → ``w8a8_block_dynamic_fp8_matmul_grouped``.",
|
| 245 |
"signature": {
|
|
|
|
| 365 |
{
|
| 366 |
"name": "moe_fused_batched",
|
| 367 |
"qualname": "moe_fused_batched",
|
| 368 |
+
"module": "_finegrained_kernels_cuda_ec5cc90.moe",
|
| 369 |
"kind": "function",
|
| 370 |
"doc": "Fused batched MoE (decode): gate_up + SiLU + requant epilogue → per-row quantized\nintermediate → batched down → routing-weighted top-k reduce. Returns\n``(num_tokens, hidden_dim)``. The base ops dispatch on the weight dtypes / scale\nlayout (block-dynamic FP8, MXFP8/MXFP4, NVFP4 — decode runs the software/swap arms\nbelow the native mxf4nvf4 M=128 staging); ``activation_format`` names the activation\nquantization for the whole block — activations and the fused intermediate requant\ncarry it (``\"mxfp4\"`` runs the all-fp4 W4A4 chain, ``\"bf16\"`` is weight-only); ``None``\nfollows the weight format, and the ops validate the pairing. The\n``*_proj_input_global_scale`` pair is the NVFP4 activation second level (a checkpoint's\ncalibrated per-projection ``input_scale``): the gate_up quantizes hidden against its own,\nrequants the intermediate against the down's, and the down consumes that as its activation\nglobal. ``None`` is dynamic quant everywhere else. ``simulate_unfused`` (testing) rounds each\nstep through the activation dtype so the output matches the unfused reference to\nreduce order. ``act_fn`` is a\n``get_supported_act_fns()`` name (fused into the gate_up epilogue where the forward fuses) or any\ncallable applied on the host to the raw gate_up output; ``gate=False`` runs an ungated\nprojection. Scales are affine or pre-swizzled (``SWIZZLE_32_4_4``, self-describing 5-D)\n— the swizzled layout is for the dot_scaled arm; weight-only chains take affine.",
|
| 371 |
"signature": {
|
|
|
|
| 521 |
{
|
| 522 |
"name": "moe_fused_grouped",
|
| 523 |
"qualname": "moe_fused_grouped",
|
| 524 |
+
"module": "_finegrained_kernels_cuda_ec5cc90.moe",
|
| 525 |
"kind": "function",
|
| 526 |
"doc": "Fused grouped MoE (prefill): gather gate_up + SiLU + requant epilogue → quantized\nexpert-ordered intermediate → grouped down → routing-weighted top-k reduce. Returns\n``(num_tokens, hidden_dim)``. The base ops dispatch on the weight dtypes / scale\nlayout (block-dynamic FP8, MXFP8/MXFP4, NVFP4); ``activation_format`` names the activation\nquantization for the whole block — activations and the fused intermediate requant\ncarry it (``\"mxfp4\"``/``\"nvfp4\"`` run all-fp4 W4A4 chains, ``\"bf16\"`` is weight-only);\n``None`` follows the weight format, and the ops validate the pairing. The\n``*_proj_input_global_scale`` pair is the NVFP4 activation second level (a checkpoint's\ncalibrated per-projection ``input_scale``): the gate_up quantizes hidden against its own,\nrequants the intermediate against the down's, and the down consumes that as its activation\nglobal. ``None`` is dynamic quant everywhere else. ``simulate_unfused`` (testing) rounds each step through\nthe activation dtype so the output matches the unfused reference to reduce order. ``act_fn`` is a\n``get_supported_act_fns()`` name (fused into the gate_up epilogue where the forward fuses) or any\ncallable applied on the host to the raw gate_up output; ``gate=False`` runs an ungated\nprojection. Scales are affine or pre-swizzled (``SWIZZLE_32_4_4``, self-describing 5-D)\n— the swizzled layout is for the dot_scaled arm; weight-only chains take affine.",
|
| 527 |
"signature": {
|
|
|
|
| 674 |
"return_annotation": "torch.Tensor"
|
| 675 |
}
|
| 676 |
},
|
| 677 |
+
{
|
| 678 |
+
"name": "embedding_lookup",
|
| 679 |
+
"qualname": "embedding_lookup",
|
| 680 |
+
"module": "_finegrained_kernels_cuda_ec5cc90.embedding",
|
| 681 |
+
"kind": "function",
|
| 682 |
+
"doc": "Gather and dequantize selected rows without expanding the embedding table.\n\n``weight_format`` selects ``fp8``, ``nvfp4``, ``mxfp8``, ``mxfp4``, ``int8``, or ``int4``.\nBy default, a global scale selects NVFP4, signed int8 weights select INT8, and otherwise\nFP8 is used. FP8 accepts scalar, per-row, or square block scales (``block_size``).\nNVFP4 uses E4M3 group-16 scales and one FP32 multiplier; MX formats use UE8M0 group-32\nscales. FP4 packs adjacent columns, low nibble first. INT8 uses per-row scales; INT4\npacks adjacent vocabulary rows and uses per-row column groups inferred from its scale\ngrid. Integer values are signed, symmetric, and have no zero point.\n\nOutputs default to the floating scale dtype, or bf16 for NVFP4/MX. Table/grid strides\nmay describe TP slices. Indices follow ``torch.nn.functional.embedding``: negative and\nout-of-range values fail; padding indices look up their stored row. Empty, repeated,\nand noncontiguous indices work.",
|
| 683 |
+
"signature": {
|
| 684 |
+
"parameters": [
|
| 685 |
+
{
|
| 686 |
+
"name": "weight",
|
| 687 |
+
"kind": "POSITIONAL_OR_KEYWORD",
|
| 688 |
+
"default": null,
|
| 689 |
+
"annotation": "torch.Tensor"
|
| 690 |
+
},
|
| 691 |
+
{
|
| 692 |
+
"name": "indices",
|
| 693 |
+
"kind": "POSITIONAL_OR_KEYWORD",
|
| 694 |
+
"default": null,
|
| 695 |
+
"annotation": "torch.Tensor"
|
| 696 |
+
},
|
| 697 |
+
{
|
| 698 |
+
"name": "scale",
|
| 699 |
+
"kind": "POSITIONAL_OR_KEYWORD",
|
| 700 |
+
"default": null,
|
| 701 |
+
"annotation": "torch.Tensor"
|
| 702 |
+
},
|
| 703 |
+
{
|
| 704 |
+
"name": "global_scale",
|
| 705 |
+
"kind": "POSITIONAL_OR_KEYWORD",
|
| 706 |
+
"default": "None",
|
| 707 |
+
"annotation": "torch.Tensor | None"
|
| 708 |
+
},
|
| 709 |
+
{
|
| 710 |
+
"name": "output_dtype",
|
| 711 |
+
"kind": "POSITIONAL_OR_KEYWORD",
|
| 712 |
+
"default": "None",
|
| 713 |
+
"annotation": "torch.dtype | None"
|
| 714 |
+
},
|
| 715 |
+
{
|
| 716 |
+
"name": "weight_format",
|
| 717 |
+
"kind": "KEYWORD_ONLY",
|
| 718 |
+
"default": "None",
|
| 719 |
+
"annotation": "str | None"
|
| 720 |
+
},
|
| 721 |
+
{
|
| 722 |
+
"name": "block_size",
|
| 723 |
+
"kind": "KEYWORD_ONLY",
|
| 724 |
+
"default": "128",
|
| 725 |
+
"annotation": "int"
|
| 726 |
+
}
|
| 727 |
+
],
|
| 728 |
+
"return_annotation": "torch.Tensor"
|
| 729 |
+
}
|
| 730 |
+
},
|
| 731 |
{
|
| 732 |
"name": "get_supported_act_fns",
|
| 733 |
"qualname": "get_supported_act_fns",
|
| 734 |
+
"module": "_finegrained_kernels_cuda_ec5cc90.formats",
|
| 735 |
"kind": "function",
|
| 736 |
"doc": "The activation names the gate|up epilogue fuses in-kernel; any other activation is applied\non the host by the MoE forwards (``act_fn`` as a callable).",
|
| 737 |
"signature": {
|
|
|
|
| 742 |
{
|
| 743 |
"name": "get_supported_norms",
|
| 744 |
"qualname": "get_supported_norms",
|
| 745 |
+
"module": "_finegrained_kernels_cuda_ec5cc90.norm",
|
| 746 |
"kind": "function",
|
| 747 |
"doc": "The norm names the kernels fuse (``post_expert_norm``), each ``x * factor * rsqrt(mean +\neps)`` over the row: ``\"rms_norm\"`` scales the normalized row by ``weight``,\n``\"centered_rms_norm\"`` by ``1 + weight`` (the zero-centered parameterization), and\n``\"input_scaled_rms_norm\"`` scales by ``1 + weight`` BEFORE normalizing, so the mean square\nis taken on the scaled row. Anything else stays a host callable.",
|
| 748 |
"signature": {
|
|
|
|
| 753 |
{
|
| 754 |
"name": "rms_norm_rows",
|
| 755 |
"qualname": "rms_norm_rows",
|
| 756 |
+
"module": "_finegrained_kernels_cuda_ec5cc90.norm",
|
| 757 |
"kind": "function",
|
| 758 |
"doc": "RMS-normalize ``(S, H)`` rows in one launch, in the ``get_supported_norms()`` form named by\n``norm`` (fp32 accumulate, input dtype out). The MoE chain folds this into\n``weighted_reduce`` instead; this is the standalone form.",
|
| 759 |
"signature": {
|
|
|
|
| 789 |
{
|
| 790 |
"name": "swizzle_mx_scales",
|
| 791 |
"qualname": "swizzle_mx_scales",
|
| 792 |
+
"module": "_finegrained_kernels_cuda_ec5cc90.swizzle",
|
| 793 |
"kind": "function",
|
| 794 |
"doc": "Reorder a block-scale tensor into the ``SWIZZLE_32_4_4`` layout the Blackwell tcgen05\nscaled-MMA consumes, one triton launch per matrix (``_swizzle_scales_kernel`` — no torch\npermute/transpose copies). The scale values are unchanged — this only rearranges them from\nplain row-major into the swizzled order the tensor core reads directly (the same layout\ncuBLAS/CUTLASS require for MXFP8/NVFP4 ``scaled_mm``). Plain row-major forces a gather that\ncaps the scaled dot below the fp8/fp4 peak; the swizzle removes it. Apply to weight scales\nonce at model load; the ops accept the result directly.\n\n``scale`` is the per-block scale grid — UE8M0 (``float8_e8m0fnu``, group-32 MXFP8/MXFP4) or\nE4M3 (``float8_e4m3fn``, group-16 NVFP4); the reorder is dtype-agnostic (moves bytes):\n\n- 2D ``(rows, K // group)``: one matrix (a dense weight's scale).\n- 3D ``(E, rows, K // group)``: an expert stack, each expert swizzled independently so its\n blocks stay ``ceil(rows/128)``-aligned (the reader indexes expert ``e`` at\n ``e * ceil(rows/128)``; byte-identical to a flat swizzle when ``rows % 128 == 0``).\n\n``gather_idx`` (2D only): a 1-D ``(padded_rows,)`` index mapping each output (sorted) row to\nits source row in ``scale`` (``-1`` = padding → zero row), folded into the kernel's load — the\nrouted/expert-sorted, per-tile-padded layout a grouped GEMM reads affine per BM=128 tile.\n``padded_rows`` must be a multiple of 128.\n\n``rows``/``cols`` are zero-padded to (128, 4) multiples; returns the 5D\n``(G, row_blocks, ceil(cols/4), 2, 256)`` artifact the ops read — ``G`` the expert count (1 for\na matrix), so an expert stack shards/gathers on its leading dim. Bit-identical to CUTLASS's\npacker (verified).",
|
| 795 |
"signature": {
|
|
|
|
| 813 |
{
|
| 814 |
"name": "unswizzle_mx_scales",
|
| 815 |
"qualname": "unswizzle_mx_scales",
|
| 816 |
+
"module": "_finegrained_kernels_cuda_ec5cc90.swizzle",
|
| 817 |
"kind": "function",
|
| 818 |
"doc": "Inverse of ``swizzle_mx_scales``: a SWIZZLE_32_4_4 artifact back to the plain row-major\n``(rows, cols)`` grid — or ``(num_experts, rows, cols)`` for an expert stack — with the\n(128, 4) padding trimmed. Pure reshape/permute on the byte view (no kernel); it runs at\nsave/dequantize time, never on a forward, so the torch-level cost is irrelevant.\n\n``rows``/``cols`` are the LOGICAL dims of ONE matrix (for a gate|up slab, the full ``2N``);\nboth are trimmed back out of the (128, 4) padding. ``num_experts`` selects the stacked\n``(E, rows, cols)`` result and must match the artifact's leading dim.",
|
| 819 |
"signature": {
|
|
|
|
| 849 |
{
|
| 850 |
"name": "mxfp8_act_quant",
|
| 851 |
"qualname": "mxfp8_act_quant",
|
| 852 |
+
"module": "_finegrained_kernels_cuda_ec5cc90.quant",
|
| 853 |
"kind": "function",
|
| 854 |
"doc": "Quantize ``(T, K)`` activations to MX once (E4M3 values + UE8M0 group-32 uint8 scales)\ninstead of inline per weight-tile — the fused gate_up re-ran the inline quant per N-tile\n(16x redundant amax/convert ALU + 2x act bytes), which held it at ~380 TFLOPS while the\npre-quantized down kernel ran at ~1080. One pass costs ~50µs at 8k tokens. Bit-exact with\nthe inline form (same group boundaries). ``swizzled=True`` emits the scale directly in\nSWIZZLE_32_4_4 for the tcgen05 fast path (same dense grid, per-element store).",
|
| 855 |
"signature": {
|
|
|
|
| 873 |
{
|
| 874 |
"name": "mxfp4_act_quant",
|
| 875 |
"qualname": "mxfp4_act_quant",
|
| 876 |
+
"module": "_finegrained_kernels_cuda_ec5cc90.quant",
|
| 877 |
"kind": "function",
|
| 878 |
"doc": "Quantize ``(T, K)`` activations to MXFP4 in one kernel pass: packed-E2M1 values\n(``(T, K//2)`` int8, two codes per byte, first value in the low nibble) + UE8M0\ngroup-32 uint8 scales (``(T, K//32)``, amax/6 ceil'd to a power of two). Bit-identical\nto the fused epilogues' inline form (shared ``mx_act_quant_inline`` arm). Feeds the\nW4A4 arm of the MX matmul ops; quantizing activations to fp4 at runtime is an\naccuracy call the caller owns — the ops never do it implicitly. ``swizzled=True`` emits the\nscale directly in SWIZZLE_32_4_4 for the tcgen05 fast path.",
|
| 879 |
"signature": {
|
|
|
|
| 897 |
{
|
| 898 |
"name": "nvfp4_act_quant",
|
| 899 |
"qualname": "nvfp4_act_quant",
|
| 900 |
+
"module": "_finegrained_kernels_cuda_ec5cc90.quant",
|
| 901 |
"kind": "function",
|
| 902 |
"doc": "Quantize ``(T, K)`` activations to NVFP4 in one kernel pass: packed-E2M1 values\n(``(T, K//2)`` int8) + E4M3 group-16 block scales (``(T, K//16)`` — ``amax/6`` rounded to\nE4M3, NOT a power of two; values divide by the DECODED scale before the E2M1 grid,\nthe standard two-step). ``global_scale`` is the CALIBRATED per-tensor second level\n(fp32, the checkpoint's ``input_scale``): values are normalized by it before\nthe block quant, so block scales stay in e4m3 range regardless of the activation's\ndynamic range — the canonical two-level format. The GEMM folds ``g_a·g_b`` back onto\nthe accumulator (pass ``As=scales`` with ``a_global_scale=global_scale``). Per-expert globals\nneed each row's expert, which ``expert_index`` gives where the caller already holds that map\n(the batched op's ``expert_ids``, sentinels and all) — it is read only when the globals are\nper expert, and ``mx_act_quant_grouped`` needs none at all, its tiles carrying an expert.\n``None`` = single-level (``g_a = 1``). ``swizzled=True`` emits the scale directly in\nSWIZZLE_32_4_4 for the tcgen05 fast path.",
|
| 903 |
"signature": {
|