@@ -18,16 +18,21 @@ import (
18
18
type completionBenchOptions struct {
19
19
file , locationRegexp string
20
20
21
- // hook to run edits before initial completion
22
- preCompletionEdits func (* Env )
21
+ // Hooks to run edits before initial completion
22
+ setup func (* Env ) // run before the benchmark starts
23
+ beforeCompletion func (* Env ) // run before each completion
23
24
}
24
25
25
26
func benchmarkCompletion (options completionBenchOptions , b * testing.B ) {
26
27
dir := benchmarkDir ()
27
28
28
29
// Use a new environment for each test, to avoid any existing state from the
29
30
// previous session.
30
- sandbox , editor , awaiter , err := connectEditor (dir )
31
+ sandbox , editor , awaiter , err := connectEditor (dir , fake.EditorConfig {
32
+ Settings : map [string ]interface {}{
33
+ "completionBudget" : "1m" , // arbitrary long completion budget
34
+ },
35
+ })
31
36
if err != nil {
32
37
b .Fatal (err )
33
38
}
@@ -45,11 +50,10 @@ func benchmarkCompletion(options completionBenchOptions, b *testing.B) {
45
50
Sandbox : sandbox ,
46
51
Awaiter : awaiter ,
47
52
}
48
- env .OpenFile (options .file )
49
53
50
54
// Run edits required for this completion.
51
- if options .preCompletionEdits != nil {
52
- options .preCompletionEdits (env )
55
+ if options .setup != nil {
56
+ options .setup (env )
53
57
}
54
58
55
59
// Run a completion to make sure the system is warm.
@@ -70,6 +74,9 @@ func benchmarkCompletion(options completionBenchOptions, b *testing.B) {
70
74
// initialization).
71
75
b .Run ("completion" , func (b * testing.B ) {
72
76
for i := 0 ; i < b .N ; i ++ {
77
+ if options .beforeCompletion != nil {
78
+ options .beforeCompletion (env )
79
+ }
73
80
env .Completion (options .file , pos )
74
81
}
75
82
})
@@ -92,7 +99,7 @@ func endPosInBuffer(env *Env, name string) fake.Pos {
92
99
func BenchmarkStructCompletion (b * testing.B ) {
93
100
file := "internal/lsp/cache/session.go"
94
101
95
- preCompletionEdits := func (env * Env ) {
102
+ setup := func (env * Env ) {
96
103
env .OpenFile (file )
97
104
originalBuffer := env .Editor .BufferText (file )
98
105
env .EditBuffer (file , fake.Edit {
@@ -102,25 +109,27 @@ func BenchmarkStructCompletion(b *testing.B) {
102
109
}
103
110
104
111
benchmarkCompletion (completionBenchOptions {
105
- file : file ,
106
- locationRegexp : `var testVariable map\[string\]bool = Session{}(\.)` ,
107
- preCompletionEdits : preCompletionEdits ,
112
+ file : file ,
113
+ locationRegexp : `var testVariable map\[string\]bool = Session{}(\.)` ,
114
+ setup : setup ,
108
115
}, b )
109
116
}
110
117
111
118
// Benchmark import completion in tools codebase.
112
119
func BenchmarkImportCompletion (b * testing.B ) {
120
+ const file = "internal/lsp/source/completion/completion.go"
113
121
benchmarkCompletion (completionBenchOptions {
114
- file : "internal/lsp/source/completion/completion.go" ,
122
+ file : file ,
115
123
locationRegexp : `go\/()` ,
124
+ setup : func (env * Env ) { env .OpenFile (file ) },
116
125
}, b )
117
126
}
118
127
119
128
// Benchmark slice completion in tools codebase.
120
129
func BenchmarkSliceCompletion (b * testing.B ) {
121
130
file := "internal/lsp/cache/session.go"
122
131
123
- preCompletionEdits := func (env * Env ) {
132
+ setup := func (env * Env ) {
124
133
env .OpenFile (file )
125
134
originalBuffer := env .Editor .BufferText (file )
126
135
env .EditBuffer (file , fake.Edit {
@@ -130,9 +139,9 @@ func BenchmarkSliceCompletion(b *testing.B) {
130
139
}
131
140
132
141
benchmarkCompletion (completionBenchOptions {
133
- file : file ,
134
- locationRegexp : `var testVariable \[\]byte (=)` ,
135
- preCompletionEdits : preCompletionEdits ,
142
+ file : file ,
143
+ locationRegexp : `var testVariable \[\]byte (=)` ,
144
+ setup : setup ,
136
145
}, b )
137
146
}
138
147
@@ -144,7 +153,7 @@ func (c *completer) _() {
144
153
c.inference.kindMatches(c.)
145
154
}
146
155
`
147
- preCompletionEdits := func (env * Env ) {
156
+ setup := func (env * Env ) {
148
157
env .OpenFile (file )
149
158
originalBuffer := env .Editor .BufferText (file )
150
159
env .EditBuffer (file , fake.Edit {
@@ -154,8 +163,42 @@ func (c *completer) _() {
154
163
}
155
164
156
165
benchmarkCompletion (completionBenchOptions {
157
- file : file ,
158
- locationRegexp : `func \(c \*completer\) _\(\) {\n\tc\.inference\.kindMatches\((c)` ,
159
- preCompletionEdits : preCompletionEdits ,
166
+ file : file ,
167
+ locationRegexp : `func \(c \*completer\) _\(\) {\n\tc\.inference\.kindMatches\((c)` ,
168
+ setup : setup ,
169
+ }, b )
170
+ }
171
+
172
+ // Benchmark completion following an arbitrary edit.
173
+ //
174
+ // Edits force type-checked packages to be invalidated, so we want to measure
175
+ // how long it takes before completion results are available.
176
+ func BenchmarkCompletionFollowingEdit (b * testing.B ) {
177
+ file := "internal/lsp/source/completion/completion2.go"
178
+ fileContent := `
179
+ package completion
180
+
181
+ func (c *completer) _() {
182
+ c.inference.kindMatches(c.)
183
+ // __MAGIC_STRING_1
184
+ }
185
+ `
186
+ setup := func (env * Env ) {
187
+ env .CreateBuffer (file , fileContent )
188
+ }
189
+
190
+ n := 1
191
+ beforeCompletion := func (env * Env ) {
192
+ old := fmt .Sprintf ("__MAGIC_STRING_%d" , n )
193
+ new := fmt .Sprintf ("__MAGIC_STRING_%d" , n + 1 )
194
+ n ++
195
+ env .RegexpReplace (file , old , new )
196
+ }
197
+
198
+ benchmarkCompletion (completionBenchOptions {
199
+ file : file ,
200
+ locationRegexp : `func \(c \*completer\) _\(\) {\n\tc\.inference\.kindMatches\((c)` ,
201
+ setup : setup ,
202
+ beforeCompletion : beforeCompletion ,
160
203
}, b )
161
204
}
0 commit comments