From 48399b1af1421e4e5dbe9125291497131f75f130 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E7=8E=AE=E6=96=87?= Date: Mon, 27 May 2024 15:30:44 +0800 Subject: [PATCH 1/2] util/sets: simply List() by using slices.Sort reduced one level of interface so the performance should be slightly better. --- .../k8s.io/apimachinery/pkg/util/sets/set.go | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/staging/src/k8s.io/apimachinery/pkg/util/sets/set.go b/staging/src/k8s.io/apimachinery/pkg/util/sets/set.go index cd961c8c593..ae3d15eb25f 100644 --- a/staging/src/k8s.io/apimachinery/pkg/util/sets/set.go +++ b/staging/src/k8s.io/apimachinery/pkg/util/sets/set.go @@ -18,7 +18,7 @@ package sets import ( "cmp" - "sort" + "slices" ) // Set is a set of the same type elements, implemented via map[comparable]struct{} for minimal memory consumption. @@ -188,22 +188,13 @@ func (s1 Set[T]) Equal(s2 Set[T]) bool { return len(s1) == len(s2) && s1.IsSuperset(s2) } -type sortableSliceOfGeneric[T cmp.Ordered] []T - -func (g sortableSliceOfGeneric[T]) Len() int { return len(g) } -func (g sortableSliceOfGeneric[T]) Less(i, j int) bool { return less[T](g[i], g[j]) } -func (g sortableSliceOfGeneric[T]) Swap(i, j int) { g[i], g[j] = g[j], g[i] } - // List returns the contents as a sorted T slice. // // This is a separate function and not a method because not all types supported // by Generic are ordered and only those can be sorted. func List[T cmp.Ordered](s Set[T]) []T { - res := make(sortableSliceOfGeneric[T], 0, len(s)) - for key := range s { - res = append(res, key) - } - sort.Sort(res) + res := s.UnsortedList() + slices.Sort(res) return res } @@ -230,7 +221,3 @@ func (s Set[T]) PopAny() (T, bool) { func (s Set[T]) Len() int { return len(s) } - -func less[T cmp.Ordered](lhs, rhs T) bool { - return lhs < rhs -} From ac1f9fb73f2b4ee0fd260d84e0a0faef027a1955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=83=A1=E7=8E=AE=E6=96=87?= Date: Mon, 18 Nov 2024 10:58:09 +0800 Subject: [PATCH 2/2] util/sets: benchmark List() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit the new implementation based on slices.Sort is 1.7x faster goos: darwin goarch: arm64 pkg: k8s.io/apimachinery/pkg/util/sets cpu: Apple M2 Pro │ master.txt │ pr-125140.txt │ │ sec/op │ sec/op vs base │ ListSmall-12 305.1n ± 4% 235.0n ± 4% -22.98% (p=0.000 n=8) ListLarge-12 968.2µ ± 1% 581.5µ ± 0% -39.94% (p=0.000 n=8) geomean 17.19µ 11.69µ -31.98% │ master.txt │ pr-125140.txt │ │ B/op │ B/op vs base │ ListSmall-12 184.0 ± 0% 160.0 ± 0% -13.04% (p=0.000 n=8) ListLarge-12 104.0Ki ± 0% 104.0Ki ± 0% -0.02% (p=0.000 n=8) geomean 4.323Ki 4.031Ki -6.76% │ master.txt │ pr-125140.txt │ │ allocs/op │ allocs/op vs base │ ListSmall-12 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=8) ListLarge-12 2.000 ± 0% 1.000 ± 0% -50.00% (p=0.000 n=8) geomean 2.000 1.000 -50.00% --- .../pkg/util/sets/set_generic_test.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/staging/src/k8s.io/apimachinery/pkg/util/sets/set_generic_test.go b/staging/src/k8s.io/apimachinery/pkg/util/sets/set_generic_test.go index 53f3383def7..e439a553d04 100644 --- a/staging/src/k8s.io/apimachinery/pkg/util/sets/set_generic_test.go +++ b/staging/src/k8s.io/apimachinery/pkg/util/sets/set_generic_test.go @@ -356,3 +356,20 @@ func TestIntersection(t *testing.T) { } } } + +func BenchmarkListSmall(b *testing.B) { + s := sets.New("a", "b", "c", "d", "e", "f", "g", "h", "i", "j") + for b.Loop() { + sets.List(s) + } +} + +func BenchmarkListLarge(b *testing.B) { + s := make(sets.Set[int], 12345) + for i := range 12345 { + s.Insert(i * 7) + } + for b.Loop() { + sets.List(s) + } +}