py/modmicropython: Add micropython.memmove() and micropython.memset(). #12487
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This was based on a discussion about providing a more optimal way to copy data between buffers, however based on benchmarks so far it seems like it might not be worth it compared to optimising "copy to/from slice" code paths written in idiomatic Python.
Summary
Adds two functions to
micropython
module, gated behind a new config option:micropython.memmove(dest, dest_idx, src, src_idx, [len])
- an optimised equivalent ofdest[dest_idx:dest_idx+len] = src[src_idx:src_idx+len]
. Copies memory contents with semantics of Cmemmove
, hence the name.len
argument is optional, length defaults to the minimum of the length of the source and destination regions.micropython.memset(dest, dest_idx=0, c=0, len=len(dest)-dest_idx)
- an optimised equivalent ofdest[dest_idx:] = bytes([c]*len)
. Modelled on C'smemset
.Unlike assigning to a slice, the destination buffer size never changes as a result of calling either of these functions. Out of bounds assignment raises an exception.
Benchmarks - memmove
Comparing memmove to current MicroPython "best practices" (unix port, i5-1248P CPU):
Honestly I found this a little underwhelming! Admittedly,
slice_copy-6-memmove.py
can do the equivalent ofslice_copy-5-lvalue_rvalue_memoryview.py
(slices on both sides of the assignment) and it's almost twice as fast, but it's only twice as fast (in a tight loop that does nothing else, working with pretty short buffers.)Maybe the C implementation of memmove() needs some tweaks to streamline the error checking 🤷 .
When rebased against PR #10160 things get even closer:
Now
slice_copy-6-memmove.py
is only 1.6x faster thanslice_copy-5-lvalue_rvalue_memoryview.py
, and no faster than assigning a buffer to an lvalue slice...Benchmarks - memset
Kind of the same story with memset, writing out a bytes array (which can be frozen to flash) is basically as fast as using the
memset()
function. The naive versions of this are a lot slower, though!Disclaimer: The new test file names take some liberties with the meaning of
lvalue
andrvalue
, happy to take suggestions for more accurate term to use.This work was funded through GitHub Sponsors.