aboutsummaryrefslogtreecommitdiffstats
path: root/research/experiments/004-direct-document-path
diff options
context:
space:
mode:
Diffstat (limited to 'research/experiments/004-direct-document-path')
-rw-r--r--research/experiments/004-direct-document-path/README.md50
-rw-r--r--research/experiments/004-direct-document-path/document-path.c207
-rw-r--r--research/experiments/004-direct-document-path/peak-launcher.c26
-rw-r--r--research/experiments/004-direct-document-path/results/2026-09-24-ext4-1m-linux-aarch64.json251
-rw-r--r--research/experiments/004-direct-document-path/results/2026-09-24-ext4-8k-linux-aarch64.json251
-rw-r--r--research/experiments/004-direct-document-path/results/2026-09-24-tmpfs-1m-preliminary-linux-aarch64.json238
-rw-r--r--research/experiments/004-direct-document-path/results/2026-09-24-tmpfs-8k-preliminary-linux-aarch64.json322
-rw-r--r--research/experiments/004-direct-document-path/run.py160
8 files changed, 1505 insertions, 0 deletions
diff --git a/research/experiments/004-direct-document-path/README.md b/research/experiments/004-direct-document-path/README.md
new file mode 100644
index 0000000..ae4e3b8
--- /dev/null
+++ b/research/experiments/004-direct-document-path/README.md
@@ -0,0 +1,50 @@
+# Direct store calls versus the Pure document path
+
+This is an end-to-end comparison for the existing `editor.pure` document app.
+Both variants perform, for each document, a conditional create, a full read,
+a conditional one-byte replacement at the end, and another full read. They
+check revisions and complete bodies and compute the same digest. Both use the
+same `store.c`: a write creates and synchronizes a replacement file, renames
+it, then synchronizes the directory. The harness verifies equal digests and
+equal final file bytes for each pair of runs.
+
+The direct executable calls `pure_store_splice` and `pure_store_select`; the
+Pure executable runs the prepared `editor.pure` plan through `PureRuntime` and
+`pure_store_host`. The direct executable mirrors only this valid-operation
+workflow. It does **not** provide the runtime's admission, ownership, budget,
+completion, or cancellation contract and is not a feature-equivalent runtime.
+The comparison isolates the cost of choosing that contract for this app path;
+it does not compare two complete products.
+
+Run on a Linux host with a C17 compiler, Python 3, GNU `size`, and `df`:
+
+```sh
+python3 research/experiments/004-direct-document-path/run.py \
+ --documents 256 --body-bytes 8192 --pairs 4 \
+ --output research/experiments/004-direct-document-path/results/local-8k.json
+python3 research/experiments/004-direct-document-path/run.py \
+ --documents 32 --body-bytes 1048576 --pairs 4 \
+ --output research/experiments/004-direct-document-path/results/local-1m.json
+```
+
+The runner uses a fresh temporary directory for each variant and alternates
+direct/Pure order between pairs. Its default `--work-root` is this directory's
+`results/`, so the store is on the repository filesystem. It records the
+filesystem type, compiler, source hashes, executable hashes, linked sections,
+operation counts, four stage times, wall time, user/system CPU time, and peak
+child RSS. A small native parent collects RSS because a Python process can
+otherwise contaminate the reported child high-water mark across `exec`.
+Warmups are untimed, and the runner refuses to compare against a changed
+`editor.pure` definition until the direct mirror is reviewed.
+
+The dated `ext4` JSON files are the report's evidence. The dated `tmpfs`
+files are exploratory runs made before filesystem recording was added; their
+store was under `/tmp` on this host. They exercised the same store calls but
+cannot represent persistent-media latency. One run, even with alternating
+order, cannot control host I/O scheduling, cache state, storage firmware, or
+clock changes. The byte digest proves this workload's result equality, not
+full behavioral equivalence in failures or concurrency.
+
+The [result and interpretation](../../../docs/research/054-direct-document-path.md)
+distinguish linked executable size from the 5,908-byte standalone core and
+avoid a speed claim unsupported by the samples.
diff --git a/research/experiments/004-direct-document-path/document-path.c b/research/experiments/004-direct-document-path/document-path.c
new file mode 100644
index 0000000..b4d6464
--- /dev/null
+++ b/research/experiments/004-direct-document-path/document-path.c
@@ -0,0 +1,207 @@
+#define _POSIX_C_SOURCE 200809L
+/* Two separately linked versions of one durable document workload. The direct
+ * build invokes the same store primitives that the Pure host uses; the Pure
+ * build runs the prepared editor.pure program through its execution core. */
+#include "store.h"
+#ifndef DIRECT_PATH
+#include "runtime.h"
+#include "store-port.h"
+#include "embedded-plan.h"
+#endif
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifndef PURE_BENCH_BODY_BYTES
+#define PURE_BENCH_BODY_BYTES 8192
+#endif
+enum { BODY_BYTES = PURE_BENCH_BODY_BYTES };
+static uint64_t digest = UINT64_C(14695981039346656037);
+
+static void fail(const char *message) {
+ fprintf(stderr, "%s\n", message);
+ exit(1);
+}
+
+static void check(int condition, const char *message) {
+ if (!condition) fail(message);
+}
+
+static void hash_body(const unsigned char *body, size_t size, int64_t revision) {
+ for (size_t i = 0; i < size; ++i) {
+ digest ^= body[i];
+ digest *= UINT64_C(1099511628211);
+ }
+ digest ^= (uint64_t)revision;
+ digest *= UINT64_C(1099511628211);
+}
+
+static uint64_t nanoseconds(void) {
+ struct timespec now;
+ if (clock_gettime(CLOCK_MONOTONIC, &now)) fail("clock_gettime failed");
+ return (uint64_t)now.tv_sec * UINT64_C(1000000000) + (uint64_t)now.tv_nsec;
+}
+
+static void pattern(unsigned char *body, unsigned document) {
+ for (size_t i = 0; i < BODY_BYTES; ++i)
+ body[i] = (unsigned char)('a' + (document + i) % 26);
+}
+
+#ifdef DIRECT_PATH
+static void create(const char *store, const char *key, unsigned document,
+ const unsigned char *expected) {
+ unsigned char *input = malloc(BODY_BYTES);
+ check(input != NULL, "direct input allocation failed");
+ pattern(input, document);
+ check(!memcmp(input, expected, BODY_BYTES), "direct input mismatch");
+ int64_t revision = 0;
+ PureResult status = pure_store_splice(store, key, 0, 0, 0,
+ (PureSpan){input, BODY_BYTES}, &revision);
+ check(status == PURE_OK && revision == 1, "direct create failed");
+ free(input);
+}
+
+static void edit_last(const char *store, const char *key, unsigned char replacement) {
+ unsigned char *input = malloc(1);
+ check(input != NULL, "direct edit allocation failed");
+ *input = replacement;
+ int64_t revision = 0;
+ PureResult status = pure_store_splice(store, key, 1, BODY_BYTES - 1, 1,
+ (PureSpan){input, 1}, &revision);
+ check(status == PURE_OK && revision == 2, "direct edit failed");
+ free(input);
+}
+
+static void read_checked(const char *store, const char *key,
+ const unsigned char *expected, int64_t revision) {
+ PureStoredView view = {0};
+ PureResult status = pure_store_select(store, key, 0, 0, true, 0,
+ 4u * 1024u * 1024u, &view);
+ check(status == PURE_OK && view.revision == revision &&
+ view.body.size == BODY_BYTES && !memcmp(view.body.data, expected, BODY_BYTES),
+ "direct read mismatch");
+ hash_body(view.body.data, view.body.size, revision);
+ pure_store_release(&view);
+}
+#else
+static PureRuntime runtime;
+static PureWork work[1];
+
+static PureOutcome completed(PureTicket ticket) {
+ PureOutcome result;
+ while (!pure_runtime_result(ticket, &result))
+ check(pure_runtime_step(&runtime), "runtime made no progress");
+ return result;
+}
+
+static void write_checked(const char *key, int64_t expected_revision,
+ size_t offset, size_t remove, size_t insert_size,
+ unsigned document, unsigned char replacement,
+ const unsigned char *expected_reply, int64_t revision) {
+ PureTicket ticket;
+ check(pure_runtime_accept(&runtime, PURE_INPUT_WRITE, key, expected_revision,
+ 8 + insert_size, &ticket) == PURE_OK, "runtime write admission failed");
+ size_t size = 0;
+ unsigned char *input = pure_runtime_ingress(ticket, &size);
+ check(input != NULL && size == 8 + insert_size, "runtime input loan failed");
+ for (unsigned i = 0; i < 4; ++i) {
+ input[i] = (unsigned char)(offset >> (8 * i));
+ input[4 + i] = (unsigned char)(remove >> (8 * i));
+ }
+ if (insert_size == BODY_BYTES) pattern(input + 8, document);
+ else input[8] = replacement;
+ check(pure_runtime_ready(ticket), "runtime publication failed");
+ PureOutcome result = completed(ticket);
+ check(result.status == PURE_OK && result.revision == revision &&
+ result.body.size == insert_size &&
+ !memcmp(result.body.data, expected_reply, insert_size),
+ "runtime write result mismatch");
+ check(pure_runtime_release(ticket) && !runtime.active && !runtime.retained,
+ "runtime write resource not released");
+}
+
+static void read_checked(const char *store, const char *key,
+ const unsigned char *expected, int64_t revision) {
+ (void)store;
+ PureTicket ticket;
+ check(pure_runtime_accept(&runtime, PURE_INPUT_READ, key, 0, 0, &ticket) == PURE_OK,
+ "runtime read admission failed");
+ PureOutcome result = completed(ticket);
+ check(result.status == PURE_OK && result.revision == revision &&
+ result.body.size == BODY_BYTES && !memcmp(result.body.data, expected, BODY_BYTES),
+ "runtime read mismatch");
+ hash_body(result.body.data, result.body.size, revision);
+ check(pure_runtime_release(ticket) && !runtime.active && !runtime.retained,
+ "runtime read resource not released");
+}
+
+static void create(const char *store, const char *key, unsigned document,
+ const unsigned char *expected) {
+ (void)store;
+ write_checked(key, 0, 0, 0, BODY_BYTES, document, 0, expected, 1);
+}
+
+static void edit_last(const char *store, const char *key, unsigned char replacement) {
+ (void)store;
+ write_checked(key, 1, BODY_BYTES - 1, 1, 1, 0, replacement, &replacement, 2);
+}
+#endif
+
+int main(int argc, char **argv) {
+ if (argc != 3) fail("usage: document-path STORE DOCUMENT_COUNT");
+ char *end = NULL;
+ unsigned long parsed = strtoul(argv[2], &end, 10);
+ check(end && !*end && parsed > 0 && parsed <= 4096,
+ "DOCUMENT_COUNT must be 1..4096");
+ unsigned documents = (unsigned)parsed;
+ check(pure_store_init(argv[1]) == PURE_OK, "store initialization failed");
+ unsigned char *expected = malloc(BODY_BYTES);
+ check(expected != NULL, "expected document allocation failed");
+#ifndef DIRECT_PATH
+ check(pure_embedded_program.splice && pure_embedded_program.write.offset == 8 &&
+ pure_embedded_program.splice_offset.value == 0 &&
+ pure_embedded_program.splice_remove.value == 4 &&
+ pure_embedded_program.reply_input && pure_embedded_program.read.to_end,
+ "prepared editor.pure no longer matches direct baseline");
+ check(pure_runtime_init(&runtime, work, 1, &pure_embedded_program,
+ pure_store_host(argv[1]), 4u * 1024u * 1024u),
+ "runtime initialization failed");
+#endif
+ uint64_t start = nanoseconds();
+ uint64_t stages[4] = {0};
+ for (unsigned document = 0; document < documents; ++document) {
+ char key[16];
+ snprintf(key, sizeof(key), "doc%04u", document);
+ pattern(expected, document);
+ uint64_t before = nanoseconds();
+ create(argv[1], key, document, expected);
+ stages[0] += nanoseconds() - before;
+ before = nanoseconds();
+ read_checked(argv[1], key, expected, 1);
+ stages[1] += nanoseconds() - before;
+ unsigned char replacement = (unsigned char)('A' + document % 26);
+ before = nanoseconds();
+ edit_last(argv[1], key, replacement);
+ stages[2] += nanoseconds() - before;
+ expected[BODY_BYTES - 1] = replacement;
+ before = nanoseconds();
+ read_checked(argv[1], key, expected, 2);
+ stages[3] += nanoseconds() - before;
+ }
+ uint64_t elapsed = nanoseconds() - start;
+ free(expected);
+ printf("{\"variant\":\"%s\",\"documents\":%u,\"operations\":%u,"
+ "\"body_bytes\":%u,\"elapsed_ns\":%" PRIu64 ","
+ "\"stage_ns\":[%" PRIu64 ",%" PRIu64 ",%" PRIu64 ",%" PRIu64 "],"
+ "\"digest\":\"%016" PRIx64 "\"}\n",
+#ifdef DIRECT_PATH
+ "direct",
+#else
+ "pure",
+#endif
+ documents, documents * 4, (unsigned)BODY_BYTES, elapsed,
+ stages[0], stages[1], stages[2], stages[3], digest);
+ return 0;
+}
diff --git a/research/experiments/004-direct-document-path/peak-launcher.c b/research/experiments/004-direct-document-path/peak-launcher.c
new file mode 100644
index 0000000..e9f6c00
--- /dev/null
+++ b/research/experiments/004-direct-document-path/peak-launcher.c
@@ -0,0 +1,26 @@
+#define _GNU_SOURCE
+/* Fork from a small native launcher so a Python orchestrator's pre-exec RSS
+ * cannot become the measured worker's high-water mark. */
+#include <stdio.h>
+#include <sys/resource.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int main(int argc, char **argv) {
+ if (argc < 2) return 2;
+ pid_t child = fork();
+ if (child < 0) return 2;
+ if (!child) {
+ execvp(argv[1], argv + 1);
+ _exit(127);
+ }
+ struct rusage usage;
+ int status;
+ if (wait4(child, &status, 0, &usage) < 0 || !WIFEXITED(status) ||
+ WEXITSTATUS(status)) return 1;
+ long user_ns = usage.ru_utime.tv_sec * 1000000000L + usage.ru_utime.tv_usec * 1000L;
+ long system_ns = usage.ru_stime.tv_sec * 1000000000L + usage.ru_stime.tv_usec * 1000L;
+ fprintf(stderr, "PURE_PEAK_RSS_KIB=%ld\nPURE_USER_NS=%ld\nPURE_SYSTEM_NS=%ld\n",
+ usage.ru_maxrss, user_ns, system_ns);
+ return 0;
+}
diff --git a/research/experiments/004-direct-document-path/results/2026-09-24-ext4-1m-linux-aarch64.json b/research/experiments/004-direct-document-path/results/2026-09-24-ext4-1m-linux-aarch64.json
new file mode 100644
index 0000000..80ae293
--- /dev/null
+++ b/research/experiments/004-direct-document-path/results/2026-09-24-ext4-1m-linux-aarch64.json
@@ -0,0 +1,251 @@
+{
+ "profile": "same-durable-document-app-direct-versus-pure",
+ "definition_sha256": "8ca6c191b98bf53a592ce24f2b5cd040e41f05c4ccdda7a072d5d7f79870c06a",
+ "prepared_sha256": "8e93861539a87c2a091f55afea1bf310fc3d1f1474521d8f8318bfacac3b0649",
+ "documents_per_variant": 32,
+ "operations_per_variant": 128,
+ "body_bytes": 1048576,
+ "pairs": 4,
+ "filesystem": {
+ "device": "/dev/mmcblk0p2",
+ "type": "ext4",
+ "mount": "/home/eunhhu/work/pure"
+ },
+ "sections": {
+ "direct": {
+ "text": 10364,
+ "data": 856,
+ "bss": 16
+ },
+ "pure": {
+ "text": 18640,
+ "data": 864,
+ "bss": 376
+ }
+ },
+ "binary_sha256": {
+ "direct": "1389e7d95e74e93ab5d9e8c8146d0b8fc5288e7a356df231c3c018d3db9d0e05",
+ "pure": "9a45a3d92eed499b849560a2c949f24da7d09deb5ec9bd956ab78ae4e8273e54"
+ },
+ "samples": [
+ {
+ "order": [
+ "direct",
+ "pure"
+ ],
+ "direct": {
+ "variant": "direct",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 4764012642,
+ "stage_ns": [
+ 2307602623,
+ 136599863,
+ 2096570951,
+ 135696119
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 4128,
+ "user_ns": 428385000,
+ "system_ns": 98253000,
+ "stored_file_bytes": 33555200,
+ "stored_files_sha256": "cd78e6871643d5ce1ae9f3b0c96985b36996ac23053f49c140c4224516d6e77a"
+ },
+ "pure": {
+ "variant": "pure",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 7285595814,
+ "stage_ns": [
+ 5142956601,
+ 117263079,
+ 1831606853,
+ 117247619
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 4128,
+ "user_ns": 382221000,
+ "system_ns": 78088000,
+ "stored_file_bytes": 33555200,
+ "stored_files_sha256": "cd78e6871643d5ce1ae9f3b0c96985b36996ac23053f49c140c4224516d6e77a"
+ }
+ },
+ {
+ "order": [
+ "pure",
+ "direct"
+ ],
+ "pure": {
+ "variant": "pure",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 3766595455,
+ "stage_ns": [
+ 1765437679,
+ 95183882,
+ 1750125337,
+ 95840266
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 4176,
+ "user_ns": 290416000,
+ "system_ns": 85416000,
+ "stored_file_bytes": 33555200,
+ "stored_files_sha256": "cd78e6871643d5ce1ae9f3b0c96985b36996ac23053f49c140c4224516d6e77a"
+ },
+ "direct": {
+ "variant": "direct",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 8005833380,
+ "stage_ns": [
+ 2106116647,
+ 136885177,
+ 5531253084,
+ 139444468
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 4160,
+ "user_ns": 454253000,
+ "system_ns": 79693000,
+ "stored_file_bytes": 33555200,
+ "stored_files_sha256": "cd78e6871643d5ce1ae9f3b0c96985b36996ac23053f49c140c4224516d6e77a"
+ }
+ },
+ {
+ "order": [
+ "direct",
+ "pure"
+ ],
+ "direct": {
+ "variant": "direct",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 10918834225,
+ "stage_ns": [
+ 2175551809,
+ 106558403,
+ 8462573310,
+ 106534958
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 4576,
+ "user_ns": 344275000,
+ "system_ns": 70420000,
+ "stored_file_bytes": 33555200,
+ "stored_files_sha256": "cd78e6871643d5ce1ae9f3b0c96985b36996ac23053f49c140c4224516d6e77a"
+ },
+ "pure": {
+ "variant": "pure",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 12394010470,
+ "stage_ns": [
+ 7847769422,
+ 133123427,
+ 4192297149,
+ 133678298
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 4128,
+ "user_ns": 443388000,
+ "system_ns": 78475000,
+ "stored_file_bytes": 33555200,
+ "stored_files_sha256": "cd78e6871643d5ce1ae9f3b0c96985b36996ac23053f49c140c4224516d6e77a"
+ }
+ },
+ {
+ "order": [
+ "pure",
+ "direct"
+ ],
+ "pure": {
+ "variant": "pure",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 19998681944,
+ "stage_ns": [
+ 6699663505,
+ 105108979,
+ 13020834566,
+ 105960162
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 4144,
+ "user_ns": 361242000,
+ "system_ns": 54606000,
+ "stored_file_bytes": 33555200,
+ "stored_files_sha256": "cd78e6871643d5ce1ae9f3b0c96985b36996ac23053f49c140c4224516d6e77a"
+ },
+ "direct": {
+ "variant": "direct",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 9851837474,
+ "stage_ns": [
+ 6446916975,
+ 136390388,
+ 3043885903,
+ 137363089
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 4592,
+ "user_ns": 460200000,
+ "system_ns": 68626000,
+ "stored_file_bytes": 33555200,
+ "stored_files_sha256": "cd78e6871643d5ce1ae9f3b0c96985b36996ac23053f49c140c4224516d6e77a"
+ }
+ }
+ ],
+ "medians": {
+ "direct": {
+ "elapsed_ms": 8928.835427,
+ "peak_rss_kib": 4368.0,
+ "user_ms": 441.319,
+ "system_ms": 75.0565,
+ "stages_ms": [
+ 2241.577216,
+ 136.4951255,
+ 4287.5694935,
+ 136.529604
+ ]
+ },
+ "pure": {
+ "elapsed_ms": 9839.803142,
+ "peak_rss_kib": 4136.0,
+ "user_ms": 371.7315,
+ "system_ms": 78.2815,
+ "stages_ms": [
+ 5921.310053,
+ 111.186029,
+ 3011.952001,
+ 111.6038905
+ ]
+ }
+ },
+ "median_elapsed_ratio_pure_over_direct": 1.102025367411893,
+ "sources_sha256": {
+ "research/experiments/004-direct-document-path/document-path.c": "032d8688db330c355082d150865aa7ade3e5402cc1bbe090b361fd55cb6325fc",
+ "research/experiments/004-direct-document-path/peak-launcher.c": "fc730205d564b60a4f9e44aa1b880df0debeb1338b86b27eabe3bde1508f3f74",
+ "research/experiments/004-direct-document-path/run.py": "ab9eaed05ed47afc29cb94e72759dad6534531b52b34a8ba2c5b3be6ded1cac1",
+ "prototypes/connections/store.c": "733ddcacaffd9e9ffbadfc385eadd4c9e62736a2b97b7bc048ad14845d83070f",
+ "prototypes/connections/runtime.c": "1ced6734ee07f3688e5c9cc0a8af639da88a1741dc3e6f65ec109baa2d826e6f",
+ "prototypes/connections/evaluate.c": "ee8b91efc733b9d305711b7cbb7b502ae5d3917e06f750b7f62b632ed0ea6d04",
+ "prototypes/connections/store-port.c": "d6bf17878b325e039360816edcbf8d68e41b373cf3e6128d7795e11ae21fdd6f",
+ "prototypes/connections/examples/editor.pure": "8ca6c191b98bf53a592ce24f2b5cd040e41f05c4ccdda7a072d5d7f79870c06a"
+ },
+ "environment": {
+ "platform": "Linux-6.18.39+rpt-rpi-2712-aarch64-with-glibc2.41",
+ "machine": "aarch64",
+ "compiler": "cc (Debian 14.2.0-19) 14.2.0",
+ "size": "GNU size (GNU Binutils for Debian) 2.44"
+ }
+}
diff --git a/research/experiments/004-direct-document-path/results/2026-09-24-ext4-8k-linux-aarch64.json b/research/experiments/004-direct-document-path/results/2026-09-24-ext4-8k-linux-aarch64.json
new file mode 100644
index 0000000..2f80581
--- /dev/null
+++ b/research/experiments/004-direct-document-path/results/2026-09-24-ext4-8k-linux-aarch64.json
@@ -0,0 +1,251 @@
+{
+ "profile": "same-durable-document-app-direct-versus-pure",
+ "definition_sha256": "8ca6c191b98bf53a592ce24f2b5cd040e41f05c4ccdda7a072d5d7f79870c06a",
+ "prepared_sha256": "8e93861539a87c2a091f55afea1bf310fc3d1f1474521d8f8318bfacac3b0649",
+ "documents_per_variant": 256,
+ "operations_per_variant": 1024,
+ "body_bytes": 8192,
+ "pairs": 4,
+ "filesystem": {
+ "device": "/dev/mmcblk0p2",
+ "type": "ext4",
+ "mount": "/home/eunhhu/work/pure"
+ },
+ "sections": {
+ "direct": {
+ "text": 10364,
+ "data": 856,
+ "bss": 16
+ },
+ "pure": {
+ "text": 18640,
+ "data": 864,
+ "bss": 376
+ }
+ },
+ "binary_sha256": {
+ "direct": "d265f60f9126da701369c26a6263474164171349867e11079a63b6d9bd1dbbc8",
+ "pure": "8e71e09bb7923de0e945f4d51c5514dd9ab07a4ff9c0982db712ab895fc54fa0"
+ },
+ "samples": [
+ {
+ "order": [
+ "direct",
+ "pure"
+ ],
+ "direct": {
+ "variant": "direct",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 7241112354,
+ "stage_ns": [
+ 3772530510,
+ 14877249,
+ 3434303263,
+ 14649999
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1072,
+ "user_ns": 21367000,
+ "system_ns": 89743000,
+ "stored_file_bytes": 2103296,
+ "stored_files_sha256": "93b837ad585f9633f60c4e3fc6c52e403238e5a4cc4ec3f6d248b3981a8f425b"
+ },
+ "pure": {
+ "variant": "pure",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 7649396059,
+ "stage_ns": [
+ 3825503100,
+ 15159869,
+ 3788264822,
+ 15324464
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1088,
+ "user_ns": 40394000,
+ "system_ns": 72710000,
+ "stored_file_bytes": 2103296,
+ "stored_files_sha256": "93b837ad585f9633f60c4e3fc6c52e403238e5a4cc4ec3f6d248b3981a8f425b"
+ }
+ },
+ {
+ "order": [
+ "pure",
+ "direct"
+ ],
+ "pure": {
+ "variant": "pure",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 7398701348,
+ "stage_ns": [
+ 3647571585,
+ 15698014,
+ 3714469244,
+ 15678618
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1088,
+ "user_ns": 32058000,
+ "system_ns": 85489000,
+ "stored_file_bytes": 2103296,
+ "stored_files_sha256": "93b837ad585f9633f60c4e3fc6c52e403238e5a4cc4ec3f6d248b3981a8f425b"
+ },
+ "direct": {
+ "variant": "direct",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 7807026262,
+ "stage_ns": [
+ 4021085986,
+ 16197799,
+ 3747754749,
+ 16384614
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1072,
+ "user_ns": 23055000,
+ "system_ns": 96831000,
+ "stored_file_bytes": 2103296,
+ "stored_files_sha256": "93b837ad585f9633f60c4e3fc6c52e403238e5a4cc4ec3f6d248b3981a8f425b"
+ }
+ },
+ {
+ "order": [
+ "direct",
+ "pure"
+ ],
+ "direct": {
+ "variant": "direct",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 8124328908,
+ "stage_ns": [
+ 3722508954,
+ 16393229,
+ 4364924440,
+ 15319853
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1072,
+ "user_ns": 45910000,
+ "system_ns": 67099000,
+ "stored_file_bytes": 2103296,
+ "stored_files_sha256": "93b837ad585f9633f60c4e3fc6c52e403238e5a4cc4ec3f6d248b3981a8f425b"
+ },
+ "pure": {
+ "variant": "pure",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 8689792618,
+ "stage_ns": [
+ 3995126011,
+ 17471391,
+ 4653440218,
+ 17835468
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1088,
+ "user_ns": 47096000,
+ "system_ns": 83726000,
+ "stored_file_bytes": 2103296,
+ "stored_files_sha256": "93b837ad585f9633f60c4e3fc6c52e403238e5a4cc4ec3f6d248b3981a8f425b"
+ }
+ },
+ {
+ "order": [
+ "pure",
+ "direct"
+ ],
+ "pure": {
+ "variant": "pure",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 7553568836,
+ "stage_ns": [
+ 3612364797,
+ 15354345,
+ 3905074609,
+ 15629392
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1088,
+ "user_ns": 23794000,
+ "system_ns": 90418000,
+ "stored_file_bytes": 2103296,
+ "stored_files_sha256": "93b837ad585f9633f60c4e3fc6c52e403238e5a4cc4ec3f6d248b3981a8f425b"
+ },
+ "direct": {
+ "variant": "direct",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 7932443534,
+ "stage_ns": [
+ 4056315266,
+ 15670869,
+ 3839621816,
+ 15698993
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1072,
+ "user_ns": 23088000,
+ "system_ns": 92353000,
+ "stored_file_bytes": 2103296,
+ "stored_files_sha256": "93b837ad585f9633f60c4e3fc6c52e403238e5a4cc4ec3f6d248b3981a8f425b"
+ }
+ }
+ ],
+ "medians": {
+ "direct": {
+ "elapsed_ms": 7869.734898,
+ "peak_rss_kib": 1072.0,
+ "user_ms": 23.0715,
+ "system_ms": 91.048,
+ "stages_ms": [
+ 3896.808248,
+ 15.934334,
+ 3793.6882825,
+ 15.509423
+ ]
+ },
+ "pure": {
+ "elapsed_ms": 7601.4824475,
+ "peak_rss_kib": 1088.0,
+ "user_ms": 36.226,
+ "system_ms": 84.6075,
+ "stages_ms": [
+ 3736.5373425,
+ 15.5261795,
+ 3846.6697155,
+ 15.654005
+ ]
+ }
+ },
+ "median_elapsed_ratio_pure_over_direct": 0.9659134069982239,
+ "sources_sha256": {
+ "research/experiments/004-direct-document-path/document-path.c": "032d8688db330c355082d150865aa7ade3e5402cc1bbe090b361fd55cb6325fc",
+ "research/experiments/004-direct-document-path/peak-launcher.c": "fc730205d564b60a4f9e44aa1b880df0debeb1338b86b27eabe3bde1508f3f74",
+ "research/experiments/004-direct-document-path/run.py": "ab9eaed05ed47afc29cb94e72759dad6534531b52b34a8ba2c5b3be6ded1cac1",
+ "prototypes/connections/store.c": "733ddcacaffd9e9ffbadfc385eadd4c9e62736a2b97b7bc048ad14845d83070f",
+ "prototypes/connections/runtime.c": "1ced6734ee07f3688e5c9cc0a8af639da88a1741dc3e6f65ec109baa2d826e6f",
+ "prototypes/connections/evaluate.c": "ee8b91efc733b9d305711b7cbb7b502ae5d3917e06f750b7f62b632ed0ea6d04",
+ "prototypes/connections/store-port.c": "d6bf17878b325e039360816edcbf8d68e41b373cf3e6128d7795e11ae21fdd6f",
+ "prototypes/connections/examples/editor.pure": "8ca6c191b98bf53a592ce24f2b5cd040e41f05c4ccdda7a072d5d7f79870c06a"
+ },
+ "environment": {
+ "platform": "Linux-6.18.39+rpt-rpi-2712-aarch64-with-glibc2.41",
+ "machine": "aarch64",
+ "compiler": "cc (Debian 14.2.0-19) 14.2.0",
+ "size": "GNU size (GNU Binutils for Debian) 2.44"
+ }
+}
diff --git a/research/experiments/004-direct-document-path/results/2026-09-24-tmpfs-1m-preliminary-linux-aarch64.json b/research/experiments/004-direct-document-path/results/2026-09-24-tmpfs-1m-preliminary-linux-aarch64.json
new file mode 100644
index 0000000..ab088e1
--- /dev/null
+++ b/research/experiments/004-direct-document-path/results/2026-09-24-tmpfs-1m-preliminary-linux-aarch64.json
@@ -0,0 +1,238 @@
+{
+ "profile": "same-durable-document-app-direct-versus-pure",
+ "definition_sha256": "8ca6c191b98bf53a592ce24f2b5cd040e41f05c4ccdda7a072d5d7f79870c06a",
+ "prepared_sha256": "8e93861539a87c2a091f55afea1bf310fc3d1f1474521d8f8318bfacac3b0649",
+ "documents_per_variant": 32,
+ "operations_per_variant": 128,
+ "body_bytes": 1048576,
+ "pairs": 4,
+ "sections": {
+ "direct": {
+ "text": 10364,
+ "data": 856,
+ "bss": 16
+ },
+ "pure": {
+ "text": 18640,
+ "data": 864,
+ "bss": 376
+ }
+ },
+ "binary_sha256": {
+ "direct": "1389e7d95e74e93ab5d9e8c8146d0b8fc5288e7a356df231c3c018d3db9d0e05",
+ "pure": "9a45a3d92eed499b849560a2c949f24da7d09deb5ec9bd956ab78ae4e8273e54"
+ },
+ "samples": [
+ {
+ "order": [
+ "direct",
+ "pure"
+ ],
+ "direct": {
+ "variant": "direct",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 340081183,
+ "stage_ns": [
+ 75261818,
+ 94500701,
+ 17506146,
+ 93772922
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 3872,
+ "user_ns": 308146000,
+ "system_ns": 32015000,
+ "stored_file_bytes": 33555200
+ },
+ "pure": {
+ "variant": "pure",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 341099421,
+ "stage_ns": [
+ 79567567,
+ 92146853,
+ 17844589,
+ 92596187
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 4336,
+ "user_ns": 305409000,
+ "system_ns": 36166000,
+ "stored_file_bytes": 33555200
+ }
+ },
+ {
+ "order": [
+ "pure",
+ "direct"
+ ],
+ "pure": {
+ "variant": "pure",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 338271706,
+ "stage_ns": [
+ 77352220,
+ 91696577,
+ 18131571,
+ 92186762
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 3872,
+ "user_ns": 310861000,
+ "system_ns": 27897000,
+ "stored_file_bytes": 33555200
+ },
+ "direct": {
+ "variant": "direct",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 348018886,
+ "stage_ns": [
+ 79216590,
+ 98943059,
+ 17171958,
+ 93268609
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 3856,
+ "user_ns": 302866000,
+ "system_ns": 40382000,
+ "stored_file_bytes": 33555200
+ }
+ },
+ {
+ "order": [
+ "direct",
+ "pure"
+ ],
+ "direct": {
+ "variant": "direct",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 337466024,
+ "stage_ns": [
+ 74499100,
+ 93470034,
+ 17836179,
+ 92757726
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 3872,
+ "user_ns": 309997000,
+ "system_ns": 28181000,
+ "stored_file_bytes": 33555200
+ },
+ "pure": {
+ "variant": "pure",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 342399605,
+ "stage_ns": [
+ 79958272,
+ 92458203,
+ 18037399,
+ 92971374
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 4336,
+ "user_ns": 311005000,
+ "system_ns": 31898000,
+ "stored_file_bytes": 33555200
+ }
+ },
+ {
+ "order": [
+ "pure",
+ "direct"
+ ],
+ "pure": {
+ "variant": "pure",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 340585627,
+ "stage_ns": [
+ 79565343,
+ 91822001,
+ 17952418,
+ 92354743
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 3872,
+ "user_ns": 301411000,
+ "system_ns": 39659000,
+ "stored_file_bytes": 33555200
+ },
+ "direct": {
+ "variant": "direct",
+ "documents": 32,
+ "operations": 128,
+ "body_bytes": 1048576,
+ "elapsed_ns": 336890525,
+ "stage_ns": [
+ 74695433,
+ 93087459,
+ 17564345,
+ 92612242
+ ],
+ "digest": "b74d25a65553ee41",
+ "peak_rss_kib": 3856,
+ "user_ns": 309291000,
+ "system_ns": 28117000,
+ "stored_file_bytes": 33555200
+ }
+ }
+ ],
+ "medians": {
+ "direct": {
+ "elapsed_ms": 338.7736035,
+ "peak_rss_kib": 3864.0,
+ "user_ms": 308.7185,
+ "system_ms": 30.098,
+ "stages_ms": [
+ 74.9786255,
+ 93.9853675,
+ 17.5352455,
+ 93.0131675
+ ]
+ },
+ "pure": {
+ "elapsed_ms": 340.842524,
+ "peak_rss_kib": 4104.0,
+ "user_ms": 308.135,
+ "system_ms": 34.032,
+ "stages_ms": [
+ 79.566455,
+ 91.984427,
+ 17.9949085,
+ 92.475465
+ ]
+ }
+ },
+ "median_elapsed_ratio_pure_over_direct": 1.0061070888600092,
+ "sources_sha256": {
+ "research/experiments/004-direct-document-path/document-path.c": "032d8688db330c355082d150865aa7ade3e5402cc1bbe090b361fd55cb6325fc",
+ "research/experiments/004-direct-document-path/peak-launcher.c": "fc730205d564b60a4f9e44aa1b880df0debeb1338b86b27eabe3bde1508f3f74",
+ "research/experiments/004-direct-document-path/run.py": "1919287fb5dc0f884cecf038c21e0d4326f2e826ee7a48eb65f5d480e27bacb7",
+ "prototypes/connections/store.c": "733ddcacaffd9e9ffbadfc385eadd4c9e62736a2b97b7bc048ad14845d83070f",
+ "prototypes/connections/runtime.c": "1ced6734ee07f3688e5c9cc0a8af639da88a1741dc3e6f65ec109baa2d826e6f",
+ "prototypes/connections/evaluate.c": "ee8b91efc733b9d305711b7cbb7b502ae5d3917e06f750b7f62b632ed0ea6d04",
+ "prototypes/connections/store-port.c": "d6bf17878b325e039360816edcbf8d68e41b373cf3e6128d7795e11ae21fdd6f",
+ "prototypes/connections/examples/editor.pure": "8ca6c191b98bf53a592ce24f2b5cd040e41f05c4ccdda7a072d5d7f79870c06a"
+ },
+ "environment": {
+ "platform": "Linux-6.18.39+rpt-rpi-2712-aarch64-with-glibc2.41",
+ "machine": "aarch64",
+ "compiler": "cc (Debian 14.2.0-19) 14.2.0",
+ "size": "GNU size (GNU Binutils for Debian) 2.44"
+ }
+}
diff --git a/research/experiments/004-direct-document-path/results/2026-09-24-tmpfs-8k-preliminary-linux-aarch64.json b/research/experiments/004-direct-document-path/results/2026-09-24-tmpfs-8k-preliminary-linux-aarch64.json
new file mode 100644
index 0000000..e8a9f5b
--- /dev/null
+++ b/research/experiments/004-direct-document-path/results/2026-09-24-tmpfs-8k-preliminary-linux-aarch64.json
@@ -0,0 +1,322 @@
+{
+ "profile": "same-durable-document-app-direct-versus-pure",
+ "definition_sha256": "8ca6c191b98bf53a592ce24f2b5cd040e41f05c4ccdda7a072d5d7f79870c06a",
+ "prepared_sha256": "8e93861539a87c2a091f55afea1bf310fc3d1f1474521d8f8318bfacac3b0649",
+ "documents_per_variant": 256,
+ "operations_per_variant": 1024,
+ "body_bytes": 8192,
+ "pairs": 6,
+ "sections": {
+ "direct": {
+ "text": 10364,
+ "data": 856,
+ "bss": 16
+ },
+ "pure": {
+ "text": 18640,
+ "data": 864,
+ "bss": 376
+ }
+ },
+ "binary_sha256": {
+ "direct": "d265f60f9126da701369c26a6263474164171349867e11079a63b6d9bd1dbbc8",
+ "pure": "8e71e09bb7923de0e945f4d51c5514dd9ab07a4ff9c0982db712ab895fc54fa0"
+ },
+ "samples": [
+ {
+ "order": [
+ "direct",
+ "pure"
+ ],
+ "direct": {
+ "variant": "direct",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 32443218,
+ "stage_ns": [
+ 8080321,
+ 7513546,
+ 5301851,
+ 7787666
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1056,
+ "user_ns": 24559000,
+ "system_ns": 8186000,
+ "stored_file_bytes": 2103296
+ },
+ "pure": {
+ "variant": "pure",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 32009201,
+ "stage_ns": [
+ 8131949,
+ 7162898,
+ 5457529,
+ 7487020
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1056,
+ "user_ns": 16183000,
+ "system_ns": 16183000,
+ "stored_file_bytes": 2103296
+ }
+ },
+ {
+ "order": [
+ "pure",
+ "direct"
+ ],
+ "pure": {
+ "variant": "pure",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 31919941,
+ "stage_ns": [
+ 8166312,
+ 7144299,
+ 5410416,
+ 7352779
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1040,
+ "user_ns": 20228000,
+ "system_ns": 12137000,
+ "stored_file_bytes": 2103296
+ },
+ "direct": {
+ "variant": "direct",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 32205996,
+ "stage_ns": [
+ 7984983,
+ 7590856,
+ 5294584,
+ 7570908
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1040,
+ "user_ns": 16322000,
+ "system_ns": 16322000,
+ "stored_file_bytes": 2103296
+ }
+ },
+ {
+ "order": [
+ "direct",
+ "pure"
+ ],
+ "direct": {
+ "variant": "direct",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 32589218,
+ "stage_ns": [
+ 8207096,
+ 7581051,
+ 5347608,
+ 7656447
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1056,
+ "user_ns": 16529000,
+ "system_ns": 16529000,
+ "stored_file_bytes": 2103296
+ },
+ "pure": {
+ "variant": "pure",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 31973552,
+ "stage_ns": [
+ 8280075,
+ 7151887,
+ 5368944,
+ 7359984
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1056,
+ "user_ns": 24311000,
+ "system_ns": 8103000,
+ "stored_file_bytes": 2103296
+ }
+ },
+ {
+ "order": [
+ "pure",
+ "direct"
+ ],
+ "pure": {
+ "variant": "pure",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 32080256,
+ "stage_ns": [
+ 8156569,
+ 7173028,
+ 5460655,
+ 7396332
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1056,
+ "user_ns": 28408000,
+ "system_ns": 4058000,
+ "stored_file_bytes": 2103296
+ },
+ "direct": {
+ "variant": "direct",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 32571829,
+ "stage_ns": [
+ 8142638,
+ 7715426,
+ 5329257,
+ 7625344
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1040,
+ "user_ns": 12350000,
+ "system_ns": 20584000,
+ "stored_file_bytes": 2103296
+ }
+ },
+ {
+ "order": [
+ "direct",
+ "pure"
+ ],
+ "direct": {
+ "variant": "direct",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 32290107,
+ "stage_ns": [
+ 8045372,
+ 7543971,
+ 5349434,
+ 7600138
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1056,
+ "user_ns": 20455000,
+ "system_ns": 12273000,
+ "stored_file_bytes": 2103296
+ },
+ "pure": {
+ "variant": "pure",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 32067756,
+ "stage_ns": [
+ 8225774,
+ 7252055,
+ 5472276,
+ 7359265
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1056,
+ "user_ns": 4064000,
+ "system_ns": 28454000,
+ "stored_file_bytes": 2103296
+ }
+ },
+ {
+ "order": [
+ "pure",
+ "direct"
+ ],
+ "pure": {
+ "variant": "pure",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 32372144,
+ "stage_ns": [
+ 8141941,
+ 7171001,
+ 5629064,
+ 7673781
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1056,
+ "user_ns": 21685000,
+ "system_ns": 10842000,
+ "stored_file_bytes": 2103296
+ },
+ "direct": {
+ "variant": "direct",
+ "documents": 256,
+ "operations": 1024,
+ "body_bytes": 8192,
+ "elapsed_ns": 32314570,
+ "stage_ns": [
+ 8063229,
+ 7512835,
+ 5380849,
+ 7585506
+ ],
+ "digest": "b8a08a9615b2eb3b",
+ "peak_rss_kib": 1056,
+ "user_ns": 16375000,
+ "system_ns": 16375000,
+ "stored_file_bytes": 2103296
+ }
+ }
+ ],
+ "medians": {
+ "direct": {
+ "elapsed_ms": 32.378894,
+ "peak_rss_kib": 1056.0,
+ "user_ms": 16.452,
+ "system_ms": 16.3485,
+ "stages_ms": [
+ 8.071775,
+ 7.562511,
+ 5.3384325,
+ 7.612741
+ ]
+ },
+ "pure": {
+ "elapsed_ms": 32.0384785,
+ "peak_rss_kib": 1056.0,
+ "user_ms": 20.9565,
+ "system_ms": 11.4895,
+ "stages_ms": [
+ 8.1614405,
+ 7.1669495,
+ 5.459092,
+ 7.378158
+ ]
+ }
+ },
+ "median_elapsed_ratio_pure_over_direct": 0.9894865000638995,
+ "sources_sha256": {
+ "research/experiments/004-direct-document-path/document-path.c": "032d8688db330c355082d150865aa7ade3e5402cc1bbe090b361fd55cb6325fc",
+ "research/experiments/004-direct-document-path/peak-launcher.c": "fc730205d564b60a4f9e44aa1b880df0debeb1338b86b27eabe3bde1508f3f74",
+ "research/experiments/004-direct-document-path/run.py": "1919287fb5dc0f884cecf038c21e0d4326f2e826ee7a48eb65f5d480e27bacb7",
+ "prototypes/connections/store.c": "733ddcacaffd9e9ffbadfc385eadd4c9e62736a2b97b7bc048ad14845d83070f",
+ "prototypes/connections/runtime.c": "1ced6734ee07f3688e5c9cc0a8af639da88a1741dc3e6f65ec109baa2d826e6f",
+ "prototypes/connections/evaluate.c": "ee8b91efc733b9d305711b7cbb7b502ae5d3917e06f750b7f62b632ed0ea6d04",
+ "prototypes/connections/store-port.c": "d6bf17878b325e039360816edcbf8d68e41b373cf3e6128d7795e11ae21fdd6f",
+ "prototypes/connections/examples/editor.pure": "8ca6c191b98bf53a592ce24f2b5cd040e41f05c4ccdda7a072d5d7f79870c06a"
+ },
+ "environment": {
+ "platform": "Linux-6.18.39+rpt-rpi-2712-aarch64-with-glibc2.41",
+ "machine": "aarch64",
+ "compiler": "cc (Debian 14.2.0-19) 14.2.0",
+ "size": "GNU size (GNU Binutils for Debian) 2.44"
+ }
+}
diff --git a/research/experiments/004-direct-document-path/run.py b/research/experiments/004-direct-document-path/run.py
new file mode 100644
index 0000000..4987fd7
--- /dev/null
+++ b/research/experiments/004-direct-document-path/run.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python3
+"""Compare the same durable document job through Pure and direct store calls."""
+import argparse
+import hashlib
+import json
+import os
+from pathlib import Path
+import platform
+import statistics
+import subprocess
+import tempfile
+
+HERE = Path(__file__).resolve().parent
+ROOT = HERE.parents[2]
+CONNECTIONS = ROOT / 'prototypes/connections'
+EDITOR_SHA256 = '8ca6c191b98bf53a592ce24f2b5cd040e41f05c4ccdda7a072d5d7f79870c06a'
+
+
+def sha(path):
+ return hashlib.sha256(path.read_bytes()).hexdigest()
+
+
+def run(command, timeout=180):
+ result = subprocess.run([str(item) for item in command], capture_output=True,
+ text=True, timeout=timeout)
+ if result.returncode:
+ raise AssertionError((result.args, result.returncode,
+ result.stdout[-2000:], result.stderr[-2000:]))
+ return result
+
+
+def compile_all(directory, cc, body_bytes):
+ flags = [cc, '-O2', '-std=c17', '-Wall', '-Wextra', '-Wpedantic', '-Werror',
+ f'-DPURE_BENCH_BODY_BYTES={body_bytes}']
+ compiler = directory / 'pure-compile'
+ run([*flags, CONNECTIONS / 'compile-program.c', CONNECTIONS / 'program.c',
+ '-o', compiler])
+ header = directory / 'embedded-plan.h'
+ run([compiler, CONNECTIONS / 'examples/editor.pure', header])
+ common = [HERE / 'document-path.c', CONNECTIONS / 'store.c']
+ direct = directory / 'direct'
+ pure = directory / 'pure'
+ run([*flags, '-DDIRECT_PATH', '-I' + str(CONNECTIONS), *common, '-o', direct])
+ run([*flags, '-I' + str(CONNECTIONS), '-I' + str(directory), *common,
+ CONNECTIONS / 'store-port.c', CONNECTIONS / 'runtime.c',
+ CONNECTIONS / 'evaluate.c', '-o', pure])
+ launcher = directory / 'peak-launcher'
+ run([*flags, HERE / 'peak-launcher.c', '-o', launcher])
+ return {'direct': direct, 'pure': pure}, launcher, header
+
+
+def sections(binary):
+ fields = run(['size', binary]).stdout.splitlines()[1].split()
+ return {'text': int(fields[0]), 'data': int(fields[1]), 'bss': int(fields[2])}
+
+
+def trial(binary, launcher, store, documents):
+ result = run([launcher, binary, store, documents])
+ measured = json.loads(result.stdout)
+ resources = dict(line.split('=', 1) for line in result.stderr.splitlines())
+ measured['peak_rss_kib'] = int(resources['PURE_PEAK_RSS_KIB'])
+ measured['user_ns'] = int(resources['PURE_USER_NS'])
+ measured['system_ns'] = int(resources['PURE_SYSTEM_NS'])
+ objects = sorted(store.glob('obj-*'))
+ assert len(objects) == documents, len(objects)
+ measured['stored_file_bytes'] = sum(path.stat().st_size for path in objects)
+ final_files = hashlib.sha256()
+ for path in objects:
+ content = path.read_bytes()
+ final_files.update(path.name.encode('ascii'))
+ final_files.update(len(content).to_bytes(8, 'little'))
+ final_files.update(content)
+ measured['stored_files_sha256'] = final_files.hexdigest()
+ assert measured['documents'] == documents and measured['operations'] == 4 * documents
+ return measured
+
+
+def main():
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument('--cc', default=os.environ.get('CC', 'cc'))
+ parser.add_argument('--documents', type=int, default=256)
+ parser.add_argument('--body-bytes', type=int, default=8192)
+ parser.add_argument('--pairs', type=int, default=4)
+ parser.add_argument('--work-root', type=Path, default=HERE / 'results',
+ help='filesystem for fresh stores; default is the repository filesystem')
+ parser.add_argument('--output', type=Path)
+ args = parser.parse_args()
+ if (not 1 <= args.documents <= 4096 or not 1 <= args.pairs <= 16 or
+ not 1 <= args.body_bytes <= 1024 * 1024):
+ parser.error('documents must be 1..4096, pairs 1..16 and body-bytes 1..1048576')
+ if args.output and args.output.exists():
+ parser.error('evidence file already exists')
+ if platform.system() != 'Linux':
+ parser.error('this release RSS apparatus uses Linux wait4 units')
+ definition = CONNECTIONS / 'examples/editor.pure'
+ assert sha(definition) == EDITOR_SHA256, 'direct baseline needs review after editor.pure changes'
+ args.work_root.mkdir(parents=True, exist_ok=True)
+ filesystem = run(['df', '-T', args.work_root]).stdout.splitlines()[1].split()
+ with tempfile.TemporaryDirectory(prefix='pure-direct-document-', dir=args.work_root) as name:
+ root = Path(name)
+ binaries, launcher, prepared = compile_all(root, args.cc, args.body_bytes)
+ sizes = {name: sections(binary) for name, binary in binaries.items()}
+ binaries_sha = {name: sha(binary) for name, binary in binaries.items()}
+ # One small untimed run per path loads shared code and catches a broken
+ # comparison before the measured alternating, fresh-store trials.
+ warmups = {name: trial(binary, launcher, root / ('warm-' + name), 4)
+ for name, binary in binaries.items()}
+ assert warmups['direct']['digest'] == warmups['pure']['digest']
+ samples = []
+ for pair in range(args.pairs):
+ order = ('direct', 'pure') if pair % 2 == 0 else ('pure', 'direct')
+ entry = {'order': list(order)}
+ for variant in order:
+ entry[variant] = trial(binaries[variant], launcher,
+ root / f'{pair}-{variant}', args.documents)
+ assert entry['direct']['digest'] == entry['pure']['digest']
+ assert entry['direct']['stored_file_bytes'] == entry['pure']['stored_file_bytes']
+ assert entry['direct']['stored_files_sha256'] == entry['pure']['stored_files_sha256']
+ samples.append(entry)
+ prepared_sha = sha(prepared)
+ medians = {variant: {'elapsed_ms': statistics.median(
+ sample[variant]['elapsed_ns'] for sample in samples) / 1e6,
+ 'peak_rss_kib': statistics.median(
+ sample[variant]['peak_rss_kib'] for sample in samples),
+ 'user_ms': statistics.median(
+ sample[variant]['user_ns'] for sample in samples) / 1e6,
+ 'system_ms': statistics.median(
+ sample[variant]['system_ns'] for sample in samples) / 1e6,
+ 'stages_ms': [statistics.median(
+ sample[variant]['stage_ns'][i] for sample in samples) / 1e6
+ for i in range(4)]}
+ for variant in ('direct', 'pure')}
+ result = {'profile': 'same-durable-document-app-direct-versus-pure',
+ 'definition_sha256': sha(definition), 'prepared_sha256': prepared_sha,
+ 'documents_per_variant': args.documents,
+ 'operations_per_variant': args.documents * 4,
+ 'body_bytes': args.body_bytes, 'pairs': args.pairs,
+ 'filesystem': {'device': filesystem[0], 'type': filesystem[1],
+ 'mount': filesystem[-1]},
+ 'sections': sizes, 'binary_sha256': binaries_sha,
+ 'samples': samples, 'medians': medians,
+ 'median_elapsed_ratio_pure_over_direct':
+ medians['pure']['elapsed_ms'] / medians['direct']['elapsed_ms'],
+ 'sources_sha256': {str(path.relative_to(ROOT)): sha(path)
+ for path in [HERE / 'document-path.c', HERE / 'peak-launcher.c',
+ HERE / 'run.py', CONNECTIONS / 'store.c',
+ CONNECTIONS / 'runtime.c', CONNECTIONS / 'evaluate.c',
+ CONNECTIONS / 'store-port.c', definition]},
+ 'environment': {'platform': platform.platform(), 'machine': platform.machine(),
+ 'compiler': run([args.cc, '--version']).stdout.splitlines()[0],
+ 'size': run(['size', '--version']).stdout.splitlines()[0]}}
+ body = json.dumps(result, indent=2) + '\n'
+ if args.output:
+ args.output.parent.mkdir(parents=True, exist_ok=True)
+ args.output.write_text(body)
+ print(body, end='')
+
+
+if __name__ == '__main__':
+ main()