inferencecost

package
v1.121.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 20, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Index

Constants

View Source
const (
	AllocationModeComputeTime = "compute_time"
	AllocationModeMultiplier  = "multiplier"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type AllocationMethod

type AllocationMethod string

AllocationMethod indicates how the input/output cost split was computed.

const (
	// AllocationMethodComputeTime splits costs proportionally by vLLM prefill and
	// decode time. inputCostPerMillionTokens uses PromptTokens as the denominator
	// (delivered tokens); see cacheSavingsFraction for KV cache benefit.
	AllocationMethodComputeTime AllocationMethod = "compute_time"

	// AllocationMethodPrefixCachingOff splits by input / output token time; prefix
	// caching is explicitly disabled on the vLLM instance. cacheSavingsFraction
	// will be zero by configuration, not by absence of cache hits.
	AllocationMethodPrefixCachingOff AllocationMethod = "prefix_caching_off"

	// AllocationMethodMultiplier splits using a fixed output/input cost multiplier
	// (vLLM timing metrics unavailable).
	AllocationMethodMultiplier AllocationMethod = "multiplier"
)

type AllocationQuerier

type AllocationQuerier interface {
	// ComputeAllocation returns an AllocationSet for the given time window.
	ComputeAllocation(start, end time.Time) (*opencost.AllocationSet, error)
}

AllocationQuerier is the subset of the cost model needed to fetch per-model infrastructure costs. Abstracted as an interface for testability.

type Calculator

type Calculator struct {
	// contains filtered or unexported fields
}

Calculator computes derived cost metrics for a slice of InferenceCost structs.

func NewCalculator

func NewCalculator(config *Config) *Calculator

NewCalculator creates a Calculator with the given config.

func (*Calculator) CalculateCosts

func (c *Calculator) CalculateCosts(metrics []*InferenceCost)

CalculateCosts populates derived cost fields on each InferenceCost in-place.

type Collector

type Collector struct {
	// contains filtered or unexported fields
}

Collector gathers per-model infrastructure costs from the OpenCost allocation layer and token/timing/cache metrics from the data source.

func NewCollector

func NewCollector(config *Config, querier AllocationQuerier, metricsQuerier source.MetricsQuerier) (*Collector, error)

NewCollector creates a Collector that uses the provided MetricsQuerier for inference metrics.

func (*Collector) CollectMetrics

func (c *Collector) CollectMetrics(ctx context.Context, start, end time.Time) ([]*InferenceCost, error)

CollectMetrics queries all data sources and returns one InferenceCost per model/namespace combination. start and end define the time window to query; the caller is responsible for choosing appropriate boundaries (e.g. the runner uses now-interval..now; the API uses the request window).

type Config

type Config struct {
	// PrometheusURL is the Prometheus server endpoint for vLLM metric queries.
	PrometheusURL string

	// CollectionInterval is how often metrics are collected.
	// Configurable via INFERENCE_COLLECTION_INTERVAL environment variable.
	// Default is 2 minutes to match the core metrics emitter query window.
	CollectionInterval time.Duration

	// Enabled controls whether the inference cost collector runs.
	Enabled bool

	// ModelLabel is the Kubernetes pod label whose value equals the vLLM
	// model_name metric label. Used to aggregate allocation costs by model.
	ModelLabel string

	// SharedInfraLabel and SharedInfraLabelValue identify shared inference
	// infrastructure pods (EPP, gateway) that lack ModelLabel.
	SharedInfraLabel      string
	SharedInfraLabelValue string

	// AllocationMode controls the input/output split method.
	// "compute_time" uses vLLM timing metrics (preferred).
	// "multiplier" uses a fixed ratio (fallback).
	AllocationMode string

	// OutputTokenCostMultiplier is the output/input cost ratio used when
	// AllocationMode is "multiplier".
	OutputTokenCostMultiplier float64
}

Config holds configuration for the inference cost collector.

func DefaultConfig

func DefaultConfig() *Config

DefaultConfig returns a Config populated from environment variables via the env package. Callers should check Enabled before starting the collector.

type CostBasis

type CostBasis string

CostBasis defines whether costs are usage-based or allocation-based.

const (
	// CostBasisUsage measures actual resource consumption only.
	// Does not reconcile to the infrastructure bill — idle and waste are unattributed.
	CostBasisUsage CostBasis = "usage"

	// CostBasisAllocation measures max(request,usage) × runtime × price plus idle
	// (ShareWeighted) and shared infra (EPP, gateway). Reconciles to the bill.
	CostBasisAllocation CostBasis = "allocation"
)

type Exporter

type Exporter struct {
	// contains filtered or unexported fields
}

Exporter registers and emits the llm_* Prometheus metrics.

func NewExporter

func NewExporter() *Exporter

NewExporter creates an Exporter with all gauge vectors initialised.

func (*Exporter) Export

func (e *Exporter) Export(metrics []*InferenceCost)

Export sets gauge values for all metrics derived from the given InferenceCost slice. Gauges are reset before each export so decommissioned models do not persist.

func (*Exporter) Register

func (e *Exporter) Register() error

Register registers all gauge vectors with the default Prometheus registry. Returns an error if any registration fails (e.g. called twice).

type InferenceCost

type InferenceCost struct {
	Properties InferenceCostProperties

	// Window is the time range over which these costs were collected.
	// Used to normalize total costs to hourly rates for Prometheus metrics.
	Window struct {
		Start time.Time
		End   time.Time
	}

	// Costs from OpenCost allocation layer.
	// AllocationTotalCost = max(request,usage)×price + idle share + shared infra share.
	AllocationTotalCost float64
	// UsageTotalCost = actual_usage×price only; does not reconcile to bill.
	UsageTotalCost float64

	// Token counts from vLLM Prometheus metrics.
	PromptTokens     float64
	GenerationTokens float64
	TotalTokens      float64

	// Processing times from vLLM Prometheus metrics (seconds in collection window).
	InputProcessingTime  float64
	OutputProcessingTime float64

	// KV cache data from vLLM Prometheus metrics.
	// CachedTokens is the number of prompt tokens served from the KV cache,
	// sourced directly from vllm:prefix_cache_hits_total (token-level counter).
	// Zero when the metric is unavailable.
	CachedTokens float64
	// PrefixCachingEnabled reflects the enable_prefix_caching label from
	// vllm:cache_config_info. False when the metric is absent.
	PrefixCachingEnabled bool
	// CacheConfigKnown is true when vllm:cache_config_info was successfully
	// joined for this model. When false, PrefixCachingEnabled is meaningless.
	CacheConfigKnown bool

	// EffectiveInputTokens is PromptTokens - CachedTokens when cache correction
	// is enabled, otherwise equals PromptTokens.
	EffectiveInputTokens float64

	// CacheSavingsFraction is CachedTokens / PromptTokens, clamped to [0, 1].
	// Represents the fraction of prompt tokens served from the KV cache. Zero
	// when PromptTokens is zero or prefix caching is disabled. The raw ratio can
	// exceed 1 in high-reuse workloads; see apitypes.go for the full explanation.
	CacheSavingsFraction float64

	// InputCost and OutputCost are the dollar amounts attributed to input and
	// output processing respectively.
	InputCost  map[CostBasis]float64
	OutputCost map[CostBasis]float64

	// AllocationMethod records which input/output split path was used.
	AllocationMethod AllocationMethod

	// Derived cost-per-million-token metrics, keyed by CostBasis.
	// Blended (input+output together), using TotalTokens as denominator.
	CostPerMillionTokens map[CostBasis]float64
	// Per-million input tokens, using PromptTokens as denominator.
	InputCostPerMillionTokens map[CostBasis]float64
	// Per-million output tokens, using GenerationTokens as denominator.
	OutputCostPerMillionTokens map[CostBasis]float64

	Timestamp time.Time
}

InferenceCost holds all cost data for a single model/namespace over a collection interval.

type InferenceCostAPIProperties

type InferenceCostAPIProperties struct {
	ModelName      string `json:"modelName"`
	ModelVersion   string `json:"modelVersion,omitempty"`
	Namespace      string `json:"namespace"`
	Cluster        string `json:"cluster,omitempty"`
	Pod            string `json:"pod,omitempty"`
	Controller     string `json:"controller,omitempty"`
	ControllerKind string `json:"controllerKind,omitempty"`
	Container      string `json:"container,omitempty"`
	WorkloadType   string `json:"workloadType"` // currently always "inference"
}

InferenceCostAPIProperties is the JSON-facing properties struct for API responses. It mirrors InferenceCostProperties but with explicit JSON tags matching the design doc field names.

type InferenceCostProperties

type InferenceCostProperties struct {
	ModelName      string
	ModelVersion   string
	Namespace      string
	Cluster        string
	Pod            string
	Controller     string
	ControllerKind string
	Container      string
	WorkloadType   string
}

InferenceCostProperties identifies a unique inference cost entity.

type InferenceCostResponse

type InferenceCostResponse struct {
	Properties InferenceCostAPIProperties `json:"properties"`
	Window     opencost.Window            `json:"window"`

	// CostBasis identifies whether these costs are usage-based or
	// allocation-based. Set from the QueryRequest.
	CostBasis CostBasis `json:"costBasis"`

	// Total infrastructure cost for the window under the chosen cost basis.
	TotalCost float64 `json:"totalCost"`

	// Token counts from vLLM metrics.
	PromptTokens     float64 `json:"promptTokens"`
	GenerationTokens float64 `json:"generationTokens"`
	TotalTokens      float64 `json:"totalTokens"`

	// Blended cost per 1M delivered tokens (input + output together).
	CostPerMillionTokens float64 `json:"costPerMillionTokens"`

	// Input/output cost split. InputCost and OutputCost sum to TotalCost if the cost basis is allocation.
	InputCost  float64 `json:"inputCost"`
	OutputCost float64 `json:"outputCost"`

	// Per-million cost metrics for differentiated pricing.
	// InputCostPerMillionTokens uses PromptTokens as the denominator (all delivered
	// input tokens, including those served from KV cache).
	InputCostPerMillionTokens  float64 `json:"inputCostPerMillionTokens"`
	OutputCostPerMillionTokens float64 `json:"outputCostPerMillionTokens"`

	// CacheSavingsFraction is the fraction of prompt tokens served from the KV
	// cache (CachedTokens / PromptTokens, clamped to [0, 1]). Zero when prefix
	// caching is disabled (see allocationMethod) or when no cache hits occurred
	// in the window.
	//
	// Note: in workloads with heavy prefix reuse (e.g. benchmarks with long
	// shared system prompts), the raw ratio can exceed 1.0 because
	// vllm:prefix_cache_hits_total counts tokens retrieved from cache per
	// request — including prefixes established by earlier requests outside the
	// current window — while vllm:prompt_tokens_total only counts new input
	// tokens delivered in this window. The value is clamped to 1.0 in that case.
	CacheSavingsFraction float64 `json:"cacheSavingsFraction"`

	// AllocationMethod records which input/output cost-split path was used.
	// Informational; omitted when empty.
	AllocationMethod AllocationMethod `json:"allocationMethod,omitempty"`
	// contains filtered or unexported fields
}

InferenceCostResponse is the flat, per-cost-basis API representation of inference costs for a single model/namespace in a time window. It is projected from the internal InferenceCost struct (which stores costs keyed by CostBasis) so that the JSON output matches the design doc shape exactly.

type InferenceCostSet

type InferenceCostSet struct {
	InferenceCosts map[string]*InferenceCostResponse `json:"inferenceCosts"`
	Window         opencost.Window                   `json:"window"`
}

InferenceCostSet holds a collection of InferenceCostResponses for a single time window, keyed by aggregation key.

type InferenceCostSetRange

type InferenceCostSetRange struct {
	InferenceCostSets []*InferenceCostSet `json:"inferenceCostSets"`
	Window            opencost.Window     `json:"window"`
}

InferenceCostSetRange holds multiple InferenceCostSets covering a broader time range. Used for the /timeseries endpoint.

type QueryRequest

type QueryRequest struct {
	Start       time.Time
	End         time.Time
	CostBasis   CostBasis
	AggregateBy []string
	Accumulate  opencost.AccumulateOption
	Filter      []filterSpec
	Step        time.Duration
}

QueryRequest holds the parsed parameters for an inference cost query.

func ParseInferenceCostRequest

func ParseInferenceCostRequest(qp mapper.PrimitiveMap) (*QueryRequest, error)

ParseInferenceCostRequest parses the common query parameters from an HTTP request into a QueryRequest. It mirrors the pattern used by customcost.ParseCustomCostTotalRequest.

Required: window (RFC3339 start,end or named range). Optional: costBasis (default: allocation), aggregate, accumulate, filter.

The step field is derived from the accumulate option.

func ParseInferenceCostTimeseriesRequest

func ParseInferenceCostTimeseriesRequest(qp mapper.PrimitiveMap) (*QueryRequest, error)

ParseInferenceCostTimeseriesRequest is identical to ParseInferenceCostRequest but requires the accumulate parameter (timeseries must have a defined step).

type QueryService

type QueryService struct {
	// contains filtered or unexported fields
}

QueryService handles HTTP requests for the /inferenceCost endpoints. It computes inference costs on demand at request time by driving the Collector and Calculator, matching the pattern of OpenCost's /allocation and /assets APIs (no stored repository).

Note: each request issues two ComputeAllocation calls per sub-window (one with idle sharing for allocation costs, one without for usage costs). This is consistent with /allocation which also recomputes from Prometheus on every request and has no result cache.

func NewQueryService

func NewQueryService(c *Collector, calc *Calculator) *QueryService

NewQueryService creates a QueryService. Both collector and calculator must be non-nil; if either is nil the handlers return 501.

func (*QueryService) GetInferenceCostTimeseriesHandler

func (qs *QueryService) GetInferenceCostTimeseriesHandler() func(http.ResponseWriter, *http.Request, httprouter.Params)

GetInferenceCostTimeseriesHandler returns an httprouter-compatible handler for GET /inferenceCost/timeseries.

The 'accumulate' parameter is required for this endpoint (it defines the time-series step size). All other parameters are the same as /total.

func (*QueryService) GetInferenceCostTotalHandler

func (qs *QueryService) GetInferenceCostTotalHandler() func(http.ResponseWriter, *http.Request, httprouter.Params)

GetInferenceCostTotalHandler returns an httprouter-compatible handler for GET /inferenceCost/total.

Query parameters:

  • window (required): RFC3339 "start,end" or named range
  • costBasis: "usage" or "allocation" (default: allocation)
  • aggregate: comma-separated list of dimensions (model_name, model_version, namespace, cluster)
  • accumulate: hour, day, week, month (optional; controls sub-window step for large windows)
  • filter: prop:value[+prop:value] (optional; Phase-1 minimal, AND semantics)

type Runner

type Runner struct {
	// contains filtered or unexported fields
}

Runner periodically drives the collect → calculate → export pipeline.

func NewRunner

func NewRunner(collector *Collector, calculator *Calculator, exporter *Exporter, interval time.Duration) *Runner

NewRunner creates a Runner. The exporter must already be registered with Prometheus (call exporter.Register() before NewRunner).

func (*Runner) Start

func (r *Runner) Start(ctx context.Context)

Start runs the collection loop until ctx is cancelled.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL