unittest: optimise for code size and memory use#1125
Conversation
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Note that using `if not expr: raise AssertionError(msg)` is pretty much equivalent in terms of bytecode to `assert expr, msg`. But the use of `raise AssertionError` is clearer and means that the code can now be compiled with -O3 and still function. Signed-off-by: Damien George <damien@micropython.org>
|
Note that this PR is at odds with #1105 which adds a lot more features to |
projectgus
left a comment
There was a problem hiding this comment.
Changes look simple to me, that's great it reduces footprint significantly! Should churn the heap a lot less with the string formatting moved into the failure path, too.
|
Thanks for the quick review. I'll let it sit a little in case @andrewleech or someone else has any comments. |
|
Thanks for the heads up, in agree these look like really good improvements! I haven't run the tests, but yes seeing as the module is used in CI here I'm comfortable with that covering most of not all the changes. Most of these changes are really clear and obvious in hindsight, and generally improve readability as well as optimising the size and runtime performance so it's a real win-win for new! |
Summary
Based on discussion and testing in micropython/micropython#16311, this PR applies some optimisations to
unittestto reduce its bytecode size, and reduce the amount of RAM it uses at runtime.msgif neededThe use of
raise AssertionErrorinstead ofassertalso means the module can now be compiled with -O3 and still function correctly (-O3 disables assert expressions!).Testing
Tested on ADAFRUIT_ITSYBITSY_M0_EXPRESS which has about 20k heap memory.
Prior to this change:
__init__.mpyhas size 5795 bytesimport unittestcosts 9648 bytes of heap RAM (measured viag.collect(); micropython.mem_info()before and after import)With this change:
__init__.pymhas size 5516 bytes (-279 byte change)import unittestcosts 9440 bytes (-208 byte change)Also, the current version of
unittestunconditionally does string formatting for the error message for each call toself.assert<Condition>(...), which is really expensive in terms of RAM use and computation. The changes here improve the situation so the string formatting ofmsgis only done if the assert fails. That should free up a lot of RAM during the execution.With these changes, ADAFRUIT_ITSYBITSY_M0_EXPRESS can successfully run the tests modified/added in micropython/micropython#16311, they now all pass or skip correctly.
Trade-offs and Alternatives
This module is no longer runnable under CPython due to removal of
tracebackmodule support. But IMO it's too restrictive to get this working under CPython, we need to be able to optimise it for running under MicroPython. The unittest test suite which runs under CI here anyway tests the behaviour, CPython is not needed for that.Generative AI
Not used.