Documentation
¶
Overview ¶
Package latencykernel implements the blis-schemas Kernel interface: it prices GPU work for one resolved deployment.
Construction resolves everything — catalog facts, registry coefficients, the engine settings a layout overrides, and the model graph flattened to a per-kind plan. After that every method is a pure function of its arguments, so a discrete-event simulator can call StepTime at any simulated instant, from any goroutine, and get the same answer.
Two constructors, for the two shapes a caller comes in. Open takes a scenario filename and the roots its names resolve against, which is what a simulator or a scoring command has. New takes the documents already parsed, which is what a configuration search producing deployment variants that were never written to disk has. Open ends in New, so both validate identically and neither can price a deployment the other would refuse.
Speed is a requirement rather than a nicety: a simulator calls StepTime once per simulated step, millions of times over a run. So the hot path does arithmetic over a short pre-aggregated slice and allocates little: the per-resource breakdown map, which StepTimeInto lets a caller reuse, and a few scratch slices that grow with the number of requests. The plan holds one entry per distinct layer kind rather than one per layer, which for the deepest model in the catalog is three entries instead of 108.
Index ¶
- Constants
- func LoadBundle(path string) (*scenario.Scenario, *deployment.Deployment, error)
- type Inputs
- type Kernel
- func (k *Kernel) AdmissionOverhead(promptTokens int) time.Duration
- func (k *Kernel) CaptureTokens() int
- func (k *Kernel) CompletionOverhead() time.Duration
- func (k *Kernel) DecodeContextParallelWidth() int
- func (k *Kernel) Deployment() deployment.Pool
- func (k *Kernel) Evidence() (measured, total int, assumed []string)
- func (k *Kernel) FixedBytes() kernel.MemoryBreakdown
- func (k *Kernel) GraphModes() (decode, other string)
- func (k *Kernel) OutputTokenOverhead() time.Duration
- func (k *Kernel) PDTransferDemand(tokens int, from, to kernel.Placement) kernel.TransferDemand
- func (k *Kernel) PDTransferTime(tokens int, from, to kernel.Placement) time.Duration
- func (k *Kernel) PreSnapshotBytes() int64
- func (k *Kernel) PrefillContextParallelWidth() int
- func (k *Kernel) Provenance() []kernel.CoefficientOrigin
- func (k *Kernel) Resolved() kernel.Resolution
- func (k *Kernel) SequenceAdmissionBytes() int64
- func (k *Kernel) SequenceBoundedBytes(inFlightTokens int) int64
- func (k *Kernel) SequenceBoundedBytesAt(computedTokens, inFlightTokens int) int64
- func (k *Kernel) SequenceFixedBytes() int64
- func (k *Kernel) SequenceVariableBytes(tokens int) int64
- func (k *Kernel) StepTime(b kernel.Batch) kernel.StepEstimate
- func (k *Kernel) StepTimeInto(b kernel.Batch, per map[kernel.Resource]time.Duration) kernel.StepEstimate
- func (k *Kernel) TierTime(tier string, dir kernel.Direction, bytes int64, queueDepth int) time.Duration
- type Repos
Examples ¶
Constants ¶
const EngineBehaviourCommit = "db9527a46873454610df6dbedf79a36d6bf1a7f6"
EngineBehaviourCommit is the commit of vLLM's EngineBehaviourVersion tag. A comment citing vllm/<path>:<lines> means those lines at this commit.
const EngineBehaviourVersion = "0.31.0"
EngineBehaviourVersion is the vLLM release whose engine behaviour this kernel encodes.
const KernelAssumptionSet = "blis-latency-kernel"
KernelAssumptionSet is the Set a Provenance entry carries when the kernel supplied the value itself rather than reading it from a registry set or the deployment. No registry set can take this name, since registry sets are named for their coefficient family, so a consumer can tell the two apart without parsing anything else.
Variables ¶
This section is empty.
Functions ¶
func LoadBundle ¶
func LoadBundle(path string) (*scenario.Scenario, *deployment.Deployment, error)
LoadBundle reads a scenario and the deployment applied to it from one file, as two YAML documents separated by `---`.
blis-schemas keeps the two apart: a Scenario is the immutable problem (model, cluster inventory, coefficient and engine-version references) and a Deployment is the tunable configuration chosen against it (pools, each a parallelism layout with its own engine settings). One `blis run` is one of each.
They share a file here, rather than sitting in a scenario and a sibling deployment file, because a measurement row addresses a deployment by a single filename — `{"scenario": "glm-5-h200-fp8-sglang-tp8.yaml", ...}` — and testdata/measurements holds over three thousand such rows. A sibling-file layout would rewrite every one of them to say nothing it does not already say.
blis-schemas' own LoadScenario and LoadDeployment each open a path and read one document, so neither can reach the second half of a pair; this reproduces their strict decoding over a single stream instead. Strictness is the point: a misspelled key that parsed silently would leave a document that validates while omitting the setting its author intended, which is the failure mode hardest to notice.
Types ¶
type Inputs ¶
type Inputs struct {
Scenario *scenario.Scenario
// Deployment is the tunable configuration applied to the scenario: the pools that lay
// the model out. It is a separate document because a scenario fixes the immutable
// problem and an optimizer sweeps deployments against it.
Deployment *deployment.Deployment
// PoolIndex selects which pool of a disaggregated deployment this kernel prices. Each
// pool runs its own engine with its own settings, so one kernel per pool.
PoolIndex int
Model *model.Graph
Chip *hardware.Chip
Fabric *hardware.Fabric
Devices []*hardware.StorageDevice
Coefficients []*coefficient.Set
// Rules carry the engine-version behaviour the resolver needs.
Rules resolve.EngineRules
// Routing is the run's resolved expert-parallel routing imbalance (blis-schemas
// routing.Resolve), which depends on the model and the traffic and so is resolved by
// the caller, as speculative acceptance is. Nil prices an expert-parallel group as
// evenly loaded and records that as an assumption.
Routing *routing.Resolution
}
Inputs are the documents a kernel is built from. They arrive already parsed: loading belongs to blis-schemas, and New takes documents rather than paths so a caller holding structs — a config search producing deployment variants never written to disk, a test, a generator — does not have to serialize them first. Open is the path-based half of the pair.
New DOES validate them, at the field layer, which is the half of blis-schemas' two-layer validation that is version-independent and always the author's to fix. See New.
func OpenInputs ¶
OpenInputs resolves one pool of a scenario file into the documents New prices it from, without building the kernel.
It is OpenPool's loading half, exported for a caller that needs the documents as well as the kernel. A scoring harness that configures a rival backend for the same deployment needs the model's name, the chip's memory and the model's expert geometry -- deployment identity, which the kernel deliberately does not re-export (blis-schemas#36 draws that line: identity for comparison is the harness's concern, not the cost model's). Reading them from these Inputs, and building the kernel with New(in), means the harness holds the SAME chip and graph the kernel priced, not a second load of files that could resolve differently.
What it must not be used for is reaching configuration the kernel resolved: widths and backends are Resolved's to report, and the pool's settings are Deployment's. Reading those from Inputs instead would rebuild the second answer to "which pool is this" that the interface exists to remove.
type Kernel ¶
type Kernel struct {
// contains filtered or unexported fields
}
Kernel prices one deployment. Obtain one from New; the zero value is not usable.
func New ¶
New resolves the inputs into a kernel.
Everything that can be decided once is decided here: which coefficients apply, which requested settings the layout overrides, and the model graph flattened to a per-kind plan. The result holds no mutable state, so its methods are pure and safe to call concurrently.
Construction is deliberately strict. A missing coefficient, an unresolvable condition or a non-positive rate is an error rather than a default, because each would otherwise produce a step time that looks plausible and is wrong by whatever the term contributes. validateDocuments extends that strictness to the documents themselves.
Example ¶
A deployment variant that was never written to disk: load the documents once, change one setting, and build a kernel from the result.
package main
import (
"fmt"
latencykernel "github.com/inference-sim/blis-latency-kernel"
)
// --8<-- [start:repos]
// The roots a scenario's names resolve against: its model, chip, fabric and coefficient sets.
var repos = latencykernel.Repos{
Scenarios: "testdata",
Catalog: "testdata/catalog",
Registry: "testdata/registry",
}
func main() {
// --8<-- [start:new]
in, err := latencykernel.OpenInputs("aisimulate/deepseek-v3-h200-fp8-sglang-tp8.yaml",
repos, 0)
if err != nil {
panic(err)
}
base, err := latencykernel.New(in)
if err != nil {
panic(err)
}
// The same deployment with a 16-bit KV cache instead of fp8. New copied what it needed,
// so changing the documents now leaves base as it was.
in.Deployment.Pools[0].Engine.CacheDType = "bfloat16"
wide, err := latencykernel.New(in)
if err != nil {
panic(err)
}
fmt.Printf("fp8: %d bytes of KV per token per rank\n", base.SequenceVariableBytes(64)/64)
fmt.Printf("bf16: %d bytes of KV per token per rank\n", wide.SequenceVariableBytes(64)/64)
// --8<-- [end:new]
}
Output: fp8: 35136 bytes of KV per token per rank bf16: 70272 bytes of KV per token per rank
func Open ¶
Open resolves one scenario file into a kernel.
The path-based half of the constructor pair. New takes documents a caller already holds; Open takes a filename and the roots its names resolve against, which is what a simulator or a scoring command has. Both end in New, so both inherit its validation and neither can price a deployment the other would reject.
It is exported because the alternative is every consumer reimplementing it. Go forbids importing another module's internal packages, so while this lived in internal/harness, inference-sim carried a copy of the sequence and said so in a comment, and blis-config-search and every future backend repo would have needed their own. The duplication was tolerable only because it was confined to loading — but "which files a scenario implies" is this package's answer to give, not each caller's to guess.
Every artifact is loaded through blis-schemas' own loaders, and the engine rules come from that package's version registry rather than from a caller, so a scenario pinned to an older release cannot silently get current behaviour.
It prices the deployment's FIRST pool, which is what a colocated deployment has. Use OpenPool to price one pool of a disaggregated one.
Example ¶
Pricing a decode step: open a scenario, describe the batch, read the estimate.
package main
import (
"fmt"
"time"
"github.com/inference-sim/blis-schemas/kernel"
latencykernel "github.com/inference-sim/blis-latency-kernel"
)
// --8<-- [start:repos]
// The roots a scenario's names resolve against: its model, chip, fabric and coefficient sets.
var repos = latencykernel.Repos{
Scenarios: "testdata",
Catalog: "testdata/catalog",
Registry: "testdata/registry",
}
func ms(d time.Duration) float64 { return d.Seconds() * 1e3 }
func main() {
// --8<-- [start:open]
// DeepSeek-V3, served in fp8 on eight H200s at tensor-parallel width 8.
const scenario = "aisimulate/deepseek-v3-h200-fp8-sglang-tp8.yaml"
k, err := latencykernel.Open(scenario, repos)
if err != nil {
panic(err)
}
// 32 requests, each decoding one token against a context of 4,096 tokens.
batch := kernel.Batch{DecodeThreshold: 8}
for range 32 {
batch.Reqs = append(batch.Reqs, kernel.ReqShape{
Scheduled: 1, Computed: 4095, PromptLen: 4096,
})
}
e := k.StepTime(batch)
fmt.Printf("between %.1f and %.1f ms, bottleneck %s\n",
ms(e.Overlap), ms(e.NoOverlap), e.Bottleneck)
for _, r := range []kernel.Resource{kernel.ResourceSM, kernel.ResourceHBM,
kernel.ResourceNVLink, kernel.ResourceHost} {
fmt.Printf("%-7s %5.1f ms\n", r, ms(e.PerResource[r]))
}
// --8<-- [end:open]
}
Output: between 24.1 and 25.7 ms, bottleneck hbm sm 4.5 ms hbm 16.5 ms nvlink 1.2 ms host 3.5 ms
func OpenPool ¶
OpenPool resolves ONE pool of a scenario file into a kernel.
A disaggregated deployment states a prefill pool and a decode pool, and the two differ in the quantities that set step time: tensor-parallel width, whether expert parallelism is on, the engine's token budget. One kernel prices one pool — each runs its own engine with its own settings — so a caller serving the roles separately opens one kernel per pool. Pricing both from pool 0 would charge the decode pool the prefill pool's parallelism, and the simulation would still run.
Open is this function at pool 0. Both exist because the common case should not have to name an index, and the disaggregated case cannot be served without one.
func (*Kernel) AdmissionOverhead ¶
AdmissionOverhead returns host time before a request can be scheduled.
func (*Kernel) CaptureTokens ¶ added in v0.3.0
CaptureTokens returns the largest step, in tokens, a captured CUDA graph covers: the deployment's max_cudagraph_capture_size or cudagraph_capture_sizes as vLLM v0.31.0 resolves them, or its default where neither is stated (see Provenance). A step of more tokens runs with no graph whatever the mode. Zero when the resolved mode captures nothing.
func (*Kernel) CompletionOverhead ¶
CompletionOverhead returns fixed host time at request completion.
func (*Kernel) DecodeContextParallelWidth ¶
DecodeContextParallelWidth returns how many ranks shard the decode KV cache.
A consumer sizing its own KV budget needs it and cannot derive it from anything else this kernel exposes: it is the only axis that shards a LATENT cache, because KVBytesPerToken floors at one KV head and a latent cache has exactly one, so no tensor-parallel width reduces it. A simulator that read Resolution's TensorParallelWidth alone would size an MLA deployment's cache as if DCP did nothing.
From the resolved layout rather than the deployment document: a Parallelism states a request and resolution settles it.
A method on this type rather than a field of kernel.Resolution only because blis-schemas v0.3.0's Resolution carries the tensor-, data- and expert-parallel widths and not the two context-parallel ones. The argument that put those three in Resolution -- a consumer that can read one width and not the others has to re-derive the rest -- applies to these two as well, so this method and its companion are interim, pending the same fields upstream.
func (*Kernel) Deployment ¶
func (k *Kernel) Deployment() deployment.Pool
Deployment returns the pool this kernel prices, as the document stated it.
The request, not the resolution: a caller wanting a width or a backend reads Resolved, and reads this for the settings resolution does not touch -- the admission settings a scheduler sizes itself from. It is the pool New was given at PoolIndex, so a caller holding several kernels of one disaggregated deployment needs no index of its own to know which pool each prices.
A deep copy, so a caller writing through one of the engine block's pointer fields changes its copy and not the kernel. blis-schemas permits returning a shallow copy and asking callers not to write; this is not a hot path, and a promise the type enforces is worth more than one a reader has to keep.
func (*Kernel) Evidence ¶
Evidence reports how much of the resolved coefficient set rests on measurement, so a caller can state a prediction's footing.
Example ¶
Evidence: how much of what a kernel used was measured, and what it assumed.
package main
import (
"fmt"
"maps"
"slices"
latencykernel "github.com/inference-sim/blis-latency-kernel"
)
// --8<-- [start:repos]
// The roots a scenario's names resolve against: its model, chip, fabric and coefficient sets.
var repos = latencykernel.Repos{
Scenarios: "testdata",
Catalog: "testdata/catalog",
Registry: "testdata/registry",
}
func main() {
k, err := latencykernel.Open("aisimulate/deepseek-v3-h200-fp8-sglang-tp8.yaml", repos)
if err != nil {
panic(err)
}
// --8<-- [start:evidence]
measured, total, assumed := k.Evidence()
fmt.Printf("%d of %d values rest on evidence; %d were assumed\n",
measured, total, len(assumed))
// The same entries, counted by the method that produced each.
byMethod := map[string]int{}
for _, o := range k.Provenance() {
byMethod[o.Method]++
}
for _, m := range slices.Sorted(maps.Keys(byMethod)) {
fmt.Printf(" %-12s %3d\n", m, byMethod[m])
}
// The kernel's own assumptions, as distinct from registry values whose method is
// "assumed", carry the set name KernelAssumptionSet.
for _, o := range k.Provenance() {
if o.Set == latencykernel.KernelAssumptionSet {
fmt.Println("the kernel assumed", o.Name)
}
}
// --8<-- [end:evidence]
}
Output: 113 of 155 values rest on evidence; 41 were assumed assumed 41 measured 99 not_charged 1 vendor_spec 14 the kernel assumed max_cudagraph_capture_size the kernel assumed engine_version
func (*Kernel) FixedBytes ¶
func (k *Kernel) FixedBytes() kernel.MemoryBreakdown
FixedBytes returns occupancy independent of the request set, per rank.
Example ¶
Memory: what one rank holds before any request arrives, and what each request adds.
package main
import (
"fmt"
latencykernel "github.com/inference-sim/blis-latency-kernel"
)
// --8<-- [start:repos]
// The roots a scenario's names resolve against: its model, chip, fabric and coefficient sets.
var repos = latencykernel.Repos{
Scenarios: "testdata",
Catalog: "testdata/catalog",
Registry: "testdata/registry",
}
func main() {
k, err := latencykernel.Open("aisimulate/deepseek-v3-h200-fp8-sglang-tp8.yaml", repos)
if err != nil {
panic(err)
}
// --8<-- [start:memory]
const gib = 1 << 30
m := k.FixedBytes()
fmt.Printf("weights %5.1f GiB\n", float64(m.Weights)/gib)
fmt.Printf("activations %5.1f GiB\n", float64(m.ActivationPeak)/gib)
fmt.Printf("CUDA graphs %5.1f GiB\n", float64(m.CUDAGraph)/gib)
fmt.Printf("comm buffers %5.1f GiB\n", float64(m.CommBuffers)/gib)
fmt.Printf("EPLB %5.1f GiB\n", float64(m.EPLBRedundant)/gib)
fmt.Printf("total %5.1f GiB per rank\n", float64(m.Total())/gib)
// The communicator and engine workspace, held before the budget is measured.
fmt.Printf("before the budget %4.1f GiB\n", float64(k.PreSnapshotBytes())/gib)
// KV cache for one request, rounded up to whole pages.
fmt.Printf("a 4,096-token request: %.0f MiB of KV cache per rank\n",
float64(k.SequenceVariableBytes(4096))/(1<<20))
// --8<-- [end:memory]
}
Output: weights 78.2 GiB activations 1.1 GiB CUDA graphs 0.8 GiB comm buffers 0.0 GiB EPLB 0.0 GiB total 80.1 GiB per rank before the budget 3.9 GiB a 4,096-token request: 137 MiB of KV cache per rank
func (*Kernel) GraphModes ¶ added in v0.3.0
GraphModes returns the CUDA graph mode the engine runs a uniform decode step under and the one it runs every other step under, as vLLM names them -- "FULL", "PIECEWISE" or "NONE" -- after the overrides Resolved reports. A step above CaptureTokens runs with no graph under either.
func (*Kernel) OutputTokenOverhead ¶
OutputTokenOverhead returns host time per emitted token.
func (*Kernel) PDTransferDemand ¶ added in v0.2.0
PDTransferDemand is the handoff PDTransferTime prices, separated into payload, floor and the links it crosses, so a simulator running several handoffs at once can arbitrate the links they share. The kernel prices one transfer; dividing a shared link among several is the simulator's work.
Decode-context parallelism deliberately does NOT divide the payload. A prefill pool holds the whole cache for a request -- DCP shards the DECODE cache, and vLLM's own wording is "Number of ranks that shard the decode KV cache" (vllm/config/parallel.py:359-362 at v0.31.0) -- so the bytes that cross between pools are the whole request's, whatever the decode pool's dcp width is.
The links mirror the three placements a handoff can have:
same node that node's NVLink domain, at the NVLink rate
same rack, one-domain NVLink rack that rack's NVLink domain, at the NVLink rate
otherwise the sender's NIC egress and the receiver's NIC
ingress, each at the NIC rate
Link IDs are derived from the placement alone, so every kernel of one deployment names a physical link the same way: a prefill pool's kernel and a decode pool's kernel describe one handoff with the same IDs, and two handoffs that cross one NIC name it alike.
The floor is the expert-group all-to-all floor, which is what PDTransferTime has always charged. Whether that is the right floor for a KV handoff is a separate question: changing it would move every P/D price, so it is not changed here.
func (*Kernel) PDTransferTime ¶
PDTransferTime prices moving one request's KV between pools: its demand, run alone.
Computed from PDTransferDemand rather than beside it, so the two cannot drift: the blis-schemas contract is that a demand alone costs exactly this price, for every argument.
func (*Kernel) PreSnapshotBytes ¶ added in v0.3.0
PreSnapshotBytes returns what a rank holds before vLLM measures the memory its gpu_memory_utilization budget is drawn from: the collective library's communicator reservation and the engine workspace -- NVIDIA's lumped allowance for the CUDA context, cuBLAS and allocator slack (blis-registry nccl_communicator_bytes_<N>rank, engine_workspace_bytes). vLLM v0.31.0 initializes the device and the distributed environment, NCCL included, and only then takes the snapshot both its requested memory (total x gpu_memory_utilization) and its non-KV figure are measured against (Worker.init_device, vllm/v1/worker/gpu_worker.py:466-493; request_memory, vllm/v1/worker/utils.py:539-557; memory_profiling, vllm/utils/mem_utils.py:300-330). So these take their room from the part's memory beyond the budget, not from the KV cache, and FixedBytes leaves them out of its Total. A consumer checking that the deployment starts at all compares gpu_memory_utilization x memory + PreSnapshotBytes with the part.
KNOWN DIVERGENCE: the workspace allowance is one lumped figure, and the part of it that arises after the snapshot -- cuBLAS and other library workspaces made at the first forward -- is charged against the KV cache by vLLM and is left out here with the rest; the registry states no split.
func (*Kernel) PrefillContextParallelWidth ¶
PrefillContextParallelWidth returns how many ranks split a prefill sequence.
The companion to DecodeContextParallelWidth, and the two are genuinely independent: PCP splits prefill computation and expands the process world size while leaving the KV cache replicated, where DCP shards the cache without expanding the world size -- it reuses the tensor-parallel ranks when pcp is 1, and spans the PCP axis or the whole TP x PCP block otherwise (vllm/config/parallel.py:359-362 at v0.31.0). A consumer sizing a deployment needs both, and neither can be derived from the other.
Interim for the same reason as DecodeContextParallelWidth.
func (*Kernel) Provenance ¶
func (k *Kernel) Provenance() []kernel.CoefficientOrigin
Provenance reports every coefficient this kernel used and its evidence.
func (*Kernel) Resolved ¶
func (k *Kernel) Resolved() kernel.Resolution
Resolved reports the configuration after resolution, including overridden requests.
func (*Kernel) SequenceAdmissionBytes ¶ added in v0.3.0
SequenceAdmissionBytes returns the per-sequence bytes the engine reserves for a request's bounded state at admission: SequenceFixedBytes with each window ring at vLLM's admission cap rather than its steady decode hold -- cdiv(window - 1 + extra_retained + max_in_flight_tokens, block) + 1 pages, max_in_flight_tokens being the concurrent batches times max_num_batched_tokens (vllm/v1/kv_cache_interface.py:840-866; vllm/config/vllm.py:592-613) -- in whole blocks of the shared pool.
It is what vLLM sizes a request at when it reports its KV capacity: the engine's "GPU KV cache size" is the pool's blocks over SequenceAdmissionBytes plus SequenceVariableBytes(max_model_len), in blocks, times max_model_len (get_kv_cache_capacity, vllm/v1/core/kv_cache_utils.py:2444-2471), and its runtime admission gate clamps a request's window reservation to the same cap (vllm/v1/core/single_type_kv_cache_manager.py:216-229). It grows with max_num_batched_tokens: on DeepSeek-V4.1-Flash at 8,192 tokens, 517 pages in each of eight window groups against the six SequenceFixedBytes holds. A caller charging every resident sequence the engine's reservation charges this; one charging the steady decode hold charges SequenceFixedBytes. It equals SequenceFixedBytes for a model with no window cache.
func (*Kernel) SequenceBoundedBytes ¶ added in v0.3.0
SequenceBoundedBytes returns the per-sequence bytes of a request's bounded state with inFlightTokens scheduled but not yet settled: each window ring at cdiv(window - 1 + extra_retained + inFlightTokens, block) + 1 pages in whole pool blocks (SlidingWindowSpec.max_admission_blocks_per_request, vllm/v1/kv_cache_interface.py:840-866 at v0.31.0), the state caches and the recurrent state as SequenceFixedBytes holds them. At 1 + num_spec_tokens it is SequenceFixedBytes, the steady decode hold, wherever the drafter retains no extra tokens (all but multi-module MTP); at the engine's max_in_flight_tokens it is SequenceAdmissionBytes. A simulator that grows a sequence's window reservation with the tokens it actually has in flight, as vLLM's scheduler does, charges this per step instead of holding the admission cap for the sequence's life.
func (*Kernel) SequenceBoundedBytesAt ¶ added in v0.3.0
SequenceBoundedBytesAt is SequenceBoundedBytes for a request that has computed only computedTokens: a window ring holds no page for a token it has not seen, so each ring pages min(computedTokens + inFlightTokens, window - 1 + extra_retained + inFlightTokens) tokens, plus the rules pack's page for a window that does not start on a page edge. That is the hold vLLM's allocate_slots reaches after remove_skipped_blocks: blocks wholly before the window's trailing edge are freed (get_num_skipped_tokens, SlidingWindowManager, vllm/v1/core/single_type_kv_cache_manager.py:1153-1175, applied by remove_skipped_blocks, :687-725), and new ones are allocated only for the tokens scheduled (get_num_blocks_to_allocate, :178-238). Past the window it equals SequenceBoundedBytes.
KNOWN over-charge: a ring that has not yet outgrown its window starts on a page edge, so its trailing page is charged though vLLM holds none, at most one page a ring.
func (*Kernel) SequenceFixedBytes ¶
SequenceFixedBytes returns per-sequence bytes that do not vary with prompt length: recurrent state, where the model has it and the cache mode keeps it bounded, and the bounded caches a graph states -- window rings and fixed state (cacheFixedBytes).
func (*Kernel) SequenceVariableBytes ¶
SequenceVariableBytes returns per-sequence KV bytes for a token count, quantized to the engine's page size.
func (*Kernel) StepTime ¶
func (k *Kernel) StepTime(b kernel.Batch) kernel.StepEstimate
StepTime prices one forward pass. This is the hot path.
The returned StepEstimate carries a freshly allocated PerResource map. A simulator that calls this per simulated step, millions of times, can use StepTimeInto instead and reuse one map across calls, which removes that allocation.
func (*Kernel) StepTimeInto ¶
func (k *Kernel) StepTimeInto(b kernel.Batch, per map[kernel.Resource]time.Duration) kernel.StepEstimate
StepTimeInto prices one forward pass, writing the per-resource breakdown into per instead of allocating a map.
per is cleared first, so a caller reuses one map for every step. Passing nil is the same as calling StepTime: a new map is allocated.
The map is the allocation a caller can remove. The step still allocates a few scratch slices that grow with the number of requests -- the prefill chunks, the decode contexts, the prefills a context gather packs -- and BenchmarkStepTimeIntoDecode reports how many.
type Repos ¶
type Repos struct {
Scenarios string // directory holding scenario files
Catalog string // a blis-catalog checkout, or a pinned copy of one
Registry string // a blis-registry checkout, or a pinned copy of one
}
Repos locates the roots a scenario's names resolve against.
A scenario names its model, hardware, fabric and coefficient sets without saying where they live — it describes a deployment, not a filesystem — so a caller supplies the roots.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
bandprobe
command
Command bandprobe prices one step per line of a CSV and prints both band edges.
|
Command bandprobe prices one step per line of a CSV and prints both band edges. |
|
overlap-probe
command
Command overlap-probe answers one question: does the per-layer overlap term change the SHAPE of the concurrency response, or only its level?
|
Command overlap-probe answers one question: does the per-layer overlap term change the SHAPE of the concurrency response, or only its level? |
|
score
command
Command score reports how well the kernel predicts published measurements.
|
Command score reports how well the kernel predicts published measurements. |
|
shape
command
Command shape scores this kernel's concurrency response against NVIDIA's end-to-end accuracy snapshot, along AISimulate's own published error on the same points.
|
Command shape scores this kernel's concurrency response against NVIDIA's end-to-end accuracy snapshot, along AISimulate's own published error on the same points. |
|
worked-table
command
Command worked-table prints a worked step-time table, computed by the kernel itself from the committed catalog and registry.
|
Command worked-table prints a worked step-time table, computed by the kernel itself from the committed catalog and registry. |
|
internal
|
|
|
artifacttest
Package artifacttest holds the rule every test package uses to decide whether a failure to load a catalog or registry artifact is a skip or a failure.
|
Package artifacttest holds the rule every test package uses to decide whether a failure to load a catalog or registry artifact is a skip or a failure. |
|
docgen
command
Command docgen writes the generated parts of the documentation into docs/generated/:
|
Command docgen writes the generated parts of the documentation into docs/generated/: |
|
harness
Package harness holds what this repository's scoring and reporting commands share: opening a kernel from a scenario file, and building the batch shapes a comparison prices.
|
Package harness holds what this repository's scoring and reporting commands share: opening a kernel from a scenario file, and building the batch shapes a comparison prices. |
|
price
Package price holds the cost laws the kernel composes: the GEMM efficiency ramp, the cross-node collective scaling, and the resource maximum.
|
Package price holds the cost laws the kernel composes: the GEMM efficiency ramp, the cross-node collective scaling, and the resource maximum. |
|
resolve
Package resolve turns a scenario, the catalog facts it names and the registry sets it lists into one frozen configuration a kernel prices against.
|
Package resolve turns a scenario, the catalog facts it names and the registry sets it lists into one frozen configuration a kernel prices against. |