From f7c0902d8d846a3b048a1d37df3c8567ea380619 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 14 Oct 2026 19:56:57 +0200 Subject: [PATCH] decode_stack tests: box the decoded result on the small thread, measured thread sizes; doctest fixture serde-able Measured on Yggdrasil: the decode needs 56 KiB (Wide32) and 80 KiB (Largest) in debug on a thread that returns a bool; returning the record through std::thread's own frames adds several copies of it, so the tests box it and size threads at 96 KiB and from 160 KiB. Co-Authored-By: Claude Sonnet 5.5 --- packages/cultcache-rs/src/lib.rs | 2 +- packages/cultcache-rs/tests/decode_stack.rs | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/cultcache-rs/src/lib.rs b/packages/cultcache-rs/src/lib.rs index 98258845..ba40b72a 100644 --- a/packages/cultcache-rs/src/lib.rs +++ b/packages/cultcache-rs/src/lib.rs @@ -655,7 +655,7 @@ const DECODE_STACK_SEGMENT: usize = 2 * 1024 * 1024; /// #[cultcache(key = 0)] /// bytes: Vec, /// #[cultcache(key = 1)] -/// header: [u8; 16 * 1024 - 64], +/// header: [[u64; 32]; 63], /// } /// ``` pub const MAX_RECORD_INLINE_BYTES: usize = 16 * 1024; diff --git a/packages/cultcache-rs/tests/decode_stack.rs b/packages/cultcache-rs/tests/decode_stack.rs index 819e9b79..444667d6 100644 --- a/packages/cultcache-rs/tests/decode_stack.rs +++ b/packages/cultcache-rs/tests/decode_stack.rs @@ -177,8 +177,11 @@ fn empty_wide() -> Wide32 { } } +/// The decode alone runs on the small thread. Its result is boxed there so that the thread's own +/// return machinery, which would hold several more copies of a large record in a debug build, does +/// not count against the stack under test; what the caller's frames hold is the caller's to size. fn decode_on(stack: usize, bytes: Vec) -> anyhow::Result { - on_stack(stack, move || decode_payload::(&bytes)) + *on_stack(stack, move || Box::new(decode_payload::(&bytes))) } #[test] @@ -312,10 +315,10 @@ fn a_wide_record_100_levels_deep_decodes_on_a_1mib_thread() { } #[test] -fn a_wide_record_decodes_on_a_64kib_thread_at_one_level_and_at_the_limit() { - in_child("a_wide_record_decodes_on_a_64kib_thread_at_one_level_and_at_the_limit", || { - decode_wide_chain(1, 64 * KIB); - decode_wide_chain(MAX_PAYLOAD_DEPTH - 1, 64 * KIB); +fn a_wide_record_decodes_on_a_96kib_thread_at_one_level_and_at_the_limit() { + in_child("a_wide_record_decodes_on_a_96kib_thread_at_one_level_and_at_the_limit", || { + decode_wide_chain(1, 96 * KIB); + decode_wide_chain(MAX_PAYLOAD_DEPTH - 1, 96 * KIB); }); } @@ -339,7 +342,7 @@ fn the_largest_record_at_the_limit_decodes_on_every_thread_size() { assert!(check_payload_depth(&rmp_serde::to_vec(&union_chain(128)).unwrap()).is_err()); (records, unions) }); - let sizes = (128..=1024).step_by(32).map(|kib| kib * KIB).chain([1536, 2048, 3072, 4096, 8192].map(|kib| kib * KIB)); + let sizes = (160..=1024).step_by(32).map(|kib| kib * KIB).chain([1536, 2048, 3072, 4096, 8192].map(|kib| kib * KIB)); for size in sizes { println!("thread of {} KiB", size / KIB); let decoded = decode_on::(size, records.clone()).unwrap();