8000 Optimize flash storage of properties by jepler · Pull Request #6337 · adafruit/circuitpython · GitHub
[go: up one dir, main page]

Skip to content

Optimize flash storage of properties #6337

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and 8000 contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 6, 2022
Merged

Conversation

jepler
Copy link
@jepler jepler commented May 3, 2022

In-flash properties with only a getter or only get+set are organized into two specific memory regions, so that it's possible to tell by their address whether they have 1, 2, or 3 proxy slots available. When accessing a property slot, code is added to check if the desired slot is available -- this affects setter & deleter paths, adding some additional conditional branching, so it probably has a minor negative performance effect as well (which I didn't attempt to measure)

A property with only a getter shrinks from 16 byte (type pointer + 3 proxy slots) to 8 bytes (type pointer + 1 proxy slot); a get+set property shrinks to 12 bytes (type pointer + 2 proxy slots). However, new tests are added in some fast paths, apparently costing ~120 bytes on samd21. Net, 96 bytes are saved on the trinket_m0 build.

Closes: #4899 (except for enabling it on all ports)

jepler added 5 commits May 3, 2022 08:48
Later, these can be changed in cunning ways to save flash storage.
This will enable setting data attributes, namely, the section of the
symbol.
.. and enable it on atmel-samd and raspberrypi. On trinket_m0 this saves
96 net bytes of flash. There are 216 bytes actually saved by reducing
the flash storage size of the property descriptors, but added code in
several paths takes back over half of the 'raw savings'.

By organizing the "get-only" and "get-set" (but no delete) properties
each in a different section, we can represent then more efficiently.

Testing performed: that a get-only property can still be gotten but
can't be set or deleted; that a get-set property can sill be gotten or
set but can't be deleted.  Tested on pygamer.

Because this requires linker file support, I only enabled it on two of
the ports.
@dhalbert
Copy link
Collaborator
dhalbert commented May 4, 2022

This is clever! I have an experiment or two I would like to try before approving.

@dhalbert
Copy link
Collaborator
dhalbert 8000 commented May 4, 2022

I did an experiment on the Trinket M0 build: I just removed the deleter slot from mp_obj_property_t.proxy, and adjusted all the intiializers referenced by the Trinket M0 build. I made no other code changes, so it's not functional, but gives us a lower bound on what would be saved.

Removing the one slot saves 144 bytes. If all the Trinket M0 properties were read-only, which is not true, then the total savings would be 288 bytes. A quick manual count shows ~24 read-only properties. And this is all without any extra code to handle slot removal.

While doing this, I discovered that some code in the samd module was always compiled and linked, even if CIRCUITPY_SAMD was turned off. Despite LTO, some residual code remained. If I removed the unused samd code, I saved 76 bytes. I'll check for other stuff like that.

Copy link
Collaborator
@dhalbert dhalbert left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though we don't save that much on the smallest builds, I think this is a good improvement, and only helps. The macros make it easy to implement. Thanks for this brainstorm!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Save space by removing slots from property proxies when possible
2 participants
0