Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Discussion options

While working with frozen modules to save RAM, I noticed that a fun_bc object is still allocated in RAM for every defined method..
If I am not mistaken, except in the cases where there are non-const default arguments, this object could also be frozen.

Would it make sense to add an LOAD_FUNCTION opcode that pushes a pre-cooked fun_bc object onto the stack, instead of using MAKE_FUNCTION which allocates it on the heap, or do you foresee a problem with that idea ?

You must be logged in to vote

Replies: 3 comments

Comment options

I gave it a try, and in my use-case, there is indeed a huge improvement in RAM usage. It might not benefit the same for everyone, though. Here is the context:

  • My build provides a relatively large library as frozen Python code (about 1'000 functions and methods)
  • My build enables SYS_SETTRACE, in order to allow the end-user to debug his Python source code via VisualStudio Code

The memory footprint penalty for this combination is huge:

  • the mp_bytecode_prelude_t structure added for SYS_SETTRACE includes several dwords for storing the decoded function signature info. Using dwords in that structure is an overkill, and some fields are never actually used as far as I could find. Overall, there is a potential for saving 32 bytes per python function defined (in code for frozen function, or in RAM for dynamically loaded functions) by optimizing the storage of mp_raw_code_t
  • the mp_obj_fun_bc_t structure uses two gc allocation units for each function, due to the extra reference to the mp_raw_code_t required by SYS_SETTRACE. However the bytecode and child_table fields in this structure are redundant in that case, and it is easy to reduce the structure to one gc allocation unit per function, saving 16 bytes of RAM per function.
  • implementing frozen mp_obj_fun_bc_t objects when there is no default argument was actually easy, without any change to the bytecode or to the compiler. It only require a change to mpy-tool and a shortcut path in mp_make_function_from_proto_fun. There is a small drawback however: it involves an overhead to access the function context, as I need to keep an indirect pointer to the context object for each frozen module. But that makes it possible to reduce the RAM usage for loading frozen functions to zero byte.

The overall results:

  • I started from a build with 185 KB of rodata for frozen modules. Loading my main frozen library used 36KB RAM (for defining classes involving about 600 methods).
  • After my optimizations, I ended up with 162 KB of rodata for frozen modules, and only 17KB RAM used after loading my main library.

Total savings: 20 KB flash, 20 KB RAM...

You must be logged in to vote
0 replies
Comment options

Josverl
Oct 22, 2025
Collaborator Sponsor

That seems good progress.
reducing the overhead of settrace will make that more approachable , so I hope you will raise a PR for this.

You must be logged in to vote
0 replies
Comment options

Will do, I just wanted first to check if anyone was interested or if it was just me...

You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Category
💡
Ideas
Labels
None yet
2 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.