fork of https://github.com/sourcegraph/zoekt
1// Copyright 2021 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package zoekt // import "github.com/sourcegraph/zoekt"
16
17import (
18 "bytes"
19 "encoding/gob"
20 "strings"
21 "testing"
22)
23
24/*
25BenchmarkMinimalRepoListEncodings/slice-8 570 2145665 ns/op 753790 bytes 3981 B/op 0 allocs/op
26BenchmarkMinimalRepoListEncodings/map-8 360 3337522 ns/op 740778 bytes 377777 B/op 13002 allocs/op
27*/
28func BenchmarkMinimalRepoListEncodings(b *testing.B) {
29 size := uint32(13000) // 2021-06-24 rough estimate of number of repos on a replica.
30
31 type Slice struct {
32 ID uint32
33 HasSymbols bool
34 Branches []RepositoryBranch
35 }
36
37 branches := []RepositoryBranch{{Name: "HEAD", Version: strings.Repeat("a", 40)}}
38 mapData := make(map[uint32]*MinimalRepoListEntry, size)
39 sliceData := make([]Slice, 0, size)
40
41 for id := uint32(1); id <= size; id++ {
42 mapData[id] = &MinimalRepoListEntry{
43 HasSymbols: true,
44 Branches: branches,
45 }
46 sliceData = append(sliceData, Slice{
47 ID: id,
48 HasSymbols: true,
49 Branches: branches,
50 })
51 }
52
53 b.Run("slice", benchmarkEncoding(sliceData))
54
55 b.Run("map", benchmarkEncoding(mapData))
56}
57
58func benchmarkEncoding(data interface{}) func(*testing.B) {
59 return func(b *testing.B) {
60 b.Helper()
61
62 var buf bytes.Buffer
63 enc := gob.NewEncoder(&buf)
64 err := enc.Encode(data)
65 if err != nil {
66 b.Fatal(err)
67 }
68
69 b.ReportAllocs()
70 b.ResetTimer()
71 b.ReportMetric(float64(buf.Len()), "bytes")
72 for i := 0; i < b.N; i++ {
73 _ = enc.Encode(data)
74 buf.Reset()
75 }
76 }
77}
78
79func TestSizeBytesSearchResult(t *testing.T) {
80 var sr = SearchResult{
81 Stats: Stats{}, // 129 bytes
82 Progress: Progress{}, // 16 bytes
83 Files: []FileMatch{{ // 24 bytes + 460 bytes
84 Score: 0, // 8 bytes
85 Debug: "", // 16 bytes
86 FileName: "", // 16 bytes
87 Repository: "", // 16 bytes
88 Branches: nil, // 24 bytes
89 LineMatches: nil, // 24 bytes
90 ChunkMatches: []ChunkMatch{{ // 24 bytes + 208 bytes (see TestSizeByteChunkMatches)
91 Content: []byte("foo"),
92 ContentStart: Location{},
93 FileName: false,
94 Ranges: []Range{{}},
95 SymbolInfo: []*Symbol{{}},
96 Score: 0,
97 DebugScore: "",
98 }},
99 RepositoryID: 0, // 4 bytes
100 RepositoryPriority: 0, // 8 bytes
101 Content: nil, // 24 bytes
102 Checksum: nil, // 24 bytes
103 Language: "", // 16 bytes
104 SubRepositoryName: "", // 16 bytes
105 SubRepositoryPath: "", // 16 bytes
106 Version: "", // 16 bytes
107 }},
108 RepoURLs: nil, // 48 bytes
109 LineFragments: nil, // 48 bytes
110 }
111
112 var wantBytes uint64 = 725
113 if sr.SizeBytes() != wantBytes {
114 t.Fatalf("want %d, got %d", wantBytes, sr.SizeBytes())
115 }
116}
117
118func TestSizeBytesChunkMatches(t *testing.T) {
119 cm := ChunkMatch{
120 Content: []byte("foo"), // 24 + 3 bytes
121 ContentStart: Location{}, // 12 bytes
122 FileName: false, // 1 byte
123 Ranges: []Range{{}}, // 24 bytes (slice header) + 24 bytes (content)
124 SymbolInfo: []*Symbol{{}}, // 24 bytes (slice header) + 4 * 16 bytes (string header) + 8 bytes (pointer)
125 Score: 0, // 8 byte
126 DebugScore: "", // 16 bytes (string header)
127 }
128
129 var wantBytes uint64 = 208
130 if cm.sizeBytes() != wantBytes {
131 t.Fatalf("want %d, got %d", wantBytes, cm.sizeBytes())
132 }
133}