1// Copyright 2014 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package model
15
16import (
17	"fmt"
18	"runtime"
19	"sync"
20	"testing"
21)
22
23func TestLabelsToSignature(t *testing.T) {
24	var scenarios = []struct {
25		in  map[string]string
26		out uint64
27	}{
28		{
29			in:  map[string]string{},
30			out: 14695981039346656037,
31		},
32		{
33			in:  map[string]string{"name": "garland, briggs", "fear": "love is not enough"},
34			out: 5799056148416392346,
35		},
36	}
37
38	for i, scenario := range scenarios {
39		actual := LabelsToSignature(scenario.in)
40
41		if actual != scenario.out {
42			t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
43		}
44	}
45}
46
47func TestMetricToFingerprint(t *testing.T) {
48	var scenarios = []struct {
49		in  LabelSet
50		out Fingerprint
51	}{
52		{
53			in:  LabelSet{},
54			out: 14695981039346656037,
55		},
56		{
57			in:  LabelSet{"name": "garland, briggs", "fear": "love is not enough"},
58			out: 5799056148416392346,
59		},
60	}
61
62	for i, scenario := range scenarios {
63		actual := labelSetToFingerprint(scenario.in)
64
65		if actual != scenario.out {
66			t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
67		}
68	}
69}
70
71func TestMetricToFastFingerprint(t *testing.T) {
72	var scenarios = []struct {
73		in  LabelSet
74		out Fingerprint
75	}{
76		{
77			in:  LabelSet{},
78			out: 14695981039346656037,
79		},
80		{
81			in:  LabelSet{"name": "garland, briggs", "fear": "love is not enough"},
82			out: 12952432476264840823,
83		},
84	}
85
86	for i, scenario := range scenarios {
87		actual := labelSetToFastFingerprint(scenario.in)
88
89		if actual != scenario.out {
90			t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
91		}
92	}
93}
94
95func TestSignatureForLabels(t *testing.T) {
96	var scenarios = []struct {
97		in     Metric
98		labels LabelNames
99		out    uint64
100	}{
101		{
102			in:     Metric{},
103			labels: nil,
104			out:    14695981039346656037,
105		},
106		{
107			in:     Metric{},
108			labels: LabelNames{"empty"},
109			out:    7187873163539638612,
110		},
111		{
112			in:     Metric{"name": "garland, briggs", "fear": "love is not enough"},
113			labels: LabelNames{"empty"},
114			out:    7187873163539638612,
115		},
116		{
117			in:     Metric{"name": "garland, briggs", "fear": "love is not enough"},
118			labels: LabelNames{"fear", "name"},
119			out:    5799056148416392346,
120		},
121		{
122			in:     Metric{"name": "garland, briggs", "fear": "love is not enough", "foo": "bar"},
123			labels: LabelNames{"fear", "name"},
124			out:    5799056148416392346,
125		},
126		{
127			in:     Metric{"name": "garland, briggs", "fear": "love is not enough"},
128			labels: LabelNames{},
129			out:    14695981039346656037,
130		},
131		{
132			in:     Metric{"name": "garland, briggs", "fear": "love is not enough"},
133			labels: nil,
134			out:    14695981039346656037,
135		},
136	}
137
138	for i, scenario := range scenarios {
139		actual := SignatureForLabels(scenario.in, scenario.labels...)
140
141		if actual != scenario.out {
142			t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
143		}
144	}
145}
146
147func TestSignatureWithoutLabels(t *testing.T) {
148	var scenarios = []struct {
149		in     Metric
150		labels map[LabelName]struct{}
151		out    uint64
152	}{
153		{
154			in:     Metric{},
155			labels: nil,
156			out:    14695981039346656037,
157		},
158		{
159			in:     Metric{"name": "garland, briggs", "fear": "love is not enough"},
160			labels: map[LabelName]struct{}{"fear": struct{}{}, "name": struct{}{}},
161			out:    14695981039346656037,
162		},
163		{
164			in:     Metric{"name": "garland, briggs", "fear": "love is not enough", "foo": "bar"},
165			labels: map[LabelName]struct{}{"foo": struct{}{}},
166			out:    5799056148416392346,
167		},
168		{
169			in:     Metric{"name": "garland, briggs", "fear": "love is not enough"},
170			labels: map[LabelName]struct{}{},
171			out:    5799056148416392346,
172		},
173		{
174			in:     Metric{"name": "garland, briggs", "fear": "love is not enough"},
175			labels: nil,
176			out:    5799056148416392346,
177		},
178	}
179
180	for i, scenario := range scenarios {
181		actual := SignatureWithoutLabels(scenario.in, scenario.labels)
182
183		if actual != scenario.out {
184			t.Errorf("%d. expected %d, got %d", i, scenario.out, actual)
185		}
186	}
187}
188
189func benchmarkLabelToSignature(b *testing.B, l map[string]string, e uint64) {
190	for i := 0; i < b.N; i++ {
191		if a := LabelsToSignature(l); a != e {
192			b.Fatalf("expected signature of %d for %s, got %d", e, l, a)
193		}
194	}
195}
196
197func BenchmarkLabelToSignatureScalar(b *testing.B) {
198	benchmarkLabelToSignature(b, nil, 14695981039346656037)
199}
200
201func BenchmarkLabelToSignatureSingle(b *testing.B) {
202	benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value"}, 5146282821936882169)
203}
204
205func BenchmarkLabelToSignatureDouble(b *testing.B) {
206	benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value", "second-label": "second-label-value"}, 3195800080984914717)
207}
208
209func BenchmarkLabelToSignatureTriple(b *testing.B) {
210	benchmarkLabelToSignature(b, map[string]string{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 13843036195897128121)
211}
212
213func benchmarkMetricToFingerprint(b *testing.B, ls LabelSet, e Fingerprint) {
214	for i := 0; i < b.N; i++ {
215		if a := labelSetToFingerprint(ls); a != e {
216			b.Fatalf("expected signature of %d for %s, got %d", e, ls, a)
217		}
218	}
219}
220
221func BenchmarkMetricToFingerprintScalar(b *testing.B) {
222	benchmarkMetricToFingerprint(b, nil, 14695981039346656037)
223}
224
225func BenchmarkMetricToFingerprintSingle(b *testing.B) {
226	benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value"}, 5146282821936882169)
227}
228
229func BenchmarkMetricToFingerprintDouble(b *testing.B) {
230	benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value"}, 3195800080984914717)
231}
232
233func BenchmarkMetricToFingerprintTriple(b *testing.B) {
234	benchmarkMetricToFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 13843036195897128121)
235}
236
237func benchmarkMetricToFastFingerprint(b *testing.B, ls LabelSet, e Fingerprint) {
238	for i := 0; i < b.N; i++ {
239		if a := labelSetToFastFingerprint(ls); a != e {
240			b.Fatalf("expected signature of %d for %s, got %d", e, ls, a)
241		}
242	}
243}
244
245func BenchmarkMetricToFastFingerprintScalar(b *testing.B) {
246	benchmarkMetricToFastFingerprint(b, nil, 14695981039346656037)
247}
248
249func BenchmarkMetricToFastFingerprintSingle(b *testing.B) {
250	benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value"}, 5147259542624943964)
251}
252
253func BenchmarkMetricToFastFingerprintDouble(b *testing.B) {
254	benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value"}, 18269973311206963528)
255}
256
257func BenchmarkMetricToFastFingerprintTriple(b *testing.B) {
258	benchmarkMetricToFastFingerprint(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676)
259}
260
261func BenchmarkEmptyLabelSignature(b *testing.B) {
262	input := []map[string]string{nil, {}}
263
264	var ms runtime.MemStats
265	runtime.ReadMemStats(&ms)
266
267	alloc := ms.Alloc
268
269	for _, labels := range input {
270		LabelsToSignature(labels)
271	}
272
273	runtime.ReadMemStats(&ms)
274
275	if got := ms.Alloc; alloc != got {
276		b.Fatal("expected LabelsToSignature with empty labels not to perform allocations")
277	}
278}
279
280func benchmarkMetricToFastFingerprintConc(b *testing.B, ls LabelSet, e Fingerprint, concLevel int) {
281	var start, end sync.WaitGroup
282	start.Add(1)
283	end.Add(concLevel)
284	errc := make(chan error, 1)
285
286	for i := 0; i < concLevel; i++ {
287		go func() {
288			start.Wait()
289			for j := b.N / concLevel; j >= 0; j-- {
290				if a := labelSetToFastFingerprint(ls); a != e {
291					select {
292					case errc <- fmt.Errorf("expected signature of %d for %s, got %d", e, ls, a):
293					default:
294					}
295				}
296			}
297			end.Done()
298		}()
299	}
300	b.ResetTimer()
301	start.Done()
302	end.Wait()
303
304	select {
305	case err := <-errc:
306		b.Fatal(err)
307	default:
308	}
309}
310
311func BenchmarkMetricToFastFingerprintTripleConc1(b *testing.B) {
312	benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 1)
313}
314
315func BenchmarkMetricToFastFingerprintTripleConc2(b *testing.B) {
316	benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 2)
317}
318
319func BenchmarkMetricToFastFingerprintTripleConc4(b *testing.B) {
320	benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 4)
321}
322
323func BenchmarkMetricToFastFingerprintTripleConc8(b *testing.B) {
324	benchmarkMetricToFastFingerprintConc(b, LabelSet{"first-label": "first-label-value", "second-label": "second-label-value", "third-label": "third-label-value"}, 15738406913934009676, 8)
325}
326