{{define "dashboard"}}
{{t "dash.sub" .NodeCount .ReadyReplicas .TotalReplicas .ModelCount}}
{{if .OnAdminListener}}{{else}}{{template "nav" .Menu}}{{end}}| {{t "dash.cap.class"}} | {{t "dash.cap.in_use"}} | {{t "dash.cap.free"}} | {{t "dash.cap.faulty"}} | {{t "dash.cap.usage"}} |
|---|---|---|---|---|
{{.Class}} |
{{.Used}}/{{.Total}} | {{.Free}} | {{if .Unhealthy}}{{.Unhealthy}}{{else}}—{{end}} | {{pct .Used .Total}}% |
{{t "dash.no_nodes"}}
{{end}} {{with .GPUMap}}{{.Legend}} {{t "dash.gpumap.note"}}
{{end}} {{with .Efficiency}}| {{t "dash.col.model"}} | GPUs | {{t "dash.eff.tps"}} | {{t "dash.eff.per_gpu"}} | {{t "dash.eff.busy"}} | {{t "dash.eff.draw"}} | {{t "dash.eff.per_wh"}} |
|---|---|---|---|---|---|---|
| {{.Model}} | {{num .GPUs 0}} | {{num .TokensPerSec 1}} | {{num .PerGPU 1}} | {{num .Util 0}}% | {{if .Watts}}{{num .Watts 0}} W{{else}}—{{end}} | {{if .PerWh}}{{num .PerWh 0}}{{else}}—{{end}} |
| {{t "dash.col.model"}} | {{t "dash.col.replica"}} | {{t "dash.col.node"}} | GPUs | {{t "dash.idle.busiest"}} | {{t "dash.idle.last_request"}} |
|---|---|---|---|---|---|
| {{.Model}} | {{.Replica}} | {{.Node}} |
{{len .GPUs}} | {{num .MaxUtil 0}}% | {{if .Idle}}{{t "dash.idle.ago" .Idle}}{{else}}{{t "dash.idle.unknown"}}{{end}} |
{{.}}
{{end}}{{with .Problem}}{{.}}
{{end}} {{if .Nodes}}| {{t "dash.col.node"}} | {{t "dash.col.state"}} | CPU | {{t "dash.nodes.ram"}} | {{if .AnyGPUs}}GPUs | {{end}}{{t "dash.nodes.disk"}} | {{t "dash.nodes.engines"}} | {{if .AnyGPUs}}{{t "dash.nodes.build"}} | {{end}}{{if .AnyClasses}}{{t "dash.nodes.classes"}} | {{end}}{{if .AnyFabrics}}{{t "dash.nodes.fabrics"}} | {{end}}{{t "dash.nodes.models"}} | {{t "dash.nodes.replicas"}} | {{t "dash.nodes.seen"}} |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
{{shortNode .ID $.NodePrefix}}{{if .MgmtAddr}} {{.MgmtAddr}}{{end}}
{{t "dash.nodes.logs"}} |
{{/* The state is a class as well as a word: the class stays, the word
is the reader's. */}}
{{t (print "dash.state." .State)}} | {{/* A dash, not an empty bar, when the agent has not measured it lately: unknown is not idle. */}}{{with .Load}}{{template "minibar" pctbar .CPUPercent}}{{num .CPUPercent 0}}%{{if .CPUs}} {{t "dash.nodes.cpus_of" .CPUs}}{{end}}{{else}}—{{end}} | {{with .Load}}{{template "minibar" pctbar .MemPercent}}{{bytes .MemUsed}} {{t "dash.nodes.mem_of" (bytes .MemTotal)}}{{else}}{{if .MemoryGB}}{{.MemoryGB}}G{{else}}—{{end}}{{end}} | {{if $.AnyGPUs}}{{if .GPUTotal}}{{.GPUFree}}/{{.GPUTotal}}{{else}}—{{end}} | {{end}} {{/* Free out of total, because the first is meaningless without the second, and an em dash where nothing was reported: an agent that was never asked about its disk must not read as a full one. */}}{{if .DiskTotalGB}}{{.DiskFreeGB}}G/{{.DiskTotalGB}}G{{else}}—{{end}} | {{if .Engines}}{{join .Engines}}{{else}}{{t "dash.nodes.no_engines"}}{{end}} | {{/* Which vLLM build the node installs: left to its hardware, or chosen. What is installed beside it, so a choice and its outcome are read together. Only a GPU node has one; changing it is for an administrator, on the page reached through a session. */}} {{if $.AnyGPUs}}{{if .GPUTotal}}{{$node := .}} {{range .Provision}}{{if eq .Engine "vllm"}}{{.Version}} {{with .Variant}}{{buildLabel .}} {{end}}{{t (print "dash.state." .State)}}{{end}}{{end}} {{if and $.Menu.CSRF .EngineBuilds}} {{end}} {{else}}—{{end}} | {{end}} {{if $.AnyClasses}}{{join .Classes}} | {{end}} {{if $.AnyFabrics}}{{join .Fabrics}} | {{end}}{{if .Models}}{{len .Models}}{{else}}—{{end}} | {{.Replicas}} | {{or .LastSeenAgo "—"}} | {{/* What is unhealthy, what an install said and the node's warnings come from the control plane and the agent, in English. */}}
| {{join .Unhealthy}} | ||||||||||||
| {{.Engine}} {{.Version}}{{if .Variant}} ({{.Variant}}){{end}} {{t (print "dash.state." .State)}}: {{.Detail}} | ||||||||||||
| {{.}} | ||||||||||||
{{t "dash.no_agents"}}
{{end}}| {{t "dash.col.model"}} | {{t "dash.models.aliases"}} | {{t "dash.models.ready"}} | {{t "dash.models.wanted"}} | {{t "dash.models.class"}} | {{t "dash.models.reserves"}} | {{t "dash.models.profiles"}} | {{if .AnyFallbacks}}{{t "dash.models.fallbacks"}} | {{end}}{{t "dash.models.for"}} |
|---|---|---|---|---|---|---|---|---|
{{.Name}} |
{{join .Aliases}} | {{.Ready}} | {{.Min}}–{{.Max}} | {{.Class}}{{if .Preempted}} −{{.Preempted}}{{end}} | {{/* The warnings are the catalogue's own, in English. */}}{{if or .MemoryGB .CPUCores}}{{.MemoryGB}}G{{if .CPUCores}} · {{.CPUCores}}c{{end}}{{else}}—{{end}} {{- if .MeasuredMemoryGB}} {{t "dash.models.used" (num .MeasuredMemoryGB 1)}}{{end}}{{if .Warnings}} ⚠{{end}} | {{if .External}}{{t "dash.models.external"}} {{.External}}{{else}}{{join .Profiles}}{{end}} | {{if $.AnyFallbacks}}{{join .Fallbacks}} | {{end}} {{/* Cut to the column, the whole sentence on hover: a row of its own for each description made the table twice as long as the catalog. */}}{{or .Description "—"}} |
{{t "dash.models.empty"}}
{{end}} {{if .Unplaced}}{{.Model}}
{{range .Rejections}}{{.Profile}} @ {{or .Pool "-"}}{{if .Node}}/{{.Node}}{{end}}: {{.Reason}}
{{end}}
{{end}}
{{end}}
| {{t "dash.col.replica"}} | {{t "dash.col.model"}} | {{t "dash.col.state"}} | {{t "dash.replicas.pool"}} | {{t "dash.replicas.endpoint"}} | {{t "dash.replicas.age"}} | {{t "dash.nodes"}} |
|---|---|---|---|---|---|---|
{{.ID}} |
{{.Model}} | {{t (print "dash.state." .State)}} | {{or .Pool "—"}} | {{if .Endpoint}}{{.Endpoint}}{{else}}—{{end}} |
{{age .AgeSec}} | {{range .Shards}}{{shortNode .Node $.NodePrefix}} {{end}} |
| {{.Err}} | ||||||
{{t "dash.replicas.none"}}
{{end}} {{if .Summary.IdleReplicas}}| {{t "dash.col.replica"}} | {{t "dash.col.model"}} | GPUs | {{t "dash.holding.unused_for"}} |
|---|---|---|---|
{{.ID}} |
{{.Model}} | {{.GPUs}} | {{age .IdleSec}} |
| {{t "dash.fabrics.fabric"}} | {{t "dash.fabrics.physically"}} | {{t "dash.nodes"}} | {{t "dash.fabrics.fully_free"}} | {{t "dash.fabrics.weights"}} |
|---|---|---|---|---|
{{.Fabric}} |
{{with $.Fabrics}}{{range .Physical}}{{if has .Declared $name}} {{.Label}}{{if .RateGbps}} · {{t "fabric.gbps" .RateGbps}}{{end}} {{end}}{{end}}{{end}} |
{{.Nodes}} | {{.LargestFreeBlock}} | {{if .NodesWithWeights}}{{t "dash.fabrics.weights_on" .Models .NodesWithWeights .Nodes}}{{else}}{{t "dash.fabrics.not_reported"}}{{end}} |
| {{t "dash.fabrics.fabric"}} | {{t "dash.fabrics.physically"}} | {{t "dash.fabrics.master"}} | {{t "dash.fabrics.standby"}} | {{t "dash.nodes"}} | {{t "dash.fabrics.last_change"}} |
|---|---|---|---|---|---|
{{if .Declared}}{{range $i, $d := .Declared}}{{if $i}}, {{end}}{{$d}}{{end}}{{else}}{{t "fabric.undeclared"}}{{end}} |
{{.Label}}{{if .RateGbps}} · {{t "fabric.gbps" .RateGbps}}{{end}} | {{if eq .Kind "roce"}}{{t "dash.fabrics.roce"}}{{else}}{{with .SM}}{{.GUID}}{{if .LID}} {{t "dash.fabrics.lid_priority" .LID .Priority}}{{end}}{{else}}—{{end}}{{end}} |
{{if eq .Kind "roce"}}—{{else if .SMs}}{{if .Standbys}}{{.Standbys}}{{else}}{{t "dash.fabrics.none"}}{{end}}{{else}}{{t "dash.fabrics.not_listed"}}{{end}} | {{len .Members}} | {{with .Changes}}{{with index . 0}}{{ago .At}}: {{.From}} → {{.To}}{{end}}{{if gt (len .) 1}} {{t "dash.fabrics.in_a_day" (len .)}}{{end}}{{else}}{{t "dash.fabrics.none_in_a_day"}}{{end}} |
{{t "dash.fabrics.note"}}
{{end}} {{with .NVLink}}{{tn "dash.nvlink.domains" (len .Domains)}}{{range .Domains}} · {{shortDomain .Key}} {{t "dash.nvlink.trays" .Usable (len .Members)}}{{end}}
{{if .Problems}} · {{tn "dash.nvlink.problems" (len .Problems)}}{{end}}
· {{t "dash.nvlink.see_racks"}}
{{t "dash.no_history" .Err}}
{{else}}{{t "dash.traffic.requests"}}
{{.RequestChart}}{{t "dash.traffic.tokens"}}
{{.TokenChart}}{{t "dash.traffic.latency"}}
{{.LatencyChart}}{{t "dash.traffic.none"}}
{{end}} {{if .HasPeople}}| {{t "dash.col.person"}} | {{t "dash.people.keys"}} | {{t "dash.col.requests"}} | {{t "dash.col.tokens"}} | {{t "dash.col.errors"}} | {{t "dash.col.spend"}} | {{t "dash.people.last_seen"}} |
|---|---|---|---|---|---|---|
| {{if .Email}}{{.Email}}{{else}}{{t "dash.people.operator_keys"}}{{end}} | {{count .Keys}} | {{count .Requests}} | {{compact .Tokens}} | {{if .Errors}}{{count .Errors}}{{else}}—{{end}} | {{units .CostMicros}} | {{ago .LastSeen}} |
| {{t "dash.col.model"}} | {{t "dash.col.requests"}} | {{t "dash.col.tokens"}} | {{t "dash.col.errors"}} | {{t "dash.traffic.latency"}} |
|---|---|---|---|---|
{{.Model}} |
{{count .Requests}} | {{compact .Tokens}} | {{if .Errors}}{{count .Errors}}{{else}}—{{end}} | {{latency .AvgLatency}} |
{{t "dash.running.note"}}
{{end}}| {{t "dash.col.person"}} | {{t "dash.usage.through"}} | {{t "dash.usage.against"}} | {{t "dash.col.requests"}} | {{t "dash.col.errors"}} | {{t "dash.usage.prompt"}} | {{t "dash.usage.completion"}} | {{t "dash.col.spend"}} | {{t "dash.usage.last"}} |
|---|---|---|---|---|---|---|---|---|
| {{or .Email "—"}} | {{if .Chat}}{{t "dash.usage.chat_page"}}{{else if .KeyName}}{{.KeyName}} {{.KeyPrefix}}{{else}}{{.KeyID}}{{end}} |
{{if .ProjectPath}}{{.ProjectPath}}{{else if .ProjectID}}{{.ProjectID}}{{else}}{{t "dash.usage.personal"}}{{end}} |
{{count .Requests}} | {{if .Errors}}{{count .Errors}}{{else}}0{{end}} | {{compact .Prompt}} | {{compact .Completion}} | {{units .CostMicros}} | {{ago .LastAt}} |
{{t "dash.usage.note"}}
{{else}}{{t "dash.usage.none"}}
{{end}} {{else}}{{t "dash.usage.auth_off"}}
{{end}} {{if not .OnAdminListener}}{{t "dash.admin_listener"}}
ssh -L 9090:127.0.0.1:9090 <control-plane>
{{t "chart.nothing_yet"}}
{{else}} {{.t.SVG}} {{t "chart.peak" .t.Peak}} {{if gt (len .t.Legend) 1}}{{.note}}