1package wire
2
3import (
4 "bytes"
5 "testing"
6
7 "google.golang.org/protobuf/proto"
8
9 "github.com/bnema/vev/internal/domain"
10 "github.com/bnema/vev/internal/domain/terminalcap"
11 "github.com/bnema/vev/internal/protocol"
12)
13
14// Baseline Protobuf envelope benchmarks frozen at the P3.3 cutover. They
15// exercise representative control, Hello, Output, and image envelopes so
16// AC8 can compare equivalent QUIC-carried microbenchmarks after P6. The
17// recorded V0 legacy-codec medians live in docs/protocol.md; these
18// benchmarks measure the same conversations through the new envelopes.
19
20func baselineHello() protocol.Hello {
21 return protocol.Hello{
22 Version: protocol.Version, Intent: protocol.IntentAttach,
23 ClientID: [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16},
24 Name: "work",
25 Size: domain.Size{Cols: 120, Rows: 40},
26 TermEnv: "xterm-256color",
27 Cwd: "/tmp/project",
28 Color: terminalcap.ColorCapabilities{Mode: terminalcap.ANSI256, Source: terminalcap.SourceDeclared},
29 MaxOutputInFlight: 8,
30 }
31}
32
33func baselineViewContext() *protocol.ViewContext {
34 return &protocol.ViewContext{
35 Publication: 1,
36 Route: protocol.CommittedRouteIdentity{Target: protocol.ExactSessionTarget{LifecycleID: domain.SessionLifecycleID{1}, SessionName: "work"}},
37 TabID: "tab-1", FocusedPaneID: "pane-1",
38 }
39}
40
41func BenchmarkHelloEnvelope(b *testing.B) {
42 hello := baselineHello()
43 converted := &Hello{
44 Version: uint32(hello.Version),
45 Intent: uint32(hello.Intent),
46 ClientId: append([]byte(nil), hello.ClientID[:]...),
47 Name: hello.Name,
48 Cols: uint32(hello.Size.Cols),
49 Rows: uint32(hello.Size.Rows),
50 TermEnv: hello.TermEnv,
51 Cwd: hello.Cwd,
52 Color: &ColorCapabilities{Mode: ColorMode_COLOR_MODE_ANSI256, Source: ColorSource_COLOR_SOURCE_DECLARED},
53 MaxOutputInFlight: uint32(hello.MaxOutputInFlight),
54 }
55 b.ReportAllocs()
56 for range b.N {
57 payload, err := proto.MarshalOptions{Deterministic: true}.Marshal(&ClientEnvelope{
58 Payload: &ClientEnvelope_Hello{Hello: converted},
59 })
60 if payload == nil || err != nil {
61 b.Fatalf("marshal hello: %v", err)
62 }
63 }
64}
65
66func BenchmarkHelloEnvelopeUnmarshal(b *testing.B) {
67 converted := &Hello{Version: uint32(protocol.Version), Intent: uint32(protocol.IntentAttach)}
68 payload, err := proto.MarshalOptions{Deterministic: true}.Marshal(&ClientEnvelope{
69 Payload: &ClientEnvelope_Hello{Hello: converted},
70 })
71 if err != nil {
72 b.Fatal(err)
73 }
74 b.ReportAllocs()
75 b.SetBytes(int64(len(payload)))
76 for range b.N {
77 decoded := &ClientEnvelope{}
78 if err := ScanEnvelope(decoded, payload); err != nil {
79 b.Fatal(err)
80 }
81 if uerr := (proto.UnmarshalOptions{DiscardUnknown: false}.Unmarshal(payload, decoded)); uerr != nil {
82 b.Fatal(err)
83 }
84 }
85}
86
87func BenchmarkInputEnvelopeRoundTrip(b *testing.B) {
88 data := []byte("ls -la\r")
89 converted := &Input{InputSeq: 1, ActionId: 2, Data: data}
90 b.ReportAllocs()
91 b.SetBytes(int64(len(data)))
92 for range b.N {
93 payload, err := proto.MarshalOptions{Deterministic: true}.Marshal(&ClientEnvelope{
94 Payload: &ClientEnvelope_Input{Input: converted},
95 })
96 if err != nil {
97 b.Fatal(err)
98 }
99 decoded := &ClientEnvelope{}
100 if err := ScanEnvelope(decoded, payload); err != nil {
101 b.Fatal(err)
102 }
103 if uerr := (proto.UnmarshalOptions{DiscardUnknown: false}.Unmarshal(payload, decoded)); uerr != nil {
104 b.Fatal(err)
105 }
106 }
107}
108
109func BenchmarkImageEnvelopeRoundTrip(b *testing.B) {
110 data := bytes.Repeat([]byte{0x89, 0x50, 0x4e, 0x47}, 4096)
111 converted := &ImagePush{InputSeq: 1, Mime: "image/png", Data: data}
112 payload, err := proto.MarshalOptions{Deterministic: true}.Marshal(&ClientEnvelope{
113 Payload: &ClientEnvelope_ImagePush{ImagePush: converted},
114 })
115 if err != nil {
116 b.Fatal(err)
117 }
118 b.ReportAllocs()
119 b.SetBytes(int64(len(payload)))
120 for range b.N {
121 decoded := &ClientEnvelope{}
122 if err := ScanEnvelope(decoded, payload); err != nil {
123 b.Fatal(err)
124 }
125 if uerr := (proto.UnmarshalOptions{DiscardUnknown: false}.Unmarshal(payload, decoded)); uerr != nil {
126 b.Fatal(err)
127 }
128 }
129}
130
131func baselineOutputData(compressible bool) []byte {
132 if compressible {
133 return bytes.Repeat([]byte("\x1b[38;2;120;180;240mstyled viewport row\x1b[0m\r\n"), 128)
134 }
135 return bytes.Repeat([]byte("0123456789abcdef"), 512)
136}
137
138func baselineOutputEnvelope(compressible bool) []byte {
139 context := baselineViewContext()
140 converted := &Output{
141 Epoch: 1, NewState: 1, Cols: 120, Rows: 40, Full: true,
142 Context: &ViewContext{
143 Publication: context.Publication,
144 Route: &CommittedRouteIdentity{Target: &ExactTarget{SessionName: "work"}},
145 TabId: string(context.TabID),
146 FocusedPaneId: string(context.FocusedPaneID),
147 },
148 Encoding: 0,
149 UncompressedLength: uint64(len(baselineOutputData(compressible))),
150 Data: baselineOutputData(compressible),
151 }
152 payload, err := proto.MarshalOptions{Deterministic: true}.Marshal(&ServerEnvelope{
153 Payload: &ServerEnvelope_Output{Output: converted},
154 })
155 if err != nil {
156 panic(err)
157 }
158 return payload
159}
160
161func BenchmarkOutputCompressibleEnvelopeRoundTrip(b *testing.B) {
162 encoded := baselineOutputEnvelope(true)
163 b.ReportAllocs()
164 b.SetBytes(int64(len(baselineOutputData(true))))
165 for range b.N {
166 decoded := &ServerEnvelope{}
167 if err := ScanEnvelope(decoded, encoded); err != nil {
168 b.Fatal(err)
169 }
170 if uerr := (proto.UnmarshalOptions{DiscardUnknown: false}.Unmarshal(encoded, decoded)); uerr != nil {
171 b.Fatal(uerr)
172 }
173 }
174}
175
176func BenchmarkOutputIncompressibleEnvelopeRoundTrip(b *testing.B) {
177 encoded := baselineOutputEnvelope(false)
178 b.ReportAllocs()
179 b.SetBytes(int64(len(baselineOutputData(false))))
180 for range b.N {
181 decoded := &ServerEnvelope{}
182 if err := ScanEnvelope(decoded, encoded); err != nil {
183 b.Fatal(err)
184 }
185 if uerr := (proto.UnmarshalOptions{DiscardUnknown: false}.Unmarshal(encoded, decoded)); uerr != nil {
186 b.Fatal(uerr)
187 }
188 }
189}