aboutsummaryrefslogtreecommitdiffstats
path: root/research
Commit message (Collapse)AuthorAgeFilesLines
* 041 runs.sh: the suite three ways (the compiled code, the executor with ↵eunhhu2026-10-055-0/+384
| | | | batches, the executor alone) and icount.c's instructions and cycles; stage 1 at 10a50dd: knapsack 13.57 ms with batches (1,040.9 alone, 7.52 compiled, C 6.23), the others as they were; the executor's instructions as e2e56dd's or fewer (roots 2.756 to 2.760 billion, cycles alike), knapsack's 21.7 to 0.46 billion with batches
* 041 join ops: the recurrence interpreted and each round's rest as 11 ↵eunhhu2026-10-053-19/+172
| | | | operations apart, interpreted, 57.8 ms (C 32.6; fused by hand 48.4, the tier 2.46x); bfs: a node with more edges than the lanes runs its round alone (tested with lanes of 16, LANES_TEST); runs again
* 041 knapsack u32_ops: the batch's operations apart and interpreted over ↵eunhhu2026-10-052-18/+70
| | | | four-byte lanes ascending in memory, 4.54 ms (C 6.38, the tier 7.5; fused 2.70): narrow lanes in memory's order are most of the gain, fusing the rest; runs again
* 041 batches: loops run a batch of rounds at a time, each operation a C loop ↵eunhhu2026-10-054-0/+707
| | | | made at build time (no code made at run time), on Pure's forms and checks, against C natural and C given the same restructuring: roots 6.79 ms (C 6.86), knapsack fused four-byte 2.70 (C 6.47, C in the batch's blocks 1.94), matmul lanes over j 6.67 (C 7.10, C swapped and vector 4.88), join 37 / 46 with its recurrence interpreted (C 30), BFS 10.3 (C 10.0, C read ahead 7.0); unfused interpreted operations 11.2 and 17.7-22.1
* 125: forms and newton runs named; BFS's time after the graph's load is the ↵eunhhu2026-10-051-0/+2
| | | | generic code's (steps 0.1%), what the tier needs for it (a list's count as a changing value); 023 cites words at e2e56dd
* Research 125: the tier's first steps against C (e2e56dd: roots 1.40, ↵eunhhu2026-10-052-0/+217
| | | | knapsack 1.19, sort 1.37, join 2.54, words 5.58, matmul 1.85, BFS 1.61; geometric mean 1.92, from 3-300x at 6b45806), what each change did, the forms measured in assembly, the apps unchanged, what is left (text in the executor, BFS's appends, spills); CHECKPOINT says so
* The tier checks a number finite in integers (its exponent's bits all ones), ↵eunhhu2026-10-052-0/+104
| | | | off the number pipes the divisions and sums wait on: roots 10.9 to 9.6 ms (1.39x C). 040 newton.c: roots' loop in the forms the tier may make it (the check as numbers 9.7 ms, in integers 8.7, none 7.7; next in r's register as gcc keeps it 7.0)
* 040 forms.c: matmul's inner loop in the forms the tier may make it (index ↵eunhhu2026-10-052-0/+93
| | | | 20.7 ms, pointer with multiply-add 13.1, apart 10.0, with checks 10.2, a bit tested before each load 13.4): the position's multiply and the pre-load branch cost, the checks hardly; 023 section 5 says so and what comes first (pointer induction, then a full list's copy)
* 040: the suite on 4bedd7f (11 rounds' medians, Pure / C): roots 1.58, ↵eunhhu2026-10-052-0/+217
| | | | knapsack 1.18, sort 1.37, join 2.62, words 5.46, matmul 3.07, BFS without reading ahead 1.58 (geometric mean 2.09; 3-300x at 6b45806)
* 040: TPC-C and the bank's queries against 6b45806 (023's criterion for the ↵eunhhu2026-10-0528-1/+136
| | | | apps there are): six pairs in turns, TPC-C's median -1.2% (the pairs -5.2 to +1.4%), the queries' medians within 1% but in_credit's (0.84 to 0.815 ms); the queries' instructions +0.3 to +1.5% on 49b6196 (2026-10-05-counts-49b6196.jsonl), -0.1 to +0.5% after the list's tree paths left HASHED's checks (2026-10-05-counts.jsonl). runs.sh serve, pairs and counts
* Research 124's floors: each workload by hand as Pure could run it (its ↵eunhhu2026-10-055-186/+987
| | | | lists' representation, its meaning) bare, with the checks a compiler could hoist, and with every check where the meaning puts it: hoisted 0.64-1.02x C (0.90 by the geometric mean), naive up to 12x
* Research 124's suite at 6b45806: Pure against C 3.3x (roots), 300x ↵eunhhu2026-10-052-0/+217
| | | | (knapsack), 4.8x (sort), 22x (join), 12x (words), 304x (matmul), BFS 1.57x without reading ahead; only roots and BFS run as code
* Research 124's suite: seven kinds of work in one event each (roots, ↵eunhhu2026-10-058-0/+568
| | | | knapsack, sort, join, words, matmul, BFS), each against the C one would write, in one process with the same inputs and answers; PURE_AHEAD=0 to measure the code without reading ahead
* Read a slice's bucket and first cell some rounds ahead of the loop that ↵eunhhu2026-10-051-1/+6
| | | | opens it, read an item and find it in key bits as one, branch back once a round: BFS core 19.6 to 14.9 ms (022)
* Design 022: stored lists as arrays with a bucket index fitted to the keys ↵eunhhu2026-10-056-7/+283
| | | | searched, narrow columns, a JIT with registers and loop guards, read ahead; criteria first
* Measure 021: BFS 190 to 90 ms over HTTP against C's 9.1, short of C; Pure's ↵eunhhu2026-10-0572-0/+1024
| | | | forms by hand beat C only packed, narrow and read ahead (123)
* Measure an index for a stored list's slices outside the list: three times a ↵eunhhu2026-10-052-0/+113
| | | | tree's seek, still seven times C's (021)
* Say what a search's floor is with stored lists as trees: 373 ns a node to ↵eunhhu2026-10-053-0/+75
| | | | find a slice against C's 21 (021)
* The same answers on the final build and the same pure-runs on the Pi, WSL2 ↵eunhhu2026-10-044-0/+145
| | | | and a Mac (121); 019 points at 020's view workers
* Measure views off the connection threads: writes' tail as with the CPU ↵eunhhu2026-10-049-3/+71
| | | | shared, two askers 1.95 times one (122)
* Measure computing faster: a search 2.1 times as fast, TPC-C 4.1%, four ↵eunhhu2026-10-0466-0/+399
| | | | fingers found and undone (121)
* The runs of research 122: writes beside views that compute, one asker and ↵eunhhu2026-10-043-0/+283
| | | | two, and a plain view's reads
* Wait for a counter before searching in bfs-run, and the runs of research 121eunhhu2026-10-042-0/+67
|
* Say where a search's time goes and how to make it and long views fast, with ↵eunhhu2026-10-041-0/+83
| | | | criteria (020)
* Wake each thread at most once a push, end streams only of stopped apps, and ↵eunhhu2026-10-043-0/+93
| | | | show a subscriber costs writes nothing (019)
* Say what pushing views costs and how fresh it keeps them (019, research 120)eunhhu2026-10-0451-0/+365
|
* Say what views that compute cost the writes beside them (018 stage 3, ↵eunhhu2026-10-046-0/+299
| | | | research 119)
* Say what computing in one event costs and finds (018 stage 2, research 118)eunhhu2026-10-043-3/+95
|
* Measure 018 stage 2: a graph search in one event, the pairs, and runs to ↵eunhhu2026-10-0434-0/+511
| | | | compare across machines (033)
* Say what a transient state saves a write (018 stage 1, research 117)eunhhu2026-10-043-0/+87
|
* Say what an app's tokens cost (017 3b, research 116)eunhhu2026-10-042-0/+109
| | | | | | | | Requests to an app that checks tokens go 2.92% slower than to an open one on 64 keep-alive connections, 2.2% of it the head the token makes longer (an open app sent the same head is as slow); hashing every request on a new connection costs 0.91%. 031 measures the three in turns.
* Say what apps that change on a running host showed (017 stage 3, research 115)eunhhu2026-10-0443-14/+605
| | | | | | | | | | Changing an app in place keeps a million items' app answering but for 1.12 ms (a host restart: 150 ms; stopping and starting it again from its store, as first built, 150.4 ms), 171.5 ms when its records change shape (332 ms). Another app's p99 stays 0.97 times as it was while one changes every 0.2 s; a host of one app is as it was (TPC-C +0.7%, instructions at most +0.02%); each module change leaves 19 KB. 030 holds the windows of both builds, the isolation, the pairs, the counts and the memory.
* Measure how long an app changing module cannot answer, against a host ↵eunhhu2026-10-046-0/+293
| | | | | | | | | | | | restart (030) An app of a million items (a list grown by doubling) or of a thousand, in a host of apps, its store in RAM: the longest gap between two answered writes while it changes module on SIGHUP (stopped and started again from its store, 71e319b), and while the host is restarted. A thousand items: 1.59 ms against 3.05 (median of 20 and 10). A million: 150.64 ms against 149.73 (10 and 5): both are the store read again (pure_app_start, 142 ms), so changing does not answer sooner than restarting.
* Trade stores with the WSL2 too: its bytes are the Pi's (029, research 114)eunhhu2026-10-044-0/+27
| | | | | | The same events make byte-identical stores on the x86_64 WSL2 (4 KiB pages) as on the Pi and the Mac, and a store made on either of the Pi and the WSL2 opens on the other and goes on the same.
* Run Pure and aup on an x86_64 WSL2 and an M3 Mac against the Pi (029)eunhhu2026-10-0226-0/+3806
| | | | | | | | | | Every pure-run of aup's check (1,053 runs of 667 modules) gives the same output, errors and exit on the Pi, the WSL2 (x86_64, 4 KiB pages, gcc 13) and the Mac (Apple clang 21); the same events make byte-identical stores on the Pi and the Mac, and either opens the other's and goes on the same. Pure's checks pass one at a time in WSL (each_check.py); its wall clock is set back about 2 s every 32 s (clock.py). stores.py streams pure-run's output, whose size grows with the square of the events.
* Run experiments under a memory guard, so they cannot freeze the Pieunhhu2026-10-021-0/+110
| | | | | | | | | | | The Pi has 8 GiB, zram swap and no OOM daemon, and the user's systemd holds no memory controller: a run that outgrows its memory has every program's code evicted before the kernel kills anything, and the machine stops answering. It was reset twice so (a run held 13 GiB of output it should have streamed). guard.py runs a command in a session of its own and kills the session when it holds more than --most MiB (3072) or the machine has less than --floor MiB available (1024, a tmpfs filled counts), and stops what it leaves running.
* Measure wires on the sending loop, and a host's threads (028)eunhhu2026-10-016-7/+211
| | | | | | | | | Five rounds of 1,000 bursts by one wire, four wires, one link and four links: a thread each (966b82f), links on the loop (94e7bb8), wires on it too (5f5603c). Medians: one wire 774k, 782k, 779k sends/s; four wires 629k, 625k, 615k (the same CPU a send); one link 581k to 948k; four links 485k to 811k. A host whose app sends to ten links and ten wires has 24 threads before and 5 after (3 with no output).
* Measure one sending loop against a thread a link, with and without push (028)eunhhu2026-10-017-0/+338
| | | | | | | | Five rounds of 1,000 bursts by one link, four links and one wire, four builds in turns: a thread a link (966b82f), those threads with push (threads-push.patch), the loop (99b2219), the loop with push (94e7bb8). Medians: one link 597k, 923k, 525k, 897k sends/s; four links 506k, 799k, 268k, 800k; the wire as it was, 789k to 794k.
* Push a turn's sends to a link at once, and round only the links that want ↵eunhhu2026-10-012-3/+5
| | | | | | | | | | | | one (017, 2b-1) The sending loop was woken by every record queued while it slept: the owner queues one by one, the loop caught up and slept between them, and every link took a round on every wake. Four links sent 64k packets of 12 records where threads sent 40k of 20, and ran at 257k sends/s against 581k. The owner now queues a turn's sends and pushes each link once; the loop rounds a link only when its socket has answers, it was pushed, or its time came.
* Measure sending between two apps of a host: local outlet or link (112)eunhhu2026-10-016-0/+166
| | | | | | | | | | Two apps of one host, src sending one message for each of 1,000 items in a burst event, 2,000 bursts a run, five rounds with the ways in turns: the local outlet stores 1,141,642 sends a second at 1.17 us of the host's CPU each, a loopback pure:// link to the host's own port 578,879 at 2.93 us (1.97 times the sends, 0.40 times the CPU). 017's second stage asked for at least the link's rate at half its CPU or less: it goes in. Every run checks dst's sum: each send came once.
* Measure one host of many apps against a process each (111)eunhhu2026-10-0158-0/+546
| | | | | | | | | | | | | | | | | | | | 017's first stage met its four criteria on the Pi (RAM stores, five rounds, the order of the ways turned): app B's 99th percentile while app A is flooded by 64 connections is 168 us, half of two processes' 336 us; the two apps busy together write 146.1k a second against 146.2k, with the same 1.4 ms tail; an app costs a host 120 KiB of its own memory (a process: 1,311 KiB PSS) and 100 apps still run on three threads; a host of one app keeps its speed (TPC-C +1.2% at the median of six pairs, two of them interfered and kept; the bank's queries within 2.6%) and its instructions (+0.94% at most). On the way: apps hopped between workers each turn (fixed in db4ee9c), connections of one app spread over all connection threads made the host a third more expensive a request and its tail a kernel tick (fixed by home threads, d24881d), and the work budget's counting cost every table row 26 instructions (fixed in be297ea). The earlier runs are kept apart (db4ee9c's isolation, d24881d's pairs and counts, the interrupted first try).
* Measure 07047c3 again on a quiet Pi (110)eunhhu2026-09-3025-0/+96
| | | | | | | | | | The six pairs rerun once the Pi had been quiet for a minute, on the same binaries. Two pairs were still interfered (the first's before at an owner share of 0.54, the sixth at 0.73 on both sides); the four clean ones are -1.7%, -0.4%, +1.8% and +1.1%, CPU per transaction 43.25 to 42.9 us. The bank's queries are as fast or faster after, though the interference fell more on the before runs; the instruction counts stay the comparison to trust.
* Count instructions where timing cannot tell 3% apart (110)eunhhu2026-09-3062-0/+718
| | | | | | | | | | | | | | | | | 016's second stage passed its criterion: six interleaved pairs against ee21aec gave TPC-C (RAM, W=1) -0.6% at the median and the bank's queries 0.0% to +2.2%, no run interfered. The ranks query was slower all six times, and chasing it showed that on this Pi timing cannot separate 1-3%: two servers asked in turns disagree with themselves (ee21aec to e02bfc9 +1.6%, e02bfc9 to 481642f -1.2%, ee21aec to 481642f +2.8%), and a query whose instructions grew 0.6% ran 3.5% faster. Instructions do not move so: pcount.c counts the server's user-mode instructions with perf_event_open (no perf here), and psample.c samples where they go. ranks had grown 0.4% in instructions (the rest was where code and data landed), per_branch 3.6% and tables 20 instructions a row, which 07047c3 halved. The six pairs of 07047c3 were interfered (another session's build, load 4-12) and are kept apart, unused.
* Say that prefetching items did not pay, and why (109)eunhhu2026-09-3017-0/+201
| | | | | | | | | Fetching a found item's cells, a leaf's keys and each level's keys ahead made finding and reading items 20% faster on 100,000 items in a micro benchmark, but TPC-C's clean pairs moved 1% at most and finding alone got 48% slower, so it is not in. The owner's finding samples were the descent, not the fields: a write right after a read copies the leaf whole anyway, and what costs is walking structures larger than the caches at random.
* Say what snapshots cost the owner, and what reusing their nodes gave (107)eunhhu2026-09-3024-2/+259
| | | | | | | | | Most of it was the allocator: leaves past glibc's thread cache, freed by whichever thread let the last snapshot go. jemalloc was 11-14% faster at more memory; reusing the nodes in Pure gave a median +9.4% over six pairs, 4-8% less CPU a transaction in all six, and 1.97x the state bytes resident where it was 2.18x. TPC-C in RAM is now 4.0x a tuned SQLite at W=1 and 3.5x at W=4; finding items is the owner's largest part now.
* Find pure-serve's owner by its thread, and sort its samples as 106 doeseunhhu2026-09-301-45/+74
|
* Say what TPC-C costs when SQLite commits in groups too, and with four ↵eunhhu2026-09-3019-0/+372
| | | | | | | | | | | | | warehouses (106) SQLite tuned first, by the criteria committed before (and, beyond them, checkpoints each 40 MB of WAL, in its favour). On the SD card Pure stays 4.2-10.8x ahead at equal terminals, SQLite writing 8-18x the bytes a transaction; in RAM 3.2-3.5x. All tables equal at W=1 and W=4, and every run consistent. In RAM the one owner is the limit (0.94 of a core at W=4, no gain from 16 to 64 terminals), a third of its busy time copying nodes the snapshots share; checkpoints and memory are within their criteria.
* Say what the windows and checkpoints cost (013 steps 2 and 3, 104)eunhhu2026-09-303-8/+22
| | | | | | | | | | | | | | | | | | 013's second step is in (d9e0b68): each transport holds a window of its output's sends. 104 measures it with the receivers down: once the window is full a node grows by the outbox alone, 219 and 218 B a send over the link and HTTP (399 and 534 B before). The third step is a measurement. A checkpoint holds one list's snapshot while it writes the image, so what it adds is what the app changed meanwhile: nothing visible on tmpfs or for a list that fits the card's fast writes; on the SD card, a 22.4 MB list written for about 8 s while 1,400 items a second were set left +3.0 and +4.4 MiB. The highest resident memory was twice the state bytes, inside 013's bound (the state and one snapshot) and its stop criterion (3x). 021's run.py takes --items, --stores (a directory on the device to measure) and --label, and reports the peak (VmHWM).
* Say where a node's memory goes, and the budget it now keeps (104, 013)eunhhu2026-09-305-0/+261
| | | | | | | | | | | | | | | | | | 104 measures a node's memory under a receiver that is down and under a snapshot held for long (021's run.py: resident memory against what was posted, 30 s a case). A held snapshot grew the node without end (6.4 to 678 MiB, fixed in d1e8f38); a slow receiver grows it by what was sent, 221 B a send, which is state until delivered, so the budget bounds state and refuses past it. 013 is that budget's design: what it counts (state bytes, deterministic), what an event over it does, why an answer takes its send's room, how links and HTTP wait, what it does not count and those bounds, and the checks. With --memory 4000000 the same load fills it in about 4 s and the node stays at 9.6-9.8 MiB (45.9 MiB and growing without). 012 records the hole the budget found in the link (the full flag), and 103 that its clock fix fell short (385754c). CHECKPOINT gains the row.
* Say what adopting the link took, and how it fares against ngtcp2 (102)eunhhu2026-09-291-0/+124
| | | | | | | | | | | | | | | | | | 102: the spec (012) and a receiver written from it alone; the four holes writing it found (REFUSED, the record's size, a peer's run places, the memo's places beside) and the credit M6 showed fixed at 1,024 records; M6 with ngtcp2 as a third, two rounds. Under reordering Pure carries the most (45 Mbit/s; ngtcp2 29-47, quinn 1-2), under random loss the three are the same, on a clean bottleneck Pure carries 3-5 % less (its framing, some 112 B a packet to QUIC's 41), and where loss and reordering meet ngtcp2 carries 1.3-3.6 times as much: undoing a loss it took for reordering, it restores the window a real loss had cut too (its log: 22 of 34 undos past the window before the last cut; none without reordering). Shares beside TCP stay within 25 %. 011 and the status table say so; 012 also says that a receiver answers within 25 ms (a sender's PTO counts on it), that a shape and a record's bytes are the app's, and why a packet of the past does no harm.