如何基准测试函数的内存使用情况?

llo*_*giq 18 memory benchmarking rust

我注意到Rust的测试有一个测量执行时间的基准模式ns/iter,但我找不到测量内存使用情况的方法.

我该如何实施这样的基准?让我们假设目前我只关心堆内存(虽然堆栈使用也肯定会很有趣).

编辑:我发现这个问题要求完全相同的事情.

Art*_*mGr 11

使用Rust 1.0和1.1,您可以使用libc crate来打印jemalloc统计信息:

#![feature(libc)]
extern crate libc;
use libc::*;
extern {fn je_malloc_stats_print (write_cb: extern fn (*const c_void, *const c_char), cbopaque: *const c_void, opts: *const c_char);}
extern fn write_cb (_: *const c_void, message: *const c_char) {
    print! ("{}", String::from_utf8_lossy (unsafe {std::ffi::CStr::from_ptr (message as *const i8) .to_bytes()}));
}

fn main() {
    unsafe {je_malloc_stats_print (write_cb, std::ptr::null(), std::ptr::null())};
}
Run Code Online (Sandbox Code Playgroud)

在后来的Rust版本(1.8 - 1.14)中,我们将其je_malloc_stats_print重命名为je_stats_print:

#![feature(libc)]
extern crate libc;
extern {fn je_stats_print (write_cb: extern fn (*const libc::c_void, *const libc::c_char), cbopaque: *const libc::c_void, opts: *const libc::c_char);}
extern fn write_cb (_: *const libc::c_void, message: *const libc::c_char) {
    print! ("{}", String::from_utf8_lossy (unsafe {std::ffi::CStr::from_ptr (message as *const i8) .to_bytes()}));}
fn main() {unsafe {je_stats_print (write_cb, std::ptr::null(), std::ptr::null())};}
Run Code Online (Sandbox Code Playgroud)

(游乐场)

在单线程程序中,应该可以让您很好地测量结构占用的内存量.只需在创建结构之前打印统计数据,然后计算差异.


您还可以使用Valgrind(Massif)来获取堆配置文件.它的工作方式与任何其他C程序一样.确保在可执行文件中启用了调试符号(例如,使用调试版本或自定义Cargo配置).例如,您可以使用http://massiftool.sourceforge.net/来分析生成的堆配置文件.

(我在Debian Jessie上验证了这一点,在不同的设置中你的里程可能会有所不同).

为了在Valgrind中使用Rust,您可能必须切换到系统分配器:

#![feature(alloc_system)]
extern crate alloc_system;
Run Code Online (Sandbox Code Playgroud)

可以告诉 jemalloc 转储内存配置文件.您可以使用Rust FFI执行此操作,但我没有调查此路线.


Chr*_*gan 8

就测量数据结构大小而言,这可以通过使用特征和小编译器插件相当容易地完成.Nicholas Nethercote在他的文章中测量数据结构大小:Firefox(C++)与Servo(Rust)演示了它在Servo中的工作原理; 它归结为#[derive(HeapSizeOf)]为你关心的每种类型添加(或偶尔手动实现).这是一种允许精确检查内存去向的好方法; 然而,它是相对侵入性的,因为它首先需要做出改变,而像jemalloc这样的东西print_stats()却没有.尽管如此,对于良好和精确的测量,这是一种合理的方法.


llo*_*giq 6

目前,获取分配信息的唯一方法是 调用jemalloc的alloc::heap::stats_print();方法(后面#![feature(alloc)])print_stats().

一旦我了解了输出的含义,我将用更多信息更新这个答案.

(请注意,我不会接受这个答案,所以如果有人想出更好的解决方案......)

  • @invis我使用[`jemalloc_ctl`](https://docs.rs/jemalloc-ctl/latest/jemalloc_ctl/),这里是[详细信息](/sf/answers/4321020511/) (2认同)

dir*_*lik 5

现在有jemalloc_ctlcrate 提供方便、安全的类型化 API。将其添加到您的Cargo.toml

[dependencies]
jemalloc-ctl = "0.3"
jemallocator = "0.3"
Run Code Online (Sandbox Code Playgroud)

然后配置jemalloc全局分配器并使用jemalloc_ctl::stats模块中的方法:


这是官方示例

use std::thread;
use std::time::Duration;
use jemalloc_ctl::{stats, epoch};

#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;

fn main() {
    loop {
        // many statistics are cached and only updated when the epoch is advanced.
        epoch::advance().unwrap();

        let allocated = stats::allocated::read().unwrap();
        let resident = stats::resident::read().unwrap();
        println!("{} bytes allocated/{} bytes resident", allocated, resident);
        thread::sleep(Duration::from_secs(10));
    }
}
Run Code Online (Sandbox Code Playgroud)