2016-08-13 7 views
3

Gibt es eine Möglichkeit, wie viel Stapelspeicher eine Funktion verwendet?Wie misst man einen Funktionsstack in Rust?

Diese Frage ist nicht spezifisch für rekursive Funktionen; Ich wollte jedoch wissen, wie viel Stapelspeicher eine rekursiv aufgerufene Funktion benötigt.

Ich war daran interessiert, die Funktion für Stack-Speicher-Nutzung zu optimieren; Aber ohne zu wissen, welche Optimierungen der Compiler bereits macht, ist es nur rätselhaft, ob dies wirklich Verbesserungen bringt oder nicht.

Um klar zu sein, ist dies nicht eine Frage darüber, wie für eine bessere Stack-Nutzung zu optimieren.

Gibt es also eine zuverlässige Möglichkeit herauszufinden, wie viel Stapelspeicher eine Funktion in Rust verwendet?


Beachten Sie, dass andere Compiler dies zu unterstützen, hat GCC -fstack-usage zum Beispiel.

+1

Verwandte: [Wie Benchmark-Speicherverbrauch einer Funktion?] (Http://Stackoverflow.com/q/30869007/155423) – Shepmaster

Antwort

2

Als letzten Ausweg können Sie den Stack-Zeiger (mit Inline-Assembly) beobachten und daraus das Ergebnis ableiten. Diese Methode ist definitiv nicht etwas, das Sie in der Produktion verwenden würden ... aber es funktioniert.

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