diff --git a/.res/bench-is-equal-10-100-mil.png b/.res/bench-is-equal-10-100-mil.png new file mode 100755 index 0000000..355ac80 Binary files /dev/null and b/.res/bench-is-equal-10-100-mil.png differ diff --git a/.res/bench-is-equal-10-million.png b/.res/bench-is-equal-10-million.png deleted file mode 100755 index 671d265..0000000 Binary files a/.res/bench-is-equal-10-million.png and /dev/null differ diff --git a/README.md b/README.md index 18bf6a7..99a0f86 100644 --- a/README.md +++ b/README.md @@ -140,8 +140,9 @@ Map benefits from sizing while NSet isn't affected, but in both cases NSet remai Another case where NSet really shines is checking if two sets are equal. Below is a benchmark that checks whether two NSets/maps with 10 Million elements in each are equal (They are equal, which is the worst case). -Here NSet finishes in `0.1ms` but Map takes almost a second with `813ms`. -![Benchmarking IsEq with 10,000,000 elements](./.res/bench-is-equal-10-million.png) +Here NSet finishes in `0.1ms` but Map takes almost a second with `813ms`. With a few large numbers NSet suffers a bit but then its performance remains or even improves with more elements, while map degrades greatly. + +![Benchmarking IsEq with 10 and 100 million elements](./.res/bench-is-equal-10-100-mil.png) Next we have `GetAllElements`, which simply returns an array of all the elements of NSet/Map (note this is dangerous in NSet. See [Memory characteristics](#memory-characteristics)). ![Benchmarking GetAllElements with 10,000,000 elements](.res/bench-getAllElements-10-million.png) diff --git a/nset_test.go b/nset_test.go index e8616a8..791bcda 100755 --- a/nset_test.go +++ b/nset_test.go @@ -447,6 +447,112 @@ func BenchmarkMapIsEq(b *testing.B) { } } +func BenchmarkNSetIsEqRand(b *testing.B) { + + b.StopTimer() + + rand.Seed(RandSeed) + s1 := nset.NewNSet[uint32]() + s2 := nset.NewNSet[uint32]() + for i := uint32(0); i < maxBenchSize; i++ { + r := rand.Uint32() + s1.Add(r) + s2.Add(r) + } + b.StartTimer() + + for i := 0; i < b.N; i++ { + s1.IsEq(s2) + } +} + +func BenchmarkMapIsEqRand(b *testing.B) { + + b.StopTimer() + + rand.Seed(RandSeed) + m1 := map[uint32]struct{}{} + m2 := map[uint32]struct{}{} + for i := uint32(0); i < maxBenchSize; i++ { + r := rand.Uint32() + m1[r] = struct{}{} + m2[r] = struct{}{} + } + b.StartTimer() + + mapsAreEq := func(m1, m2 map[uint32]struct{}) bool { + + if len(m1) != len(m2) { + return false + } + + for k := range m1 { + if _, ok := m2[k]; !ok { + return false + } + } + + return true + } + + for i := 0; i < b.N; i++ { + mapsAreEq(m1, m2) + } +} + +func BenchmarkNSetIsEqRand100Mil(b *testing.B) { + + b.StopTimer() + + rand.Seed(RandSeed) + s1 := nset.NewNSet[uint32]() + s2 := nset.NewNSet[uint32]() + for i := uint32(0); i < 100_000_000; i++ { + r := rand.Uint32() + s1.Add(r) + s2.Add(r) + } + b.StartTimer() + + for i := 0; i < b.N; i++ { + s1.IsEq(s2) + } +} + +func BenchmarkMapIsEqRand100Mil(b *testing.B) { + + b.StopTimer() + + rand.Seed(RandSeed) + m1 := map[uint32]struct{}{} + m2 := map[uint32]struct{}{} + for i := uint32(0); i < 100_000_000; i++ { + r := rand.Uint32() + m1[r] = struct{}{} + m2[r] = struct{}{} + } + b.StartTimer() + + mapsAreEq := func(m1, m2 map[uint32]struct{}) bool { + + if len(m1) != len(m2) { + return false + } + + for k := range m1 { + if _, ok := m2[k]; !ok { + return false + } + } + + return true + } + + for i := 0; i < b.N; i++ { + mapsAreEq(m1, m2) + } +} + var getIntersectionNset *nset.NSet[uint32] func BenchmarkNSetGetIntersection(b *testing.B) {