Top: one beat — graphs, numbers and the process table change on the same tick
Graphs stepped once a history point (1 s at a 5 min window) while the numbers changed every tick; they now slide a fraction of a column each tick. The process table (and the GPU boxes, MHz and watts it carries) was polled on its own timer; it is now read per sample and committed with it. GPU clients are walked every sample, and the 1–2 s floors on the gallery, Network, Docker and ZFS ARC live views are gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
8fc71496f0
commit
70bebcb18b
+10
-8
@@ -84,9 +84,9 @@ type gpuDev struct {
|
||||
type gpuState struct {
|
||||
devs []*gpuDev
|
||||
listedAt time.Time
|
||||
clients map[string]clientPrev // device key + client id → engine totals at the previous scan
|
||||
last []drmFD // the newest client walk, reused between walks
|
||||
scanAt time.Time
|
||||
clients map[string]clientPrev // device key + client id → engine totals at the previous scan
|
||||
last []drmFD // the newest client walk
|
||||
scan func() ([]drmFD, bool) // the walk; nil is scanClients (tests stand a fake list in)
|
||||
helper *drmHelper
|
||||
ok bool // the last walk saw every process
|
||||
}
|
||||
@@ -96,8 +96,7 @@ type clientPrev struct {
|
||||
at time.Time
|
||||
}
|
||||
|
||||
const gpuRelist = time.Minute // how often the card list is re-read: hotplug is rare, the readdir is cheap
|
||||
const gpuScanEvery = time.Second // engine shares over less than this are noise
|
||||
const gpuRelist = time.Minute // how often the card list is re-read: hotplug is rare, the readdir is cheap
|
||||
|
||||
// gpus is the GPU section of a sample. cpuTemp stands in for an integrated GPU's
|
||||
// temperature: it is the same die.
|
||||
@@ -112,10 +111,13 @@ func (c *Collector) gpus(now time.Time, cpuTemp float64) []GPU {
|
||||
if g.clients == nil {
|
||||
g.clients = map[string]clientPrev{}
|
||||
}
|
||||
if g.scanAt.IsZero() || now.Sub(g.scanAt) >= gpuScanEvery {
|
||||
g.last, g.ok = c.scanClients()
|
||||
g.scanAt = now
|
||||
// The clients are read on every sample, like everything else in it: their engine shares
|
||||
// move on the same tick as the device's own numbers, at whatever rate is set.
|
||||
scan := c.scanClients
|
||||
if g.scan != nil {
|
||||
scan = g.scan
|
||||
}
|
||||
g.last, g.ok = scan()
|
||||
out := make([]GPU, 0, len(g.devs))
|
||||
live := map[string]bool{}
|
||||
for _, d := range g.devs {
|
||||
|
||||
@@ -61,7 +61,7 @@ func TestGPUClientsShare(t *testing.T) {
|
||||
c.gpu.clients = map[string]clientPrev{}
|
||||
t0 := time.Now()
|
||||
c.gpu.last = []drmFD{{PID: 7, Comm: "ffmpeg", Info: fdinfoA}}
|
||||
c.gpu.scanAt = t0 // no walk: the fake list stands
|
||||
c.gpu.scan = func() ([]drmFD, bool) { return c.gpu.last, true } // no walk: the fake list stands
|
||||
first := c.gpus(t0, 40)
|
||||
if len(first) != 1 || len(first[0].Clients) != 1 || first[0].Clients[0].Usage != 0 {
|
||||
t.Fatalf("first pass: %+v", first)
|
||||
@@ -73,7 +73,6 @@ func TestGPUClientsShare(t *testing.T) {
|
||||
later = replace(later, "drm-engine-render: 1000000000 ns", "drm-engine-render: 1500000000 ns")
|
||||
later = replace(later, "drm-engine-video: 2000000000 ns", "drm-engine-video: 4000000000 ns")
|
||||
c.gpu.last = []drmFD{{PID: 7, Comm: "ffmpeg", Info: later}}
|
||||
c.gpu.scanAt = t0.Add(time.Second)
|
||||
got := c.gpus(t0.Add(time.Second), 40)
|
||||
cl := got[0].Clients[0]
|
||||
if cl.Engines["render"] != 50 || cl.Engines["video"] != 100 || cl.Usage != 100 {
|
||||
|
||||
Reference in New Issue
Block a user