shuyi_alloc_count/
global.rs1#[cfg(all(debug_assertions, not(shuyi_no_heap_count)))]
25use std::alloc::System;
26
27#[cfg(all(debug_assertions, not(shuyi_no_heap_count)))]
28use crate::{CountingAlloc, Tagged};
29use crate::{Counts, TagCounts};
30
31pub const COUNTING: bool = cfg!(all(debug_assertions, not(shuyi_no_heap_count)));
34
35#[cfg(all(debug_assertions, not(shuyi_no_heap_count)))]
36#[global_allocator]
37static HEAP: CountingAlloc<System, Tagged> = CountingAlloc::with_tags(System);
38
39pub fn reading() -> Option<Counts> {
42 COUNTING.then(read)
43}
44
45pub fn rows() -> Option<Vec<TagCounts>> {
48 COUNTING.then(read_rows)
49}
50
51#[cfg(all(debug_assertions, not(shuyi_no_heap_count)))]
55use {counted as read, counted_rows as read_rows};
56#[cfg(not(all(debug_assertions, not(shuyi_no_heap_count))))]
57use {uncounted as read, uncounted_rows as read_rows};
58
59#[cfg(all(debug_assertions, not(shuyi_no_heap_count)))]
61fn counted() -> Counts {
62 HEAP.counts()
63}
64
65#[cfg(all(debug_assertions, not(shuyi_no_heap_count)))]
67fn counted_rows() -> Vec<TagCounts> {
68 HEAP.rows()
69}
70
71#[cfg(not(all(debug_assertions, not(shuyi_no_heap_count))))]
73fn uncounted() -> Counts {
74 Counts::default()
75}
76
77#[cfg(not(all(debug_assertions, not(shuyi_no_heap_count))))]
79fn uncounted_rows() -> Vec<TagCounts> {
80 Vec::new()
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn a_debug_test_build_counts_unless_it_opted_out() {
89 let counting = cfg!(all(debug_assertions, not(shuyi_no_heap_count)));
90 assert_eq!(COUNTING, counting);
91 assert_eq!(reading().is_some(), counting);
92 assert_eq!(rows().is_some(), counting);
93 }
94
95 #[cfg(all(debug_assertions, not(shuyi_no_heap_count)))]
98 #[test]
99 fn the_global_counter_sees_a_block_this_thread_keeps() {
100 let block = vec![1u8; 1 << 20];
101 let counts = reading().unwrap();
102 assert!(counts.live_bytes >= 1 << 20, "{counts:?}");
105 assert!(counts.peak_bytes >= 1 << 20, "{counts:?}");
106 drop(block);
107 }
108
109 #[cfg(all(debug_assertions, not(shuyi_no_heap_count)))]
111 fn span(name: &'static str) -> u16 {
112 crate::tags::tag(2, name)
113 }
114
115 #[cfg(all(debug_assertions, not(shuyi_no_heap_count)))]
117 fn row(tag: u16) -> Option<TagCounts> {
118 rows().unwrap().into_iter().find(|r| r.tag == tag)
119 }
120
121 #[cfg(all(debug_assertions, not(shuyi_no_heap_count)))]
125 #[test]
126 fn a_list_grown_under_another_tag_counts_under_it() {
127 use crate::tags::{enter, leave};
128 let (made, grown) = (span("global-test-made"), span("global-test-grown"));
129 let before = enter(made);
130 let mut list: Vec<u8> = Vec::with_capacity(1000);
131 enter(grown);
132 list.reserve_exact(4000);
133 leave(before);
134 let capacity = u64::try_from(list.capacity()).unwrap();
135 let made_row = row(made).unwrap();
136 assert_eq!((made_row.live_bytes, made_row.live_blocks), (0, 0));
137 assert_eq!(made_row.allocated_bytes, 1000);
138 assert_eq!(made_row.peak_bytes, 1000);
139 let grown_row = row(grown).unwrap();
140 assert_eq!((grown_row.live_bytes, grown_row.live_blocks), (capacity, 1));
141 assert_eq!(grown_row.name, "global-test-grown");
142 assert_eq!(grown_row.class, 2);
143 drop(list);
144 assert_eq!(row(grown).unwrap().live_bytes, 0);
145 }
146}