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