aboutsummaryrefslogtreecommitdiffstats
path: root/core/module.c
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-09-30 03:09:18 +0100
committereunhhu <[email protected]>2026-09-30 03:09:18 +0100
commita5ecc5f1ae83a6ad6d5522f826a1c6d2707264bc (patch)
tree1ddba7f4beef6955327e35cc4ee196206ca91146 /core/module.c
parenta6df26a8499522033277ce4f3cd76eee155169ee (diff)
downloadpure-a5ecc5f1ae83a6ad6d5522f826a1c6d2707264bc.tar.gz
pure-a5ecc5f1ae83a6ad6d5522f826a1c6d2707264bc.zip
Count only the states the memory budget counts
An event under a budget counted its states twice, before and after, walking every state. For the smallest event (a number added, no store) that cost 21 ns in an app of one state and 125 ns in one of 32 (+17 %, +38 %). The app now keeps a bit for each list (not a message's rows) and text when it opens its module, and walks those alone: +10 ns and +29 ns (+8 %, +9 %), and nothing without a budget. A served write costs tens of microseconds, so its throughput does not see it.
Diffstat (limited to 'core/module.c')
-rw-r--r--core/module.c14
1 files changed, 9 insertions, 5 deletions
diff --git a/core/module.c b/core/module.c
index cbf0efe..ac46fb3 100644
--- a/core/module.c
+++ b/core/module.c
@@ -2728,13 +2728,12 @@ static void clear_rows(PureApp *app) {
void pure_app_memory(PureApp *app, size_t bytes) { app->memory = bytes; }
size_t pure_app_state_bytes(const PureApp *app) {
- const PureModule *m = app->module;
size_t bytes = (app->outbox ? pure_list_size(app->outbox) : 0) + (app->heard ? pure_list_size(app->heard) : 0);
- for (uint32_t i = 0; i < m->states; ++i) {
- if (app->lists[i] && !(m->state_flags[i] & PURE_LIST_ROWS >> 8)) bytes += pure_list_size(app->lists[i]);
- else if (app->texts[i]) bytes += pure_draft_size(app->texts[i]);
+ for (uint32_t left = app->counted; left; left &= left - 1) {
+ unsigned i = (unsigned)__builtin_ctz(left);
+ bytes += app->lists[i] ? pure_list_size(app->lists[i]) : app->texts[i] ? pure_draft_size(app->texts[i]) : 0;
}
- return bytes; /* a message's rows are its own, gone when it ends */
+ return bytes;
}
/* One event: every handler for it runs in module order against pending
@@ -3550,6 +3549,11 @@ PURE_COLD static PureResult open_module(PureApp *app, const PureModule *module)
if (old) remap_outputs(app, old, module, true);
drop_passes(app); /* kept by instruction of the module they were made for */
app->module = module;
+ app->counted = 0;
+ for (uint32_t i = 0; i < module->states; ++i)
+ if (module->state_type[i] == PURE_STATE_TEXT ||
+ (module->state_type[i] == PURE_STATE_LIST && !(module->state_flags[i] & PURE_LIST_ROWS >> 8)))
+ app->counted |= UINT32_C(1) << i; /* a message's rows are its own, gone when it ends */
++app->changes;
return PURE_OK;
}