Small deserialization speedup (#2852)

When walking AriVtx, parsing integers and nibbles actually becomes a
hotspot - these trivial changes reduces CPU usage during initial key
cache computation by ~15%.
This commit is contained in:
Jacek Sieka 2024-11-20 16:04:32 +01:00 committed by GitHub
parent 3ea5c531d1
commit 6086c2903c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 111 additions and 17 deletions

View File

@ -68,10 +68,12 @@ proc deblobify*[T: uint64|VertexID](data: openArray[byte], _: type T): Result[T,
if data.len < 1 or data.len > 8:
return err(Deblob64LenUnsupported)
var tmp: array[8, byte]
discard tmp.toOpenArray(8 - data.len, 7).copyFrom(data)
var tmp = 0'u64
let start = 8 - data.len
for i in 0..<data.len:
tmp += uint64(data[i]) shl (8*(7-(i + start)))
ok T(uint64.fromBytesBE(tmp))
ok T(tmp)
proc deblobify*(data: openArray[byte], _: type UInt256): Result[UInt256,AristoError] =
if data.len < 1 or data.len > 32:

View File

@ -78,9 +78,9 @@ func slice*(r: NibblesBuf, ibegin: int, iend = -1): NibblesBuf {.noinit.} =
result.iend = e.int8
func replaceSuffix*(r: NibblesBuf, suffix: NibblesBuf): NibblesBuf =
for i in 0..<r.len - suffix.len:
for i in 0 ..< r.len - suffix.len:
result[i] = r[i]
for i in 0..<suffix.len:
for i in 0 ..< suffix.len:
result[i + r.len - suffix.len] = suffix[i]
result.iend = min(64, r.len + suffix.len).int8
@ -122,28 +122,33 @@ func startsWith*(lhs, rhs: NibblesBuf): bool =
func fromHexPrefix*(
T: type NibblesBuf, r: openArray[byte]
): tuple[isLeaf: bool, nibbles: NibblesBuf] =
): tuple[isLeaf: bool, nibbles: NibblesBuf] {.noinit.} =
result.nibbles.ibegin = 0
if r.len > 0:
result.isLeaf = (r[0] and 0x20) != 0
let hasOddLen = (r[0] and 0x10) != 0
var i = 0'i8
if hasOddLen:
result.nibbles[0] = r[0] and 0x0f
i += 1
result.nibbles.iend =
if hasOddLen:
result.nibbles.bytes[0] = r[0] shl 4
for j in 1 ..< r.len:
if i >= 64:
break
result.nibbles[i] = r[j] shr 4
result.nibbles[i + 1] = r[j] and 0x0f
i += 2
let bytes = min(31, r.len - 1)
for j in 0 ..< bytes:
result.nibbles.bytes[j] = result.nibbles.bytes[j] or r[j + 1] shr 4
result.nibbles.bytes[j + 1] = r[j + 1] shl 4
result.nibbles.iend = i
int8(bytes) * 2 + 1
else:
let bytes = min(32, r.len - 1)
assign(result.nibbles.bytes.toOpenArray(0, bytes - 1), r.toOpenArray(1, bytes))
int8(bytes) * 2
else:
result.isLeaf = false
result.nibbles.iend = 0
func `&`*(a, b: NibblesBuf): NibblesBuf {.noinit.} =
result.ibegin = 0
for i in 0 ..< a.len:
result[i] = a[i]

View File

@ -20,6 +20,7 @@ import
./replay/pp,
./test_aristo/test_blobify,
./test_aristo/test_merge_proof,
./test_aristo/test_nibbles,
./test_aristo/test_portal_proof,
./test_aristo/test_compute,
./test_aristo/[

View File

@ -0,0 +1,86 @@
# Nimbus
# Copyright (c) 2024 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or
# distributed except according to those terms.
{.used.}
import
std/sequtils,
stew/byteutils,
unittest2,
../../nimbus/db/aristo/aristo_desc/desc_nibbles
suite "Nibbles":
test "trivial cases":
block:
let n = NibblesBuf.fromBytes([])
check:
n.len == 0
block:
let n = NibblesBuf.fromBytes([byte 0x10])
check:
n.len == 2
n[0] == 1
n[1] == 0
$n.slice(1) == "0"
$n.slice(2) == ""
block:
let n = NibblesBuf.fromBytes(repeat(byte 0x12, 32))
check:
n.len == 64
n[0] == 1
n[63] == 2
block:
let n = NibblesBuf.fromBytes(repeat(byte 0x12, 33))
check:
n.len == 64
n[0] == 1
n[63] == 2
test "to/from hex encoding":
block:
let n = NibblesBuf.fromBytes([byte 0x12, 0x34, 0x56])
let
he = n.toHexPrefix(true)
ho = n.slice(1).toHexPrefix(true)
check:
NibblesBuf.fromHexPrefix(he.data()) == (true, n)
NibblesBuf.fromHexPrefix(ho.data()) == (true, n.slice(1))
block:
let n = NibblesBuf.fromBytes(repeat(byte 0x12, 32))
let
he = n.toHexPrefix(true)
ho = n.slice(1).toHexPrefix(true)
check:
NibblesBuf.fromHexPrefix(he.data()) == (true, n)
NibblesBuf.fromHexPrefix(ho.data()) == (true, n.slice(1))
NibblesBuf.fromHexPrefix(@(he.data()) & @[byte 1]) == (true, n)
NibblesBuf.fromHexPrefix(@(ho.data()) & @[byte 1]) == (true, n.slice(1))
test "long":
let n = NibblesBuf.fromBytes(
hexToSeqByte("0100000000000000000000000000000000000000000000000000000000000000")
)
check $n == "0100000000000000000000000000000000000000000000000000000000000000"
check $n.slice(1) == "100000000000000000000000000000000000000000000000000000000000000"
let
he = n.toHexPrefix(true)
ho = n.slice(1).toHexPrefix(true)
check:
NibblesBuf.fromHexPrefix(he.data()) == (true, n)
NibblesBuf.fromHexPrefix(ho.data()) == (true, n.slice(1))