diff options
| author | eunhhu <[email protected]> | 2026-09-30 02:25:43 +0100 |
|---|---|---|
| committer | eunhhu <[email protected]> | 2026-09-30 02:25:43 +0100 |
| commit | d1e8f38f100571d55aaa98527ae2873e6d247f80 (patch) | |
| tree | 216998a90e39d3dd90141e0e1b78267f9ed4c02f /core/test-module.c | |
| parent | c72284953bb6938ff480ae9be11d5d0c3c4154f6 (diff) | |
| download | pure-d1e8f38f100571d55aaa98527ae2873e6d247f80.tar.gz pure-d1e8f38f100571d55aaa98527ae2873e6d247f80.zip | |
Let a held snapshot keep the states of its time, not all that came after
An app's snapshots formed a chain, each holding the next, and what the
app's lists let go while a snapshot was the newest went with it. So one
snapshot held for long held every later one and every node and text let
go since: a surface holding the snapshot of 20,000 items while their
notes were set again grew the node from 6.5 MB to 696 MB in 30 s, 3.4 KB
an update, without end.
A snapshot reads only what was made before it. Snapshots are now
numbered (their epoch, given to the lists' copies and so to each node
and text made after), and the ones held are linked under a register
they share. What the app lets go while a snapshot is its newest goes
with it, as before; when that one goes, what the newest older one still
held may read (made before its epoch) goes to it, and the rest back to
the system at once. The links move under a spin the register keeps; what
is freed is freed outside it. The same held snapshot now costs its
states once: 6.6 MB to 10.6 MB, flat after the notes diverge.
test-module's snapshot_held holds a snapshot through 40,000 events and
snapshots: none of the second 20,000's allocations stays (0 B; with the
chain's keeping, it fails). The kept-snapshots tests read eight held in
random order, and the module tests pass under AddressSanitizer too.
Diffstat (limited to 'core/test-module.c')
| -rw-r--r-- | core/test-module.c | 57 |
1 files changed, 54 insertions, 3 deletions
diff --git a/core/test-module.c b/core/test-module.c index 788bfc6..1446e73 100644 --- a/core/test-module.c +++ b/core/test-module.c @@ -5,6 +5,9 @@ #include "store.h" #include <dirent.h> #include <fcntl.h> +#ifdef __GLIBC__ +#include <malloc.h> +#endif #include <math.h> #include <pthread.h> #include <stdio.h> @@ -1056,6 +1059,7 @@ static void list_trees(void) { Model shared[SHARES] = {{0}}; PureRetired retired[SHARES + 1] = {{0}}; unsigned first = 0, held = 0, splits_seen = 0; + uint64_t epoch = 0; /* the copies', one after another */ size_t largest = 0, events = 0, undone = 0; for (unsigned event = 0; event < 6000; ++event) { size_t mark = undo.count, journal = pure_list_changes(list).size; @@ -1137,7 +1141,7 @@ static void list_trees(void) { --held; } unsigned slot = (first + held) % SHARES; - CHECK((copies[slot] = pure_list_share(list, &retired[slot]))); + CHECK((copies[slot] = pure_list_share(list, &retired[slot], ++epoch))); model_copy(&shared[slot], &model); ++held; } @@ -1201,7 +1205,7 @@ static void list_trees(void) { CHECK(keyed); for (unsigned round = 0; round < 40000; ++round) { if (round == 20000) { - PureList *copy = pure_list_share(keyed, &keyed_retired); + PureList *copy = pure_list_share(keyed, &keyed_retired, 1); CHECK(copy && pure_list_keyed(keyed, 0) == PURE_OK && same_items(copy, &keys) && same_items(keyed, &keys)); pure_list_free(copy); } @@ -3675,6 +3679,51 @@ static void snapshots_read(Spec spec, void (*event)(PureApp *, uint32_t *), unsi remove_store(path); } +/* A snapshot held while the app goes on for long keeps the states as they + * were then, and nothing the app makes and lets go after it: holding one + * costs the states of its time, however many events and snapshots follow + * (it held them all before, each snapshot holding the next). */ +static size_t snapshot_held_growth; + +static void snapshot_held(Spec spec, void (*event)(PureApp *, uint32_t *)) { + static char was[1 << 16], shown_text[1 << 16]; + char *path = new_store(); + PureStore *store; + CHECK(load(spec, &module_a) == PURE_OK && pure_store_open(path, &store) == PURE_OK); + PureApp app, reader = {0}; + CHECK(pure_app_start(&app, &module_a, pure_store_data(store)) == PURE_OK); + uint32_t seed = 0x401du; + for (unsigned step = 0; step < 200; ++step) event(&app, &seed); + PureSnapshot *held = pure_app_snapshot(&app); + CHECK(held); + Shown before = {was, 0, sizeof(was)}, shown = {shown_text, 0, sizeof(shown_text)}; + describe(&app, &before); + size_t used[3] = {0, 0, 0}; + for (unsigned half = 0; half < 2; ++half) { +#ifdef __GLIBC__ + used[half] = mallinfo2().uordblks; +#endif + for (unsigned step = 0; step < 20000; ++step) { + event(&app, &seed); + pure_snapshot_release(pure_app_snapshot(&app)); + } + } +#ifdef __GLIBC__ + used[2] = mallinfo2().uordblks; + /* The first half may make the app's own copies of what the held one shares; the second makes none to keep. */ + snapshot_held_growth = used[2] > used[1] ? used[2] - used[1] : 0; + CHECK(snapshot_held_growth < 256 * 1024); +#endif + pure_app_read(&reader, held); + describe(&reader, &shown); + CHECK(!strcmp(before.text, shown.text)); + pure_snapshot_release(held); + pure_app_stop(&reader); + pure_app_stop(&app); + pure_store_close(store); + remove_store(path); +} + static void crash_event(PureApp *app, uint32_t *seed) { (void)seed; CHECK(pure_app_input(app, 0, PURE_EDGE_DOWN) == PURE_OK); @@ -3688,6 +3737,7 @@ static void snapshots(void) { snapshots_kept(keyed, &unkeyed, keyed_event, 3000); snapshots_kept(crashing, NULL, crash_event, 300); snapshots_read(keyed, keyed_event, 3000); + snapshot_held(keyed, keyed_event); snapshots_read(crashing, crash_event, 300); /* Without stored states (texts only in memory) there is no snapshot. */ CHECK(load(crashing, &module_a) == PURE_OK); @@ -3695,7 +3745,8 @@ static void snapshots(void) { CHECK(pure_app_start(&app, &module_a, (PureData){0}) == PURE_OK && !pure_app_snapshot(&app)); pure_app_stop(&app); CHECK(snapshot_retired > 100); - printf("{\"snapshots\":6600,\"items_retired\":%zu,\"reads_on_threads\":%zu}\n", snapshot_retired, snapshot_reads); + printf("{\"snapshots\":6600,\"items_retired\":%zu,\"reads_on_threads\":%zu,\"held_growth_bytes\":%zu}\n", + snapshot_retired, snapshot_reads, snapshot_held_growth); } /* A message of a text, a number, bytes and a u32, in that order: the prefix |
