From 969959895200686eef33874ba2e3b98d698817a1 Mon Sep 17 00:00:00 2001 From: Oleg Zaytsev Date: Sun, 17 Mar 2024 16:56:12 +0100 Subject: [PATCH 1/2] Improve Labels.Compare performance w/stringlabels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit I was bored on a train and I spent some amount of time trying to scratch some nanoseconds off the Labels.Compare when running with stringlabels. I would be ashamed to admit the real amount of time I spent on it. The worst thing is, I can't really explain why this is performing so much better, and someone should re-run the benchmarks on their machine to confirm that it's not something related to general relativity because the train is moving. I also added some extra real-life benchmark cases with longer labelsets (these aren't the longest we have in production, but kubernetes labelsets are fairly common in Prometheus so I thought it would be nice to have them). My benchmarks show this diff: goos: darwin goarch: arm64 pkg: github.com/prometheus/prometheus/model/labels │ old │ new │ │ sec/op │ sec/op vs base │ Labels_Compare/equal 5.898n ± 0% 5.875n ± 1% -0.40% (p=0.037 n=10) Labels_Compare/not_equal 11.78n ± 2% 11.01n ± 1% -6.54% (p=0.000 n=10) Labels_Compare/different_sizes 4.959n ± 1% 4.906n ± 2% -1.05% (p=0.050 n=10) Labels_Compare/lots 21.32n ± 0% 17.54n ± 5% -17.75% (p=0.000 n=10) Labels_Compare/real_long_equal 15.06n ± 1% 14.92n ± 0% -0.93% (p=0.000 n=10) Labels_Compare/real_long_different_end 25.20n ± 0% 24.43n ± 0% -3.04% (p=0.000 n=10) geomean 11.86n 11.25n -5.16% Signed-off-by: Oleg Zaytsev --- model/labels/labels_stringlabels.go | 8 ++------ model/labels/labels_test.go | 10 ++++++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/model/labels/labels_stringlabels.go b/model/labels/labels_stringlabels.go index 2e718c2b1..44a2e0fb5 100644 --- a/model/labels/labels_stringlabels.go +++ b/model/labels/labels_stringlabels.go @@ -363,12 +363,8 @@ func Compare(a, b Labels) int { // Now we know that there is some difference before the end of a and b. // Go back through the fields and find which field that difference is in. - firstCharDifferent := i - for i = 0; ; { - size, nextI := decodeSize(a.data, i) - if nextI+size > firstCharDifferent { - break - } + firstCharDifferent, i := i, 0 + for size, nextI := decodeSize(a.data, i); nextI+size <= firstCharDifferent; size, nextI = decodeSize(a.data, i) { i = nextI + size } // Difference is inside this entry. diff --git a/model/labels/labels_test.go b/model/labels/labels_test.go index 49b4b4e67..cedeb95a6 100644 --- a/model/labels/labels_test.go +++ b/model/labels/labels_test.go @@ -532,6 +532,16 @@ var comparisonBenchmarkScenarios = []struct { FromStrings("aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "nnn", "ooo", "ppp", "qqq", "rrz"), FromStrings("aaa", "bbb", "ccc", "ddd", "eee", "fff", "ggg", "hhh", "iii", "jjj", "kkk", "lll", "mmm", "nnn", "ooo", "ppp", "qqq", "rrr"), }, + { + "real long equal", + FromStrings("__name__", "kube_pod_container_status_last_terminated_exitcode", "cluster", "prod-af-north-0", " container", "prometheus", "instance", "kube-state-metrics-0:kube-state-metrics:ksm", "job", "kube-state-metrics/kube-state-metrics", " namespace", "observability-prometheus", "pod", "observability-prometheus-0", "uid", "d3ec90b2-4975-4607-b45d-b9ad64bb417e"), + FromStrings("__name__", "kube_pod_container_status_last_terminated_exitcode", "cluster", "prod-af-north-0", " container", "prometheus", "instance", "kube-state-metrics-0:kube-state-metrics:ksm", "job", "kube-state-metrics/kube-state-metrics", " namespace", "observability-prometheus", "pod", "observability-prometheus-0", "uid", "d3ec90b2-4975-4607-b45d-b9ad64bb417e"), + }, + { + "real long different end", + FromStrings("__name__", "kube_pod_container_status_last_terminated_exitcode", "cluster", "prod-af-north-0", " container", "prometheus", "instance", "kube-state-metrics-0:kube-state-metrics:ksm", "job", "kube-state-metrics/kube-state-metrics", " namespace", "observability-prometheus", "pod", "observability-prometheus-0", "uid", "d3ec90b2-4975-4607-b45d-b9ad64bb417e"), + FromStrings("__name__", "kube_pod_container_status_last_terminated_exitcode", "cluster", "prod-af-north-0", " container", "prometheus", "instance", "kube-state-metrics-0:kube-state-metrics:ksm", "job", "kube-state-metrics/kube-state-metrics", " namespace", "observability-prometheus", "pod", "observability-prometheus-0", "uid", "deadbeef-0000-1111-2222-b9ad64bb417e"), + }, } func BenchmarkLabels_Equals(b *testing.B) { From d12e785075ed42f0d0edafe7018e2d512d0f8ce6 Mon Sep 17 00:00:00 2001 From: Oleg Zaytsev Date: Mon, 18 Mar 2024 11:16:09 +0100 Subject: [PATCH 2/2] Improve readability As suggested by @bboreham Signed-off-by: Oleg Zaytsev --- model/labels/labels_stringlabels.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/model/labels/labels_stringlabels.go b/model/labels/labels_stringlabels.go index 44a2e0fb5..9ef764dae 100644 --- a/model/labels/labels_stringlabels.go +++ b/model/labels/labels_stringlabels.go @@ -364,8 +364,10 @@ func Compare(a, b Labels) int { // Now we know that there is some difference before the end of a and b. // Go back through the fields and find which field that difference is in. firstCharDifferent, i := i, 0 - for size, nextI := decodeSize(a.data, i); nextI+size <= firstCharDifferent; size, nextI = decodeSize(a.data, i) { + size, nextI := decodeSize(a.data, i) + for nextI+size <= firstCharDifferent { i = nextI + size + size, nextI = decodeSize(a.data, i) } // Difference is inside this entry. aStr, _ := decodeString(a.data, i)