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 "time"
23)
24
25/*
26BenchmarkMinimalRepoListEncodings/slice-8 570 2145665 ns/op 753790 bytes 3981 B/op 0 allocs/op
27BenchmarkMinimalRepoListEncodings/map-8 360 3337522 ns/op 740778 bytes 377777 B/op 13002 allocs/op
28*/
29func BenchmarkMinimalRepoListEncodings(b *testing.B) {
30 size := uint32(13000) // 2021-06-24 rough estimate of number of repos on a replica.
31
32 type Slice struct {
33 ID uint32
34 HasSymbols bool
35 Branches []RepositoryBranch
36 IndexTimeUnix int64
37 }
38
39 branches := []RepositoryBranch{{Name: "HEAD", Version: strings.Repeat("a", 40)}}
40 mapData := make(map[uint32]*MinimalRepoListEntry, size)
41 sliceData := make([]Slice, 0, size)
42 indexTime := time.Now().Unix()
43
44 for id := uint32(1); id <= size; id++ {
45 mapData[id] = &MinimalRepoListEntry{
46 HasSymbols: true,
47 Branches: branches,
48 IndexTimeUnix: indexTime,
49 }
50 sliceData = append(sliceData, Slice{
51 ID: id,
52 HasSymbols: true,
53 Branches: branches,
54 IndexTimeUnix: indexTime,
55 })
56 }
57
58 b.Run("slice", benchmarkEncoding(sliceData))
59
60 b.Run("map", benchmarkEncoding(mapData))
61}
62
63func benchmarkEncoding(data interface{}) func(*testing.B) {
64 return func(b *testing.B) {
65 b.Helper()
66
67 var buf bytes.Buffer
68 enc := gob.NewEncoder(&buf)
69 err := enc.Encode(data)
70 if err != nil {
71 b.Fatal(err)
72 }
73
74 b.ReportAllocs()
75 b.ResetTimer()
76 b.ReportMetric(float64(buf.Len()), "bytes")
77 for i := 0; i < b.N; i++ {
78 _ = enc.Encode(data)
79 buf.Reset()
80 }
81 }
82}
83
84func TestSizeBytesSearchResult(t *testing.T) {
85 var sr = SearchResult{
86 Stats: Stats{}, // 129 bytes
87 Progress: Progress{}, // 16 bytes
88 Files: []FileMatch{{ // 24 bytes + 460 bytes
89 Score: 0, // 8 bytes
90 Debug: "", // 16 bytes
91 FileName: "", // 16 bytes
92 Repository: "", // 16 bytes
93 Branches: nil, // 24 bytes
94 LineMatches: nil, // 24 bytes
95 ChunkMatches: []ChunkMatch{{ // 24 bytes + 208 bytes (see TestSizeByteChunkMatches)
96 Content: []byte("foo"),
97 ContentStart: Location{},
98 FileName: false,
99 Ranges: []Range{{}},
100 SymbolInfo: []*Symbol{{}},
101 Score: 0,
102 DebugScore: "",
103 }},
104 RepositoryID: 0, // 4 bytes
105 RepositoryPriority: 0, // 8 bytes
106 Content: nil, // 24 bytes
107 Checksum: nil, // 24 bytes
108 Language: "", // 16 bytes
109 SubRepositoryName: "", // 16 bytes
110 SubRepositoryPath: "", // 16 bytes
111 Version: "", // 16 bytes
112 }},
113 RepoURLs: nil, // 48 bytes
114 LineFragments: nil, // 48 bytes
115 }
116
117 var wantBytes uint64 = 725
118 if sr.SizeBytes() != wantBytes {
119 t.Fatalf("want %d, got %d", wantBytes, sr.SizeBytes())
120 }
121}
122
123func TestSizeBytesChunkMatches(t *testing.T) {
124 cm := ChunkMatch{
125 Content: []byte("foo"), // 24 + 3 bytes
126 ContentStart: Location{}, // 12 bytes
127 FileName: false, // 1 byte
128 Ranges: []Range{{}}, // 24 bytes (slice header) + 24 bytes (content)
129 SymbolInfo: []*Symbol{{}}, // 24 bytes (slice header) + 4 * 16 bytes (string header) + 8 bytes (pointer)
130 Score: 0, // 8 byte
131 DebugScore: "", // 16 bytes (string header)
132 }
133
134 var wantBytes uint64 = 208
135 if cm.sizeBytes() != wantBytes {
136 t.Fatalf("want %d, got %d", wantBytes, cm.sizeBytes())
137 }
138}