← index #4081PR #3448
Related · high · value 0.584
QUERY · ISSUE

Scoped allocation

openby adritiumopened 2018-08-27updated 2024-09-19
enhancement

@dpgeorge's comment is from here:

I'm thinking: @micropython.temp serves as a context which results in a C-call to switch a malloc function

Yes, I think this is a pretty decent idea. I had a similar idea for a while which is "scoped allocation", whereby all allocations within a function call are allocated in a new "heap scope", and then the entire scope is freed upon exit of the function. Eg:

@micropython.heap_on_stack(200)
def foo(x, y):
l = [x, y]
return len(l)
The idea here is that the function foo() is wrapped in a new heap and the semantics of calling foo are:

200 bytes are allocated on the C stack and used to create a temporary "heap"
allocation on this heap is simply a matter of incrementing a pointer and checking that it didn't go beyond the extents (of 200 bytes in this case); there is no GC'ing of this temporary heap
all malloc/free functions in the runtime are switched to use this temporary heap for the duration of the foo execution
the function foo runs, allocates a new list, computes its length, and returns this integer
as foo returns the temporary heap is destroyed, along with all objects created on it (in this case the list l)
the result of foo is a small int and doesn't need the heap and is returned to the caller
The execution of foo is highly deterministic, in terms of memory use and execution time. Using scoped allocation allows you to allocate in a hard interrupt. The downside of this approach is that foo must not leak any scope-allocated objects into the outer scope, because these objects won't exist once foo returns. Note also that you can nest the allocation scopes.

CANDIDATE · PULL REQUEST

Add 3rd memory region: a global Python stack for scoped allocation

mergedby dpgeorgeopened 2017-11-20updated 2017-12-13

This patch introduces the MICROPY_ENABLE_PYSTACK option (disabled by default) which enables a "Python stack" that allows to allocate and free memory in a scoped way, similar to alloca(). When MICROPY_ENABLE_PYSTACK is enabled then alloca() is no longer required or used.

The benefits of enabling this option are:

  • Toolchains without alloca() can use this feature to obtain correct and efficient scoped memory allocation (compared to using the heap instead of alloca(), which is slower). The heapless properties of uPy still hold without the use of alloca (eg you can call functions without allocating on the heap).
  • Even if alloca() is available, enabling the Py-stack gives slightly more efficient use of stack space when calling nested Python functions, due to the way that compilers implement alloca().
  • Enabling the Py-stack with the stackless mode allows for even more efficient stack usage, as well as retaining high performance (because the heap is no longer used to build and destroy stackless code states).
  • With Py-stack and stackless enabled, Python-calling-Python is no longer recursive in the C mp_execute_bytecode function.
  • With Py-stack enabled it's now possible to do calls of the form f(*arg) and f(**kw) without allocating on the heap.

The micropython.pystack_use() function is included to measure usage of the Python stack.

To use the Python stack:

  • enable MICROPY_ENABLE_PYSTACK compile-time option
  • allocate some RAM (statically) for the Python stack region (1-2k bytes seems good)
  • call mp_pystack_init(region_start, region_end) before calling mp_init()
  • optionally enable MICROPY_STACKLESS and MICROPY_STACKLESS_STRICT

It may be possible in the future for bare-metal systems to use the other end of the C stack for the Python stack (C stack grows down, Python stack grows up). This way it wouldn't require to have a separate region for the Python stack and allows to make maximum use of the stack region. But that's a feature for the future.

Note that I called this new feature a "Python stack" because it originated from the desire to get the stackless mode of uPy working without needing to allocate on the heap, and so the new memory region was exclusively used for the Python stack when calling Python functions. But it now turned into a generic "scoped allocation" mechanism, so it might be an idea to change the naming to reflect that.

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied