Skip to content

Commit 6086c29

Browse files
authored
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%.
1 parent 3ea5c53 commit 6086c29

File tree

4 files changed

+111
-17
lines changed

4 files changed

+111
-17
lines changed

nimbus/db/aristo/aristo_blobify.nim

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,12 @@ proc deblobify*[T: uint64|VertexID](data: openArray[byte], _: type T): Result[T,
6868
if data.len < 1 or data.len > 8:
6969
return err(Deblob64LenUnsupported)
7070

71-
var tmp: array[8, byte]
72-
discard tmp.toOpenArray(8 - data.len, 7).copyFrom(data)
71+
var tmp = 0'u64
72+
let start = 8 - data.len
73+
for i in 0..<data.len:
74+
tmp += uint64(data[i]) shl (8*(7-(i + start)))
7375

74-
ok T(uint64.fromBytesBE(tmp))
76+
ok T(tmp)
7577

7678
proc deblobify*(data: openArray[byte], _: type UInt256): Result[UInt256,AristoError] =
7779
if data.len < 1 or data.len > 32:

nimbus/db/aristo/aristo_desc/desc_nibbles.nim

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ func slice*(r: NibblesBuf, ibegin: int, iend = -1): NibblesBuf {.noinit.} =
7878
result.iend = e.int8
7979

8080
func replaceSuffix*(r: NibblesBuf, suffix: NibblesBuf): NibblesBuf =
81-
for i in 0..<r.len - suffix.len:
81+
for i in 0 ..< r.len - suffix.len:
8282
result[i] = r[i]
83-
for i in 0..<suffix.len:
83+
for i in 0 ..< suffix.len:
8484
result[i + r.len - suffix.len] = suffix[i]
8585
result.iend = min(64, r.len + suffix.len).int8
8686

@@ -122,28 +122,33 @@ func startsWith*(lhs, rhs: NibblesBuf): bool =
122122

123123
func fromHexPrefix*(
124124
T: type NibblesBuf, r: openArray[byte]
125-
): tuple[isLeaf: bool, nibbles: NibblesBuf] =
125+
): tuple[isLeaf: bool, nibbles: NibblesBuf] {.noinit.} =
126+
result.nibbles.ibegin = 0
127+
126128
if r.len > 0:
127129
result.isLeaf = (r[0] and 0x20) != 0
128130
let hasOddLen = (r[0] and 0x10) != 0
129131

130-
var i = 0'i8
131-
if hasOddLen:
132-
result.nibbles[0] = r[0] and 0x0f
133-
i += 1
132+
result.nibbles.iend =
133+
if hasOddLen:
134+
result.nibbles.bytes[0] = r[0] shl 4
134135

135-
for j in 1 ..< r.len:
136-
if i >= 64:
137-
break
138-
result.nibbles[i] = r[j] shr 4
139-
result.nibbles[i + 1] = r[j] and 0x0f
140-
i += 2
136+
let bytes = min(31, r.len - 1)
137+
for j in 0 ..< bytes:
138+
result.nibbles.bytes[j] = result.nibbles.bytes[j] or r[j + 1] shr 4
139+
result.nibbles.bytes[j + 1] = r[j + 1] shl 4
141140

142-
result.nibbles.iend = i
141+
int8(bytes) * 2 + 1
142+
else:
143+
let bytes = min(32, r.len - 1)
144+
assign(result.nibbles.bytes.toOpenArray(0, bytes - 1), r.toOpenArray(1, bytes))
145+
int8(bytes) * 2
143146
else:
144147
result.isLeaf = false
148+
result.nibbles.iend = 0
145149

146150
func `&`*(a, b: NibblesBuf): NibblesBuf {.noinit.} =
151+
result.ibegin = 0
147152
for i in 0 ..< a.len:
148153
result[i] = a[i]
149154

tests/test_aristo.nim

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import
2020
./replay/pp,
2121
./test_aristo/test_blobify,
2222
./test_aristo/test_merge_proof,
23+
./test_aristo/test_nibbles,
2324
./test_aristo/test_portal_proof,
2425
./test_aristo/test_compute,
2526
./test_aristo/[

tests/test_aristo/test_nibbles.nim

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
# Nimbus
2+
# Copyright (c) 2024 Status Research & Development GmbH
3+
# Licensed under either of
4+
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
5+
# http://www.apache.org/licenses/LICENSE-2.0)
6+
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
7+
# http://opensource.org/licenses/MIT)
8+
# at your option. This file may not be copied, modified, or
9+
# distributed except according to those terms.
10+
11+
{.used.}
12+
13+
import
14+
std/sequtils,
15+
stew/byteutils,
16+
unittest2,
17+
../../nimbus/db/aristo/aristo_desc/desc_nibbles
18+
19+
suite "Nibbles":
20+
test "trivial cases":
21+
block:
22+
let n = NibblesBuf.fromBytes([])
23+
check:
24+
n.len == 0
25+
block:
26+
let n = NibblesBuf.fromBytes([byte 0x10])
27+
check:
28+
n.len == 2
29+
n[0] == 1
30+
n[1] == 0
31+
$n.slice(1) == "0"
32+
$n.slice(2) == ""
33+
34+
block:
35+
let n = NibblesBuf.fromBytes(repeat(byte 0x12, 32))
36+
check:
37+
n.len == 64
38+
n[0] == 1
39+
n[63] == 2
40+
41+
block:
42+
let n = NibblesBuf.fromBytes(repeat(byte 0x12, 33))
43+
check:
44+
n.len == 64
45+
n[0] == 1
46+
n[63] == 2
47+
48+
test "to/from hex encoding":
49+
block:
50+
let n = NibblesBuf.fromBytes([byte 0x12, 0x34, 0x56])
51+
52+
let
53+
he = n.toHexPrefix(true)
54+
ho = n.slice(1).toHexPrefix(true)
55+
56+
check:
57+
NibblesBuf.fromHexPrefix(he.data()) == (true, n)
58+
NibblesBuf.fromHexPrefix(ho.data()) == (true, n.slice(1))
59+
block:
60+
let n = NibblesBuf.fromBytes(repeat(byte 0x12, 32))
61+
62+
let
63+
he = n.toHexPrefix(true)
64+
ho = n.slice(1).toHexPrefix(true)
65+
66+
check:
67+
NibblesBuf.fromHexPrefix(he.data()) == (true, n)
68+
NibblesBuf.fromHexPrefix(ho.data()) == (true, n.slice(1))
69+
70+
NibblesBuf.fromHexPrefix(@(he.data()) & @[byte 1]) == (true, n)
71+
NibblesBuf.fromHexPrefix(@(ho.data()) & @[byte 1]) == (true, n.slice(1))
72+
73+
test "long":
74+
let n = NibblesBuf.fromBytes(
75+
hexToSeqByte("0100000000000000000000000000000000000000000000000000000000000000")
76+
)
77+
78+
check $n == "0100000000000000000000000000000000000000000000000000000000000000"
79+
check $n.slice(1) == "100000000000000000000000000000000000000000000000000000000000000"
80+
81+
let
82+
he = n.toHexPrefix(true)
83+
ho = n.slice(1).toHexPrefix(true)
84+
check:
85+
NibblesBuf.fromHexPrefix(he.data()) == (true, n)
86+
NibblesBuf.fromHexPrefix(ho.data()) == (true, n.slice(1))

0 commit comments

Comments
 (0)