2016-08-13 6 views
3

Есть ли способ, который я могу измерить, сколько памяти стека использует функция?Как измерить использование стека функций в Rust?

Этот вопрос не относится к рекурсивным функциям; однако мне было интересно узнать, сколько памяти стека примет функция, называемая рекурсивно.

Мне было интересно оптимизировать функцию для использования памяти стека; однако, не зная, какие оптимизации компилятор уже делает, это просто угадайте, если это делает реальные улучшения или нет.

Чтобы быть ясным, это не вопрос вопрос о том, как оптимизировать для лучшего использования стека.

Так есть ли какой-нибудь надежный способ узнать, сколько памяти стека использует функция в Rust?


Обратите внимание, что другие компиляторы поддерживают это, GCC имеет -fstack-usage, например.

+1

Связанный: [Как оценивать использование памяти функцией?] (Http://stackoverflow.com/q/30869007/155423) – Shepmaster

ответ

2

В крайнем случае вы можете наблюдать указатель стека (используя встроенную сборку) и вывести результат из этого. Этот метод определенно не то, что вы будете использовать в производстве ... но он работает.

#![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); 
    } 
}