Как оценивать использование памяти функцией?

Я замечаю, что тест Rust имеет эталонный режим, который будет измерять время выполнения в ns/iter, но я не смог найти способ измерения использования памяти.

Как мне реализовать такой бенчмарк? Предположим, что на данный момент я только забочусь о памяти кучи (хотя использование стека также, безусловно, было бы интересно).

Изменить: я нашел эту проблему, которая запрашивает то же самое.

Ответы

Ответ 1

С Rust 1.0 и 1.1 вы можете использовать ящик libc, чтобы распечатать статистику 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())};
}

В более поздних версиях 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())};}

(игровая площадка)

В однопоточной программе, которая должна позволить вам получить хорошее измерение того, сколько памяти занимает структура. Просто распечатайте статистику до создания структуры, а затем и вычислите разницу.


Вы также можете использовать Valgrind (Massif), чтобы получить профиль кучи. Он работает так же, как и с любой другой программой на C. Убедитесь, что в исполняемом файле включены символы отладки (например, с использованием отладочной сборки или пользовательской конфигурации груза). Вы можете использовать, скажем, http://massiftool.sourceforge.net/, чтобы проанализировать сгенерированный профиль кучи.

(Я проверил это, чтобы работать на Debian Jessie, в другой настройке ваш пробег может меняться).

Чтобы использовать Rust с Valgrind, вам, вероятно, придется переключиться на системный распределитель:

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

jemalloc можно сообщить, чтобы сбросить профиль памяти. Возможно, вы можете сделать это с помощью Rust FFI, но я не исследовал этот маршрут.

Ответ 2

Что касается размеров структуры данных, это можно сделать довольно легко с помощью использования признаков и небольшого плагина компилятора. Nicholas Nethercote в своей статье Измерение размеров структуры данных: Firefox (С++) и Servo (Rust) демонстрирует, как это работает в Servo; это сводится к добавлению #[derive(HeapSizeOf)] (или иногда к ручной реализации) к каждому типу, который вас интересует. Это хороший способ обеспечить точную проверку того, где происходит память; он, однако, сравнительно навязчив, поскольку требует внесения изменений, в первую очередь, где-то вроде jemallocs print_stats() doesnt. Тем не менее, для хороших и точных измерений его звуковой подход.

Ответ 3

В настоящее время единственным способом получить информацию о размещении является метод alloc::heap::stats_print(); (за #![feature(alloc)]), который вызывает jemalloc print_stats().

Я обновлю этот ответ с дополнительной информацией, как только узнаю, что означает выход.

(Заметьте, что я не буду принимать этот ответ, поэтому, если кто-то придумает лучшее решение...)