From f9e2fb6b87e207c586332667d6f5ab5bdb51becc Mon Sep 17 00:00:00 2001 From: Brad Moylan Date: Thu, 7 Sep 2023 19:29:10 -0700 Subject: [PATCH] improvement: Use go1.21's slices package to avoid allocation in sorting (#323) --- metrics/registry.go | 5 ++--- metrics/sort.go | 23 +++++++++++++++++++++++ metrics/sort_go121.go | 30 ++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 metrics/sort.go create mode 100644 metrics/sort_go121.go diff --git a/metrics/registry.go b/metrics/registry.go index 8848bcd8..24638e4c 100644 --- a/metrics/registry.go +++ b/metrics/registry.go @@ -6,7 +6,6 @@ package metrics import ( "context" - "sort" "strings" "sync" "time" @@ -269,7 +268,7 @@ func (r *rootRegistry) Each(f MetricVisitor) { sortedMetricIDs = append(sortedMetricIDs, name) allMetrics[name] = metric }) - sort.Strings(sortedMetricIDs) + sortStrings(sortedMetricIDs) for _, id := range sortedMetricIDs { r.idToMetricMutex.RLock() @@ -401,6 +400,6 @@ func toMetricTagsID(name string, tags Tags) metricTagsID { // newSortedTags copies the tag slice before sorting so that in-place mutation does not affect the input slice. func newSortedTags(tags Tags) Tags { tagsCopy := append(tags[:0:0], tags...) - sort.Sort(tagsCopy) + sortTags(tagsCopy) return tagsCopy } diff --git a/metrics/sort.go b/metrics/sort.go new file mode 100644 index 00000000..54104372 --- /dev/null +++ b/metrics/sort.go @@ -0,0 +1,23 @@ +// Copyright (c) 2023 Palantir Technologies. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !go1.21 + +package metrics + +import ( + "sort" +) + +// sortStrings is the default sort.Strings function. +// Unfortunately this forces the slice to escape to the heap. +// See https://github.com/golang/go/issues/17332 +// Go 1.21's slices package does not have this issue. +var sortStrings = sort.Strings + +// sortTags is the default sort.Sort function. +// Unfortunately this forces the slice to escape to the heap. +// See https://github.com/golang/go/issues/17332 +// Go 1.21's slices package does not have this issue. +var sortTags = sort.Sort diff --git a/metrics/sort_go121.go b/metrics/sort_go121.go new file mode 100644 index 00000000..d5abb8e6 --- /dev/null +++ b/metrics/sort_go121.go @@ -0,0 +1,30 @@ +// Copyright (c) 2023 Palantir Technologies. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build go1.21 + +package metrics + +import ( + "slices" +) + +// sortStrings is the default slices.Sort function which does not force allocation like sort.Strings. +var sortStrings = slices.Sort[[]string] + +// sortTags uses slices.SortFunc which does not force allocation like sort.Sort. +func sortTags(tags Tags) { + slices.SortFunc(tags, compareTags) +} + +func compareTags(a, b Tag) int { + switch { + case a.keyValue > b.keyValue: + return 1 + case a.keyValue == b.keyValue: + return 0 + default: + return -1 + } +}