Major Refactor for MicroPython Efficiency (v2.0.0)#2
Major Refactor for MicroPython Efficiency (v2.0.0)#2tadeubas wants to merge 31 commits intoselfcustody:masterfrom
Conversation
Benchmark Results (MicroPython)The firmware size reduction with The benchmark uses arbitrary input data (81 bytes) multiplied by a scale factor to stress execution time and memory usage. In
Benchmark Setup
from krux.wdt import wdt
wdt.stop()
import time
import gc
gc.collect()
print("\n\n------ start foundation-ur-py test\n\n")
# memory control
mem_list = []
mem_list.append(gc.mem_free())
from ur.cbor_lite import CBOREncoder, CBORDecoder
from ur.ur_decoder import URDecoder
from ur.ur_encoder import UREncoder
from ur.ur import UR
scale_factor = 1
data = b'1234567890abcdefghijklmnopqrstuvwxyz-=+_/.,;:ABCDEFGHIJKLMNOPQRSTUVWXYZ0987654321'
data = data * scale_factor
# time control
time_b = time.ticks_ms()
# Encode CBOR
cbor_enc = CBOREncoder()
cbor_enc.encodeBytes(data)
# memory control
mem_list.append(gc.mem_free())
encoded = cbor_enc.get_bytes()
#print("CBOREncoder")
#print(encoded)
# memory control
mem_list.append(gc.mem_free())
## Decode CBOR
cbor_dec = CBORDecoder(encoded)
# memory control
mem_list.append(gc.mem_free())
decoded, _ = cbor_dec.decodeBytes()
# memory control
mem_list.append(gc.mem_free())
decoded = bytes(decoded)
#print("\nCBORDecoder")
#print(decoded)
#assert(data == decoded)
# memory control
mem_list.append(gc.mem_free())
# ----------
# UR
ur_obj = UR("bytes", encoded)
#print("\nUR:", ur_obj.type, ur_obj.cbor)
# memory control
mem_list.append(gc.mem_free())
# single-UR
ur_encoded_data = UREncoder.encode(ur_obj)
#print("\nUREncoder")
#print(ur_encoded_data)
# memory control
mem_list.append(gc.mem_free())
decoded_ur_obj = URDecoder.decode(ur_encoded_data)
#print("\nURDecoder")
#print(decoded_ur_obj.type, decoded_ur_obj.cbor)
#assert(ur_obj.type == decoded_ur_obj.type)
#assert(ur_obj.cbor == decoded_ur_obj.cbor)
# memory control
mem_list.append(gc.mem_free())
## -----------
encoder = UREncoder(ur_obj, 100, 0)
# memory control
mem_list.append(gc.mem_free())
decoder = URDecoder()
i = 0
while True:
part = encoder.next_part()
# every 3 parts misses 1
if i % 3 != 0:
decoder.receive_part(part)
# print(decoder.fountain_decoder.received_part_indexes, decoder.fountain_decoder.processed_parts_count, decoder.fountain_decoder.expected_part_indexes, decoder.expected_part_count())
if(decoder.is_complete()):
break
i+=1
#print("\nMultipart (fountain) encoder/decoder")
#print(decoder.result.type, decoder.result.cbor)
#assert ur_obj.type == decoder.result.type
#assert ur_obj.cbor == decoder.result.cbor
# -------------
time_a = time.ticks_ms()
mem_list.append(gc.mem_free())
print("data scale factor: %d - total len: %d" % (scale_factor, len(data) * scale_factor))
print("\n------\n")
print("time before:", time_b)
print("time after:", time_a)
print("diff time:", time_a - time_b)
print("\n------\n")
mem_before = mem_list[0]
for val in mem_list:
gc_called_str = ""
mem_diff = "diff: %d" % (mem_before - val)
if val > mem_before and mem_before != 0:
gc_called_str = "GC was called!"
print("mem value:", val, mem_diff, gc_called_str)
mem_before = val
print("diff mem (first - last):", mem_list[0] - mem_list[-1])
print("\n\n------ end foundation-ur-py test\n\n") |
|
v0.1.0: data scale factor: 1 - total len: 81 time before: 14164 mem value: 1451776 diff: 0 ------ end foundation-ur-py test data scale factor: 3 - total len: 729 time before: 6960 mem value: 1451776 diff: 0 ------ end foundation-ur-py test data scale factor: 10 - total len: 8100 time before: 6711 mem value: 1451776 diff: 0 ------ end foundation-ur-py test data scale factor: 15 - total len: 18225 time before: 8735 mem value: 1451776 diff: 0 ------ end foundation-ur-py test data scale factor: 20 - total len: 32400 time before: 12980 mem value: 1451776 diff: 0 ------ end foundation-ur-py test data scale factor: 100 - total len: 810000 time before: 74838 mem value: 1382496 diff: 0 ------ end foundation-ur-py test data scale factor: 200 - total len: 3240000 time before: 8950 mem value: 1451776 diff: 0 ------ end foundation-ur-py test |
v2.0.0:------ start foundation-ur-py test data scale factor: 1 - total len: 81 time before: 253936 mem value: 1451776 diff: 0 ------ end foundation-ur-py test data (243) scale factor: 3 - total len: 729 time before: 9527 mem value: 1451776 diff: 0 ------ end foundation-ur-py test data scale factor: 10 - total len: 8100 time before: 535900 mem value: 1451360 diff: 0 ------ end foundation-ur-py test data scale factor: 15 - total len: 18225 time before: 215864 mem value: 1451776 diff: 0 ------ end foundation-ur-py test data scale factor: 20 - total len: 32400 time before: 7602 mem value: 1451776 diff: 0 ------ end foundation-ur-py test data scale factor: 100 - total len: 810000 time before: 7109 mem value: 1451776 diff: 0 ------ end foundation-ur-py test data scale factor: 200 - total len: 3240000 time before: 64497 mem value: 1378720 diff: 0 ------ end foundation-ur-py test |
0446558 to
74cc6a5
Compare
74cc6a5 to
562a019
Compare
7550a79 to
49a10f6
Compare
|
Finished optimizations, values are ~10% better than tests exposed above 👍 |
|
Krux firmware changes needed:
Almost all of those changes are made on this PR: selfcustody/krux#825 |
160eade to
d3fd09c
Compare
This PR introduces breaking changes and should be released as v2.0.0.
Benchmarks are detailed below. This achieves: firmware size reduction, less RAM usage and fast code execution!
This PR removes ~600 lines of code (without new lines from tests and poetry.lock)
Summary of Changes
Split
bytewords.pyinto two focused modules, following the library’s usage pattern (encode and decode are rarely needed together):bytewords_encode.pybytewords_decode.pyUnified decoder architecture:
ur_decoder.pyandfountain_decoder.pyto share a common base class,BasicDecoder.Simplified CRC handling:
crc32implementation incrc32.pyin favor ofbinascii.crc32, which is already available in Krux.Code cleanup and simplification:
MicroPython optimizations:
Testing and documentation:
README.mdwith revised usage and setup instructions.Tooling additions:
Added development dependencies:
pytestpytest-covpylintvultureblackConfiguration updates:
.pylintrcpoetry.lock