feat/data-dnd e05cb15

flip_stats.go RawHistoryFolder

1package drm
2
3import "time"
4
5// flipStats are the flip timing counters of one output, reported and
6// reset by the periodic stats entry. They are plain fields owned by the
7// output goroutine. All times are CLOCK_MONOTONIC (kernel flip
8// timestamps and userspace reads), so they tell a late composition from a
9// late read of the event (see accountFlip).
10type flipStats struct {
11	// missedVblanks counts due frame flips whose kernel timestamp is over
12	// 1.5 refresh periods after the previous frame flip (never under VRR,
13	// where the period is not fixed).
14	missedVblanks int
15	// maxInterval is the longest time between two frame flips, of the
16	// frames that were due.
17	maxInterval time.Duration
18	// maxCommitDelay is the longest time a due frame waited between the
19	// moment it was due (wanted, the previous flip landed, or the VRR
20	// flip gap ended) and its commit: late event read, slow composition.
21	maxCommitDelay time.Duration
22	// maxFlipToRead is the longest time between a flip's kernel timestamp
23	// and the output reading its event: the event delivery latency.
24	maxFlipToRead time.Duration
25	// lateFences counts missed vblanks whose fences signalled after the
26	// vblank the frame targeted (never under VRR). Fence times are only
27	// read while flip tracing is on.
28	lateFences int
29}
30
31// nominalPeriod is the time between two vblanks at the mode's refresh
32// rate. Under VRR it is the shortest period: the fastest the output
33// flips.
34func (o *Output) nominalPeriod() time.Duration {
35	return time.Duration(int64(time.Second) * 1000 / int64(max(1, o.mode.refreshMilli())))
36}
37
38// refreshPeriod is the time between two vblanks of the current mode (0:
39// not fixed, VRR).
40func (o *Output) refreshPeriod() time.Duration {
41	if o.vrrOn {
42		return 0
43	}
44	return o.nominalPeriod()
45}
46
47// setVRR records the VRR state. The flip interval chain restarts when it
48// changes: the period of the two states differs.
49func (o *Output) setVRR(on bool) {
50	if o.vrrOn != on {
51		o.lastFlipAt = 0
52	}
53	o.vrrOn = on
54}
55
56// accountFlip counts the completion ev of a frame commit made at
57// commitAt for a frame due at wantedAt (0: unknown, the commit time; see
58// pendingFrame.dueAt). All times are CLOCK_MONOTONIC. fenceAt is when the
59// commit's fences signalled (0: none or unknown). It updates lastFlipAt
60// for frame flips and never allocates.
61//
62// An output renders only on change, so a gap after an idle period says
63// nothing about missed vblanks. The interval to the previous flip counts
64// only for a frame that was due: wanted less than one period after the
65// previous flip, so it was meant for the very next vblank, whenever it was
66// committed. A frame that waited for the previous flip's event or for its
67// composition is due as soon as it is wanted. Then:
68//
69//   - a flip over 1.5 periods after the previous one missed a vblank
70//     (never counted under VRR, where the period is not fixed);
71//   - if it missed one and its fences signalled after the vblank it
72//     targeted (the previous flip plus one period), the frame was late: a
73//     late fence. A fence before that vblank is not;
74//   - the commit delay is the time from when the frame was due (wanted,
75//     and not before the previous flip) to its commit. A missed vblank
76//     with a long commit delay and no late fence points at the commit
77//     path: late event read, slow composition on the CPU.
78func (o *Output) accountFlip(ev flipEvent, frame bool, wantedAt, commitAt, fenceAt time.Duration) {
79	if !frame {
80		return
81	}
82	if wantedAt == 0 {
83		wantedAt = commitAt
84	}
85	if prev := o.lastFlipAt; prev != 0 && wantedAt-prev < o.nominalPeriod() {
86		s := &o.flipStats
87		interval := ev.when - prev
88		s.maxInterval = max(s.maxInterval, interval)
89		s.maxCommitDelay = max(s.maxCommitDelay, commitAt-max(wantedAt, prev))
90		if period := o.refreshPeriod(); period != 0 && 2*interval > 3*period {
91			s.missedVblanks++
92			if fenceAt != 0 && fenceAt > prev+period {
93				s.lateFences++
94			}
95		}
96	}
97	o.lastFlipAt = ev.when
98}
99
100// accountRead tracks the delivery latency of the event ev handled at now.
101func (o *Output) accountRead(ev flipEvent, now time.Duration) {
102	o.flipStats.maxFlipToRead = max(o.flipStats.maxFlipToRead, now-ev.when)
103}
104
105// takeFlipStats returns the counters and starts over.
106func (o *Output) takeFlipStats() flipStats {
107	s := o.flipStats
108	o.flipStats = flipStats{}
109	return s
110}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 25

Tags 10

↑↓ moveenter openesc close