core: seq walks over concrete collections are linear (bench TOTAL -18%)
Reviewing flatiron's morsel batching for applicability turned up something better hiding under the lazy machinery: every cell over a concrete collection was produced by slicing the REMAINDER ((tuple/slice c 1) per element in coll->cells, and rest/next sliced the same way), so any full walk was O(n^2). mapv over 40k elements took 10.4 SECONDS; a 20k-element first/rest loop took two. Cells over indexed collections now walk by INDEX (one shared indexed-cells helper, O(1) per step), and rest/next of a vector/tuple/list return an O(1) lazy view from index 1 — which also makes (rest [1 2 3]) a SEQ, as in Clojure (it was a vector-typed slice; seq?/vector? rows pin the change). mapv 40k: 10405 -> 182 ms. rest-loop 20k: 2040 -> 31 ms. Whole bench: seq-pipe -28%, into-vec -24%, str-join -18%, hof -26%, TOTAL 4565 -> 3753 (-18% vs main, back to back). Chunked seqs (jolt-yqc) drop in priority: the quadratic walks were the actual cost; chunking now only amortizes per-element closure allocation. Nine regression rows incl. 20k/50k linear-scaling smoke tests. Gate exit 0.
This commit is contained in:
parent
c24c7617b8
commit
4f78f6be33
2 changed files with 38 additions and 6 deletions
|
|
@ -273,3 +273,20 @@
|
|||
["splitv-at" "[[1 2] [3 4]]" "(splitv-at 2 [1 2 3 4])"]
|
||||
["splitv-at first is vector" "true" "(vector? (first (splitv-at 2 [1 2 3])))"]
|
||||
["splitv-at past end" "[[1 2] []]" "(splitv-at 5 [1 2])"])
|
||||
|
||||
# Linear seq walks (flatiron review find): cell chains over concrete
|
||||
# collections walk by INDEX. Slicing the remainder per step made every full
|
||||
# walk O(n^2) — mapv over 40k elements took ten seconds, a 20k first/rest
|
||||
# loop took two. rest/next of an indexed collection is an O(1) lazy view —
|
||||
# and therefore a SEQ, as in Clojure (it was a vector-typed slice).
|
||||
(defspec "sequences / linear walks over concrete collections"
|
||||
["rest of vector is a seq" "true" "(seq? (rest [1 2 3]))"]
|
||||
["rest of vector not vector" "false" "(vector? (rest [1 2 3]))"]
|
||||
["rest values" "(quote (2 3))" "(rest [1 2 3])"]
|
||||
["next of vector" "(quote (2 3))" "(next [1 2 3])"]
|
||||
["next exhausts to nil" "nil" "(next [1])"]
|
||||
["rest exhausts to ()" "()" "(rest [1])"]
|
||||
["rest-loop scales (20k linear)" "20000"
|
||||
"(loop [xs (seq (vec (range 20000))) n 0] (if xs (recur (next xs) (inc n)) n))"]
|
||||
["mapv scales (50k linear)" "50000" "(count (mapv inc (vec (range 50000))))"]
|
||||
["nested walk" "[2 3]" "(vec (rest (mapv inc [0 1 2])))"])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue