货物测试 - release会导致堆栈溢出.货舱为何没有?

Jos*_*osh 9 testing benchmarking stack rust rust-cargo

在尝试编写优化的DSP算法时,我想知道堆栈分配和堆分配之间的相对速度,以及堆栈分配的数组的大小限制.我意识到堆栈帧大小限制,但我不明白为什么以下运行,生成看似真实的基准测试结果cargo bench,但运行时出现堆栈溢出失败cargo test --release.

#![feature(test)]
extern crate test;

#[cfg(test)]
mod tests {
    use test::Bencher;

    #[bench]
    fn it_works(b: &mut Bencher) {
        b.iter(|| { let stack = [[[0.0; 2]; 512]; 512]; });
    }
}
Run Code Online (Sandbox Code Playgroud)

ken*_*ytm 16

为了更好地理解,请注意阵列的大小为8×2×512×512 = 4 MiB.

cargo test崩溃,但cargo bench不是因为"test" it_works() 在新线程中调用该函数,而"bench" 在主线程中调用它.

主线程的默认堆栈大小通常为8 MiB,因此该阵列将占用可用堆栈的一半.这是很多,但仍然有空间,所以基准测试正常运行.

但是,新线程堆栈大小通常要小得多.在Linux上它是2 MiB,其他平台可能更小.因此,您的4 MiB阵列很容易溢出线程的堆栈并导致堆栈溢出/段错误.

您可以通过设置RUST_MIN_STACK环境变量来增加新线程的默认堆栈大小.

$ RUST_MIN_STACK=8388608 cargo test 
Run Code Online (Sandbox Code Playgroud)

cargo test 以并行线程运行测试以改善总测试时间,同时在同一线程中按顺序运行基准测试以降低噪声.

由于堆栈大小有限,在堆栈上分配此数组是个坏主意.您必须将其存储在堆(boxit)上或作为全局存储static mut.

  • @Shepmaster我在LLDB中运行它并注意到测试是在"thread#1"(主线程)中运行 - 带有--bench标志,"thread#2"运行--test标志,当我将数组大小调到5120.相关代码似乎在这里:https://github.com/rust-lang/rust/blob/8c4f2c64c6759a82f143e23964a46a65c67509c9/src/libtest/lib.rs#L1337-L1369.--test生成一个新线程,而--bench直接运行.另外,`catch_unwind`不会启动新线程. (4认同)