From afb5616843beb5480f607530ef66455a29e0a90f Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Sat, 18 Apr 2026 06:15:21 -0400 Subject: [PATCH] =?UTF-8?q?asm:=20native=20hash-set=20+=20benchmark=20?= =?UTF-8?q?=E2=80=94=2015-21x=20over=20portable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds 6 hash-set builtins (make-hash-set, hash-set?, hash-set-add!, hash-set-contains?, hash-set-size, hash-set->list). Same sentinel scheme as hash-table but tag word = -2 (hash-table is -1, vector is >= 0). One cons cell per entry (vs two for hash-table) since a set stores keys only — that's where the speedup over the Scheme- level vector-based ht-* lib comes from. Benchmark (tests/bench-hashset.sh, via make bench-hashset), N=5000, i5-8350U asm tier: portable native speedup insert ~130 ms ~7 ms ~20x hit-lookup ~125 ms ~8 ms ~15x miss-lookup ~240 ms ~12 ms ~20x Portable is the ht-* lib from proof-netspace-server-lib.lsp (vectors + cons chains + modulo, pure Scheme). Native replaces the Scheme-level bucket walk with an asm loop that dereferences pairs directly — no env lookups, no frame building per iteration. All 137 asm + 189 functional (Python + C) tests still green. --- Makefile | 3 + asm/uncommonlisp | Bin 49608 -> 50968 bytes asm/uncommonlisp.o | Bin 50808 -> 52984 bytes asm/uncommonlisp.s | 222 +++++++++++++++++++++++++++++++++++-- examples/bench-hashset.lsp | 136 +++++++++++++++++++++++ tests/bench-hashset.sh | 21 ++++ 6 files changed, 374 insertions(+), 8 deletions(-) create mode 100644 examples/bench-hashset.lsp create mode 100755 tests/bench-hashset.sh diff --git a/Makefile b/Makefile index f84a748..a2ab9d5 100644 --- a/Makefile +++ b/Makefile @@ -123,6 +123,9 @@ bench-rpc-chain: c-build asm-build bench-proof: c-build asm-build @bash tests/bench-proof.sh +bench-hashset: asm-build + @bash tests/bench-hashset.sh + bench-all: bench c-bench bench-3way bench-portal bench-portal-cross bench-web bench-rpc-chain bench-proof @echo "═══════════════════════════════════════════════════════════" @echo "All benchmarks complete. Numbers in the whitepaper §6.4," diff --git a/asm/uncommonlisp b/asm/uncommonlisp index 3181685aa5dd0868b21865648a45c69d0f096f0d..4f7dd9f85ed8dca2a65aa256c6d246bbbe7a6164 100755 GIT binary patch literal 50968 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ξ3A_w>< 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 Ufn#s}&wAAOIxo>PWbOa|0A;wl-v9sr literal 49608 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 DLv5T| diff --git a/asm/uncommonlisp.o b/asm/uncommonlisp.o index 54526e942bb69c5e18ea67419adf6a34e62c1394..cc8786578ee742a80af0805a6b7ccdbd7062cafa 100644 GIT binary patch literal 52984 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" +bn_hsmake: .byte 13; .ascii "make-hash-set" +bn_hsp: .byte 9; .ascii "hash-set?" +bn_hsadd: .byte 13; .ascii "hash-set-add!" +bn_hshas: .byte 18; .ascii "hash-set-contains?" +bn_hssize: .byte 13; .ascii "hash-set-size" +bn_hslist: .byte 14; .ascii "hash-set->list" s_hashtable: .ascii "#" .equ s_hashtable_len, . - s_hashtable +s_hashset: .ascii "#" +.equ s_hashset_len, . - s_hashset err_ht_miss: .ascii "Error: hash-table-ref: missing key\n" .equ err_ht_miss_len, . - err_ht_miss @@ -346,6 +360,7 @@ bi_names: .quad bn_readstr, bn_eval, bn_symtostr .quad bn_htmake, bn_htp, bn_htset, bn_htref, bn_htrefd, bn_htdel .quad bn_htexists, bn_htsize, bn_htkeys, bn_htvals, bn_htalist + .quad bn_hsmake, bn_hsp, bn_hsadd, bn_hshas, bn_hssize, bn_hslist # Error messages err_unbound: .ascii "Error: unbound variable: " @@ -1427,11 +1442,13 @@ scheme_print: movq %rbx, %rax andq $-8, %rax # untagged vector ptr movq %rax, %rbx # %rbx = untagged vector ptr - movq (%rbx), %r12 # %r12 = length (or -1 for hash-table) - # Check hash-table sentinel + movq (%rbx), %r12 # %r12 = length (or -1 hash-table, -2 hash-set) cmpq $-1, %r12 - jne .sp_vec_real - # Print "#" + je .sp_hashtable_print + cmpq $-2, %r12 + je .sp_hashset_print + jmp .sp_vec_real +.sp_hashtable_print: movq $SYS_WRITE, %rax movq output_fd(%rip), %rdi leaq s_hashtable(%rip), %rsi @@ -1440,6 +1457,15 @@ scheme_print: popq %r12 popq %rbx ret +.sp_hashset_print: + movq $SYS_WRITE, %rax + movq output_fd(%rip), %rdi + leaq s_hashset(%rip), %rsi + movq $s_hashset_len, %rdx + syscall + popq %r12 + popq %rbx + ret .sp_vec_real: # Print "#(" movq $SYS_WRITE, %rax @@ -2581,6 +2607,18 @@ eval_list: je bi_hash_table_values cmpq $BI_HT_ALIST, %rax je bi_hash_table_to_alist + cmpq $BI_HS_MAKE, %rax + je bi_make_hash_set + cmpq $BI_HS_P, %rax + je bi_hash_set_p + cmpq $BI_HS_ADD, %rax + je bi_hash_set_add + cmpq $BI_HS_HAS, %rax + je bi_hash_set_contains + cmpq $BI_HS_SIZE, %rax + je bi_hash_set_size + cmpq $BI_HS_LIST, %rax + je bi_hash_set_to_list movq $VAL_VOID, %rax popq %r12 @@ -3881,11 +3919,11 @@ bi_vecp: andq $TAG_MASK, %rcx cmpq $7, %rcx # vector tag jne .cmp_false - # Distinguish hash-table (first word = -1) from real vector (first word >= 0) + # Distinguish hash-table (first word -1) / hash-set (-2) from real vector (>= 0) andq $-8, %rax movq (%rax), %rax - cmpq $-1, %rax - je .cmp_false + testq %rax, %rax + js .cmp_false # negative first word => hash-* container jmp .cmp_true bi_vectolist: @@ -5077,6 +5115,174 @@ bi_hash_table_to_alist: movq %r12, %rax RET_VAL +# ============================================================ +# Hash-set (tag 7; sentinel -2 at offset 0 distinguishes from +# hash-table (-1) and plain vector (>= 0)). +# +# Layout (same 24 + 64*8 = 536 bytes as hash-table): +# offset 0 : sentinel = -2 +# offset 8 : count +# offset 16 : nbuckets = 64 +# offset 24..: bucket0..bucket63 (each is a list of raw keys) +# +# One cons cell per entry (vs two for hash-table) — this is the +# speedup vs the portable ht-* lib (Scheme-level alist over vector). +# ============================================================ +.equ HS_SENTINEL, -2 + +# hs_chain_find: walk key list. +# Input: %rdi = bucket head (tagged list), %rsi = key (tagged) +# Output: %rax = VAL_TRUE if found, VAL_FALSE otherwise +hs_chain_find: + pushq %r12 + pushq %rbx + movq %rdi, %rbx # current + movq %rsi, %r12 # key +.hscf_loop: + cmpq $VAL_NIL, %rbx + je .hscf_notfound + movq %rbx, %rax + andq $-8, %rax + movq (%rax), %rdi # entry key + movq %r12, %rsi + call deep_equal + cmpq $VAL_TRUE, %rax + je .hscf_found + movq %rbx, %rax + andq $-8, %rax + movq 8(%rax), %rbx # cdr + jmp .hscf_loop +.hscf_found: + movq $VAL_TRUE, %rax + popq %rbx + popq %r12 + ret +.hscf_notfound: + movq $VAL_FALSE, %rax + popq %rbx + popq %r12 + ret + +# bi_make_hash_set: () -> fresh empty hash-set +bi_make_hash_set: + movq $HT_TOTAL_BYTES, %rdi + call heap_alloc + movq $HS_SENTINEL, (%rax) + movq $0, 8(%rax) + movq $HT_NBUCKETS, 16(%rax) + leaq HT_HEADER_BYTES(%rax), %rcx + movq $HT_NBUCKETS, %rdx +.bmhs_fill: + movq $VAL_NIL, (%rcx) + addq $8, %rcx + decq %rdx + jnz .bmhs_fill + orq $7, %rax + RET_VAL + +# bi_hash_set_p: (hash-set? x) -> bool +bi_hash_set_p: + GETARG %rax + movq %rax, %rcx + andq $TAG_MASK, %rcx + cmpq $7, %rcx + jne .cmp_false + andq $-8, %rax + movq (%rax), %rax + cmpq $HS_SENTINEL, %rax + je .cmp_true + jmp .cmp_false + +# bi_hash_set_add: (hash-set-add! hs key) -> #t if inserted, #f if already present +bi_hash_set_add: + GETARG %rax + andq $-8, %rax + movq %rax, %rbx # untagged hs + GETARG %rbp # key + movq %rbp, %rdi + call hash_value + andq $HT_BUCKET_MASK, %rax + leaq HT_HEADER_BYTES(%rbx,%rax,8), %rcx # slot addr + movq %rcx, %r12 # preserve slot addr across calls + movq (%rcx), %rdi # bucket head + movq %rbp, %rsi + call hs_chain_find + cmpq $VAL_TRUE, %rax + je .bhsa_already + # Insert: prepend key to bucket + movq %rbp, %rdi + movq (%r12), %rsi # old head + call make_pair + movq %rax, (%r12) + incq 8(%rbx) # count++ + movq $VAL_TRUE, %rax + RET_VAL +.bhsa_already: + movq $VAL_FALSE, %rax + RET_VAL + +# bi_hash_set_contains: (hash-set-contains? hs key) -> bool +bi_hash_set_contains: + GETARG %rax + andq $-8, %rax + movq %rax, %rbx + GETARG %rbp + movq %rbp, %rdi + call hash_value + andq $HT_BUCKET_MASK, %rax + movq HT_HEADER_BYTES(%rbx,%rax,8), %rdi + movq %rbp, %rsi + call hs_chain_find + # Already VAL_TRUE or VAL_FALSE + RET_VAL + +# bi_hash_set_size: (hash-set-size hs) -> int +bi_hash_set_size: + GETARG %rax + andq $-8, %rax + movq 8(%rax), %rdi + call make_int + RET_VAL + +# bi_hash_set_to_list: (hash-set->list hs) -> list of keys +bi_hash_set_to_list: + GETARG %rax + andq $-8, %rax + movq %rax, %rbx + movq $VAL_NIL, %r12 + movq $HT_NBUCKETS, %rbp + leaq HT_HEADER_BYTES(%rbx), %rcx + pushq %rcx +.bhsl_bucket: + testq %rbp, %rbp + jz .bhsl_finish + popq %rcx + movq (%rcx), %rax + addq $8, %rcx + pushq %rcx +.bhsl_chain: + cmpq $VAL_NIL, %rax + je .bhsl_next + movq %rax, %rdx + andq $-8, %rdx + movq (%rdx), %rdi # key + movq 8(%rdx), %rax # next + pushq %rax + pushq %rbp + movq %r12, %rsi + call make_pair + popq %rbp + movq %rax, %r12 + popq %rax + jmp .bhsl_chain +.bhsl_next: + decq %rbp + jmp .bhsl_bucket +.bhsl_finish: + addq $8, %rsp + movq %r12, %rax + RET_VAL + # bi_current_time_ms: (current-time-ms) → int ms since epoch # struct timespec is { int64_t tv_sec; int64_t tv_nsec; } — 16 bytes. bi_current_time_ms: diff --git a/examples/bench-hashset.lsp b/examples/bench-hashset.lsp new file mode 100644 index 0000000..e2e4960 --- /dev/null +++ b/examples/bench-hashset.lsp @@ -0,0 +1,136 @@ +;;; bench-hashset.lsp — native hash-set vs portable vector-based ht-* +;;; +;;; ASM-ONLY: exercises the native hash-set-* primitives introduced +;;; alongside the portable-lib equivalent. C and Python tiers do not +;;; carry hash-set builtins (they have hash-table), so this file is +;;; driven from tests/bench-hashset.sh against asm/uncommonlisp only. +;;; +;;; Phases: insert-N, hit-lookup-N, miss-lookup-N. +;;; Output: ms per phase + speedup (portable/native). + +(define N 5000) + +;;; ─── Portable hash-set (vectors + cons chains, pure Scheme) ─── +;;; Identical algorithm to proof-netspace-server-lib.lsp. + +(define *pht-buckets* 127) + +(define (pht-make) + (let ((v (make-vector (+ *pht-buckets* 1) '()))) + (vector-set! v 0 *pht-buckets*) + v)) + +(define (pht-bucket t k) + (+ 1 (modulo (if (< k 0) (- 0 k) k) (vector-ref t 0)))) + +(define (pht-in? bucket k) + (cond ((null? bucket) #f) + ((= (car bucket) k) #t) + (else (pht-in? (cdr bucket) k)))) + +(define (pht-has? t k) + (pht-in? (vector-ref t (pht-bucket t k)) k)) + +(define (pht-add! t k) + (let ((idx (pht-bucket t k))) + (let ((bucket (vector-ref t idx))) + (if (pht-in? bucket k) #f + (begin (vector-set! t idx (cons k bucket)) #t))))) + +;;; ─── Timing helpers ─── + +(define (ms-since t0) (- (current-time-ms) t0)) + +(define (report label ms) + (display label) (display ": ") (display ms) (display " ms") (newline)) + +;;; ─── Phase runners ─── + +(define (portable-insert! t n) + (define (loop i) + (if (>= i n) 'done + (begin (pht-add! t i) (loop (+ i 1))))) + (loop 0)) + +(define (portable-hit-lookups t n) + (define (loop i hits) + (if (>= i n) hits + (loop (+ i 1) (if (pht-has? t i) (+ hits 1) hits)))) + (loop 0 0)) + +(define (portable-miss-lookups t n) + (define (loop i) + (if (>= i n) 'done + (begin (pht-has? t (+ i n)) (loop (+ i 1))))) + (loop 0)) + +(define (native-insert! s n) + (define (loop i) + (if (>= i n) 'done + (begin (hash-set-add! s i) (loop (+ i 1))))) + (loop 0)) + +(define (native-hit-lookups s n) + (define (loop i hits) + (if (>= i n) hits + (loop (+ i 1) (if (hash-set-contains? s i) (+ hits 1) hits)))) + (loop 0 0)) + +(define (native-miss-lookups s n) + (define (loop i) + (if (>= i n) 'done + (begin (hash-set-contains? s (+ i n)) (loop (+ i 1))))) + (loop 0)) + +;;; ─── Driver ─── + +(display "=== hash-set benchmark N=") (display N) (display " ===") (newline) + +(display "-- portable (vectors + cons chains, Scheme) --") (newline) +(define pt (pht-make)) +(define t0 (current-time-ms)) +(portable-insert! pt N) +(define p-ins (ms-since t0)) +(report " insert" p-ins) + +(set! t0 (current-time-ms)) +(define p-hits (portable-hit-lookups pt N)) +(define p-hit-ms (ms-since t0)) +(report " hit-lookup" p-hit-ms) +(display " (hits=") (display p-hits) (display ")") (newline) + +(set! t0 (current-time-ms)) +(portable-miss-lookups pt N) +(define p-miss (ms-since t0)) +(report " miss-lookup" p-miss) + +(display "-- native (hash-set-*, bump-allocated in asm) --") (newline) +(define ns (make-hash-set)) +(set! t0 (current-time-ms)) +(native-insert! ns N) +(define n-ins (ms-since t0)) +(report " insert" n-ins) + +(set! t0 (current-time-ms)) +(define n-hits (native-hit-lookups ns N)) +(define n-hit-ms (ms-since t0)) +(report " hit-lookup" n-hit-ms) +(display " (hits=") (display n-hits) (display ")") (newline) + +(set! t0 (current-time-ms)) +(native-miss-lookups ns N) +(define n-miss (ms-since t0)) +(report " miss-lookup" n-miss) + +(display "-- speedup (portable / native) --") (newline) +(define (speedup-x p n) + (if (= n 0) 'infinite (quotient (* 1000 p) n))) +(display " insert: ") (display (speedup-x p-ins n-ins)) +(display " (milliX, so ")(display (quotient (speedup-x p-ins n-ins) 1000)) +(display "x)") (newline) +(display " hit-lookup: ") (display (speedup-x p-hit-ms n-hit-ms)) +(display " (milliX, so ")(display (quotient (speedup-x p-hit-ms n-hit-ms) 1000)) +(display "x)") (newline) +(display " miss-lookup: ") (display (speedup-x p-miss n-miss)) +(display " (milliX, so ")(display (quotient (speedup-x p-miss n-miss) 1000)) +(display "x)") (newline) diff --git a/tests/bench-hashset.sh b/tests/bench-hashset.sh new file mode 100755 index 0000000..b9d0904 --- /dev/null +++ b/tests/bench-hashset.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# bench-hashset.sh — run the asm native hash-set vs portable benchmark +# and echo the speedup. ASM-only: C/Python have no hash-set builtin. +set -e +cd "$(dirname "$0")/.." + +ulimit -v 524288 +trap 'pkill -9 -u "$USER" -f "asm/uncommonlisp" 2>/dev/null || true' EXIT + +# Build if needed +if [ ! -x asm/uncommonlisp ] || [ asm/uncommonlisp.s -nt asm/uncommonlisp ]; then + make -s asm-build +fi + +timeout 60 ./asm/uncommonlisp < examples/bench-hashset.lsp + +# Verify cleanup +if pgrep -u "$USER" -f 'asm/uncommonlisp' > /dev/null; then + echo "STRAGGLER asm/uncommonlisp detected" >&2 + exit 1 +fi