diff --git a/README.md b/README.md index ed6f129..1038323 100644 --- a/README.md +++ b/README.md @@ -54,3 +54,49 @@ beyond the first or last item. If the map is changing while the iteration is in-flight it may produce unexpected behavior. + +## Performance + +CPU: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz + +RAM: 8GB + +System: Windows 10 + +```shell +$go test -benchmem -run=^$ github.com/elliotchance/orderedmap -bench BenchmarkAll +``` + +map[int]bool + +| | map | orderedmap | +| ------- | ------------------- | ------------------- | +| set | 198 ns/op, 44 B/op | 722 ns/op, 211 B/op | +| get | 18 ns/op, 0 B/op | 37.3 ns/op, 0 B/op | +| delete | 888 ns/op, 211 B/op | 280 ns/op, 44 B/op | +| Iterate | 206 ns/op, 44 B/op | 693 ns/op, 259 B/op | + +map[string]bool(PS : Use strconv.Iota()) + +| | map | orderedmap | +| ----------- | ------------------- | ----------------------- | +| set | 421 ns/op, 86 B/op | 1048 ns/op, 243 B/op | +| get | 81.1 ns/op, 2 B/op | 97.8 ns/op, 2 B/op | +| delete | 737 ns/op, 122 B/op | 1188 ns/op, 251 B/op | +| Iterate all | 14706 ns/op, 1 B/op | 52671 ns/op, 16391 B/op | + +Big map[int]bool (10000000 keys) + +| | map | orderedmap | +| ----------- | -------------------------------- | ------------------------------- | +| set all | 1.834559 s/op, 423.9470291 MB/op | 7.5564667 s/op, 1784.1483 MB/op | +| get all | 2.6367878 s/op, 423.9698 MB/op | 9.0232475 s/op, 1784.1086 MB/op | +| Iterate all | 1.9526784 s/op, 423.9042 MB/op | 8.2495265 s/op, 1936.7619 MB/op | + +Big map[string]bool (10000000 keys) + +| | map | orderedmap | +| ----------- | --------------------------------- | ----------------------------------- | +| set all | 4.8893923 s/op, 921.33435 MB/op | 10.4405527 s/op, 2089.0144 MB/op | +| get all | 7.122791 s/op, 997.3802643 MB/op | 13.2613692 s/op, 2165.09521 MB/op | +| Iterate all | 5.1688922 s/op, 921.4619293 MB/op | 12.6623711 s/op, 2241.5272064 MB/op | diff --git a/orderedmap_test.go b/orderedmap_test.go index 782d479..644ee79 100644 --- a/orderedmap_test.go +++ b/orderedmap_test.go @@ -2,9 +2,11 @@ package orderedmap_test import ( "fmt" + "strconv" + "testing" + "github.com/elliotchance/orderedmap" "github.com/stretchr/testify/assert" - "testing" ) func TestNewOrderedMap(t *testing.T) { @@ -302,6 +304,19 @@ func TestOrderedMap_Back(t *testing.T) { }) } +func benchmarkMap_Set(multiplier int) func(b *testing.B) { + return func(b *testing.B) { + m := make(map[int]bool) + for i := 0; i < b.N*multiplier; i++ { + m[i] = true + } + } +} + +func BenchmarkMap_Set(b *testing.B) { + benchmarkMap_Set(1)(b) +} + func benchmarkOrderedMap_Set(multiplier int) func(b *testing.B) { return func(b *testing.B) { m := orderedmap.NewOrderedMap() @@ -315,6 +330,23 @@ func BenchmarkOrderedMap_Set(b *testing.B) { benchmarkOrderedMap_Set(1)(b) } +func benchmarkMap_Get(multiplier int) func(b *testing.B) { + m := make(map[int]bool) + for i := 0; i < 1000*multiplier; i++ { + m[i] = true + } + + return func(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = m[i%1000*multiplier] + } + } +} + +func BenchmarkMap_Get(b *testing.B) { + benchmarkMap_Get(1)(b) +} + func benchmarkOrderedMap_Get(multiplier int) func(b *testing.B) { m := orderedmap.NewOrderedMap() for i := 0; i < 1000*multiplier; i++ { @@ -323,7 +355,7 @@ func benchmarkOrderedMap_Get(multiplier int) func(b *testing.B) { return func(b *testing.B) { for i := 0; i < b.N; i++ { - m.Get(1000 * multiplier % b.N) + m.Get(i % 1000 * multiplier) } } } @@ -355,6 +387,23 @@ func BenchmarkOrderedMap_Len(b *testing.B) { benchmarkOrderedMap_Len(1)(b) } +func benchmarkMap_Delete(multiplier int) func(b *testing.B) { + return func(b *testing.B) { + m := make(map[int]bool) + for i := 0; i < b.N*multiplier; i++ { + m[i] = true + } + + for i := 0; i < b.N; i++ { + delete(m, i) + } + } +} + +func BenchmarkMap_Delete(b *testing.B) { + benchmarkMap_Delete(1)(b) +} + func benchmarkOrderedMap_Delete(multiplier int) func(b *testing.B) { return func(b *testing.B) { m := orderedmap.NewOrderedMap() @@ -363,7 +412,7 @@ func benchmarkOrderedMap_Delete(multiplier int) func(b *testing.B) { } for i := 0; i < b.N; i++ { - m.Delete(b.N) + m.Delete(i) } } } @@ -372,6 +421,43 @@ func BenchmarkOrderedMap_Delete(b *testing.B) { benchmarkOrderedMap_Delete(1)(b) } +func benchmarkMap_Iterate(multiplier int) func(b *testing.B) { + m := make(map[int]bool) + for i := 0; i < 1000*multiplier; i++ { + m[i] = true + } + return func(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, v := range m { + nothing(v) + } + } + } +} +func BenchmarkMap_Iterate(b *testing.B) { + benchmarkMap_Iterate(1)(b) +} + +func benchmarkOrderedMap_Iterate(multiplier int) func(b *testing.B) { + m := orderedmap.NewOrderedMap() + for i := 0; i < 1000*multiplier; i++ { + m.Set(i, true) + } + + return func(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, key := range m.Keys() { + _, v := m.Get(key) + nothing(v) + } + } + } +} + +func BenchmarkOrderedMap_Iterate(b *testing.B) { + benchmarkOrderedMap_Iterate(1)(b) +} + func benchmarkOrderedMap_Keys(multiplier int) func(b *testing.B) { m := orderedmap.NewOrderedMap() for i := 0; i < 1000*multiplier; i++ { @@ -385,6 +471,145 @@ func benchmarkOrderedMap_Keys(multiplier int) func(b *testing.B) { } } +func benchmarkMapString_Set(multiplier int) func(b *testing.B) { + return func(b *testing.B) { + m := make(map[string]bool) + a := "12345678" + for i := 0; i < b.N*multiplier; i++ { + m[a+strconv.Itoa(i)] = true + } + } +} + +func BenchmarkMapString_Set(b *testing.B) { + benchmarkMapString_Set(1)(b) +} + +func benchmarkOrderedMapString_Set(multiplier int) func(b *testing.B) { + return func(b *testing.B) { + m := orderedmap.NewOrderedMap() + a := "12345678" + for i := 0; i < b.N*multiplier; i++ { + m.Set(a+strconv.Itoa(i), true) + } + } +} + +func BenchmarkOrderedMapString_Set(b *testing.B) { + benchmarkOrderedMapString_Set(1)(b) +} + +func benchmarkMapString_Get(multiplier int) func(b *testing.B) { + m := make(map[string]bool) + a := "12345678" + for i := 0; i < 1000*multiplier; i++ { + m[a+strconv.Itoa(i)] = true + } + + return func(b *testing.B) { + for i := 0; i < b.N; i++ { + _ = m[a+strconv.Itoa(i%1000*multiplier)] + } + } +} + +func BenchmarkMapString_Get(b *testing.B) { + benchmarkMapString_Get(1)(b) +} + +func benchmarkOrderedMapString_Get(multiplier int) func(b *testing.B) { + m := orderedmap.NewOrderedMap() + a := "12345678" + for i := 0; i < 1000*multiplier; i++ { + m.Set(a+strconv.Itoa(i), true) + } + + return func(b *testing.B) { + for i := 0; i < b.N; i++ { + m.Get(a + strconv.Itoa(i%1000*multiplier)) + } + } +} + +func BenchmarkOrderedMapString_Get(b *testing.B) { + benchmarkOrderedMapString_Get(1)(b) +} + +func benchmarkMapString_Delete(multiplier int) func(b *testing.B) { + return func(b *testing.B) { + m := make(map[string]bool) + a := "12345678" + for i := 0; i < b.N*multiplier; i++ { + m[a+strconv.Itoa(i)] = true + } + + for i := 0; i < b.N; i++ { + delete(m, a+strconv.Itoa(i)) + } + } +} + +func BenchmarkMapString_Delete(b *testing.B) { + benchmarkMapString_Delete(1)(b) +} + +func benchmarkOrderedMapString_Delete(multiplier int) func(b *testing.B) { + return func(b *testing.B) { + m := orderedmap.NewOrderedMap() + a := "12345678" + for i := 0; i < b.N*multiplier; i++ { + m.Set(a+strconv.Itoa(i), true) + } + + for i := 0; i < b.N; i++ { + m.Delete(a + strconv.Itoa(i)) + } + } +} + +func BenchmarkOrderedMapString_Delete(b *testing.B) { + benchmarkOrderedMapString_Delete(1)(b) +} + +func benchmarkMapString_Iterate(multiplier int) func(b *testing.B) { + m := make(map[string]bool) + a := "12345678" + for i := 0; i < 1000*multiplier; i++ { + m[a+strconv.Itoa(i)] = true + } + return func(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, v := range m { + nothing(v) + } + } + } +} +func BenchmarkMapString_Iterate(b *testing.B) { + benchmarkMapString_Iterate(1)(b) +} + +func benchmarkOrderedMapString_Iterate(multiplier int) func(b *testing.B) { + m := orderedmap.NewOrderedMap() + a := "12345678" + for i := 0; i < 1000*multiplier; i++ { + m.Set(a+strconv.Itoa(i), true) + } + + return func(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, key := range m.Keys() { + _, v := m.Get(key) + nothing(v) + } + } + } +} + +func BenchmarkOrderedMapString_Iterate(b *testing.B) { + benchmarkOrderedMapString_Iterate(1)(b) +} + func BenchmarkOrderedMap_Keys(b *testing.B) { benchmarkOrderedMap_Keys(1)(b) } @@ -413,3 +638,259 @@ func ExampleOrderedMap_Front() { fmt.Println(el) } } + +func nothing(v interface{}) { + v = false +} + +func benchmarkBigMap_Set() func(b *testing.B) { + return func(b *testing.B) { + for j := 0; j < b.N; j++ { + m := make(map[int]bool) + for i := 0; i < 10000000; i++ { + m[i] = true + } + } + } +} + +func BenchmarkBigMap_Set(b *testing.B) { + benchmarkBigMap_Set()(b) +} + +func benchmarkBigOrderedMap_Set() func(b *testing.B) { + return func(b *testing.B) { + for j := 0; j < b.N; j++ { + m := orderedmap.NewOrderedMap() + for i := 0; i < 10000000; i++ { + m.Set(i, true) + } + } + } +} + +func BenchmarkBigOrderedMap_Set(b *testing.B) { + benchmarkBigOrderedMap_Set()(b) +} + +func benchmarkBigMap_Get() func(b *testing.B) { + m := make(map[int]bool) + for i := 0; i < 10000000; i++ { + m[i] = true + } + + return func(b *testing.B) { + for j := 0; j < b.N; j++ { + for i := 0; i < 10000000; i++ { + _ = m[i] + } + } + } +} + +func BenchmarkBigMap_Get(b *testing.B) { + benchmarkBigMap_Get()(b) +} + +func benchmarkBigOrderedMap_Get() func(b *testing.B) { + m := orderedmap.NewOrderedMap() + for i := 0; i < 10000000; i++ { + m.Set(i, true) + } + + return func(b *testing.B) { + for j := 0; j < b.N; j++ { + for i := 0; i < 10000000; i++ { + m.Get(i) + } + } + } +} + +func BenchmarkBigOrderedMap_Get(b *testing.B) { + benchmarkBigOrderedMap_Get()(b) +} + +func benchmarkBigMap_Iterate() func(b *testing.B) { + m := make(map[int]bool) + for i := 0; i < 10000000; i++ { + m[i] = true + } + return func(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, v := range m { + nothing(v) + } + } + } +} +func BenchmarkBigMap_Iterate(b *testing.B) { + benchmarkBigMap_Iterate()(b) +} + +func benchmarkBigOrderedMap_Iterate() func(b *testing.B) { + m := orderedmap.NewOrderedMap() + for i := 0; i < 10000000; i++ { + m.Set(i, true) + } + + return func(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, key := range m.Keys() { + _, v := m.Get(key) + nothing(v) + } + } + } +} + +func BenchmarkBigOrderedMap_Iterate(b *testing.B) { + benchmarkBigOrderedMap_Iterate()(b) +} + +func benchmarkBigMapString_Set() func(b *testing.B) { + return func(b *testing.B) { + for j := 0; j < b.N; j++ { + m := make(map[string]bool) + a := "1234567" + for i := 0; i < 10000000; i++ { + m[a+strconv.Itoa(i)] = true + } + } + } +} + +func BenchmarkBigMapString_Set(b *testing.B) { + benchmarkBigMapString_Set()(b) +} + +func benchmarkBigOrderedMapString_Set() func(b *testing.B) { + return func(b *testing.B) { + for j := 0; j < b.N; j++ { + m := orderedmap.NewOrderedMap() + a := "1234567" + for i := 0; i < 10000000; i++ { + m.Set(a+strconv.Itoa(i), true) + } + } + } +} + +func BenchmarkBigOrderedMapString_Set(b *testing.B) { + benchmarkBigOrderedMapString_Set()(b) +} + +func benchmarkBigMapString_Get() func(b *testing.B) { + m := make(map[string]bool) + a := "1234567" + for i := 0; i < 10000000; i++ { + m[a+strconv.Itoa(i)] = true + } + + return func(b *testing.B) { + for j := 0; j < b.N; j++ { + for i := 0; i < 10000000; i++ { + _ = m[a+strconv.Itoa(i)] + } + } + } +} + +func BenchmarkBigMapString_Get(b *testing.B) { + benchmarkBigMapString_Get()(b) +} + +func benchmarkBigOrderedMapString_Get() func(b *testing.B) { + m := orderedmap.NewOrderedMap() + a := "1234567" + for i := 0; i < 10000000; i++ { + m.Set(a+strconv.Itoa(i), true) + } + + return func(b *testing.B) { + for j := 0; j < b.N; j++ { + for i := 0; i < 10000000; i++ { + m.Get(a + strconv.Itoa(i)) + } + } + } +} + +func BenchmarkBigOrderedMapString_Get(b *testing.B) { + benchmarkBigOrderedMapString_Get()(b) +} + +func benchmarkBigMapString_Iterate() func(b *testing.B) { + m := make(map[string]bool) + a := "12345678" + for i := 0; i < 10000000; i++ { + m[a+strconv.Itoa(i)] = true + } + return func(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, v := range m { + nothing(v) + } + } + } +} +func BenchmarkBigMapString_Iterate(b *testing.B) { + benchmarkBigMapString_Iterate()(b) +} + +func benchmarkBigOrderedMapString_Iterate() func(b *testing.B) { + m := orderedmap.NewOrderedMap() + a := "12345678" + for i := 0; i < 10000000; i++ { + m.Set(a+strconv.Itoa(i), true) + } + + return func(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, key := range m.Keys() { + _, v := m.Get(key) + nothing(v) + } + } + } +} + +func BenchmarkBigOrderedMapString_Iterate(b *testing.B) { + benchmarkBigOrderedMapString_Iterate()(b) +} + +func BenchmarkAll(b *testing.B) { + b.Run("BenchmarkOrderedMap_Keys", BenchmarkOrderedMap_Keys) + + b.Run("BenchmarkOrderedMap_Set", BenchmarkOrderedMap_Set) + b.Run("BenchmarkMap_Set", BenchmarkMap_Set) + b.Run("BenchmarkOrderedMap_Get", BenchmarkOrderedMap_Get) + b.Run("BenchmarkMap_Get", BenchmarkMap_Get) + b.Run("BenchmarkOrderedMap_Delete", BenchmarkOrderedMap_Delete) + b.Run("BenchmarkMap_Delete", BenchmarkMap_Delete) + b.Run("BenchmarkOrderedMap_Iterate", BenchmarkOrderedMap_Iterate) + b.Run("BenchmarkMap_Iterate", BenchmarkMap_Iterate) + + b.Run("BenchmarkBigMap_Set", BenchmarkBigMap_Set) + b.Run("BenchmarkBigOrderedMap_Set", BenchmarkBigOrderedMap_Set) + b.Run("BenchmarkBigMap_Get", BenchmarkBigMap_Get) + b.Run("BenchmarkBigOrderedMap_Get", BenchmarkBigOrderedMap_Get) + b.Run("BenchmarkBigOrderedMap_Iterate", BenchmarkBigOrderedMap_Iterate) + b.Run("BenchmarkBigMap_Iterate", BenchmarkBigMap_Iterate) + + b.Run("BenchmarkOrderedMapString_Set", BenchmarkOrderedMapString_Set) + b.Run("BenchmarkMapString_Set", BenchmarkMapString_Set) + b.Run("BenchmarkOrderedMapString_Get", BenchmarkOrderedMapString_Get) + b.Run("BenchmarkMapString_Get", BenchmarkMapString_Get) + b.Run("BenchmarkOrderedMapString_Delete", BenchmarkOrderedMapString_Delete) + b.Run("BenchmarkMapString_Delete", BenchmarkMapString_Delete) + b.Run("BenchmarkOrderedMapString_Iterate", BenchmarkOrderedMapString_Iterate) + b.Run("BenchmarkMapString_Iterate", BenchmarkMapString_Iterate) + + b.Run("BenchmarkBigMapString_Set", BenchmarkBigMapString_Set) + b.Run("BenchmarkBigOrderedMapString_Set", BenchmarkBigOrderedMapString_Set) + b.Run("BenchmarkBigMapString_Get", BenchmarkBigMapString_Get) + b.Run("BenchmarkBigOrderedMapString_Get", BenchmarkBigOrderedMapString_Get) + b.Run("BenchmarkBigOrderedMapString_Iterate", BenchmarkBigOrderedMapString_Iterate) + b.Run("BenchmarkBigMapString_Iterate", BenchmarkBigMapString_Iterate) +}