Get the current memory usage of a variable? [duplicate] - performance

I notice that Rust's test has a benchmark mode that will measure execution time in ns/iter, but I could not find a way to measure memory usage.
How would I implement such a benchmark? Let us assume for the moment that I only care about heap memory at the moment (though stack usage would also certainly be interesting).
Edit: I found this issue which asks for the exact same thing.

You can use the jemalloc allocator to print the allocation statistics. For example,
Cargo.toml:
[package]
name = "stackoverflow-30869007"
version = "0.1.0"
edition = "2018"
[dependencies]
jemallocator = "0.5"
jemalloc-sys = {version = "0.5", features = ["stats"]}
libc = "0.2"
src/main.rs:
use libc::{c_char, c_void};
use std::ptr::{null, null_mut};
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
extern "C" fn write_cb(_: *mut c_void, message: *const c_char) {
print!("{}", String::from_utf8_lossy(unsafe {
std::ffi::CStr::from_ptr(message as *const i8).to_bytes()
}));
}
fn mem_print() {
unsafe { jemalloc_sys::malloc_stats_print(Some(write_cb), null_mut(), null()) }
}
fn main() {
mem_print();
let _heap = Vec::<u8>::with_capacity (1024 * 128);
mem_print();
}
In a single-threaded program that should allow you to get a good measurement of how much memory a structure takes. Just print the statistics before the structure is created and after and calculate the difference.
(The "total:" of "allocated" in particular.)
You can also use Valgrind (Massif) to get the heap profile. It works just like with any other C program. Make sure you have debug symbols enabled in the executable (e.g. using debug build or custom Cargo configuration). You can use, say, http://massiftool.sourceforge.net/ to analyse the generated heap profile.
(I verified this to work on Debian Jessie, in a different setting your mileage may vary).
(In order to use Rust with Valgrind you'll probably have to switch back to the system allocator).
P.S. There is now also a better DHAT.
jemalloc can be told to dump a memory profile. You can probably do this with the Rust FFI but I haven't investigated this route.

As far as measuring data structure sizes is concerned, this can be done fairly easily through the use of traits and a small compiler plugin. Nicholas Nethercote in his article Measuring data structure sizes: Firefox (C++) vs. Servo (Rust) demonstrates how it works in Servo; it boils down to adding #[derive(HeapSizeOf)] (or occasionally a manual implementation) to each type you care about. This is a good way of allowing precise checking of where memory is going, too; it is, however, comparatively intrusive as it requires changes to be made in the first place, where something like jemalloc’s print_stats() doesn’t. Still, for good and precise measurements, it’s a sound approach.

Currently, the only way to get allocation information is the alloc::heap::stats_print(); method (behind #![feature(alloc)]), which calls jemalloc's print_stats().
I'll update this answer with further information once I have learned what the output means.
(Note that I'm not going to accept this answer, so if someone comes up with a better solution...)

Now there is jemalloc_ctl crate which provides convenient safe typed API. Add it to your Cargo.toml:
[dependencies]
jemalloc-ctl = "0.3"
jemallocator = "0.3"
Then configure jemalloc to be global allocator and use methods from jemalloc_ctl::stats module:
jemalloc_ctl::stats::allocated
jemalloc_ctl::stats::resident
Here is official example:
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));
}
}

There's a neat little solution someone put together here: https://github.com/discordance/trallocator/blob/master/src/lib.rs
use std::alloc::{GlobalAlloc, Layout};
use std::sync::atomic::{AtomicU64, Ordering};
pub struct Trallocator<A: GlobalAlloc>(pub A, AtomicU64);
unsafe impl<A: GlobalAlloc> GlobalAlloc for Trallocator<A> {
unsafe fn alloc(&self, l: Layout) -> *mut u8 {
self.1.fetch_add(l.size() as u64, Ordering::SeqCst);
self.0.alloc(l)
}
unsafe fn dealloc(&self, ptr: *mut u8, l: Layout) {
self.0.dealloc(ptr, l);
self.1.fetch_sub(l.size() as u64, Ordering::SeqCst);
}
}
impl<A: GlobalAlloc> Trallocator<A> {
pub const fn new(a: A) -> Self {
Trallocator(a, AtomicU64::new(0))
}
pub fn reset(&self) {
self.1.store(0, Ordering::SeqCst);
}
pub fn get(&self) -> u64 {
self.1.load(Ordering::SeqCst)
}
}
Usage: (from: https://www.reddit.com/r/rust/comments/8z83wc/comment/e2h4dp9)
// needed for Trallocator struct (as written, anyway)
#![feature(integer_atomics, const_fn_trait_bound)]
use std::alloc::System;
#[global_allocator]
static GLOBAL: Trallocator<System> = Trallocator::new(System);
fn main() {
GLOBAL.reset();
println!("memory used: {} bytes", GLOBAL.get());
{
let mut vec = vec![1, 2, 3, 4];
for i in 5..20 {
vec.push(i);
println!("memory used: {} bytes", GLOBAL.get());
}
for v in vec {
println!("{}", v);
}
}
// For some reason this does not print zero =/
println!("memory used: {} bytes", GLOBAL.get());
}
I've just started using it, and it seems to work well! Straight-forward, realtime, requires no external packages, and doesn't require changing your base memory allocator.
It's also nice that, because it's intercepting the allocate/deallocate calls, you should be able to add custom logic if desired (eg. if memory usage goes above X, print the stack-trace to see what's triggering the allocations) -- although I haven't tried this yet.
I also haven't yet tested to see how much overhead this approach adds. If someone does a test for this, let me know!

Related

Rust nalgebra - new_random() throws error for DMatrix

Im trying to port https://github.com/markkraay/mnist-from-scratch to rust as an introduction to ML and the rust programming language.
I've decided to use nalgebra instead of rewriting a matrix library. However, im running into an error stating function or associated item not found in `Matrix<f64, Dynamic, Dynamic, VecStorage<f64, Dynamic, Dynamic>> when attempting to run new_random() on a DMatrix and I cant see how to fix It.
For context this is my code
pub fn new(input: usize, hidden: usize, output: usize, learning_rate: usize) -> NeuralNetwork {
let hidden_weights = na::DMatrix::<f64>::new_random(hidden, input);
let output_weights = na::DMatrix::<f64>::new_random(output, hidden);
NeuralNetwork {
input,
hidden,
output,
learning_rate,
hidden_weights,
output_weights
}
}
Ive tried removing <f64> so that it is instead
na::DMatrix::new_random(hidden, input);
but there is no difference
To use new_random you have to enable the rand feature of nalgebra like so in Cargo.toml:
[dependencies]
nalgebra = { version = "0.31.4", features = ["rand"] }
after that your code should work as you posted it.
If you have cargo-edit installed you can also do:
cargo add nalgebra --features rand

Cannot borrow data in dereference of `std::sync::RwLockReadGuard<'_, LruCache<i32, bytes::Bytes>>` as mutable

I am quite new to Rust. I'm trying to build a global cache using lru::LruCache and a RwLock for safety. It needs to be globally accessible based on my program's architecture.
//Size to take up 5MB
const CACHE_ENTRIES: usize = (GIBYTE as usize/ 200) / (BLOCK_SIZE);
pub type CacheEntry = LruCache<i32, Bytes>;
static mut CACHE : CacheEntry = LruCache::new(CACHE_ENTRIES);
lazy_static!{
static ref BLOCKCACHE: RwLock<CacheEntry> = RwLock::new(CACHE);
}
//this gets called from another setup function
async fn download_block(&self,
context: &BlockContext,
buf: &mut [u8],
count: u32, //bytes to read
offset: u64,
buf_index: u32
) -> Result<u32> {
let block_index = context.block_index;
let block_data : Bytes = match {BLOCKCACHE.read().unwrap().get(&block_index)} {
Some(data) => data.to_owned(),
None => download_block_from_remote(context).await.unwrap().to_owned(),
};
//the rest of the function does stuff with the block_data
}
async fn download_block_from_remote(context: &BlockContext) -> Result<Bytes>{
//code to download block data from remote into block_data
{BLOCKCACHE.write().unwrap().put(block_index, block_data.clone())};
Ok(block_data)
}
Right now I am getting an error on this line:
let block_data = match {BLOCKCACHE.read().unwrap().get(&block_index)} {
"cannot borrow as mutable" for the value inside the braces.
"help: trait DerefMut is required to modify through a dereference, but it is not implemented for std::sync::RwLockReadGuard<'_, LruCache<i32, bytes::Bytes>>"
I have gotten some other errors involving ownership and mutability, but I can't seem to get rid of this. Is anyone able to offer guidance on how to get this to work, or set me on the right path if it's just not possible/feasible?
The problem here is that LruCache::get() requires mutable access to the cache object. (Reason: it's a cache object, which has to change its internal state when querying things for the actual caching)
Therefore, if you use an RwLock, you need to use the write() method instead of the read() method.
That said, the fact that get() requires mutable access makes the entire RwLock pretty pointless, and I'd use a normal Mutex instead. There is very rarely the necessity to use an RwLock as it has more overhead compared to a simple Mutex.

Immutable Strings and Cloning

I have the mindset keeping my Strings immutable, a single source of truth.
As I take the same mindset into Rust, I find I have to do a lot of cloning.
Since the Strings do not change, all the cloning is unnecessary.
Below there is an example of this and link to the relevant playground.
Borrowing does not seem like an option as I would have to deal with references and their lifetimes. My next thought is to use something like Rc or Cow struct. But wrapping all the Strings with something like Rc feels unnatural. In my limited experience of Rust, I have never seen any exposed ownership/memory management structs, that is Rc and Cow. I am curious how a more experience Rust developer would handle such a problem.
Is it actually natural in Rust to expose ownership/memory management structs like Rc and Cow? Should I be using slices?
use std::collections::HashSet;
#[derive(Debug)]
enum Check {
Known(String),
Duplicate(String),
Missing(String),
Unknown(String)
}
fn main() {
let known_values: HashSet<_> = [
"a".to_string(),
"b".to_string(),
"c".to_string()]
.iter().cloned().collect();
let provided_values = vec![
"a".to_string(),
"b".to_string(),
"z".to_string(),
"b".to_string()
];
let mut found = HashSet::new();
let mut check_values: Vec<_> = provided_values.iter().cloned()
.map(|v| {
if known_values.contains(&v) {
if found.contains(&v) {
Check::Duplicate(v)
} else {
found.insert(v.clone());
Check::Known(v)
}
} else {
Check::Unknown(v)
}
}).collect();
let missing = known_values.difference(&found);
check_values = missing
.cloned()
.fold(check_values, |mut cv, m| {
cv.push(Check::Missing(m));
cv
});
println!("check_values: {:#?}", check_values);
}
From the discussion in the comments of my question, all the cloning of immutable Strings in the example is correct. The cloning is necessary due to Rust handling memory via ownership rather than a reference in other languages.
At best, without using Rc, I can see some reduction in the cloning by using move semantics on provided_values.
Update: Some interesting reading
https://www.reddit.com/r/rust/comments/5xjl95/rc_or_cloning/
https://medium.com/swlh/ownership-managing-memory-in-rust-ce7bf3f5c9d5
How to create a Rust struct with string members?
Cow would not work in my example as it involves a borrowing of a reference. Rc would be what I would have to use. In my example everything has to be converted to Rc but I can see the potential that this could all be hidden away through encapsulation.
use std::collections::HashSet;
use std::rc::Rc;
#[derive(Debug)]
enum Check {
Known(Rc<String>),
Duplicate(Rc<String>),
Missing(Rc<String>),
Unknown(Rc<String>)
}
fn main() {
let known_values: HashSet<_> = [
Rc::new("a".to_string()),
Rc::new("b".to_string()),
Rc::new("c".to_string())]
.iter().cloned().collect();
let provided_values = vec![
Rc::new("a".to_string()),
Rc::new("b".to_string()),
Rc::new("z".to_string()),
Rc::new("b".to_string())
];
let mut found = HashSet::new();
let mut check_values: Vec<_> = provided_values.iter().cloned()
.map(|v| {
if known_values.contains(&v) {
if found.contains(&v) {
Check::Duplicate(v)
} else {
found.insert(v.clone());
Check::Known(v)
}
} else {
Check::Unknown(v)
}
}).collect();
let missing = known_values.difference(&found);
check_values = missing
.cloned()
.fold(check_values, |mut cv, m| {
cv.push(Check::Missing(m));
cv
});
println!("check_values: {:#?}", check_values);
}
Playground

How to create a subscription for events in Windows using Rust and the winapi crate?

I'm trying to subscribe to Windows events using EvtSubscribe from the winapi crate, but I'm getting ERROR_INVALID_PARAMETER.
I can not find an example in Rust, but did find a C++ example.
My code that produces ERROR_INVALID_PARAMETER:
fn main() {
unsafe {
let mut callback: winapi::um::winevt::EVT_SUBSCRIBE_CALLBACK = None;
let mut session = std::ptr::null_mut();
let mut signal_event = std::ptr::null_mut();
let mut bookmark = std::ptr::null_mut();
let mut context = std::ptr::null_mut();
let channel_path = "Security";
let channel_path: winnt::LPWSTR = to_wchar(channel_path);
let query = "Event/System[EventID=4624]";
let query: winnt::LPWSTR = to_wchar(query);
let event_handle = winevt::EvtSubscribe(
session,
signal_event,
channel_path,
query,
bookmark,
context,
callback,
winevt::EvtSubscribeStartAtOldestRecord,
);
//println!("{:?}", &event_handle);
println!("{:?}", &winapi::um::errhandlingapi::GetLastError());
} //unsafe end
}
fn to_vec(str: &str) -> Vec<u16> {
return OsStr::new(str)
.encode_wide()
.chain(Some(0).into_iter())
.collect();
}
fn to_wchar(str: &str) -> *mut u16 {
return to_vec(str).as_mut_ptr();
}
The documentation for EvtSubscribe states:
SignalEvent
[...] This parameter must be NULL if the Callback parameter is not
NULL.
Callback
[...] This parameter must be NULL if the SignalEvent parameter is
not NULL.
The unstated implication here is that exactly one of these parameters must be provided. Passing both is explicitly disallowed, but passing neither would not make sense, as otherwise there would be no way for your code to receive the event.
Passing one of these values should cause the code to start working.
Editorially, this is a good example of where a Rust enum would have been a better way to model the API. This would clearly show that the two options are mutually exclusive and one is required:
enum Subscriber {
EventObject(HANDLE),
Callback(EVT_SUBSCRIBE_CALLBACK),
}
Incidentally, your implementation of to_wchar is incorrect and likely leads to memory unsafety. to_vec allocates memory, you take a pointer to it, then that memory is deallocated, creating a dangling pointer. The bad pointer is read by the C code inside of the unsafe block — part of the reason unsafe is needed.
You either need to use mem::forget, as shown in How to expose a Rust `Vec<T>` to FFI? (and then you need to prevent leaking the memory somehow), or you need to take a reference to the data instead of taking the raw pointer.

A way to resize a stack (or other dynamically resizable types)

First off, I've read this question:
What's the right way to make a stack (or other dynamically resizable vector-like thing) in Rust?
The problem
The selected answer just tells the question asker to use the standard library instead of explaining the implementation, which is fine if my goal was to build something. Except I'm trying to learn about the implementation of a stack, while following a data structure textbook written for Java (Algorithms by Robert Sedgwick & Kevin Wayne), where they implement a stack via resizing an array (Page 136).
I'm in the process of implementing the resize method, and it turns out the size of the array needs to be a constant expression.
meta: are arrays in rust called slices?
use std::mem;
struct DynamicStack<T> {
length: uint,
internal: Box<[T]>,
}
impl<T> DynamicStack<T> {
fn new() -> DynamicStack<T> {
DynamicStack {
length: 0,
internal: box [],
}
}
fn resize(&mut self, new_size: uint) {
let mut temp: Box<[T, ..new_size]> = box unsafe { mem::uninitialized() };
// ^^ error: expected constant expr for array
// length: non-constant path in constant expr
// code for copying elements from self.internal
self.internal = temp;
}
}
For brevity the compiler error was this
.../src/lib.rs:51:23: 51:38 error: expected constant expr for array length: non-constant path in constant expr
.../src/lib.rs:51 let mut temp: Box<[T, ..new_size]> = box unsafe { mem::uninitialized() };
^~~~~~~~~~~~~~~
.../src/lib.rs:51:23: 51:38 error: expected constant expr for array length: non-constant path in constant expr
.../src/lib.rs:51 let mut temp: Box<[T, ..new_size]> = box unsafe { mem::uninitialized() };
^~~~~~~~~~~~~~~
The Question
Surely there is a way in rust to initialize an array with it's size determined at runtime (even if it's unsafe)? Could you also provide an explanation of what's going on in your answer?
Other attempts
I've considered it's probably possible to implement the stack in terms of
struct DynamicStack<T> {
length: uint,
internal: Box<Optional<T>>
}
But I don't want the overhead of matching optional value to remove the unsafe memory operations, but this still doesn't resolve the issue of unknown array sizes.
I also tried this (which doesn't even compile)
fn resize(&mut self, new_size: uint) {
let mut temp: Box<[T]> = box [];
let current_size = self.internal.len();
for i in range(0, current_size) {
temp[i] = self.internal[i];
}
for i in range(current_size, new_size) {
temp[i] = unsafe { mem::uninitialized() };
}
self.internal = temp;
}
And I got this compiler error
.../src/lib.rs:55:17: 55:21 error: cannot move out of dereference of `&mut`-pointer
.../src/lib.rs:55 temp[i] = self.internal[i];
^~~~
.../src/lib.rs:71:19: 71:30 error: cannot use `self.length` because it was mutably borrowed
.../src/lib.rs:71 self.resize(self.length * 2);
^~~~~~~~~~~
.../src/lib.rs:71:7: 71:11 note: borrow of `*self` occurs here
.../src/lib.rs:71 self.resize(self.length * 2);
^~~~
.../src/lib.rs:79:18: 79:22 error: cannot move out of dereference of `&mut`-pointer
.../src/lib.rs:79 let result = self.internal[self.length];
^~~~
.../src/lib.rs:79:9: 79:15 note: attempting to move value to here
.../src/lib.rs:79 let result = self.internal[self.length];
^~~~~~
.../src/lib.rs:79:9: 79:15 help: to prevent the move, use `ref result` or `ref mut result` to capture value by reference
.../src/lib.rs:79 let result = self.internal[self.length];
I also had a look at this, but it's been awhile since I've done any C/C++
How should you do pointer arithmetic in rust?
Surely there is a way in Rust to initialize an array with it's size determined at runtime?
No, Rust arrays are only able to be created with a size known at compile time. In fact, each tuple of type and size constitutes a new type! The Rust compiler uses that information to make optimizations.
Once you need a set of things determined at runtime, you have to add runtime checks to ensure that Rust's safety guarantees are always valid. For example, you can't access uninitialized memory (such as by walking off the beginning or end of a set of items).
If you truly want to go down this path, I expect that you are going to have to get your hands dirty with some direct memory allocation and unsafe code. In essence, you will be building a smaller version of Vec itself! To that end, you can check out the source of Vec.
At a high level, you will need to allocate chunks of memory big enough to hold N objects of some type. Then you can provide ways of accessing those elements, using pointer arithmetic under the hood. When you add more elements, you can allocate more space and move old values around. There are lots of nuanced things that may or may not come up, but it sounds like you are on the beginning of a fun journey!
Edit
Of course, you could choose to pretend that most of the methods of Vec don't even exist, and just use the ones that are analogs of Java's array. You'll still need to use Option to avoid uninitialized values though.

Resources