From 280ae83376f867b1f3afbec7ed1c1e0ef3f7934f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Toma=C5=BE=20Jerman?= Date: Wed, 31 Jan 2024 15:38:24 +0100 Subject: [PATCH] Add/tweak tests for TypedVale.Clone --- server/pkg/expr/expr_types.go | 24 +++--- server/pkg/expr/expr_types_test.go | 127 +++++++++++++++++++++++++---- 2 files changed, 123 insertions(+), 28 deletions(-) diff --git a/server/pkg/expr/expr_types.go b/server/pkg/expr/expr_types.go index 7f4b8251b..2b05c4e94 100644 --- a/server/pkg/expr/expr_types.go +++ b/server/pkg/expr/expr_types.go @@ -60,13 +60,13 @@ func (v *Vars) Clone() (out TypedValue, err error) { } if len(v.value) > cloneParallelItemThreshold { - return v.cloneParallel() + return v.cloneParallel(cloneParallelItemThreshold) } - return v.clone() + return v.cloneSeq() } -func (v *Vars) clone() (out TypedValue, err error) { +func (v *Vars) cloneSeq() (out TypedValue, err error) { aux := &Vars{ value: make(map[string]TypedValue, len(v.value)), } @@ -84,7 +84,7 @@ func (v *Vars) clone() (out TypedValue, err error) { return aux, nil } -func (v *Vars) cloneParallel() (out TypedValue, err error) { +func (v *Vars) cloneParallel(threshold int) (out TypedValue, err error) { keys := make([]string, 0, len(v.value)) for k := range v.value { keys = append(keys, k) @@ -94,12 +94,12 @@ func (v *Vars) cloneParallel() (out TypedValue, err error) { errors := make([]error, len(v.value)) wg := sync.WaitGroup{} - for i := 0; i < len(keys); i += cloneParallelItemThreshold { + for i := 0; i < len(keys); i += threshold { wg.Add(1) go func(i int) { defer wg.Done() - for j, k := range keys[i:int(math.Min(float64(i+cloneParallelItemThreshold), float64(len(keys))-1))] { + for j, k := range keys[i:int(math.Min(float64(i+threshold), float64(len(keys))))] { aux, err := v.value[k].Clone() if err != nil { errors[i+j] = err @@ -961,13 +961,13 @@ func (v *Any) Clone() (out TypedValue, err error) { func (v *Array) Clone() (out TypedValue, err error) { if len(v.value) > cloneParallelItemThreshold { - return v.cloneParallel() + return v.cloneParallel(cloneParallelItemThreshold) } - return v.clone() + return v.cloneSeq() } -func (v *Array) clone() (_ TypedValue, err error) { +func (v *Array) cloneParallel(threshold int) (_ TypedValue, err error) { errors := make([]error, len(v.value)) wg := sync.WaitGroup{} @@ -975,12 +975,12 @@ func (v *Array) clone() (_ TypedValue, err error) { value: make([]TypedValue, len(v.value)), } - for i := 0; i < len(v.value); i += cloneParallelItemThreshold { + for i := 0; i < len(v.value); i += threshold { wg.Add(1) go func(i int) { defer wg.Done() - for j, v := range v.value[i:int(math.Min(float64(i+cloneParallelItemThreshold), float64(len(v.value))-1))] { + for j, v := range v.value[i:int(math.Min(float64(i+threshold), float64(len(v.value))))] { aux, err := v.Clone() if err != nil { errors[i+j] = err @@ -1002,7 +1002,7 @@ func (v *Array) clone() (_ TypedValue, err error) { return out, nil } -func (v *Array) cloneParallel() (out TypedValue, err error) { +func (v *Array) cloneSeq() (out TypedValue, err error) { aux := &Array{ value: make([]TypedValue, len(v.value)), } diff --git a/server/pkg/expr/expr_types_test.go b/server/pkg/expr/expr_types_test.go index c74bb94c6..14adf85db 100644 --- a/server/pkg/expr/expr_types_test.go +++ b/server/pkg/expr/expr_types_test.go @@ -551,31 +551,126 @@ func TestArrayDecode(t *testing.T) { req.Len(foo.Values, 2) } +func TestVarsClone(t *testing.T) { + var ( + req = require.New(t) + + v = &Vars{ + value: map[string]TypedValue{ + "a1": Must(NewInteger(1)), + "a2": Must(NewInteger(2)), + "a3": Must(NewInteger(3)), + "a4": Must(NewInteger(4)), + "a5": Must(NewInteger(5)), + "a6": Must(NewInteger(6)), + "a7": Must(NewInteger(7)), + "a8": Must(NewInteger(8)), + "a9": Must(NewInteger(9)), + "a10": Must(NewInteger(10)), + }, + } + ) + + check := func(out TypedValue, err error) { + req.NoError(err) + outVars := out.(*Vars) + req.Len(outVars.value, len(v.value)) + + for k, v := range v.value { + req.Contains(outVars.value, k) + req.Equal(v.Get(), outVars.value[k].Get()) + } + } + + t.Run("sequential", func(t *testing.T) { + check(v.cloneSeq()) + }) + + t.Run("parallel", func(t *testing.T) { + check(v.cloneParallel(2)) + }) + + t.Run("parallel odd", func(t *testing.T) { + check(v.cloneParallel(3)) + }) + + t.Run("parallel one chunk", func(t *testing.T) { + check(v.cloneParallel(11)) + }) +} + +func TestArrayClone(t *testing.T) { + var ( + req = require.New(t) + + vv = &Array{ + value: []TypedValue{ + Must(NewInteger(1)), + Must(NewInteger(2)), + Must(NewInteger(3)), + Must(NewInteger(4)), + Must(NewInteger(5)), + Must(NewInteger(6)), + Must(NewInteger(7)), + Must(NewInteger(8)), + Must(NewInteger(9)), + Must(NewInteger(10)), + }, + } + ) + + check := func(out TypedValue, err error) { + req.NoError(err) + outArray := out.(*Array) + req.Len(outArray.value, len(vv.value)) + + for i, v := range vv.value { + req.Equal(v.Get(), outArray.value[i].Get()) + } + } + + t.Run("sequential", func(t *testing.T) { + check(vv.cloneSeq()) + }) + + t.Run("parallel", func(t *testing.T) { + check(vv.cloneParallel(2)) + }) + + t.Run("parallel odd", func(t *testing.T) { + check(vv.cloneParallel(3)) + }) + + t.Run("parallel one chunk", func(t *testing.T) { + check(vv.cloneParallel(11)) + }) +} + // Original // goos: darwin // goarch: arm64 // pkg: github.com/cortezaproject/corteza/server/pkg/expr -// BenchmarkVarsUnref_10_10-12 2623 459222 ns/op 370399 B/op 4886 allocs/op -// BenchmarkVarsUnref_100_100-12 25 46813440 ns/op 42108291 B/op 453755 allocs/op -// BenchmarkVarsUnref_1000_1000-12 1 4572438792 ns/op 4004143648 B/op 45064443 allocs/op +// BenchmarkVarsClone_10_10-12 2623 459222 ns/op 370399 B/op 4886 allocs/op +// BenchmarkVarsClone_100_100-12 25 46813440 ns/op 42108291 B/op 453755 allocs/op +// BenchmarkVarsClone_1000_1000-12 1 4572438792 ns/op 4004143648 B/op 45064443 allocs/op // Reworked, all seq. // goos: darwin // goarch: arm64 // pkg: github.com/cortezaproject/corteza/server/pkg/expr -// BenchmarkVarsUnref_10_10-12 37764 31204 ns/op 90607 B/op 859 allocs/op -// BenchmarkVarsUnref_100_100-12 303 3630116 ns/op 9128270 B/op 80430 allocs/op -// BenchmarkVarsUnref_1000_1000-12 3 372980819 ns/op 898107160 B/op 8004031 allocs/op +// BenchmarkVarsClone_10_10-12 37764 31204 ns/op 90607 B/op 859 allocs/op +// BenchmarkVarsClone_100_100-12 303 3630116 ns/op 9128270 B/op 80430 allocs/op +// BenchmarkVarsClone_1000_1000-12 3 372980819 ns/op 898107160 B/op 8004031 allocs/op // Reworked, seq threshold to parallel // goos: darwin // goarch: arm64 // pkg: github.com/cortezaproject/corteza/server/pkg/expr -// BenchmarkVarsUnref_10_10-12 35852 33396 ns/op 90606 B/op 859 allocs/op -// BenchmarkVarsUnref_100_100-12 320 3692905 ns/op 9128270 B/op 80430 allocs/op -// BenchmarkVarsUnref_1000_1000-12 7 175036667 ns/op 946114581 B/op 8003063 allocs/op +// BenchmarkVarsClone_10_10-12 35852 33396 ns/op 90606 B/op 859 allocs/op +// BenchmarkVarsClone_100_100-12 320 3692905 ns/op 9128270 B/op 80430 allocs/op +// BenchmarkVarsClone_1000_1000-12 7 175036667 ns/op 946114581 B/op 8003063 allocs/op -func benchmarkVarsUnref(b *testing.B, rootCount, nestedCount int) { +func benchmarkVarsClone(b *testing.B, rootCount, nestedCount int) { nest := &Vars{ value: map[string]TypedValue{}, } @@ -622,14 +717,14 @@ func benchmarkVarsUnref(b *testing.B, rootCount, nestedCount int) { } } -func BenchmarkVarsUnref_10_10(b *testing.B) { - benchmarkVarsUnref(b, 10, 10) +func BenchmarkVarsClone_10_10(b *testing.B) { + benchmarkVarsClone(b, 10, 10) } -func BenchmarkVarsUnref_100_100(b *testing.B) { - benchmarkVarsUnref(b, 100, 100) +func BenchmarkVarsClone_100_100(b *testing.B) { + benchmarkVarsClone(b, 100, 100) } -func BenchmarkVarsUnref_1000_1000(b *testing.B) { - benchmarkVarsUnref(b, 1000, 1000) +func BenchmarkVarsClone_1000_1000(b *testing.B) { + benchmarkVarsClone(b, 1000, 1000) }