aboutsummaryrefslogtreecommitdiffstats
path: root/research/experiments/044-specs/layout_time.c
diff options
context:
space:
mode:
authoreunhhu <[email protected]>2026-10-19 06:18:49 +0100
committereunhhu <[email protected]>2026-10-19 06:18:49 +0100
commit6215b1177e377b512aaa1296faa6311f809135f2 (patch)
treed2be13b3e5d4cb0b7150b0a6d186fc313842de18 /research/experiments/044-specs/layout_time.c
parent8071832bc7857634f66c94592b27b188c882ea54 (diff)
downloadpure-6215b1177e377b512aaa1296faa6311f809135f2.tar.gz
pure-6215b1177e377b512aaa1296faa6311f809135f2.zip
140's 8, box layout, written in aup with no new opcode (aup's examples/layout.aup: a subset of CSS Flexbox 1 written down first, one line, row or column, padding, gap, six justify-content, four align-items, grow and shrink with 9.7's loop, cross sizes stretched, nothing sized by content): 2,000 random trees (29,388 nodes; 7,659 items frozen at their padding by the loop) are Taffy 0.15's within 0.01 (layout_taffy, built by cargo; the worst 8.3e-5) and layout.py's bit for bit on the three paths, the paths the same; the single-pass subset first tried refused 66% of trees, so the loop came in; Taffy given min sizes equal to the padding (given 0 it floors at 0 while resolving lengths, where 9.7 floors the content box), the reference adding from the left (sum compensates since Python 3.12); module_specs in make check: 100 trees (tests/specs/layout); bars: 116 lines against Python's 54, 4,754 ns a node, Taffy's 644 (7.4x), pure Python 5,396 (Pure 1.14x faster), 1,494 instructions a node (9.7's loop 44%); four frictions; aup's rows read by position no longer copy (99,067 ns a node before); the suite table's row 8; CHECKPOINT's direction row
Diffstat (limited to 'research/experiments/044-specs/layout_time.c')
-rw-r--r--research/experiments/044-specs/layout_time.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/research/experiments/044-specs/layout_time.c b/research/experiments/044-specs/layout_time.c
new file mode 100644
index 0000000..3f2ce52
--- /dev/null
+++ b/research/experiments/044-specs/layout_time.c
@@ -0,0 +1,99 @@
+/* Research 140: box layout (a subset of CSS Flexbox 1) in aup (aup's examples/layout.aup, run by Pure), timed on the
+ * trees layout_check.py writes (each a u32 count, its nodes' rows of 14 binary64s in preorder, then their boxes, four
+ * binary64s each, as layout.py works them out). Each tree is a message; its boxes must be the file's, bit for bit; then
+ * the median of seven runs of ROUNDS passes. Taffy's time is layout_taffy --time's.
+ *
+ * cc -O2 -std=c17 -I../../../core layout_time.c ../../../build/libpure.a -lm -pthread -o layout_time
+ * ./layout_time layout.pmod TREES ROUNDS
+ *
+ * One JSON line: the trees and nodes, the nanoseconds per node, and the instructions Pure counted for one pass. */
+#define _POSIX_C_SOURCE 200809L
+#include "module.h"
+#include "module-list.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+static double now_ns(void) {
+ struct timespec t;
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return (double)t.tv_sec * 1e9 + (double)t.tv_nsec;
+}
+
+static int by_value(const void *a, const void *b) {
+ double x = *(const double *)a, y = *(const double *)b;
+ return (x > y) - (x < y);
+}
+
+static unsigned char *whole(const char *path, size_t *size) {
+ FILE *f = fopen(path, "rb");
+ if (!f) return NULL;
+ fseek(f, 0, SEEK_END);
+ *size = (size_t)ftell(f);
+ rewind(f);
+ unsigned char *bytes = malloc(*size ? *size : 1);
+ if (fread(bytes, 1, *size, f) != *size) { free(bytes); bytes = NULL; }
+ fclose(f);
+ return bytes;
+}
+
+typedef struct { uint32_t count; const unsigned char *rows; const unsigned char *boxes; } Tree;
+
+int main(int argc, char **argv) {
+ if (argc != 4) { fprintf(stderr, "usage: %s MODULE TREES ROUNDS\n", argv[0]); return 2; }
+ size_t size;
+ unsigned char *bytes = whole(argv[2], &size);
+ int rounds = atoi(argv[3]);
+ if (!bytes) { fprintf(stderr, "cannot read the trees\n"); return 1; }
+ static Tree trees[1 << 16];
+ size_t count = 0, nodes = 0;
+ for (size_t at = 0; at + 4 <= size && count < sizeof(trees) / sizeof(*trees); ++count) {
+ Tree *t = &trees[count];
+ memcpy(&t->count, bytes + at, 4);
+ t->rows = bytes + at + 4;
+ t->boxes = t->rows + 112 * (size_t)t->count;
+ at += 4 + 144 * (size_t)t->count;
+ nodes += t->count;
+ }
+
+ PureModule module = {0};
+ char error[160];
+ if (pure_module_read(argv[1], &module, error, sizeof(error)) != PURE_OK) { fprintf(stderr, "%s\n", error); return 1; }
+ PureApp app;
+ if (pure_app_start(&app, &module, (PureData){0}) != PURE_OK) return 1;
+ int input = pure_module_input(&module, "tree"), boxes = pure_module_state(&module, "boxes");
+ size_t right = 0;
+ uint64_t work = 0;
+ for (size_t k = 0; k < count; ++k) {
+ const Tree *t = &trees[k];
+ bool same = pure_app_message(&app, (uint32_t)input, (PureSpan){t->rows, 112 * (size_t)t->count}) == PURE_OK &&
+ pure_list_count(app.lists[boxes]) == t->count;
+ work += app.work;
+ for (uint32_t i = 0; same && i < t->count; ++i)
+ for (unsigned f = 0; same && f < 4; ++f) {
+ double want;
+ memcpy(&want, t->boxes + 32 * (size_t)i + 8 * f, 8);
+ same = pure_list_get(app.lists[boxes], i, f).num == want;
+ }
+ right += same;
+ }
+ if (right != count) { fprintf(stderr, "trees %zu: Pure right %zu\n", count, right); return 1; }
+ double runs[7];
+ for (int r = 0; r < 7; ++r) {
+ double start = now_ns();
+ for (int i = 0; i < rounds; ++i)
+ for (size_t k = 0; k < count; ++k)
+ if (pure_app_message(&app, (uint32_t)input, (PureSpan){trees[k].rows, 112 * (size_t)trees[k].count}) != PURE_OK)
+ return 1;
+ runs[r] = (now_ns() - start) / rounds;
+ }
+ qsort(runs, 7, sizeof(double), by_value);
+ const char *jit = getenv("PURE_JIT"), *batch = getenv("PURE_BATCH");
+ printf("{\"trees\":%zu,\"nodes\":%zu,\"right\":%zu,\"jit\":\"%s\",\"batch\":\"%s\",\"pure_ns_per_node\":%.1f,"
+ "\"instructions\":%llu,\"instructions_per_node\":%.1f}\n",
+ count, nodes, right, jit ? jit : "", batch ? batch : "", runs[3] / (double)nodes, (unsigned long long)work,
+ (double)work / (double)nodes);
+ pure_app_stop(&app);
+ return 0;
+}