Memory allocation for lists of different types

C programming, build, interpreter/VM.
Target audience: MicroPython Developers.
Post Reply
amvasil
Posts: 3
Joined: Thu Jun 20, 2019 9:41 am

Memory allocation for lists of different types

Post by amvasil » Thu Jun 20, 2019 10:02 am

Hello!

I'm working on a port of MicroPython for the CC1312 chip. MicroPython is used as an embedded scripting engine: I compile some Python code using cross compiler and lauch it in a separate thread running MicroPython VM. I need to pass some data between the python environment and the main C program, so I'm looking into micropython data types implementation.

In classic python lists store references to the elements, and the elements of list are stored somewhere separately, as described in https://www.laurentluce.com/posts/pytho ... mentation/ . Possibly, small integers may be an exception because python may pre-allocate them in constant memory.

So here comes the question:

The following code creates a list of large integers:
[code]
lst = [1000000] * 200
for i in range(0,200):
lst[i] = i + 1000000

print(lst[0])
[/code]
and this code requires 1200 bytes of heap memory, which means the 200-element list uses only 800 bytes (4 bytes per element). This should mean, if I'm correct, that the integer values are somehow stored directly in list, because if list was storing references, the required space must have been bigger, at least by sizeof(reference)*N.

If i modify the code to use floats:
[code]
lst = [1000000.0] * 200
for i in range(0,200):
lst[i] = i + 1000000.0

print(lst[0])
[/code]
code uses 4448 bytes, which means lists uses 4000 bytes to store data, and single value needs 4000/200 = 20 bytes. This is probably size of references in the list and the actual values stored separately, which seems to be the expected result.

memory usage is provided by gc debug output

So, how are lists of different types stored in memory in MicroPython?

stijn
Posts: 735
Joined: Thu Apr 24, 2014 9:13 am

Re: Memory allocation for lists of different types

Post by stijn » Thu Jun 20, 2019 11:43 am

I compile some Python code using cross compiler and lauch it in a separate thread running MicroPython VM
Just wondering, why did you chose this approach? If you have the memory for it, you could also do dimpler and possibly faster things like passing a string containing all code into execute_from lexer.

As for your question:in MicroPython lists do store 'references', more specifically mp_obj_t instances and mp_obj_t is something like void*. And possibly depending on configuration options for your particular port, small integers are stored directly into mp_obj_t whereas floating point numbers are not (in which case mp_obj_t is a pointer to the object storing the number).

amvasil
Posts: 3
Joined: Thu Jun 20, 2019 9:41 am

Re: Memory allocation for lists of different types

Post by amvasil » Thu Jun 20, 2019 12:26 pm

Hi stijn!

Thanks for the detailed reply!

1. About cross compiler usage - the goal was not to include compiler code into MCU firmware to save code space. Also, as far as I understand, the code is executed as follows:

(1) string containing python script text => (2) compilation => (3) VM bytecodes -> (4) VM engine

and I do 1 and 2 steps on a PC, pass bytecodes array to the MCU and then execute it. This seems to be faster, since first steps are performed on a PC. The top-level idea here is to enable cc1312 to execute small scripts which it receives over the air. Compiled code is smaller than program text.

2. OK, the behaviour is clear. I'm troubled with finding the exact code and config options which control storing values directly inside list object. Probably I need to go deeper.
Maybe it is possible to store not only 32-bit ints, but also 32-bit floats inside lists? This would massively improve my code's performance

User avatar
jimmo
Posts: 2754
Joined: Tue Aug 08, 2017 1:57 am
Location: Sydney, Australia
Contact:

Re: Memory allocation for lists of different types

Post by jimmo » Thu Jun 20, 2019 12:52 pm

amvasil wrote:
Thu Jun 20, 2019 12:26 pm
I'm troubled with finding the exact code and config options which control storing values directly inside list object.
As stjin said, the lists store mp_obj_t, so I think probably a good place to start is how the representation of mp_obj_t works. Probably a good place to start is to look at the top of py/mpconfig.h where the `MICROPY_OBJ_REPR_A/B/C/D` definitions are. Different ports use different representations (due to various constraints), but in particular, representations C and D can encode floats.

stijn
Posts: 735
Joined: Thu Apr 24, 2014 9:13 am

Re: Memory allocation for lists of different types

Post by stijn » Thu Jun 20, 2019 1:19 pm

amvasil wrote:
Thu Jun 20, 2019 12:26 pm
the goal was not to include compiler code into MCU firmware to save code space
yes, makes sense.

Also check py/obj.h for actual implementation of the object representation/packing etc.

amvasil
Posts: 3
Joined: Thu Jun 20, 2019 9:41 am

Re: Memory allocation for lists of different types

Post by amvasil » Fri Jun 21, 2019 6:08 am

Added line into mpconfigport.h:

#define MICROPY_OBJ_REPR (MICROPY_OBJ_REPR_C)

now a list of 200 float values takes 800 bytes in heap, which is exactly what was needed.

Thanks!

Post Reply