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..8100d1ad --- /dev/null +++ b/metrics/sort.go @@ -0,0 +1,19 @@ +//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..843174d0 --- /dev/null +++ b/metrics/sort_go121.go @@ -0,0 +1,26 @@ +//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 + } +}