【问题标题】:How to measure a functions stack usage in Rust?如何测量 Rust 中的函数堆栈使用情况?
【发布时间】:2016-12-20 03:36:20
【问题描述】:

有没有一种方法可以测量一个函数使用了多少堆栈内存?

这个问题不是针对递归函数的;但是我很想知道递归调用的函数会占用多少堆栈内存。

我有兴趣优化堆栈内存使用的函数;但是,在不知道编译器已经进行了哪些优化的情况下,这只是猜测是否会进行真正的改进。

明确地说,这不是关于如何优化以更好地使用堆栈的问题。

那么有没有一些可靠的方法可以找出函数在 Rust 中使用了多少堆栈内存?


请注意,其他编译器也支持这一点,例如 GCC 有 -fstack-usage

【问题讨论】:

标签: rust stack-memory


【解决方案1】:

作为最后的手段,您可以观察堆栈指针(使用内联汇编)并从中推断结果。这种方法绝对不是你在生产中使用的东西……但它确实有效。

#![feature(asm)]

use std::cell::Cell;
use std::cmp;
use std::usize;

// This global variable tracks the highest point of the stack
thread_local!(static STACK_END: Cell<usize> = Cell::new(usize::MAX));

macro_rules! stack_ptr {
    () => ({
        // Grab a copy of the stack pointer
        let x: usize;
        unsafe {
            asm!("mov %rsp, $0" : "=r"(x) ::: "volatile");
        }
        x
    })
}

/// Saves the current position of the stack. Any function
/// being profiled must call this macro.
macro_rules! tick {
    () => ({
        // Save the current stack pointer in STACK_END
        let stack_end = stack_ptr!();
        STACK_END.with(|c| {
            // Since the stack grows down, the "tallest"
            // stack must have the least pointer value
            let best = cmp::min(c.get(), stack_end);
            c.set(best);
        });
    })
}

/// Runs the given callback, and returns its maximum stack usage
/// as reported by the `tick!()` macro.
fn measure<T, F: FnOnce() -> T>(callback: F) -> (T, usize) {
    STACK_END.with(|c| c.set(usize::MAX));
    let stack_start = stack_ptr!();
    let r = callback();
    let stack_end = STACK_END.with(|c| c.get());
    if stack_start < stack_end {
        panic!("tick!() was never called");
    }
    (r, stack_start - stack_end)
}

/// Example recursive function
fn fibonacci(n: i64) -> i64 {
    tick!();
    match n {
        0 => 0,
        1 => 1,
        _ => fibonacci(n-1) + fibonacci(n-2)
    }
}

fn main() {
    // Stack usage should grow linearly with `i`
    for i in 0 .. 10 {
        let (result, stack) = measure(|| fibonacci(i));
        println!("fibonacci({}) = {}: used {} bytes of stack", i, result, stack);
    }
}

【讨论】:

    【解决方案2】:

    目前有一些实验性工具可以估计堆栈使用情况:https://crates.io/crates/cargo-call-stack 它使用实验性的-Z emit-stack-sizes 来获取每个函数的堆栈,然后设法提取调用图并从中生成最坏情况估计

    【讨论】:

      猜你喜欢
      • 2015-04-13
      • 2012-05-09
      • 2021-03-01
      • 2010-09-08
      • 1970-01-01
      • 2011-12-15
      • 2011-06-23
      • 2021-05-18
      • 2013-08-18
      相关资源
      最近更新 更多