1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
//! Thread specific operations. use std::io; use {name_to_mib, get}; /// A type providing access to the total number of bytes allocated by the current thread. /// /// Unlike [`stats::Allocated`], the value returned by this type is not the number of bytes /// *currently* allocated, but rather the number of bytes that have *ever* been allocated by this /// thread. /// /// The `get` method doesn't return the value directly, but actually a pointer to the value. This /// allows for very fast repeated lookup, since there is no function call overhead. The pointer type /// cannot be sent to other threads, but `Allocated::get` can be called on different threads and /// will return the appropriate pointer for each of them. /// /// # Example /// /// ``` /// use jemalloc_ctl::thread::Allocated; /// /// let allocated = Allocated::new().unwrap(); /// let allocated = allocated.get().unwrap(); /// /// let a = allocated.get(); /// let buf = vec![0; 1024 * 1024]; /// let b = allocated.get(); /// drop(buf); /// let c = allocated.get(); /// /// assert!(a < b); /// assert_eq!(b, c); /// ``` /// /// [`stats::Allocated`]: ../stats/struct.Allocated.html #[derive(Copy, Clone)] pub struct Allocated([usize; 2]); impl Allocated { /// Returns a new `Allocated`. pub fn new() -> io::Result<Allocated> { let mut mib = [0; 2]; unsafe { name_to_mib("thread.allocatedp\0", &mut mib)?; } Ok(Allocated(mib)) } /// Returns a thread-local pointer to the total number of bytes allocated by this thread. pub fn get(&self) -> io::Result<ThreadLocal<u64>> { unsafe { let ptr = get::<*mut u64>(&self.0)?; Ok(ThreadLocal(ptr)) } } } /// A type providing access to the total number of bytes deallocated by the current thread. /// /// The `get` method doesn't return the value directly, but actually a pointer to the value. This /// allows for very fast repeated lookup, since there is no function call overhead. The pointer type /// cannot be sent to other threads, but `Deallocated::get` can be called on different threads and /// will return the appropriate pointer for each of them. /// /// # Example /// /// ``` /// use jemalloc_ctl::thread::Deallocated; /// /// let deallocated = Deallocated::new().unwrap(); /// let deallocated = deallocated.get().unwrap(); /// /// let a = deallocated.get(); /// let buf = vec![0; 1024 * 1024]; /// let b = deallocated.get(); /// drop(buf); /// let c = deallocated.get(); /// /// assert_eq!(a, b); /// assert!(b < c); /// ``` #[derive(Copy, Clone)] pub struct Deallocated([usize; 2]); impl Deallocated { /// Returns a new `Deallocated`. pub fn new() -> io::Result<Deallocated> { let mut mib = [0; 2]; unsafe { name_to_mib("thread.deallocatedp\0", &mut mib)?; } Ok(Deallocated(mib)) } /// Returns a thread-local pointer to the total number of bytes deallocated by this thread. pub fn get(&self) -> io::Result<ThreadLocal<u64>> { unsafe { let ptr = get::<*mut u64>(&self.0)?; Ok(ThreadLocal(ptr)) } } } /// A a thread-local pointer. /// /// It is neither `Sync` nor `Send`. // NB we need *const here specifically since it's !Sync + !Send #[derive(Copy, Clone)] pub struct ThreadLocal<T>(*const T); impl<T> ThreadLocal<T> where T: Copy, { /// Returns the current value at the pointer. #[inline] pub fn get(&self) -> T { unsafe { *self.0 } } }