@@ -6,41 +6,47 @@ package bench
6
6
7
7
import (
8
8
"fmt"
9
+ "sync/atomic"
9
10
"testing"
11
+ "time"
10
12
13
+ "golang.org/x/tools/gopls/internal/lsp/fake"
11
14
"golang.org/x/tools/gopls/internal/lsp/protocol"
12
15
)
13
16
17
+ // Use a global edit counter as bench function may execute multiple times, and
18
+ // we want to avoid cache hits. Use time.Now to also avoid cache hits from the
19
+ // shared file cache.
20
+ var editID int64 = time .Now ().UnixNano ()
21
+
22
+ var didChangeTests = []struct {
23
+ repo string
24
+ file string
25
+ }{
26
+ {"istio" , "pkg/fuzz/util.go" },
27
+ {"kubernetes" , "pkg/controller/lookup_cache.go" },
28
+ {"kuma" , "api/generic/insights.go" },
29
+ {"pkgsite" , "internal/frontend/server.go" },
30
+ {"starlark" , "starlark/eval.go" },
31
+ {"tools" , "internal/lsp/cache/snapshot.go" },
32
+ }
33
+
14
34
// BenchmarkDidChange benchmarks modifications of a single file by making
15
35
// synthetic modifications in a comment. It controls pacing by waiting for the
16
36
// server to actually start processing the didChange notification before
17
37
// proceeding. Notably it does not wait for diagnostics to complete.
18
38
func BenchmarkDidChange (b * testing.B ) {
19
- tests := []struct {
20
- repo string
21
- file string
22
- }{
23
- {"istio" , "pkg/fuzz/util.go" },
24
- {"kubernetes" , "pkg/controller/lookup_cache.go" },
25
- {"kuma" , "api/generic/insights.go" },
26
- {"pkgsite" , "internal/frontend/server.go" },
27
- {"starlark" , "starlark/eval.go" },
28
- {"tools" , "internal/lsp/cache/snapshot.go" },
29
- }
30
-
31
- for _ , test := range tests {
32
- edits := 0 // bench function may execute multiple times
39
+ for _ , test := range didChangeTests {
33
40
b .Run (test .repo , func (b * testing.B ) {
34
41
env := getRepo (b , test .repo ).sharedEnv (b )
35
42
env .OpenFile (test .file )
36
- env .AfterChange ()
37
43
// Insert the text we'll be modifying at the top of the file.
38
44
env .EditBuffer (test .file , protocol.TextEdit {NewText : "// __REGTEST_PLACEHOLDER_0__\n " })
39
45
env .AfterChange ()
40
46
b .ResetTimer ()
41
47
42
48
for i := 0 ; i < b .N ; i ++ {
43
- edits ++
49
+ edits := atomic . AddInt64 ( & editID , 1 )
44
50
env .EditBuffer (test .file , protocol.TextEdit {
45
51
Range : protocol.Range {
46
52
Start : protocol.Position {Line : 0 , Character : 0 },
@@ -54,3 +60,40 @@ func BenchmarkDidChange(b *testing.B) {
54
60
})
55
61
}
56
62
}
63
+
64
+ func BenchmarkDiagnoseChange (b * testing.B ) {
65
+ for _ , test := range didChangeTests {
66
+ b .Run (test .repo , func (b * testing.B ) {
67
+ // Use a new env to avoid the diagnostic delay: we want to measure how
68
+ // long it takes to produce the diagnostics.
69
+ env := repos [test .repo ].newEnv (b , "diagnoseChange" , fake.EditorConfig {
70
+ Settings : map [string ]interface {}{
71
+ "diagnosticsDelay" : "0s" ,
72
+ },
73
+ })
74
+ env .OpenFile (test .file )
75
+ // Insert the text we'll be modifying at the top of the file.
76
+ env .EditBuffer (test .file , protocol.TextEdit {NewText : "// __REGTEST_PLACEHOLDER_0__\n " })
77
+ env .AfterChange ()
78
+ b .ResetTimer ()
79
+
80
+ // We must use an extra subtest layer here, so that we only set up the
81
+ // shared env once (otherwise we pay additional overhead and the profiling
82
+ // flags don't work).
83
+ b .Run ("diagnose" , func (b * testing.B ) {
84
+ for i := 0 ; i < b .N ; i ++ {
85
+ edits := atomic .AddInt64 (& editID , 1 )
86
+ env .EditBuffer (test .file , protocol.TextEdit {
87
+ Range : protocol.Range {
88
+ Start : protocol.Position {Line : 0 , Character : 0 },
89
+ End : protocol.Position {Line : 1 , Character : 0 },
90
+ },
91
+ // Increment the placeholder text, to ensure cache misses.
92
+ NewText : fmt .Sprintf ("// __REGTEST_PLACEHOLDER_%d__\n " , edits ),
93
+ })
94
+ env .AfterChange ()
95
+ }
96
+ })
97
+ })
98
+ }
99
+ }
0 commit comments