copy_scroll_performance_test.go RawHistoryFolder

1package daemon
2
3import (
4	"testing"
5
6	renderer "github.com/bnema/vev-vt"
7	"github.com/bnema/vev/internal/adapters/sessionwire"
8	"github.com/bnema/vev/internal/domain"
9	"github.com/bnema/vev/internal/protocol"
10	scopy "github.com/bnema/vev/internal/usecase/copy"
11	"github.com/stretchr/testify/require"
12)
13
14func TestCopyCompositionDoesNotAllocateIntermediateFrame(t *testing.T) {
15	rows := make([][]renderer.Cell, 53)
16	for y := range rows {
17		rows[y] = testRow("scrollback")
18	}
19	mode := scopy.NewMode(scopy.NewDocument(scopy.NewSnapshotFromRows(rows, 182, 53), ""))
20	frame := renderer.NewFrame(182, 55)
21	target := domain.Rect{Y: 1, Width: 182, Height: 53}
22	styles := resolveStyles(nil)
23	// A reusable semantic row and status text fit in 32 KiB. A second compact
24	// viewport alone needs over 150 KiB and must not be built just to copy it.
25	assertRenderByteBudget(t, func() {
26		composeCopyClientFrame(mode, target, frame, styles)
27	}, 32<<10)
28}
29
30// unmarshalBenchmarkOutput decodes one captured output envelope under a
31// benchmark harness, mirroring unmarshalTestOutput.
32func unmarshalBenchmarkOutput(tb testing.TB, payload []byte) protocol.Output {
33	tb.Helper()
34	message, err := sessionwire.DecodeServerEnvelope(payload)
35	require.NoError(tb, err)
36	output, ok := message.(protocol.Output)
37	require.True(tb, ok, "expected Output, got %T", message)
38	return output
39}
40
41// Each operation renders two wheel movements, up three rows then down three.
42// Keep history setup and copy entry outside the measured steady-state scroll.
43func BenchmarkDaemonHistoryCopyScroll(b *testing.B) {
44	for _, size := range []struct {
45		name string
46		size domain.Size
47	}{
48		{"120x40", domain.Size{Cols: 120, Rows: 40}},
49		{"182x53", domain.Size{Cols: 182, Rows: 53}},
50		{"240x70", domain.Size{Cols: 240, Rows: 70}},
51	} {
52		b.Run(size.name, func(b *testing.B) {
53			f := newPerformanceFixture(b, performanceConfig{size: size.size, tabs: 1, panes: 1, historyRows: 10000})
54			require.True(b, f.hasHistoryTopology(1, 1, 10000))
55			f.d.enterCopyMode(f.sess, f.ac)
56			f.d.copyWheel(f.sess, f.ac, -5000)
57			f.ac.ackOutputState(f.ac.output.currentEpoch(), f.ac.output.next)
58			b.ReportAllocs()
59			f.output.reset()
60			for b.Loop() {
61				f.d.copyWheel(f.sess, f.ac, -3)
62				f.ac.ackOutputState(f.ac.output.currentEpoch(), f.ac.output.next)
63				f.d.copyWheel(f.sess, f.ac, 3)
64				f.ac.ackOutputState(f.ac.output.currentEpoch(), f.ac.output.next)
65			}
66			metrics := f.output.metrics()
67			b.ReportMetric(float64(metrics.payloadBytes)/float64(2*b.N), "wire-B/wheel")
68			output := unmarshalBenchmarkOutput(b, f.output.lastPayload())
69			b.ReportMetric(float64(len(output.Data)), "last-ANSI-B/wheel")
70		})
71	}
72}

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 12

Tags 11

↑↓ moveenter openesc close