| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724 |
- # SPDX-License-Identifier: Apache-2.0
- # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
- """Engram: n-gram hash lookups gated into the hyper-connection stream.
- Port of the reference ``inference/engram.py`` + ``Engram`` /
- ``ParallelEngramEmbedding`` from ``inference/model.py`` (DeepSeek V4.1
- checkpoint layout). Engram modules live on the backbone layers listed in
- ``engram_layer_ids`` only.
- Two pieces of cross-forward state are needed because vLLM streams tokens
- chunk-by-chunk while an n-gram at position ``p`` needs the token ids at
- ``p-1..p-3``:
- - ``token_map``: token id -> compressed vocab id, built once from the
- model's tokenizer at init (deterministic; asserted against
- ``engram_compressed_vocab_size``).
- - ``hash_cache``: one int32 slot per KV slot of the first local layer's
- sliding-window cache, holding the compressed id (or DEAD) of the token
- last written to that slot. Slots are stable per (request, position) —
- the block table pins a position to a physical slot, prefix-cache hits
- reuse both the physical blocks and the identical token ids, and
- spec-decode rollbacks rewrite the same slots — so lookbacks read back
- exactly what the owning request wrote. Lookback depth (3) is far inside
- the sliding window (128), so window eviction never frees a block a
- live lookback still needs.
- Slots are not part of the KV cache, so KV loaded from another instance
- (P/D, offload connectors) leaves them unwritten. The runner therefore
- passes ``lookback_token_ids``, the ids just before each request's chunk
- start, which take precedence over the slots. The V2 runner reads them
- from its device-resident token history and needs no slot cache; the V1
- runner's CPU token table holds placeholders for generated tokens under
- async scheduling, so it passes prompt positions only and keeps the slot
- cache for the rest.
- """
- import weakref
- import numpy as np
- import torch
- from torch import nn
- # --- Tech2Wild/Kai 2026-09-10: disk-backed Engram tables for DGX Spark (UMA) ---
- import json as _kai_json
- import os as _kai_os
- import struct as _kai_struct
- from concurrent.futures import ThreadPoolExecutor as _KaiPool
- from vllm.config import VllmConfig, get_current_vllm_config
- from vllm.distributed import (
- get_tensor_model_parallel_rank,
- get_tensor_model_parallel_world_size,
- tensor_model_parallel_all_gather,
- )
- from vllm.logger import init_logger
- from vllm.model_executor.layers.linear import ReplicatedLinear
- from vllm.model_executor.layers.quantization import QuantizationConfig
- from vllm.model_executor.utils import set_weight_attrs
- from vllm.triton_utils import tl, triton
- from vllm.utils.platform_utils import is_uva_available
- from vllm.utils.torch_utils import get_accelerator_view_from_cpu_tensor
- logger = init_logger(__name__)
- # Cache value for tokens that take no part in an n-gram (image spans).
- DEAD_ID = -1
- def _is_prime(n: int) -> bool:
- """Deterministic Miller-Rabin for n < 2**32 (avoids a sympy import)."""
- if n < 2:
- return False
- for p in (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37):
- if n % p == 0:
- return n == p
- d = n - 1
- r = 0
- while d % 2 == 0:
- d //= 2
- r += 1
- for a in (2, 7, 61):
- x = pow(a, d, n)
- if x in (1, n - 1):
- continue
- for _ in range(r - 1):
- x = x * x % n
- if x == n - 1:
- break
- else:
- return False
- return True
- def find_next_prime(start: int, seen_primes: set[int]) -> int:
- """The smallest prime above `start` that has not been handed out yet."""
- candidate = start + 1
- while not _is_prime(candidate) or candidate in seen_primes:
- candidate += 1
- return candidate
- def build_compressed_token_map(tokenizer) -> tuple[list[int], int]:
- """Map every token id onto a smaller id space where tokens that normalize
- alike collapse together.
- N-grams are hashed over these compressed ids, so " The", "the" and "THE"
- all hash the same way. The compressed size matters beyond bounds checking:
- every hash multiplier is derived from it.
- """
- from tokenizers import Regex, normalizers
- # A private-use char, so a token that is exactly one space survives
- # Strip() instead of collapsing to the empty string and merging with
- # unrelated tokens.
- sentinel = "\ue000"
- normalizer = normalizers.Sequence(
- [
- normalizers.NFKC(),
- normalizers.NFD(),
- normalizers.StripAccents(),
- normalizers.Lowercase(),
- normalizers.Replace(Regex(r"[ \t\r\n]+"), " "),
- normalizers.Replace(Regex(r"^ $"), sentinel),
- normalizers.Strip(),
- normalizers.Replace(sentinel, " "),
- ]
- )
- # The raw Rust tokenizer, matching what training decodes with
- # (no clean_up_tokenization_spaces).
- backend = tokenizer.backend_tokenizer
- key_to_new: dict[str, int] = {}
- lookup = [0] * len(tokenizer)
- for token_id in range(len(tokenizer)):
- text = backend.decode([token_id], skip_special_tokens=False)
- if "\ufffd" in text:
- # A partial UTF-8 byte token: nothing to normalize, so key it
- # by its raw form.
- key = backend.id_to_token(token_id)
- else:
- normalized = normalizer.normalize_str(text)
- key = normalized if normalized else text
- new_id = key_to_new.get(key)
- if new_id is None:
- new_id = len(key_to_new)
- key_to_new[key] = new_id
- lookup[token_id] = new_id
- return lookup, len(key_to_new)
- def compute_hash_multipliers(
- layer_ids: tuple[int, ...], max_ngram_size: int, compressed_vocab_size: int
- ) -> torch.Tensor:
- """One multiplier per (layer, lookback), from a per-layer RNG so layers
- hash differently. Kept odd and bounded so `token_id * multiplier` cannot
- overflow int64.
- """
- max_long = np.iinfo(np.int64).max
- multiplier_bound = max(1, (max_long // compressed_vocab_size) // 2)
- rows = []
- for layer_id in layer_ids:
- generator = np.random.default_rng(10007 * layer_id)
- values = generator.integers(
- low=0,
- high=multiplier_bound,
- size=(max_ngram_size,),
- dtype=np.int64,
- )
- rows.append(torch.tensor(values * 2 + 1))
- return torch.stack(rows)
- class EngramLayout:
- """Bucket layout of the n-gram hash tables.
- A position is hashed as `max_ngram_size - 1` n-grams (2-gram .. max), each
- split over `n_heads` heads. Every (n-gram size, head) pair owns its own
- prime-sized bucket range in the layer's table; the primes are drawn in
- order and never reused, which keeps the ranges disjoint.
- """
- def __init__(self, config) -> None:
- self.layer_ids: tuple[int, ...] = tuple(config.engram_layer_ids)
- self.num_embeddings: tuple[int, ...] = tuple(config.engram_num_embeddings)
- self.max_ngram_size: int = config.engram_max_ngram_size
- self.n_heads: int = config.engram_n_heads
- self.head_dim: int = config.engram_head_dim
- self.compressed_vocab_size: int = config.engram_compressed_vocab_size
- self.pad_token_id: int = config.engram_pad_token_id
- assert len(self.layer_ids) == len(self.num_embeddings)
- primes = []
- seen: set[int] = set()
- for _ in self.layer_ids:
- per_ngram = []
- for _ in range(self.max_ngram_size - 1):
- sizes, current = [], config.engram_vocab_size - 1
- for _ in range(self.n_heads):
- current = find_next_prime(current, seen)
- seen.add(current)
- sizes.append(current)
- per_ngram.append(tuple(sizes))
- primes.append(tuple(per_ngram))
- self.primes: tuple[tuple[tuple[int, ...], ...], ...] = tuple(primes)
- self.n_hash_cols = (self.max_ngram_size - 1) * self.n_heads
- flat = [[p for per_ngram in layer for p in per_ngram] for layer in primes]
- offsets = [np.cumsum([0, *sizes[:-1]]) for sizes in flat]
- self.offsets = torch.tensor(np.array(offsets)) # [n_layers, n_hash_cols]
- @classmethod
- def from_config(cls, config) -> "EngramLayout | None":
- if not getattr(config, "engram_layer_ids", None):
- return None
- return cls(config)
- @triton.jit(do_not_specialize=["num_tokens"])
- def _write_hash_cache_kernel(
- input_ids,
- token_map,
- dead_mask,
- slot_mapping,
- cache,
- num_tokens,
- input_stride,
- mask_stride,
- slot_stride,
- BLOCK_SIZE: tl.constexpr,
- dead_id,
- ):
- token_idx = tl.program_id(0) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
- slot = tl.load(
- slot_mapping + token_idx * slot_stride, token_idx < num_tokens, other=-1
- ).to(tl.int64)
- valid = (token_idx < num_tokens) & (slot >= 0)
- token = tl.load(input_ids + token_idx * input_stride, valid, other=0)
- value = tl.load(token_map + token, valid, other=0)
- dead = tl.load(dead_mask + token_idx * mask_stride, valid, other=False)
- value = tl.where(dead, dead_id, value)
- tl.store(cache + slot, value, valid)
- @triton.jit(
- do_not_specialize=[
- "num_tokens",
- "num_slots",
- "num_query_rows",
- "num_table_rows",
- "max_blocks",
- ]
- )
- def _hash_ids_kernel(
- input_ids,
- token_map,
- dead_mask,
- positions,
- block_table,
- query_start_loc,
- multipliers,
- primes,
- offsets,
- cache,
- lookback_token_ids,
- lookback_dead_mask,
- output,
- num_tokens,
- num_slots,
- pad_id,
- input_stride,
- mask_stride,
- position_stride,
- table_stride,
- table_col_stride,
- query_stride,
- num_query_rows,
- num_table_rows,
- max_blocks,
- cache_block_size,
- MAX_NGRAM: tl.constexpr,
- num_heads,
- BLOCK_T: tl.constexpr,
- BLOCK_H: tl.constexpr,
- dead_id,
- lookback_depth,
- lookback_row_stride,
- lookback_col_stride,
- lookback_mask_row_stride,
- lookback_mask_col_stride,
- ):
- token = tl.program_id(0) * BLOCK_T + tl.arange(0, BLOCK_T)
- layer = tl.program_id(1)
- num_layers = tl.num_programs(1)
- valid = token < num_tokens
- # Upper bound in query_start_loc[1:], including repeated padding boundaries.
- lo = tl.full((BLOCK_T,), 0, tl.int32)
- hi = tl.full((BLOCK_T,), num_query_rows, tl.int32)
- while tl.sum((lo < hi).to(tl.int32), 0) > 0:
- mid = (lo + hi) // 2
- end = tl.load(
- query_start_loc + (mid + 1) * query_stride,
- lo < hi,
- other=0,
- )
- right = token >= end
- active = lo < hi
- lo = tl.where(active & right, mid + 1, lo)
- hi = tl.where(active & ~right, mid, hi)
- req = tl.minimum(lo, num_query_rows - 1).to(tl.int64)
- chunk_idx = tl.load(query_start_loc + req * query_stride)
- chunk_idx = tl.minimum(chunk_idx, num_tokens - 1).to(tl.int64)
- chunk_start = tl.load(positions + chunk_idx * position_stride)
- position = tl.load(positions + token * position_stride, valid, other=0).to(tl.int64)
- head = tl.arange(0, BLOCK_H)
- blocked = tl.full((BLOCK_T,), False, tl.int1)
- rolling = tl.full((BLOCK_T,), 0, tl.int64)
- for shift in tl.static_range(MAX_NGRAM):
- lookback = position - shift
- in_batch = lookback >= chunk_start
- batch_idx = tl.maximum(token - shift, 0)
- batch_token = tl.load(
- input_ids + batch_idx * input_stride, valid & in_batch, other=0
- )
- batch_source = tl.load(token_map + batch_token, valid & in_batch, other=0)
- batch_dead = tl.load(
- dead_mask + batch_idx * mask_stride, valid & in_batch, other=False
- )
- batch_source = tl.where(batch_dead, dead_id, batch_source)
- col = chunk_start - 1 - lookback
- in_window = valid & ~in_batch & (col >= 0) & (col < lookback_depth)
- col = tl.minimum(tl.maximum(col, 0), lookback_depth - 1)
- window_token = tl.load(
- lookback_token_ids + req * lookback_row_stride + col * lookback_col_stride,
- in_window,
- other=-1,
- )
- known = in_window & (window_token >= 0)
- window_source = tl.load(token_map + window_token, known, other=0)
- window_dead = tl.load(
- lookback_dead_mask
- + req * lookback_mask_row_stride
- + col * lookback_mask_col_stride,
- known,
- other=False,
- )
- window_source = tl.where(window_dead, dead_id, window_source)
- if cache is not None:
- clamped = tl.minimum(
- tl.maximum(lookback, 0), max_blocks * cache_block_size - 1
- )
- block_row = tl.minimum(req, num_table_rows - 1)
- needs_cache = valid & ~in_batch & ~known
- block = tl.load(
- block_table
- + block_row * table_stride
- + (clamped // cache_block_size) * table_col_stride,
- needs_cache,
- other=0,
- ).to(tl.int64)
- slot = tl.minimum(
- tl.maximum(block * cache_block_size + clamped % cache_block_size, 0),
- num_slots - 1,
- )
- fallback = tl.load(cache + slot, needs_cache, other=0)
- else:
- fallback = tl.full((BLOCK_T,), pad_id, tl.int32)
- source = tl.where(
- in_batch, batch_source, tl.where(known, window_source, fallback)
- ).to(tl.int64)
- blocked |= (lookback < 0) | (source == dead_id)
- value = tl.where(blocked, pad_id, source)
- multiplier = tl.load(multipliers + layer * MAX_NGRAM + shift)
- rolling ^= value * multiplier
- if shift > 0:
- col = (shift - 1) * num_heads + head
- param_offset = layer * (MAX_NGRAM - 1) * num_heads + col
- prime = tl.load(primes + param_offset, head < num_heads, other=1)
- offset = tl.load(offsets + param_offset, head < num_heads, other=0)
- hashed = rolling[:, None] % prime[None, :] + offset[None, :]
- out_offset = (token.to(tl.int64) * num_layers + layer)[:, None] * (
- (MAX_NGRAM - 1) * num_heads
- ) + col[None, :]
- tl.store(output + out_offset, hashed, valid[:, None] & (head < num_heads))
- class NgramHashState(nn.Module):
- """Maps each position to the hash ids of the n-grams ending there.
- Stateless on the V2 runner, which supplies every lookback token id. On
- the V1 runner it also keeps `hash_cache`, the slot-keyed rolling store
- of compressed ids (see module docstring), for generated tokens.
- """
- def __init__(
- self,
- vllm_config: VllmConfig,
- layout: EngramLayout,
- swa_cache_module: nn.Module,
- ) -> None:
- super().__init__()
- self.layout = layout
- self.swa_cache_module = swa_cache_module
- self.block_size: int = swa_cache_module.block_size
- self.lookback_depth: int = layout.max_ngram_size - 1
- self.use_slot_cache: bool = not vllm_config.use_v2_model_runner
- self._cache: torch.Tensor | None = None
- self._kv_cache_ref: weakref.ReferenceType[torch.Tensor] | None = None
- model_config = vllm_config.model_config
- from transformers import AutoTokenizer
- tokenizer = AutoTokenizer.from_pretrained(
- model_config.tokenizer,
- trust_remote_code=model_config.trust_remote_code,
- revision=model_config.revision,
- )
- token_map, vocab_size = build_compressed_token_map(tokenizer)
- if vocab_size != layout.compressed_vocab_size:
- raise ValueError(
- f"Compressed vocab size mismatch: built {vocab_size} from the "
- f"tokenizer, config expects {layout.compressed_vocab_size}; "
- "every hash multiplier derives from it, so the engram tables "
- "would be silently rehashed."
- )
- self.pad_id = token_map[layout.pad_token_id]
- multipliers = compute_hash_multipliers(
- layout.layer_ids, layout.max_ngram_size, vocab_size
- )
- self.register_buffer(
- "token_map", torch.tensor(token_map, dtype=torch.int32), persistent=False
- )
- self.register_buffer("primes", torch.tensor(layout.primes), persistent=False)
- self.register_buffer("offsets", layout.offsets, persistent=False)
- self.register_buffer("multipliers", multipliers, persistent=False)
- logger.info(
- "Built engram token map (%d -> %d ids) for layers %s",
- len(token_map),
- vocab_size,
- layout.layer_ids,
- )
- def ensure_cache(self) -> bool:
- """Lazily size the slot-keyed cache from the bound SWA KV cache.
- Returns False while the KV cache is unbound (profile run); the caller
- skips engram hashing then. Without the slot cache only that check
- remains.
- """
- kv_cache = self.swa_cache_module.kv_cache
- if kv_cache.numel() == 0:
- self._cache = None
- self._kv_cache_ref = None
- return False
- if not self.use_slot_cache:
- return True
- if self._kv_cache_ref is not None and self._kv_cache_ref() is kv_cache:
- return True
- # Graph memory profiling binds a temporary, smaller KV cache first.
- # Rebinding must discard its hash history without retaining KV storage.
- self._cache = torch.zeros(
- kv_cache.shape[0] * self.block_size,
- dtype=torch.int32,
- device=kv_cache.device,
- )
- self._kv_cache_ref = weakref.ref(kv_cache)
- return True
- def forward(
- self,
- input_ids: torch.Tensor,
- positions: torch.Tensor,
- query_start_loc: torch.Tensor,
- dead_mask: torch.Tensor,
- lookback_token_ids: torch.Tensor,
- lookback_dead_mask: torch.Tensor,
- slot_mapping: torch.Tensor | None,
- block_table: torch.Tensor | None,
- ) -> torch.Tensor:
- """Compute [tokens, layers, hash columns] int32 n-gram hashes.
- History comes from the current chunk, then the runner's lookback
- window, then the optional V1 slot cache. V2 needs only one launch.
- """
- cache = self._cache if self.use_slot_cache else None
- num_tokens = input_ids.shape[0]
- num_layers, max_ngram = self.multipliers.shape
- num_heads = self.primes.shape[-1]
- output = input_ids.new_empty(
- (num_tokens, num_layers, (max_ngram - 1) * num_heads), dtype=torch.int32
- )
- if num_tokens == 0:
- return output
- if self.use_slot_cache:
- assert cache is not None and slot_mapping is not None
- assert block_table is not None
- # Finish writes before other thread blocks read fallback history.
- _write_hash_cache_kernel[(triton.cdiv(num_tokens, 256),)](
- input_ids,
- self.token_map,
- dead_mask,
- slot_mapping,
- cache,
- num_tokens,
- input_ids.stride(0),
- dead_mask.stride(0),
- slot_mapping.stride(0),
- 256,
- DEAD_ID,
- )
- _hash_ids_kernel[(triton.cdiv(num_tokens, 32), num_layers)](
- input_ids,
- self.token_map,
- dead_mask,
- positions,
- block_table,
- query_start_loc,
- self.multipliers,
- self.primes,
- self.offsets,
- cache,
- lookback_token_ids,
- lookback_dead_mask,
- output,
- num_tokens,
- cache.shape[0] if cache is not None else 0,
- self.pad_id,
- input_stride=input_ids.stride(0),
- mask_stride=dead_mask.stride(0),
- position_stride=positions.stride(0),
- table_stride=block_table.stride(0) if block_table is not None else 0,
- table_col_stride=block_table.stride(1) if block_table is not None else 0,
- query_stride=query_start_loc.stride(0),
- num_query_rows=query_start_loc.numel() - 1,
- num_table_rows=block_table.shape[0] if block_table is not None else 0,
- max_blocks=block_table.shape[1] if block_table is not None else 0,
- cache_block_size=self.block_size,
- MAX_NGRAM=max_ngram,
- num_heads=num_heads,
- BLOCK_T=32,
- BLOCK_H=triton.next_power_of_2(num_heads),
- dead_id=DEAD_ID,
- lookback_depth=lookback_token_ids.shape[1],
- lookback_row_stride=lookback_token_ids.stride(0),
- lookback_col_stride=lookback_token_ids.stride(1),
- lookback_mask_row_stride=lookback_dead_mask.stride(0),
- lookback_mask_col_stride=lookback_dead_mask.stride(1),
- num_warps=4,
- )
- return output
- def _engram_head_shard_weight_loader(
- param: torch.nn.Parameter, loaded_weight: torch.Tensor
- ) -> None:
- """Load this rank's complete head buckets. ue8m0 scales arrive as
- float8_e8m0fnu; keep the raw bytes (the param stores uint8)."""
- part_rows = param.shape[0]
- if loaded_weight.dtype == torch.float8_e8m0fnu:
- loaded_weight = loaded_weight.view(torch.uint8)
- shard = loaded_weight.narrow(0, param.engram_vocab_start, part_rows)
- assert shard.shape == param.shape, (
- f"engram shard {tuple(shard.shape)} does not fit param {tuple(param.shape)}"
- )
- param.data.copy_(shard)
- @triton.jit
- def _engram_lookup_kernel(
- weight,
- scales,
- ids,
- out,
- vocab_start,
- vocab_end,
- num_rows,
- ids_stride_t,
- ids_stride_h,
- HEAD_START: tl.constexpr,
- LOCAL_HEADS: tl.constexpr,
- TOTAL_HEADS: tl.constexpr,
- DIM: tl.constexpr,
- QUANT_BLOCK: tl.constexpr,
- BLOCK_R: tl.constexpr,
- GRID: tl.constexpr,
- ):
- """Gather fp8 rows, apply their ue8m0 block scales, write bf16.
- Only this rank's heads are read; padded heads write zeros for all-gather.
- `weight`/`scales` may address pinned host memory through UVA.
- """
- cols = tl.arange(0, DIM)
- scale_cols = cols // QUANT_BLOCK
- for base in tl.range(tl.program_id(0) * BLOCK_R, num_rows, GRID * BLOCK_R):
- rows = base + tl.arange(0, BLOCK_R)
- valid = rows < num_rows
- head = HEAD_START + rows % LOCAL_HEADS
- token = (rows // LOCAL_HEADS).to(tl.int64)
- index = tl.load(
- ids + token * ids_stride_t + head * ids_stride_h,
- mask=valid & (head < TOTAL_HEADS),
- other=-1,
- ).to(tl.int64)
- owned = valid & (head < TOTAL_HEADS)
- owned &= (index >= vocab_start) & (index < vocab_end)
- local = tl.where(owned, index - vocab_start, 0)
- values = tl.load(
- weight + local[:, None] * DIM + cols[None, :],
- mask=owned[:, None],
- other=0.0,
- )
- scale = tl.load(
- scales + local[:, None] * (DIM // QUANT_BLOCK) + scale_cols[None, :],
- mask=owned[:, None],
- other=0,
- )
- # ue8m0 is a power of two, so its byte *is* the fp32 exponent field.
- scale = (scale.to(tl.int32) << 23).to(tl.float32, bitcast=True)
- tl.store(
- out + rows[:, None] * DIM + cols[None, :],
- (values.to(tl.float32) * scale).to(tl.bfloat16),
- mask=valid[:, None],
- )
- _DSV41_ENGRAM_DISK = _kai_os.environ.get("DSV41_ENGRAM_DISK", "0") == "1"
- # --- Tech2Wild/Kai 2026-09-10 (CUDA graphs): one process-wide read pool shared
- # by every DiskEngramTable. A step's reads for BOTH engram layers (weight and
- # scale rows) go out as one batch, so decode latency is ~one pread instead of
- # 24 serial ones (measured on Reddie: 7.7 ms serial vs 3.1 ms parallel, C1).
- _KAI_THREADS = int(_kai_os.environ.get("DSV41_ENGRAM_DISK_THREADS", "32"))
- _KAI_CHUNK = int(_kai_os.environ.get("DSV41_ENGRAM_DISK_CHUNK", "16"))
- _KAI_POOL: _KaiPool | None = None
- # Stage 6: gather rows through a read-only memory map (one NumPy fancy-index copy
- # per chunk) instead of one preadv syscall per row.
- _KAI_MMAP = _kai_os.environ.get("DSV41_ENGRAM_MMAP", "0") == "1"
- # The gather releases the GIL, so more threads = more page faults in flight
- # (3 of 4 ranks fault rows in over NFS; each cold row is one round trip).
- _KAI_MMAP_THREADS = int(_kai_os.environ.get("DSV41_ENGRAM_MMAP_THREADS", "96"))
- # Stage 8: hash-ahead prefetch of the next prefill chunk's rows into the page
- # cache while the current chunk computes (the prompt is known up front).
- _KAI_PREFETCH = _kai_os.environ.get("DSV41_ENGRAM_PREFETCH", "0") == "1"
- _KAI_PREFETCH_MODE = _kai_os.environ.get("DSV41_ENGRAM_PREFETCH_MODE", "fadvise") # fadvise | pread
- _KAI_PREFETCH_THREADS = int(_kai_os.environ.get("DSV41_ENGRAM_PREFETCH_THREADS", "32"))
- _KAI_PREFETCH_TASK_ROWS = 512
- # Gathers smaller than this many unique rows (per table) keep the preadv path
- # (0 = memmap for every size). Lets decode steps (72 rows) and prefill chunks
- # (tens of thousands) use different paths.
- _KAI_MMAP_MIN_ROWS = int(_kai_os.environ.get("DSV41_ENGRAM_MMAP_MIN_ROWS", "0"))
- # v3 (window 8: 72 decode rows cost 5-6 ms = one NVMe latency per row, serialized by
- # the per-task faults): gathers up to this many rows skip the pool -- first an async
- # readahead of every row page (posix_fadvise WILLNEED, ~2 us each, all reads in
- # flight together), then ONE fancy-index gather per table on the calling thread.
- _KAI_MMAP_INLINE_ROWS = int(_kai_os.environ.get("DSV41_ENGRAM_MMAP_INLINE_ROWS", "2048"))
- def _kai_pool() -> _KaiPool:
- global _KAI_POOL
- if _KAI_POOL is None:
- _KAI_POOL = _KaiPool(
- max_workers=_KAI_MMAP_THREADS if _KAI_MMAP else _KAI_THREADS,
- thread_name_prefix="engram-disk",
- )
- return _KAI_POOL
- def _kai_prefetch_rows(table, rows: list) -> None:
- """Warm rank-local rows `rows` of `table` in the page cache: weight rows by
- exact byte range, scale rows by 4 KiB page (32 rows share one)."""
- if not rows:
- return
- dim, sb = table.dim, table.sb
- if _KAI_PREFETCH_MODE == "pread":
- buf = bytearray(dim)
- for r in rows:
- try:
- _kai_os.preadv(table.w_fd, [buf], table.w_off + r * dim)
- except OSError:
- pass
- sbuf = bytearray(4096)
- for p in {(table.s_off + r * sb) >> 12 for r in rows}:
- try:
- _kai_os.preadv(table.s_fd, [sbuf], p << 12)
- except OSError:
- pass
- return
- adv = _kai_os.POSIX_FADV_WILLNEED
- for r in rows:
- try:
- _kai_os.posix_fadvise(table.w_fd, table.w_off + r * dim, dim, adv)
- except OSError:
- pass
- for p in {(table.s_off + r * sb) >> 12 for r in rows}:
- try:
- _kai_os.posix_fadvise(table.s_fd, p << 12, 4096, adv)
- except OSError:
- pass
- def _kai_map_file(path: str):
- """Read-only shared mapping of a whole shard with readahead DISABLED
- (MADV_RANDOM, the mmap twin of the preadv path's POSIX_FADV_RANDOM): a
- fault brings exactly the 4 KiB page of the row. Window 7 (2026-09-11)
- showed why: without it every cold-row fault pulled an NFS readahead window
- (rsize 1 MiB) — 9K prefill 14.7 s vs 8.1 s, code decode 53 vs 61 tok/s."""
- import mmap as _mmap
- import numpy as _np
- fd = _kai_os.open(path, _kai_os.O_RDONLY)
- try:
- mm = _mmap.mmap(fd, 0, access=_mmap.ACCESS_READ)
- finally:
- _kai_os.close(fd)
- try:
- mm.madvise(_mmap.MADV_RANDOM)
- except (AttributeError, OSError): # pragma: no cover - old kernels
- pass
- return mm, _np.frombuffer(mm, dtype=_np.uint8)
- def _kai_mmap_rows(view, rel, lo: int, hi: int, row_bytes: int, buf) -> None:
- """Copy rows rel[lo:hi] of the [num_rows, row_bytes] memmap view into buf
- (a flat uint8 memoryview). One fancy-index gather: C memcpy for resident
- pages, page faults for cold ones; the GIL is released inside NumPy."""
- import numpy as _np
- dst = _np.frombuffer(buf, dtype=_np.uint8)[lo * row_bytes : hi * row_bytes].reshape(
- hi - lo, row_bytes
- )
- _np.take(view, _np.asarray(rel[lo:hi], dtype=_np.int64), axis=0, out=dst)
- def _kai_pread_rows(
- fd: int, base: int, rel: list, lo: int, hi: int, row_bytes: int, buf
- ) -> None:
- for i in range(lo, hi):
- off = base + rel[i] * row_bytes
- view = buf[i * row_bytes : (i + 1) * row_bytes]
- got = 0
- while got < row_bytes:
- n = _kai_os.preadv(fd, [view[got:]], off + got)
- if n <= 0:
- raise OSError("engram disk table: short read")
- got += n
- def _kai_parallel_read(jobs: list) -> None:
- """jobs: [(fd, base, rel_list, row_bytes, memoryview)]. Every row of every job
- is in flight at once: a task carries ceil(total / threads) rows (1 row at
- decode sizes), capped at DSV41_ENGRAM_DISK_CHUNK for prefill-sized batches.
- Only the calling thread submits, so the shared pool cannot deadlock."""
- total = sum(len(job[2]) for job in jobs)
- if total == 0:
- return
- def _run(job, lo, hi):
- fd, base, rel, row_bytes, buf = job[:5]
- view = job[5] if len(job) > 5 else None
- if view is not None:
- _kai_mmap_rows(view, rel, lo, hi, row_bytes, buf)
- else:
- _kai_pread_rows(fd, base, rel, lo, hi, row_bytes, buf)
- if total == 1:
- for job in jobs:
- _run(job, 0, len(job[2]))
- return
- # Memmap gathers: spread the rows over every pool thread (cold rows fault
- # in sequentially within a task, so more tasks = more reads in flight).
- if any(len(job) > 5 and job[5] is not None for job in jobs):
- if total <= _KAI_MMAP_INLINE_ROWS and all(len(job) > 5 and job[5] is not None for job in jobs):
- adv = _kai_os.POSIX_FADV_WILLNEED
- for fd, base, rel, row_bytes, buf, view in jobs:
- for r in rel:
- try:
- _kai_os.posix_fadvise(fd, base + r * row_bytes, row_bytes, adv)
- except OSError:
- pass
- for fd, base, rel, row_bytes, buf, view in jobs:
- _kai_mmap_rows(view, rel, 0, len(rel), row_bytes, buf)
- return
- chunk = max(1, -(-total // _KAI_MMAP_THREADS))
- else:
- chunk = max(1, min(_KAI_CHUNK, -(-total // _KAI_THREADS)))
- pool = _kai_pool()
- futs = [
- pool.submit(_run, job, lo, min(lo + chunk, len(job[2])))
- for job in jobs
- for lo in range(0, len(job[2]), chunk)
- ]
- for fut in futs:
- fut.result()
- def _dsv41_engram_local_dir(model_dir: str, layer_id: int, row_start: int, num_rows) -> str:
- """Tech2Wild 2026-09-10: node-local Engram rows. DSV41_ENGRAM_DIR points at a sparse copy
- of the Engram shards holding only this rank's rows at the original byte offsets, plus
- engram-local.json with the copied row range per layer (tools/engram_local.py). It is used
- only when that range covers this table's rows; otherwise the table reads model_dir as before,
- so a changed rank map can never read the copy's empty holes."""
- local = _kai_os.environ.get("DSV41_ENGRAM_DIR", "")
- if not local:
- return model_dir
- try:
- with open(_kai_os.path.join(local, "engram-local.json")) as f:
- lo, hi = _kai_json.load(f)["layers"][str(layer_id)]
- except Exception as e: # noqa: BLE001
- logger.warning("DSV41_ENGRAM_DIR=%s unusable for layer %d (%s); reading %s",
- local, layer_id, e, model_dir)
- return model_dir
- if num_rows is None or not (lo <= row_start and row_start + num_rows <= hi):
- logger.warning("DSV41_ENGRAM_DIR=%s holds layer %d rows [%d, %d), this rank needs "
- "[%d, +%s); reading %s", local, layer_id, lo, hi, row_start, num_rows, model_dir)
- return model_dir
- logger.info("Engram layer %d rows [%d, %d) read from node-local %s",
- layer_id, row_start, row_start + num_rows, local)
- return local
- class DiskEngramTable:
- """Tech2Wild/Kai 2026-09-10: read Engram rows straight from the safetensors
- shards with positional preads on a thread pool, so the per-rank Engram
- shard (~47 GiB at TP4) never occupies memory. Built for DGX Spark, where
- "pinned host memory" is the same 128 GB pool the GPU uses. Rows are
- dequantized on the CPU (fp8 e4m3 x ue8m0 block scales -> bf16) and copied
- into the GPU staging buffer. Enable with DSV41_ENGRAM_DISK=1.
- Lineage: our own PLE-on-disk patch for Qwen3.8-Flash-Next (2026-09-05).
- """
- def __init__(
- self,
- model_dir: str,
- layer_id: int,
- dim: int,
- block_size: int,
- row_start: int = 0,
- num_rows: int | None = None,
- ):
- model_dir = _dsv41_engram_local_dir(model_dir, layer_id, row_start, num_rows)
- idx_path = _kai_os.path.join(model_dir, "model.safetensors.index.json")
- with open(idx_path) as f:
- weight_map = _kai_json.load(f)["weight_map"]
- wname = f"layers.{layer_id}.engram.embed.weight"
- sname = f"layers.{layer_id}.engram.embed.scale"
- self.w_fd, self.w_off, self.w_shape = self._open(model_dir, weight_map[wname], wname)
- self.s_fd, self.s_off, self.s_shape = self._open(model_dir, weight_map[sname], sname)
- self._w_path = _kai_os.path.join(model_dir, weight_map[wname])
- self._s_path = _kai_os.path.join(model_dir, weight_map[sname])
- self.dim = dim
- self.sb = dim // block_size
- assert self.w_shape[1] == dim, (self.w_shape, dim)
- assert self.s_shape[1] == self.sb, (self.s_shape, self.sb)
- assert self.s_shape[0] == self.w_shape[0], (self.s_shape, self.w_shape)
- # The checkpoint holds the FULL table (every TP rank's hash heads) per layer,
- # while callers pass rank-local row ids (global - vocab_start), so reads must
- # start at this rank's first row.
- if num_rows is None:
- num_rows = self.w_shape[0] - row_start
- assert 0 <= row_start and row_start + num_rows <= self.w_shape[0], (
- row_start, num_rows, self.w_shape)
- self.w_off += row_start * dim
- self.s_off += row_start * self.sb
- self.row_start = row_start
- self.num_rows = num_rows
- # Stage 6: [num_rows, row_bytes] uint8 views of this rank's rows through a
- # read-only memory map of each shard (opened once; pages come and go
- # with the OS page cache, nothing is pinned).
- self.w_view = self.s_view = None
- if _KAI_MMAP:
- import numpy as _np
- self._w_mm, w_buf = _kai_map_file(self._w_path)
- self._s_mm, s_buf = _kai_map_file(self._s_path)
- self.w_view = _np.ndarray(
- (num_rows, dim), dtype=_np.uint8, buffer=w_buf, offset=self.w_off
- )
- self.s_view = _np.ndarray(
- (num_rows, self.sb), dtype=_np.uint8, buffer=s_buf, offset=self.s_off
- )
- self.threads = _KAI_THREADS
- self.chunk = _KAI_CHUNK
- self.pool = _kai_pool() # shared by all tables (was one pool per table)
- logger.info(
- "Engram DISK mode: layer %d rows [%d, %d) read from %s (off=%d) and %s (off=%d); "
- "%d threads, chunk %d",
- layer_id, row_start, row_start + num_rows, weight_map[wname], self.w_off,
- weight_map[sname], self.s_off, self.threads, self.chunk,
- )
- @staticmethod
- def _open(model_dir: str, fname: str, tname: str):
- path = _kai_os.path.join(model_dir, fname)
- fd = _kai_os.open(path, _kai_os.O_RDONLY)
- try:
- _kai_os.posix_fadvise(fd, 0, 0, _kai_os.POSIX_FADV_RANDOM)
- except Exception: # noqa: BLE001
- pass
- with open(path, "rb") as f:
- n = _kai_struct.unpack("<Q", f.read(8))[0]
- hdr = _kai_json.loads(f.read(n))
- meta = hdr[tname]
- start = meta["data_offsets"][0]
- return fd, 8 + n + start, tuple(meta["shape"])
- def _read_rows(self, fd: int, base: int, rel: list, row_bytes: int, buf) -> None:
- _kai_parallel_read([(fd, base, rel, row_bytes, buf)])
- def read_jobs(self, rel_l: list, w: torch.Tensor, s: torch.Tensor) -> list:
- """Read jobs for rank-local rows `rel_l` into uint8 w [R, dim], s [R, sb]."""
- if self.w_view is not None and len(rel_l) >= _KAI_MMAP_MIN_ROWS:
- return [
- (self.w_fd, self.w_off, rel_l, self.dim, memoryview(w.numpy()).cast("B"), self.w_view),
- (self.s_fd, self.s_off, rel_l, self.sb, memoryview(s.numpy()).cast("B"), self.s_view),
- ]
- return [
- (self.w_fd, self.w_off, rel_l, self.dim, memoryview(w.numpy()).cast("B")),
- (self.s_fd, self.s_off, rel_l, self.sb, memoryview(s.numpy()).cast("B")),
- ]
- def dequant(self, w: torch.Tensor, s: torch.Tensor) -> torch.Tensor:
- """fp8 e4m3 rows (as uint8) x ue8m0 block scales -> [R, dim] fp32."""
- R = w.shape[0]
- vals = w.view(torch.float8_e4m3fn).to(torch.float32).view(
- R, self.sb, self.dim // self.sb
- )
- # ue8m0 byte is the fp32 exponent field: 2^(e-127)
- scale = (s.to(torch.int32) << 23).view(torch.float32)
- return (vals * scale[:, :, None]).reshape(R, self.dim)
- def gather_dequant(self, rel: torch.Tensor, owned: torch.Tensor) -> torch.Tensor:
- """rel: [R] int64 CPU local row ids; owned: [R] bool. Returns [R, dim] bf16 CPU."""
- return gather_dequant_many([(self, rel, owned)])[0]
- def gather_dequant_many(requests: list) -> list[torch.Tensor]:
- """Tech2Wild/Kai 2026-09-10: requests = [(DiskEngramTable, rel [R] int64 CPU,
- owned [R] bool)] -> one [R, dim] bf16 CPU tensor per request. Rows are
- de-duplicated per table (repeated n-grams, zero-filled dummy batches) and the
- reads of every table go out in ONE parallel batch. Same math as before."""
- plans, jobs = [], []
- for table, rel, owned in requests:
- uniq, inverse = torch.unique(rel, return_inverse=True)
- w = torch.empty((uniq.numel(), table.dim), dtype=torch.uint8)
- s = torch.empty((uniq.numel(), table.sb), dtype=torch.uint8)
- jobs += table.read_jobs(uniq.tolist(), w, s)
- plans.append((table, w, s, inverse, owned))
- _kai_parallel_read(jobs)
- outs = []
- for table, w, s, inverse, owned in plans:
- out = table.dequant(w, s)[inverse]
- out[~owned] = 0
- outs.append(out.to(torch.bfloat16))
- return outs
- class ParallelEngramEmbedding(nn.Module):
- """The n-gram hash table, sharded by complete hash heads over TP ranks.
- Rows stay fp8 and are dequantized with ue8m0 per-32 scales on lookup.
- With `cpu_offload` the shard lives in pinned host memory and is read over
- UVA instead of HBM; the TP sharding is unchanged either way.
- """
- def __init__(
- self,
- num_embeddings: int,
- dim: int,
- head_sizes: tuple[int, ...],
- block_size: int = 32,
- cpu_offload: bool = False,
- model_dir: str | None = None,
- layer_id: int | None = None,
- ):
- super().__init__()
- self.disk: DiskEngramTable | None = None
- if _DSV41_ENGRAM_DISK:
- cpu_offload = False
- tp_size = get_tensor_model_parallel_world_size()
- tp_rank = get_tensor_model_parallel_rank()
- assert head_sizes and all(size > 0 for size in head_sizes)
- assert sum(head_sizes) <= num_embeddings
- if cpu_offload and not is_uva_available():
- raise RuntimeError("Engram CPU offload requires UVA support")
- self.num_embeddings = num_embeddings
- self.dim = dim
- self.block_size = block_size
- self.n_hash_cols = len(head_sizes)
- self.part_n_hash_cols = triton.cdiv(self.n_hash_cols, tp_size)
- self.head_start = tp_rank * self.part_n_hash_cols
- head_end = self.head_start + self.part_n_hash_cols
- self.vocab_start_idx = sum(head_sizes[: self.head_start])
- self.vocab_end_idx = sum(head_sizes[:head_end])
- self.part_num_embeddings = self.vocab_end_idx - self.vocab_start_idx
- self.tp_size = tp_size
- self.cpu_offload = cpu_offload
- self._views: tuple[torch.Tensor, torch.Tensor] | None = None
- self._view_src: tuple[int, int] | None = None
- self._num_sms = torch.cuda.get_device_properties(
- torch.accelerator.current_device_index()
- ).multi_processor_count
- # Explicit device: model init runs under a `torch.device("cuda")`
- # context, which would otherwise put the shard in HBM.
- kwargs = {"device": "cpu", "pin_memory": True} if cpu_offload else {}
- if _DSV41_ENGRAM_DISK:
- assert model_dir is not None and layer_id is not None
- self.disk = DiskEngramTable(
- model_dir, layer_id, dim, block_size,
- row_start=self.vocab_start_idx, num_rows=self.part_num_embeddings,
- )
- # 1-row placeholders as BUFFERS (not Parameters): the checkpoint
- # rows are skipped by the weights iterator and must not trip the
- # "weights not initialized" check.
- self.register_buffer("weight", torch.zeros(1, dim, dtype=torch.float8_e4m3fn, device="cpu"), persistent=False)
- self.register_buffer("weight_scale_inv", torch.zeros(1, dim // block_size, dtype=torch.uint8, device="cpu"), persistent=False)
- logger.info(
- "Engram table DISK-backed: %d rows x %d per rank stay on disk (%.2f GiB not allocated)",
- self.part_num_embeddings, dim,
- self.part_num_embeddings * (dim + dim // block_size) / 1024**3,
- )
- return
- self.weight = nn.Parameter(
- torch.empty(
- self.part_num_embeddings, dim, dtype=torch.float8_e4m3fn, **kwargs
- ),
- requires_grad=False,
- )
- self.weight_scale_inv = nn.Parameter(
- torch.empty(
- self.part_num_embeddings,
- dim // block_size,
- dtype=torch.uint8,
- **kwargs,
- ),
- requires_grad=False,
- )
- for param in (self.weight, self.weight_scale_inv):
- set_weight_attrs(
- param,
- {
- "weight_loader": _engram_head_shard_weight_loader,
- "engram_vocab_start": self.vocab_start_idx,
- },
- )
- if cpu_offload:
- logger.info(
- "Engram table offloaded to pinned host memory: %d rows x %d, "
- "%.2f GiB per rank",
- self.part_num_embeddings,
- dim,
- self.part_num_embeddings * (dim + dim // block_size) / 1024**3,
- )
- def _storage(self) -> tuple[torch.Tensor, torch.Tensor]:
- """Parameters when resident, else cached UVA views of the pinned shard.
- Rebuilt if anything swaps `.data`, so a stale device pointer cannot
- survive silently.
- """
- if not self.cpu_offload:
- return self.weight.data, self.weight_scale_inv.data
- src = (self.weight.data_ptr(), self.weight_scale_inv.data_ptr())
- if self._view_src != src:
- self._views = (
- get_accelerator_view_from_cpu_tensor(self.weight.data),
- get_accelerator_view_from_cpu_tensor(self.weight_scale_inv.data),
- )
- self._view_src = src
- assert self._views is not None
- return self._views
- def lookup(
- self, indices: torch.Tensor, out: torch.Tensor, background: bool = False
- ) -> None:
- """Look up local heads of [T, heads] into [T, local_heads, dim] bf16.
- `background` limits the grid to leave SMs for concurrent work.
- """
- rows = indices.shape[0] * self.part_n_hash_cols
- if not rows:
- return
- if self.disk is not None:
- self._disk_lookup(indices, out)
- return
- weight, scales = self._storage()
- # The table dwarfs TLB reach, so a persistent grid near the SM count
- # beats one program per row; halve it to leave SMs for the main stream.
- tiles = triton.cdiv(rows, 16)
- grid = min(tiles, self._num_sms // 2 if background else self._num_sms)
- _engram_lookup_kernel[(grid,)](
- weight,
- scales,
- indices,
- out,
- self.vocab_start_idx,
- self.vocab_end_idx,
- rows,
- indices.stride(0),
- indices.stride(1),
- HEAD_START=self.head_start,
- LOCAL_HEADS=self.part_n_hash_cols,
- TOTAL_HEADS=self.n_hash_cols,
- DIM=self.dim,
- QUANT_BLOCK=self.block_size,
- BLOCK_R=16,
- GRID=grid,
- )
- def disk_rel_owned(self, local: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
- """local: [T, <=L] int64 CPU hash ids of this rank's heads -> flat
- (rel [T*L] rank-local row ids, owned [T*L] bool). Padded heads (beyond
- TOTAL_HEADS) and ids outside this rank's range are not owned (zeros)."""
- T = local.shape[0]
- L = self.part_n_hash_cols
- if local.shape[1] < L:
- pad = torch.full((T, L - local.shape[1]), -1, dtype=torch.int64)
- local = torch.cat([local, pad], dim=1)
- rows = local.reshape(-1)
- owned = (rows >= self.vocab_start_idx) & (rows < self.vocab_end_idx)
- rel = torch.where(owned, rows - self.vocab_start_idx, torch.zeros_like(rows))
- return rel, owned
- def _disk_lookup(self, indices: torch.Tensor, out: torch.Tensor) -> None:
- """Host-side gather + dequant for DISK mode, then H2D into `out`
- ([T, local_heads, dim] bf16). Padded heads (beyond TOTAL_HEADS) and
- rows outside this rank's range write zeros, matching the kernel.
- In-forward fallback only (V1 runner / eager). Under the V2 runner the
- rows are staged by EngramDiskStager before the forward instead."""
- if torch.cuda.is_available() and torch.cuda.is_current_stream_capturing():
- raise RuntimeError(
- "Engram DISK lookup reached a CUDA-graph capture: it needs a host "
- "round trip. Stage rows before the forward (EngramDiskStager, V2 "
- "runner + patched nvidia/model_state.py) or run --enforce-eager."
- )
- T = indices.shape[0]
- L = self.part_n_hash_cols
- ids = indices.detach().to("cpu", dtype=torch.int64)
- head_end = min(self.head_start + L, self.n_hash_cols)
- rel, owned = self.disk_rel_owned(ids[:, self.head_start:head_end])
- assert self.disk is not None
- deq = self.disk.gather_dequant(rel, owned)
- out[:T].copy_(deq.view(T, L, self.dim))
- def forward(self, indices: torch.Tensor) -> torch.Tensor:
- """indices: [num_tokens, n_hash_cols] -> [num_tokens, n_hash_cols, dim]
- bf16, gathered from all TP shards."""
- out = torch.empty(
- (indices.shape[0], self.part_n_hash_cols, self.dim),
- dtype=torch.bfloat16,
- device=indices.device,
- )
- self.lookup(indices, out)
- if self.tp_size > 1:
- out = tensor_model_parallel_all_gather(out, dim=1)
- out = out[:, : self.n_hash_cols]
- return out
- @triton.jit(do_not_specialize=["num_kv_tokens"])
- def _fused_engram_post_wkv_kernel(
- hidden_states,
- kv,
- q_weight,
- k_weight,
- token_mask,
- output,
- num_kv_tokens,
- hidden_stride_t,
- hidden_stride_h,
- hidden_stride_d,
- kv_stride_t,
- kv_stride_d,
- q_stride_h,
- q_stride_d,
- k_stride_h,
- k_stride_d,
- mask_stride,
- output_stride_t,
- output_stride_h,
- output_stride_d,
- eps,
- clamp_value,
- DIM: tl.constexpr,
- HC_MULT: tl.constexpr,
- BLOCK_SIZE: tl.constexpr,
- HAS_MASK: tl.constexpr,
- ):
- program_idx = tl.program_id(0)
- token_idx = program_idx // HC_MULT
- hc_idx = program_idx % HC_MULT
- token_idx = token_idx.to(tl.int64)
- source_idx = token_idx
- source_valid = source_idx < num_kv_tokens
- dim_offsets = tl.arange(0, BLOCK_SIZE)
- dim_valid = dim_offsets < DIM
- hidden = tl.load(
- hidden_states
- + token_idx * hidden_stride_t
- + hc_idx * hidden_stride_h
- + dim_offsets * hidden_stride_d,
- mask=dim_valid,
- other=0.0,
- ).to(tl.float32)
- key = tl.load(
- kv + source_idx * kv_stride_t + (hc_idx * DIM + dim_offsets) * kv_stride_d,
- mask=source_valid & dim_valid,
- other=0.0,
- ).to(tl.float32)
- q = tl.load(
- q_weight + hc_idx * q_stride_h + dim_offsets * q_stride_d,
- mask=dim_valid,
- other=0.0,
- ).to(tl.float32)
- k = tl.load(
- k_weight + hc_idx * k_stride_h + dim_offsets * k_stride_d,
- mask=dim_valid,
- other=0.0,
- ).to(tl.float32)
- hidden_rms = tl.rsqrt(tl.sum(hidden * hidden, axis=0) / DIM + eps)
- key_rms = tl.rsqrt(tl.sum(key * key, axis=0) / DIM + eps)
- dot = tl.sum(hidden * q * k * key, axis=0)
- dot *= hidden_rms * key_rms * tl.rsqrt(DIM * 1.0)
- gate_input = tl.sqrt(tl.maximum(tl.abs(dot), clamp_value))
- gate_input = tl.where(dot < 0.0, -gate_input, gate_input)
- gate = tl.sigmoid(gate_input)
- if HAS_MASK:
- active = tl.load(
- token_mask + source_idx * mask_stride,
- mask=source_valid,
- other=0,
- )
- gate = tl.where(active, gate, 0.0)
- value = tl.load(
- kv + source_idx * kv_stride_t + (HC_MULT * DIM + dim_offsets) * kv_stride_d,
- mask=source_valid & dim_valid,
- other=0.0,
- ).to(tl.float32)
- tl.store(
- output
- + token_idx * output_stride_t
- + hc_idx * output_stride_h
- + dim_offsets * output_stride_d,
- hidden + gate * value,
- mask=dim_valid,
- )
- @triton.jit(do_not_specialize=["num_tokens", "token_start", "num_elements"])
- def _engram_sp_rows_kernel(
- gathered,
- output,
- num_tokens,
- token_start,
- num_elements,
- LOCAL_WIDTH: tl.constexpr,
- WIDTH: tl.constexpr,
- BLOCK_SIZE: tl.constexpr,
- ):
- offsets = tl.program_id(0).to(tl.int64) * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
- tokens = token_start + offsets // WIDTH
- cols = offsets % WIDTH
- source = (cols // LOCAL_WIDTH * num_tokens + tokens) * LOCAL_WIDTH
- source += cols % LOCAL_WIDTH
- values = tl.load(
- gathered + source, (offsets < num_elements) & (tokens < num_tokens), other=0
- )
- tl.store(output + offsets, values, offsets < num_elements)
- class Engram(nn.Module):
- """Writes an n-gram lookup into the residual stream, gated by how well it
- matches that stream.
- The hash ids fetch `n_hash_cols` rows; `wkv` turns them into one key per
- hc copy plus a shared value. The gate is a normalized dot product of the
- stream against the key, signed-sqrt'ed before the sigmoid (matching the
- training kernel).
- """
- def __init__(
- self,
- config,
- quant_config: QuantizationConfig | None,
- layout: EngramLayout,
- layer_hash_index: int,
- use_sequence_parallel: bool,
- prefix: str,
- ) -> None:
- super().__init__()
- self.layer_hash_index = layer_hash_index
- self.dim = config.hidden_size
- self.hc_mult = config.hc_mult
- self.eps = config.rms_norm_eps
- self.clamp_value = 1e-6
- self.use_sequence_parallel = use_sequence_parallel
- # Named ``embed_tokens`` so the checkpoint's ``engram.embed.weight``
- # survives the mapper's ``embed.weight`` -> ``embed_tokens.weight``
- # suffix rule.
- engram_config = get_current_vllm_config().engram_config
- self.embed_tokens = ParallelEngramEmbedding(
- layout.num_embeddings[layer_hash_index],
- layout.head_dim,
- tuple(size for order in layout.primes[layer_hash_index] for size in order),
- cpu_offload=engram_config.cpu_offload if engram_config else True,
- model_dir=get_current_vllm_config().model_config.model,
- layer_id=layout.layer_ids[layer_hash_index],
- )
- n_hash_cols = (layout.max_ngram_size - 1) * layout.n_heads
- self.wkv = ReplicatedLinear(
- n_hash_cols * layout.head_dim,
- self.dim * (self.hc_mult + 1),
- bias=False,
- quant_config=quant_config,
- return_bias=False,
- prefix=f"{prefix}.wkv",
- )
- self.q_weight = nn.Parameter(
- torch.empty(self.hc_mult, self.dim, dtype=torch.bfloat16),
- requires_grad=False,
- )
- self.k_weight = nn.Parameter(
- torch.empty(self.hc_mult, self.dim, dtype=torch.bfloat16),
- requires_grad=False,
- )
- max_tokens = get_current_vllm_config().scheduler_config.max_num_batched_tokens
- # Tech2Wild/Kai 2026-09-10 (CUDA graphs): under the V2 runner a DISK
- # table is staged by the model state (EngramDiskStager) BEFORE the
- # forward, so the forward holds no host round trip and can be captured
- # (FULL decode graphs included). The V1 runner keeps the in-forward path.
- self.prestage = self.embed_tokens.disk is not None and bool(
- getattr(get_current_vllm_config(), "use_v2_model_runner", False)
- )
- # Keep lookup results alive across breakable graph segments. Zeroed so
- # rows of cudagraph padding tokens (never staged) stay finite.
- self.staged_rows = torch.zeros(
- max_tokens,
- self.embed_tokens.part_n_hash_cols,
- layout.head_dim,
- dtype=torch.bfloat16,
- )
- def prepare_embeddings(self, hash_ids: torch.Tensor) -> None:
- """Gather this layer's rows on the main stream before decoder layers."""
- if self.prestage:
- # Already staged for this step by EngramDiskStager.stage().
- return
- self.embed_tokens.lookup(hash_ids, self.staged_rows[: hash_ids.shape[0]])
- def embed(self, hash_ids: torch.Tensor) -> torch.Tensor:
- """Gather heads, returning only local tokens when SP is enabled."""
- rows = self.staged_rows[: hash_ids.shape[0]]
- if self.embed_tokens.tp_size == 1:
- return rows
- if self.use_sequence_parallel:
- tp_size = self.embed_tokens.tp_size
- num_tokens, local_heads, dim = rows.shape
- gathered = tensor_model_parallel_all_gather(rows, dim=0)
- chunk = (num_tokens + tp_size - 1) // tp_size
- rows = rows.new_empty((chunk, self.embed_tokens.n_hash_cols, dim))
- _engram_sp_rows_kernel[(triton.cdiv(rows.numel(), 1024),)](
- gathered,
- rows,
- num_tokens,
- get_tensor_model_parallel_rank() * chunk,
- rows.numel(),
- local_heads * dim,
- self.embed_tokens.n_hash_cols * dim,
- BLOCK_SIZE=1024,
- )
- return rows
- rows = tensor_model_parallel_all_gather(rows, dim=1)
- return rows[:, : self.embed_tokens.n_hash_cols]
- def forward(
- self,
- hidden_states: torch.Tensor,
- hash_ids: torch.Tensor,
- token_mask: torch.Tensor | None = None,
- ) -> torch.Tensor:
- # Stage 7: phase "engram_fwd" of the prefill budget (inert unless enabled).
- from vllm.model_executor.kernels.attention.dsa.candidate_blocks import _PrefillTimer
- with _PrefillTimer("engram_fwd", int(hash_ids.shape[0])):
- return self._forward_impl(hidden_states, hash_ids, token_mask)
- def _forward_impl(
- self,
- hidden_states: torch.Tensor,
- hash_ids: torch.Tensor,
- token_mask: torch.Tensor | None = None,
- ) -> torch.Tensor:
- """hidden_states: [T, hc_mult, dim]; hash_ids: [T, n_hash_cols] (all
- tokens, pre sequence-parallel shard); token_mask: [T], False shuts
- the gate so those positions pass through untouched."""
- kv = self.wkv(self.embed(hash_ids).flatten(-2))
- num_kv_tokens = hash_ids.shape[0]
- assert token_mask is None or token_mask.shape == (num_kv_tokens,)
- if self.use_sequence_parallel:
- tp_size = get_tensor_model_parallel_world_size()
- tp_rank = get_tensor_model_parallel_rank()
- shard_size = (num_kv_tokens + tp_size - 1) // tp_size
- assert hidden_states.shape[0] == shard_size
- start = min(tp_rank * shard_size, num_kv_tokens)
- num_kv_tokens = min(shard_size, num_kv_tokens - start)
- if token_mask is not None:
- token_mask = token_mask[start : start + num_kv_tokens]
- num_tokens, hc_mult, dim = hidden_states.shape
- assert hc_mult == self.hc_mult and dim == self.dim
- assert kv.ndim == 2 and kv.shape[1] == (hc_mult + 1) * dim
- output = torch.empty_like(hidden_states)
- if num_tokens == 0:
- return output
- block_size = triton.next_power_of_2(dim)
- num_warps = 8 if block_size >= 2048 else 4
- mask = token_mask if token_mask is not None else hidden_states
- _fused_engram_post_wkv_kernel[(num_tokens * hc_mult,)](
- hidden_states,
- kv,
- self.q_weight,
- self.k_weight,
- mask,
- output,
- num_kv_tokens,
- hidden_states.stride(0),
- hidden_states.stride(1),
- hidden_states.stride(2),
- kv.stride(0),
- kv.stride(1),
- self.q_weight.stride(0),
- self.q_weight.stride(1),
- self.k_weight.stride(0),
- self.k_weight.stride(1),
- token_mask.stride(0) if token_mask is not None else 0,
- output.stride(0),
- output.stride(1),
- output.stride(2),
- self.eps,
- self.clamp_value,
- DIM=dim,
- HC_MULT=hc_mult,
- BLOCK_SIZE=block_size,
- HAS_MASK=token_mask is not None,
- num_warps=num_warps,
- )
- return output
- class EngramDiskStager:
- """Tech2Wild/Kai 2026-09-10 (CUDA graphs): stage DISK-mode Engram rows
- OUTSIDE the model forward.
- The V2 model state calls :meth:`stage` from ``prepare_inputs`` once per
- step, after the runner has written this step's input ids, positions and
- query_start_loc (all on the current stream). It hashes the step on the GPU
- (same kernel, same inputs as the forward), copies only this rank's hash
- columns to pinned host memory, waits on ONE event, reads every row of every
- engram layer in one parallel batch, dequantizes on the CPU exactly like the
- in-forward path, and copies (async, from pinned memory) into each layer's
- persistent ``staged_rows``. The forward (eager, breakable PIECEWISE or FULL
- graph) only reads ``staged_rows``, so it never needs the host.
- """
- def __init__(self, hash_state: NgramHashState, engrams: list["Engram"]) -> None:
- assert engrams and all(e.embed_tokens.disk is not None for e in engrams)
- self.hash_state = hash_state
- self.engrams = sorted(engrams, key=lambda e: e.layer_hash_index)
- emb = self.engrams[0].embed_tokens
- self.local_heads = emb.part_n_hash_cols
- self.head_start = emb.head_start
- self.head_end = min(emb.head_start + emb.part_n_hash_cols, emb.n_hash_cols)
- self.dim = emb.dim
- self.max_tokens = self.engrams[0].staged_rows.shape[0]
- num_layers = hash_state.multipliers.shape[0]
- self.hash_host = torch.empty(
- (self.max_tokens, num_layers, self.head_end - self.head_start),
- dtype=torch.int32,
- device="cpu",
- pin_memory=True,
- )
- self.rows_host = [
- torch.empty(
- (self.max_tokens, self.local_heads, self.dim),
- dtype=torch.bfloat16,
- device="cpu",
- pin_memory=True,
- )
- for _ in self.engrams
- ]
- self.hashes_ready = torch.cuda.Event()
- self.num_staged = 0
- # DSV41_ENGRAM_TIMING=1: host wall-clock of stage() phases (diagnostic).
- self._timing = _kai_os.environ.get("DSV41_ENGRAM_TIMING", "0") == "1"
- # two buckets (decode: n <= 16 tokens, prefill: n > 16): sync, gather+dequant, tail, total, calls, rows, unique rows
- self._t_acc = [[0.0, 0.0, 0.0, 0.0, 0, 0, 0] for _ in range(2)]
- self._t_last_total_ms = 0.0 # stage 7 reads it after each timed prefill step
- # Stage 8: hash-ahead prefetch state (see _hash_ahead).
- self._prefetch = _KAI_PREFETCH
- if self._prefetch:
- self.hash_host_next = torch.empty_like(self.hash_host)
- self.hashes_next_ready = torch.cuda.Event()
- self.last_pos_host = torch.zeros(256, dtype=torch.int64, device="cpu", pin_memory=True)
- self._prefetch_pool = _KaiPool(
- max_workers=_KAI_PREFETCH_THREADS, thread_name_prefix="engram-prefetch"
- )
- self._prefetch_futs: list = []
- self._prefetch_stats = [0, 0, 0.0] # lookaheads, rows, host seconds
- logger.info(
- "Engram DISK prefetch: hash-ahead of the next prefill chunk (%s, %d threads)",
- _KAI_PREFETCH_MODE, _KAI_PREFETCH_THREADS,
- )
- logger.info(
- "Engram DISK rows staged before the forward (graph-safe): %d layers, "
- "heads [%d, %d) of %d, up to %d tokens/step, %d read threads",
- len(self.engrams),
- self.head_start,
- self.head_end,
- emb.n_hash_cols,
- self.max_tokens,
- _KAI_THREADS,
- )
- def _hash_ahead(self, input_batch, req_states, positions, query_start_loc, lookback_token_ids) -> None:
- """Stage 8: for the batch's longest still-prefilling request, hash the
- NEXT chunk of its (known) prompt with the same kernel and warm this
- rank's rows in the page cache while the current step computes."""
- if torch.cuda.is_current_stream_capturing():
- return
- import time as _kai_time
- from .mm_preprocess import image_sentinel_mask
- t0 = _kai_time.perf_counter()
- n_reqs = int(input_batch.num_reqs)
- if n_reqs <= 0:
- return
- idx_np = input_batch.idx_mapping_np[:n_reqs]
- prompt_len = req_states.prompt_len.np[idx_np]
- next_start = self.last_pos_host[:n_reqs].numpy() + 1 # valid after hashes_ready.synchronize()
- remaining = prompt_len - next_start
- i = int(remaining.argmax())
- if remaining[i] <= 0:
- return
- req_idx = int(idx_np[i])
- s = int(next_start[i])
- L = int(min(remaining[i], self.max_tokens))
- tok = req_states.all_token_ids.gpu
- ids = tok[req_idx, s : s + L]
- pos = torch.arange(s, s + L, dtype=positions.dtype, device=positions.device)
- qsl = torch.tensor([0, L], dtype=query_start_loc.dtype, device=query_start_loc.device)
- depth = int(lookback_token_ids.shape[1])
- lb = torch.full((1, depth), -1, dtype=lookback_token_ids.dtype, device=lookback_token_ids.device)
- k = min(depth, s)
- if k > 0:
- lb[0, :k] = tok[req_idx, s - k : s].flip(0).to(lb.dtype)
- hashes = self.hash_state(
- ids, pos, qsl, image_sentinel_mask(ids), lb, image_sentinel_mask(lb), None, None
- )
- host = self.hash_host_next[:L]
- host.copy_(hashes[:, :, self.head_start : self.head_end], non_blocking=True)
- self.hashes_next_ready.record()
- self.hashes_next_ready.synchronize()
- self._prefetch_futs = [f for f in self._prefetch_futs if not f.done()]
- total_rows = 0
- for engram in self.engrams:
- local = host[:, engram.layer_hash_index, :].to(torch.int64)
- rel, owned = engram.embed_tokens.disk_rel_owned(local)
- rows = torch.unique(rel[owned]).tolist()
- total_rows += len(rows)
- table = engram.embed_tokens.disk
- for lo in range(0, len(rows), _KAI_PREFETCH_TASK_ROWS):
- self._prefetch_futs.append(
- self._prefetch_pool.submit(
- _kai_prefetch_rows, table, rows[lo : lo + _KAI_PREFETCH_TASK_ROWS]
- )
- )
- st = self._prefetch_stats
- st[0] += 1
- st[1] += total_rows
- st[2] += _kai_time.perf_counter() - t0
- if st[0] % 16 == 0 or L >= 4096:
- logger.info(
- "Engram prefetch: next chunk %d tokens from %d (prompt %d), %d unique rows queued, "
- "host %.1f ms (%d lookaheads so far, avg %.0f rows, %.1f ms)",
- L, s, int(prompt_len[i]), total_rows, 1e3 * (_kai_time.perf_counter() - t0),
- st[0], st[1] / st[0], 1e3 * st[2] / st[0],
- )
- @torch.inference_mode()
- def stage(
- self,
- input_ids: torch.Tensor,
- positions: torch.Tensor,
- query_start_loc: torch.Tensor,
- lookback_token_ids: torch.Tensor,
- num_tokens: int,
- input_batch=None,
- req_states=None,
- ) -> int:
- """Stage rows for the first `num_tokens` (unpadded) tokens of this step.
- Returns the number staged; 0 while the KV cache is unbound (profiling),
- matching the forward, which skips engram then."""
- n = min(int(num_tokens), self.max_tokens)
- if n <= 0 or not self.hash_state.ensure_cache():
- return 0
- from .mm_preprocess import image_sentinel_mask
- timing = self._timing
- if timing:
- import time as _kai_time
- _t0 = _kai_time.perf_counter()
- ids = input_ids[:n]
- hashes = self.hash_state(
- ids,
- positions[:n],
- query_start_loc,
- image_sentinel_mask(ids),
- lookback_token_ids,
- image_sentinel_mask(lookback_token_ids),
- None,
- None,
- )
- host = self.hash_host[:n]
- host.copy_(hashes[:, :, self.head_start : self.head_end], non_blocking=True)
- prefetch = self._prefetch and input_batch is not None and req_states is not None
- if prefetch:
- # last position of every request in this step -> next chunk start
- n_reqs = int(input_batch.num_reqs)
- if n_reqs > self.last_pos_host.shape[0]:
- self.last_pos_host = torch.zeros(
- n_reqs * 2, dtype=torch.int64, device="cpu", pin_memory=True
- )
- ends = torch.as_tensor(
- input_batch.query_start_loc_np[1 : n_reqs + 1].astype("int64") - 1,
- device=positions.device,
- )
- self.last_pos_host[:n_reqs].copy_(positions[ends], non_blocking=True)
- self.hashes_ready.record()
- # The one host sync per step. It also orders this step's rewrite of the
- # pinned buffers after the previous step's async H2D copies from them.
- self.hashes_ready.synchronize()
- if timing:
- _t1 = _kai_time.perf_counter()
- requests = []
- for engram in self.engrams:
- local = host[:, engram.layer_hash_index, :].to(torch.int64)
- rel, owned = engram.embed_tokens.disk_rel_owned(local)
- requests.append((engram.embed_tokens.disk, rel, owned))
- rows_per_layer = gather_dequant_many(requests)
- if timing:
- _t2 = _kai_time.perf_counter()
- _acc = self._t_acc[0 if n <= 16 else 1]
- _acc[0] += _t1 - _t0
- _acc[1] += _t2 - _t1
- _acc[4] += 1
- _rows = sum(int(r[1].numel()) for r in requests)
- _uniq = sum(int(torch.unique(r[1]).numel()) for r in requests)
- _acc[5] += _rows
- _acc[6] += _uniq
- # the H2D tail is timed by the caller-visible end of stage(): record
- # the total when the call returns (see the return sites below)
- self._t_mid = _t2
- self._t_last = (_rows, _uniq, _t2 - _t1)
- for engram, rows, buf in zip(self.engrams, rows_per_layer, self.rows_host):
- staged = buf[:n]
- staged.copy_(rows.view(n, self.local_heads, self.dim))
- engram.staged_rows[:n].copy_(staged, non_blocking=True)
- self.num_staged = n
- if timing:
- _t3 = _kai_time.perf_counter()
- _acc = self._t_acc[0 if n <= 16 else 1]
- _acc[2] += _t3 - self._t_mid
- _acc[3] += _t3 - _t0
- self._t_last_total_ms = 1e3 * (_t3 - _t0)
- # stage 6 defines _KAI_MMAP (memmap gather); resolved at call time
- _mode = (
- "mmap"
- if globals().get("_KAI_MMAP", False)
- and self._t_last[0] >= globals().get("_KAI_MMAP_MIN_ROWS", 0) * len(self.engrams)
- else "preadv"
- )
- if n >= 1024:
- logger.info(
- "Engram prefill stage [%s]: %d tokens, %d rows (%d unique), "
- "gather+dequant %.1f ms, total %.1f ms",
- _mode, n, self._t_last[0], self._t_last[1],
- 1e3 * self._t_last[2], 1e3 * (_t3 - _t0),
- )
- if _acc[4] % (200 if n <= 16 else 20) == 0:
- logger.info(
- "Engram stage timing [%s, %s]: total %.2f ms/step (sync wait %.2f, "
- "disk+dequant %.2f, h2d+rest %.2f), %.1f rows/step (%.1f unique), "
- "avg of %d steps",
- _mode, "decode" if n <= 16 else "prefill",
- 1e3 * _acc[3] / _acc[4],
- 1e3 * _acc[0] / _acc[4],
- 1e3 * _acc[1] / _acc[4],
- 1e3 * _acc[2] / _acc[4],
- _acc[5] / _acc[4],
- _acc[6] / _acc[4],
- _acc[4],
- )
- for i in range(7):
- _acc[i] = 0
- if prefetch:
- try:
- self._hash_ahead(input_batch, req_states, positions, query_start_loc, lookback_token_ids)
- except Exception as e: # noqa: BLE001 - prefetch is best effort
- logger.warning_once("Engram prefetch disabled after error: %r", e)
- self._prefetch = False
- return n
|