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 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
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments. < 10000 button type="button" data-view-component="true" class="js-toc-retry btn-link"> Retry
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion extmod/vfs_fat.c
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ STATIC const mp_obj_property_t fat_vfs_label_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&fat_vfs_getlabel_obj,
(mp_obj_t)&fat_vfs_setlabel_obj,
(mp_obj_t)MP_ROM_NONE},
MP_ROM_NONE},
};
#endif

Expand Down
33 changes: 9 additions & 24 deletions ports/atmel-samd/bindings/samd/Clock.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,8 @@ STATIC mp_obj_t samd_clock_get_enabled(mp_obj_t self_in) {

MP_DEFINE_CONST_FUN_OBJ_1(samd_clock_get_enabled_obj, samd_clock_get_enabled);

const mp_obj_property_t samd_clock_enabled_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&samd_clock_get_enabled_obj,
MP_ROM_NONE,
MP_ROM_NONE,},
};
MP_PROPERTY_GETTER(samd_clock_enabled_obj,
(mp_obj_t)&samd_clock_get_enabled_obj);

//| parent: Union[Clock, None]
//| """Clock parent. (read-only)"""
Expand All @@ -82,12 +78,8 @@ STATIC mp_obj_t samd_clock_get_parent(mp_obj_t self_in) {

MP_DEFINE_CONST_FUN_OBJ_1(samd_clock_get_parent_obj, samd_clock_get_parent);

const mp_obj_property_t samd_clock_parent_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&samd_clock_get_parent_obj,
MP_ROM_NONE,
MP_ROM_NONE,},
};
MP_PROPERTY_GETTER(samd_clock_parent_obj,
(mp_obj_t)&samd_clock_get_parent_obj);

//| frequency: int
//| """Clock frequency in Herz. (read-only)"""
Expand All @@ -99,12 +91,8 @@ STATIC mp_obj_t samd_clock_get_frequency(mp_obj_t self_in) {

MP_DEFINE_CONST_FUN_OBJ_1(samd_clock_get_frequency_obj, samd_clock_get_frequency);

const mp_obj_property_t samd_clock_frequency_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&samd_clock_get_frequency_obj,
MP_ROM_NONE,
MP_ROM_NONE,},
};
MP_PROPERTY_GETTER(samd_clock_frequency_obj,
(mp_obj_t)&samd_clock_get_frequency_obj);

//| calibration: int
//| """Clock calibration. Not all clocks can be calibrated."""
Expand All @@ -130,12 +118,9 @@ STATIC mp_obj_t samd_clock_set_calibration(mp_obj_t self_in, mp_obj_t calibratio

MP_DEFINE_CONST_FUN_OBJ_2(samd_clock_set_calibration_obj, samd_clock_set_calibration);

const mp_obj_property_t samd_clock_calibration_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&samd_clock_get_calibration_obj,
(mp_obj_t)&samd_clock_set_calibration_obj,
MP_ROM_NONE,},
};
MP_PROPERTY_GETSET(samd_clock_calibration_obj,
(mp_obj_t)&samd_clock_get_calibration_obj,
(mp_obj_t)&samd_clock_set_calibration_obj);

STATIC const mp_rom_map_elem_t samd_clock_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_enabled), MP_ROM_PTR(&samd_clock_enabled_obj) },
Expand Down
7 changes: 7 additions & 0 deletions ports/atmel-samd/boards/common.template.ld
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ SECTIONS
_sfixed = .;
< E377 /td> KEEP(*(.vectors)) /* isr vector table */

__property_getter_start = .;
*(.property_getter)
__property_getter_end = .;
__property_getset_start = .;
*(.property_getset)
__property_getset_end = .;

/* Sort text sections so that they have fewer *fill* bytes needed. */
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.text))) /* .text sections (code) */
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.text*))) /* .text* sections (code) */
Expand Down
1 change: 1 addition & 0 deletions ports/atmel-samd/mpconfigport.mk
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ INTERNAL_LIBM = 1
USB_NUM_ENDPOINT_PAIRS = 8

CIRCUITPY_ROTARYIO_SOFTENCODER = 1
CIRCUITPY_OPTIMIZE_PROPERTY_FLASH_SIZE ?= 1

######################################################################
# Put samd21-only choices here.
Expand Down
16 changes: 4 additions & 12 deletions ports/broadcom/bindings/videocore/Framebuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,8 @@ STATIC mp_obj_t videocore_framebuffer_get_width(mp_obj_t self_in) {
return MP_OBJ_NEW_SMALL_INT(common_hal_videocore_framebuffer_get_width(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(videocore_framebuffer_get_width_obj, videocore_framebuffer_get_width);
const mp_obj_property_t videocore_framebuffer_width_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&videocore_framebuffer_get_width_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
MP_PROPERTY_GETTER(videocore_framebuffer_width_obj,
(mp_obj_t)&videocore_framebuffer_get_width_obj);

//| height: int
//| """The height of the display, in pixels"""
Expand All @@ -113,12 +109,8 @@ STATIC mp_obj_t videocore_framebuffer_get_height(mp_obj_t self_in) {
}
MP_DEFINE_CONST_FUN_OBJ_1(videocore_framebuffer_get_height_obj, videocore_framebuffer_get_height);

const mp_obj_property_t videocore_framebuffer_height_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&videocore_framebuffer_get_height_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
MP_PROPERTY_GETTER(videocore_framebuffer_height_obj,
(mp_obj_t)&videocore_framebuffer_get_height_obj);

STATIC const mp_rom_map_elem_t videocore_framebuffer_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&videocore_framebuffer_deinit_obj) },
Expand Down
25 changes: 7 additions & 18 deletions ports/raspberrypi/bindings/rp2pio/StateMachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -729,12 +729,9 @@ STATIC mp_obj_t rp2pio_statemachine_obj_set_frequency(mp_obj_t self_in, mp_obj_t
}
MP_DEFINE_CONST_FUN_OBJ_2(rp2pio_statemachine_set_frequency_obj, rp2pio_statemachine_obj_set_frequency);

const mp_obj_property_t rp2pio_statemachine_frequency_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&rp2pio_statemachine_get_frequency_obj,
(mp_obj_t)&rp2pio_statemachine_set_frequency_obj,
MP_ROM_NONE},
};
MP_PROPERTY_GETSET(rp2pio_statemachine_frequency_obj,
(mp_obj_t)&rp2pio_statemachine_get_frequency_obj,
(mp_obj_t)&rp2pio_statemachine_set_frequency_obj);

//| rxstall: bool
//| """True when the state machine has stalled due to a full RX FIFO since the last
Expand All @@ -748,12 +745,8 @@ STATIC mp_obj_t rp2pio_statemachine_obj_get_rxstall(mp_obj_t self_in) {
}
MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_rxstall_obj, rp2pio_statemachine_obj_get_rxstall);

const mp_obj_property_t rp2pio_statemachine_rxstall_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&rp2pio_statemachine_get_rxstall_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
MP_PROPERTY_GETTER(rp2pio_statemachine_rxstall_obj,
(mp_obj_t)&rp2pio_statemachine_get_rxstall_obj);

//| in_waiting: int
//| """The number of words available to readinto"""
Expand All @@ -766,12 +759,8 @@ STATIC mp_obj_t rp2pio_statemachine_obj_get_in_waiting(mp_obj_t self_in) {
}
MP_DEFINE_CONST_FUN_OBJ_1(rp2pio_statemachine_get_in_waiting_obj, rp2pio_statemachine_obj_get_in_waiting);

const mp_obj_property_t rp2pio_statemachine_in_waiting_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&rp2pio_statemachine_get_in_waiting_obj,
MP_ROM_NONE,
MP_ROM_NONE},
};
MP_PROPERTY_GETTER(rp2pio_statemachine_in_waiting_obj,
(mp_obj_t)&rp2pio_statemachine_get_in_waiting_obj);

STATIC const mp_rom_map_elem_t rp2pio_statemachine_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&rp2pio_statemachine_deinit_obj) },
Expand Down
8 changes: 8 additions & 0 deletions ports/raspberrypi/link.ld
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ SECTIONS
/* bit of a hack right now to exclude all floating point and time critical (e.g. memset, memcpy) code from
* FLASH ... we will include any thing excluded here in .data below by default */
*(.init)

__property_getter_start = .;
*(.property_getter)
__property_getter_end = .;
__property_getset_start = .;
*(.property_getset)
__property_getset_end = .;

*(EXCLUDE_FILE(*libgcc.a: *libc.a:*lib_a-mem*.o *libm.a:) .text*)
*(.fini)
/* Pull all c'tors into .text */
Expand Down
1 change: 1 addition & 0 deletions ports/raspberrypi/mpconfigport.mk
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# All raspberrypi ports have longints.
LONGINT_IMPL = MPZ

CIRCUITPY_OPTIMIZE_PROPERTY_FLASH_SIZE ?= 1
CIRCUITPY_ALARM ?= 1

CIRCUITPY_RP2PIO ?= 1
Expand Down
2 changes: 2 additions & 0 deletions py/circuitpy_mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -573,4 +573,6 @@ void supervisor_run_background_tasks_if_tick(void);
#define MICROPY_WRAP_MP_EXECUTE_BYTECODE PLACE_IN_ITCM
#endif

#define MICROPY_PY_OPTIMIZE_PROPERTY_FLASH_SIZE (CIRCUITPY_OPTIMIZE_PROPERTY_FLASH_SIZE)

#endif // __INCLUDED_MPCONFIG_CIRCUITPY_H
5 changes: 5 additions & 0 deletions py/circuitpy_mpconfig.mk
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@
CIRCUITPY_FULL_BUILD ?= 1
CFLAGS += -DCIRCUITPY_FULL_BUILD=$(CIRCUITPY_FULL_BUILD)

# Reduce the size of in-flash properties. Requires support in the .ld linker
# file, so not enabled by default.
CIRCUITPY 10000 _OPTIMIZE_PROPERTY_FLASH_SIZE ?= 0
CFLAGS += -DCIRCUITPY_OPTIMIZE_PROPERTY_FLASH_SIZE=$(CIRCUITPY_OPTIMIZE_PROPERTY_FLASH_SIZE)

# async/await language keyword support
MICROPY_PY_ASYNC_AWAIT ?= $(CIRCUITPY_FULL_BUILD)
CFLAGS += -DMICROPY_PY_ASYNC_AWAIT=$(MICROPY_PY_ASYNC_AWAIT)
Expand Down
5 changes: 5 additions & 0 deletions py/mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,11 @@ typedef double mp_float_t;
#define MICROPY_PY_BUILTINS_PROPERTY (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_CORE_FEATURES)
#endif

// Whether to optimize property flash storage size (requires linker script support)
#ifndef MICROPY_PY_BUILTINS_PROPERTY
#define MICROPY_PY_BUILTINS_PROPERTY (0)
#endif

// Whether to implement the start/stop/step attributes (readback) on
// the "range" builtin type. Rarely used, and costs ~60 bytes (x86).
#ifndef MICROPY_PY_BUILTINS_RANGE_ATTRS
Expand Down
8 changes: 2 additions & 6 deletions py/obj.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,11 +356,7 @@ typedef struct _mp_rom_obj_t { mp_const_obj_t o; } mp_rom_obj_t;

#define MP_DEFINE_CONST_PROP_GET(obj_name, fun_name) \
const mp_obj_fun_builtin_fixed_t fun_name##_obj = {{&mp_type_fun_builtin_1}, .fun._1 = fun_name}; \
const mp_obj_property_t obj_name = { \
.base.type = &mp_type_property, \
.proxy = {(mp_obj_t)&fun_name##_obj, \
MP_ROM_NONE, \
MP_ROM_NONE}, }
MP_PROPERTY_GETTER(obj_name, (mp_obj_t)&fun_name##_obj);

// These macros are used to define constant or mutable map/dict objects
// You can put "static" in front of the definition to make it local
Expand Down Expand Up @@ -1111,7 +1107,7 @@ typedef struct _mp_rom_obj_static_class_method_t {
} mp_rom_obj_static_class_method_t;

// property
const mp_obj_t *mp_obj_property_get(mp_obj_t self_in);
const mp_obj_t *mp_obj_property_get(mp_obj_t self_in, size_t *n_proxy);

// sequence helpers

Expand Down
17 changes: 16 additions & 1 deletion py/objproperty.c
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,24 @@ const mp_obj_type_t mp_type_property = {
.locals_dict = (mp_obj_dict_t *)&property_locals_dict,
};

const mp_obj_t *mp_obj_property_get(mp_obj_t self_in) {
#if MICROPY_PY_OPTIMIZE_PROPERTY_FLASH_SIZE
extern const mp_obj_property_t __property_getter_start, __property_getter_end, __property_getset_start, __property_getset_end;
#endif

const mp_obj_t *mp_obj_property_get(mp_obj_t self_in, size_t *n_proxy) {
mp_check_self(mp_obj_is_type(self_in, &mp_type_property));
mp_obj_property_t *self = MP_OBJ_TO_PTR(self_in);
#if MICROPY_PY_OPTIMIZE_PROPERTY_FLASH_SIZE
if (self >= &__property_getter_start && self < &__property_getter_end) {
*n_proxy = 1;
} else if (self >= &__property_getset_start && self < &__property_getset_end) {
*n_proxy = 2;
} else {
*n_proxy = 3;
}
#else
*n_proxy = 3;
#endif
return self->proxy;
}

Expand Down
22 changes: 22 additions & 0 deletions py/objproperty.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,28 @@ typedef struct _mp_obj_property_t {
mp_obj_t proxy[3]; // getter, setter, deleter
} mp_obj_property_t;

#if MICROPY_PY_OPTIMIZE_PROPERTY_FLASH_SIZE
typedef struct _mp_obj_property_getter_t {
mp_obj_base_t base;
mp_obj_t proxy[1]; // getter
} mp_obj_property_getter_t;

typedef struct _mp_obj_property_getset_t {
mp_obj_base_t base;
mp_obj_t proxy[2]; // getter, setter
} mp_obj_property_getset_t;

#define MP_PROPERTY_GETTER(P, G) const mp_obj_property_getter_t P __attribute((section(".property_getter"))) = {.base.type = &mp_type_property, .proxy = {G}}
#define MP_PROPERTY_GETSET(P, G, S) const mp_obj_property_getset_t P __attribute((section(".property_getset"))) = {.base.type = &mp_type_property, .proxy = {G, S}}

#else
typedef struct _mp_obj_property_t mp_obj_property_getter_t;
typedef struct _mp_obj_property_t mp_obj_property_getset_t;

#define MP_PROPERTY_GETTER(P, G) const mp_obj_property_t P = {.base.type = &mp_type_property, .proxy = {G, MP_ROM_NONE, MP_ROM_NONE}}
#define MP_PROPERTY_GETSET(P, G, S) const mp_obj_property_t P = {.base.type = &mp_type_property, .proxy = {G, S, MP_ROM_NONE}}
#endif

#endif // MICROPY_PY_BUILTINS_PROPERTY

#endif // MICROPY_INCLUDED_PY_OBJPROPERTY_H
13 changes: 8 additions & 5 deletions py/objtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,8 @@ STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *des
// be called by the descriptor code down below. But that way
// requires overhead for the nested mp_call's and overhead for
// the code.
const mp_obj_t *proxy = mp_obj_property_get(member);
size_t n_proxy;
const mp_obj_t *proxy = mp_obj_property_get(member, &n_proxy);
if (proxy[0] == mp_const_none) {
mp_raise_AttributeError(MP_ERROR_TEXT("unreadable attribute"));
} else {
Expand Down Expand Up @@ -740,11 +741,12 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val
// would be called by the descriptor code down below. But that way
// requires overhead for the nested mp_call's and overhead for
// the code.
const mp_obj_t *proxy = mp_obj_property_get(member[0]);
size_t n_proxy;
const mp_obj_t *proxy = mp_obj_property_get(member[0], &n_proxy);
mp_obj_t dest[2] = {self_in, value};
if (value == MP_OBJ_NULL) {
// delete attribute
if (proxy[2] == mp_const_none) {
if (n_proxy < 3 || proxy[2] == mp_const_none) {
// TODO better error message?
return false;
} else {
Expand All @@ -753,7 +755,7 @@ STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val
}
} else {
// store attribute
if (proxy[1] == mp_const_none) {
if (n_proxy < 2 || proxy[1] == mp_const_none) {
// TODO better error message?
return false;
} else {
Expand Down Expand Up @@ -1374,7 +1376,8 @@ STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
// here...
#if MICROPY_PY_BUILTINS_PROPERTY
if (mp_obj_is_type(member, &mp_type_property)) {
const mp_obj_t *proxy = mp_obj_property_get(member);
size_t n_proxy;
const mp_obj_t *proxy = mp_obj_property_get(member, &n_proxy);
if (proxy[0] == mp_const_none) {
mp_raise_AttributeError(MP_ERROR_TEXT("unreadable attribute"));
} else {
Expand Down
10 changes: 6 additions & 4 deletions py/runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -1087,7 +1087,8 @@ void mp_convert_member_lookup(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t
// be called by the descriptor code down below. But that way
// requires overhead for the nested mp_call's and overhead for
// the code.
const mp_obj_t *proxy = mp_obj_property_get(member);
size_t n_proxy;
const mp_obj_t *proxy = mp_obj_property_get(member, &n_proxy);
if (proxy[0] == mp_const_none) {
mp_raise_AttributeError(MP_ERROR_TEXT("unreadable attribute"));
} else {
Expand Down Expand Up @@ -1226,15 +1227,16 @@ void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) {
// would be called by the descriptor code down below. But that way
// requires overhead for the nested mp_call's and overhead for
// the code.
const mp_obj_t *proxy = mp_obj_property_get(elem->value);
size_t n_proxy;
const mp_obj_t *proxy = mp_obj_property_get(elem->value, &n_proxy);
mp_obj_t dest[2] = {base, value};
if (value == MP_OBJ_NULL) {
// delete attribute
if (proxy[2] != mp_const_none) {
if (n_proxy == 3 && proxy[2] != mp_const_none) {
mp_call_function_n_kw(proxy[2], 1, 0, dest);
return;
}
} else if (proxy[1] != mp_const_none) {
} else if (n_proxy > 1 && proxy[1] != mp_const_none) {
mp_call_function_n_kw(proxy[1], 2, 0, dest);
return;
}
Expand Down
Loading
0