From eb7bd7b99bd0770f7f9b241c525c58040a7ee14f Mon Sep 17 00:00:00 2001 From: Evgeniy Stratonikov Date: Mon, 12 Jul 2021 14:12:00 +0300 Subject: [PATCH] core: optimize `storageFind` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Because `Map` stores elements in arbitrary order, addition of new element takes linear time (`Index` iterates over all keys). Thus our `storageFind` is actually quadratic in time. Optimize this by creating map from sorted slice. ``` name old time/op new time/op delta StorageFind-8 157µs ± 2% 112µs ± 1% -28.60% (p=0.000 n=10+10) name old alloc/op new alloc/op delta StorageFind-8 69.4kB ± 0% 60.5kB ± 0% -12.90% (p=0.000 n=9+10) name old allocs/op new allocs/op delta StorageFind-8 2.21k ± 0% 2.00k ± 0% -9.37% (p=0.000 n=10+7) ``` Signed-off-by: Evgeniy Stratonikov --- pkg/core/interop_system.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/pkg/core/interop_system.go b/pkg/core/interop_system.go index e009fa778..e7578180f 100644 --- a/pkg/core/interop_system.go +++ b/pkg/core/interop_system.go @@ -192,18 +192,23 @@ func storageFind(ic *interop.Context) error { return err } - filteredMap := stackitem.NewMap() + arr := make([]stackitem.MapElement, 0, len(siMap)) for k, v := range siMap { - key := append(prefix, []byte(k)...) - keycopy := make([]byte, len(key)) - copy(keycopy, key) - filteredMap.Add(stackitem.NewByteArray(keycopy), stackitem.NewByteArray(v)) + keycopy := make([]byte, len(k)+len(prefix)) + copy(keycopy, prefix) + copy(keycopy[len(prefix):], k) + arr = append(arr, stackitem.MapElement{ + Key: stackitem.NewByteArray(keycopy), + Value: stackitem.NewByteArray(v), + }) } - sort.Slice(filteredMap.Value().([]stackitem.MapElement), func(i, j int) bool { - return bytes.Compare(filteredMap.Value().([]stackitem.MapElement)[i].Key.Value().([]byte), - filteredMap.Value().([]stackitem.MapElement)[j].Key.Value().([]byte)) == -1 + sort.Slice(arr, func(i, j int) bool { + k1 := arr[i].Key.Value().([]byte) + k2 := arr[j].Key.Value().([]byte) + return bytes.Compare(k1, k2) == -1 }) + filteredMap := stackitem.NewMapWithValue(arr) item := istorage.NewIterator(filteredMap, len(prefix), opts) ic.VM.Estack().PushVal(stackitem.NewInterop(item))