detached a667323

test(perf): expand VT baseline coverage

commit
a667323e9602b9da58d4081c30da44bfae37898c
author
brice · · 2026-08-20 08:28 UTC
parent
52147d7
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
1 file · +59 -0
M benchmark_test.go +59 -0
@@ -10,6 +10,7 @@ import (
1010 var (
1111 benchmarkHistoryViewSink HistoryView
1212 benchmarkHistorySnapshotSink HistorySnapshotView
13+ benchmarkDamageCaptureSink DamageCapture
1314 benchmarkHistoryBlobSink []byte
1415 benchmarkHistoryBlobsSink [][]byte
1516 )
@@ -200,6 +201,14 @@ func benchmarkScreenResizeReflow(b *testing.B, historyRows int) {
200201 for range historyRows {
201202 requireHistoryAppend(b, s.history, make([]renderer.Cell, 120))
202203 }
204+ // History normally receives rows evicted from this screen, whose IDs are
205+ // allocated after every existing live or historical row. This fixture
206+ // prepopulates history directly, so advance and refresh the live IDs to
207+ // preserve that invariant before exercising resize eviction.
208+ s.nextRowID = s.history.nextRowID - 1
209+ for y := range s.buffer.rowIDs {
210+ s.buffer.rowIDs[y] = s.nextRowIDValue()
211+ }
203212 }
204213 s.Write(bytes.Repeat([]byte("x"), 120*39))
205214 s.ClearDamage()
@@ -217,6 +226,56 @@ func benchmarkScreenResizeReflow(b *testing.B, historyRows int) {
217226 }
218227 }
219228
229+func BenchmarkScreenPrintableASCII(b *testing.B) {
230+ s := NewScreen(120, 40)
231+ chunk := append(bytes.Repeat([]byte("x"), 119), '\r')
232+ b.SetBytes(int64(len(chunk)))
233+ b.ReportAllocs()
234+ for b.Loop() {
235+ s.Write(chunk)
236+ s.ClearDamage()
237+ }
238+}
239+
240+func BenchmarkScreenMixedUTF8(b *testing.B) {
241+ s := NewScreen(120, 40)
242+ chunk := append(bytes.Repeat([]byte("Aé界"), 20), '\r')
243+ b.SetBytes(int64(len(chunk)))
244+ b.ReportAllocs()
245+ for b.Loop() {
246+ s.Write(chunk)
247+ s.ClearDamage()
248+ }
249+}
250+
251+func BenchmarkScreenCSIHeavy(b *testing.B) {
252+ s := NewScreen(120, 40)
253+ chunk := []byte("\x1b[1;1H\x1b[2K\x1b[31;48;2;1;2;3mstatus\x1b[0m\x1b[10C\x1b[?25l\x1b[?25h\r")
254+ b.SetBytes(int64(len(chunk)))
255+ b.ReportAllocs()
256+ for b.Loop() {
257+ s.Write(chunk)
258+ s.ClearDamage()
259+ }
260+}
261+
262+func BenchmarkScreenCaptureDamage(b *testing.B) {
263+ s := NewScreen(120, 40)
264+ chunk := []byte("x")
265+ s.ClearDamage()
266+ b.ReportAllocs()
267+ for b.Loop() {
268+ s.Write(chunk)
269+ benchmarkDamageCaptureSink = s.CaptureDamage()
270+ if len(benchmarkDamageCaptureSink.Damage) == 0 {
271+ b.Fatal("expected captured damage")
272+ }
273+ if !s.AcknowledgeDamage(benchmarkDamageCaptureSink.Generation) {
274+ b.Fatal("expected current damage acknowledgement")
275+ }
276+ }
277+}
278+
220279 func BenchmarkScreenShellRedrawBurst(b *testing.B) {
221280 chunk := []byte("\r\x1b[K❯ abc\x1b[90m autosuggestion\x1b[39m\r\x1b[5C")
222281 b.ReportAllocs()
@@ -10,6 +10,7 @@ import (
10 var (10 var (
11 benchmarkHistoryViewSink HistoryView11 benchmarkHistoryViewSink HistoryView
12 benchmarkHistorySnapshotSink HistorySnapshotView12 benchmarkHistorySnapshotSink HistorySnapshotView
13+ benchmarkDamageCaptureSink DamageCapture
13 benchmarkHistoryBlobSink []byte14 benchmarkHistoryBlobSink []byte
14 benchmarkHistoryBlobsSink [][]byte15 benchmarkHistoryBlobsSink [][]byte
15 )16 )
@@ -200,6 +201,14 @@ func benchmarkScreenResizeReflow(b *testing.B, historyRows int) {
200 for range historyRows {201 for range historyRows {
201 requireHistoryAppend(b, s.history, make([]renderer.Cell, 120))202 requireHistoryAppend(b, s.history, make([]renderer.Cell, 120))
202 }203 }
204+ // History normally receives rows evicted from this screen, whose IDs are
205+ // allocated after every existing live or historical row. This fixture
206+ // prepopulates history directly, so advance and refresh the live IDs to
207+ // preserve that invariant before exercising resize eviction.
208+ s.nextRowID = s.history.nextRowID - 1
209+ for y := range s.buffer.rowIDs {
210+ s.buffer.rowIDs[y] = s.nextRowIDValue()
211+ }
203 }212 }
204 s.Write(bytes.Repeat([]byte("x"), 120*39))213 s.Write(bytes.Repeat([]byte("x"), 120*39))
205 s.ClearDamage()214 s.ClearDamage()
@@ -217,6 +226,56 @@ func benchmarkScreenResizeReflow(b *testing.B, historyRows int) {
217 }226 }
218 }227 }
219 228
229+func BenchmarkScreenPrintableASCII(b *testing.B) {
230+ s := NewScreen(120, 40)
231+ chunk := append(bytes.Repeat([]byte("x"), 119), '\r')
232+ b.SetBytes(int64(len(chunk)))
233+ b.ReportAllocs()
234+ for b.Loop() {
235+ s.Write(chunk)
236+ s.ClearDamage()
237+ }
238+}
239+
240+func BenchmarkScreenMixedUTF8(b *testing.B) {
241+ s := NewScreen(120, 40)
242+ chunk := append(bytes.Repeat([]byte("Aé界"), 20), '\r')
243+ b.SetBytes(int64(len(chunk)))
244+ b.ReportAllocs()
245+ for b.Loop() {
246+ s.Write(chunk)
247+ s.ClearDamage()
248+ }
249+}
250+
251+func BenchmarkScreenCSIHeavy(b *testing.B) {
252+ s := NewScreen(120, 40)
253+ chunk := []byte("\x1b[1;1H\x1b[2K\x1b[31;48;2;1;2;3mstatus\x1b[0m\x1b[10C\x1b[?25l\x1b[?25h\r")
254+ b.SetBytes(int64(len(chunk)))
255+ b.ReportAllocs()
256+ for b.Loop() {
257+ s.Write(chunk)
258+ s.ClearDamage()
259+ }
260+}
261+
262+func BenchmarkScreenCaptureDamage(b *testing.B) {
263+ s := NewScreen(120, 40)
264+ chunk := []byte("x")
265+ s.ClearDamage()
266+ b.ReportAllocs()
267+ for b.Loop() {
268+ s.Write(chunk)
269+ benchmarkDamageCaptureSink = s.CaptureDamage()
270+ if len(benchmarkDamageCaptureSink.Damage) == 0 {
271+ b.Fatal("expected captured damage")
272+ }
273+ if !s.AcknowledgeDamage(benchmarkDamageCaptureSink.Generation) {
274+ b.Fatal("expected current damage acknowledgement")
275+ }
276+ }
277+}
278+
220 func BenchmarkScreenShellRedrawBurst(b *testing.B) {279 func BenchmarkScreenShellRedrawBurst(b *testing.B) {
221 chunk := []byte("\r\x1b[K❯ abc\x1b[90m autosuggestion\x1b[39m\r\x1b[5C")280 chunk := []byte("\r\x1b[K❯ abc\x1b[90m autosuggestion\x1b[39m\r\x1b[5C")
222 b.ReportAllocs()281 b.ReportAllocs()

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 2

Tags 13

↑↓ moveenter openesc close