1 //! Benchmarks the cost of the different allocation functions by doing a
2 //! roundtrip (allocate, deallocate).
3 #![feature(test, allocator_api)]
4 #![cfg(feature = "alloc_trait")]
5 
6 extern crate test;
7 
8 use jemallocator::Jemalloc;
9 use libc::c_int;
10 use std::{
11     alloc::{Alloc, Excess, Layout},
12     ptr,
13 };
14 use test::Bencher;
15 use tikv_jemalloc_sys::MALLOCX_ALIGN;
16 
17 #[global_allocator]
18 static A: Jemalloc = Jemalloc;
19 
20 // FIXME: replace with jemallocator::layout_to_flags
21 #[cfg(all(any(
22     target_arch = "arm",
23     target_arch = "mips",
24     target_arch = "mipsel",
25     target_arch = "powerpc"
26 )))]
27 const MIN_ALIGN: usize = 8;
28 #[cfg(all(any(
29     target_arch = "x86",
30     target_arch = "x86_64",
31     target_arch = "aarch64",
32     target_arch = "powerpc64",
33     target_arch = "powerpc64le",
34     target_arch = "loongarch64",
35     target_arch = "mips64",
36     target_arch = "riscv64",
37     target_arch = "s390x",
38     target_arch = "sparc64"
39 )))]
40 const MIN_ALIGN: usize = 16;
41 
layout_to_flags(layout: &Layout) -> c_int42 fn layout_to_flags(layout: &Layout) -> c_int {
43     if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() {
44         0
45     } else {
46         MALLOCX_ALIGN(layout.align())
47     }
48 }
49 
50 macro_rules! rt {
51     ($size:expr, $align:expr) => {
52         paste::paste! {
53             #[bench]
54             fn [<rt_mallocx_size_ $size _align_ $align>](b: &mut Bencher) {
55                 b.iter(|| unsafe {
56                     use jemalloc_sys as jemalloc;
57                     let flags = layout_to_flags(&Layout::from_size_align($size, $align).unwrap());
58                     let ptr = jemalloc::mallocx($size, flags);
59                     test::black_box(ptr);
60                     jemalloc::sdallocx(ptr, $size, flags);
61                 });
62             }
63 
64             #[bench]
65             fn [<rt_mallocx_nallocx_size_ $size _align_ $align>](b: &mut Bencher) {
66                 b.iter(|| unsafe {
67                     use jemalloc_sys as jemalloc;
68                     let flags = layout_to_flags(&Layout::from_size_align($size, $align).unwrap());
69                     let ptr = jemalloc::mallocx($size, flags);
70                     test::black_box(ptr);
71                     let rsz = jemalloc::nallocx($size, flags);
72                     test::black_box(rsz);
73                     jemalloc::sdallocx(ptr, rsz, flags);
74                 });
75             }
76 
77             #[bench]
78             fn [<rt_alloc_layout_checked_size_ $size _align_ $align>](b: &mut Bencher) {
79                 b.iter(|| unsafe {
80                     let layout = Layout::from_size_align($size, $align).unwrap();
81                     let ptr = Jemalloc.alloc(layout.clone()).unwrap();
82                     test::black_box(ptr);
83                     Jemalloc.dealloc(ptr, layout);
84                 });
85             }
86 
87             #[bench]
88             fn [<rt_alloc_layout_unchecked_size_ $size _align_ $align>](b: &mut Bencher) {
89                 b.iter(|| unsafe {
90                     let layout = Layout::from_size_align_unchecked($size, $align);
91                     let ptr = Jemalloc.alloc(layout.clone()).unwrap();
92                     test::black_box(ptr);
93                     Jemalloc.dealloc(ptr, layout);
94                 });
95             }
96 
97             #[bench]
98             fn [<rt_alloc_excess_unused_size_ $size _align_ $align>](b: &mut Bencher) {
99                 b.iter(|| unsafe {
100                     let layout = Layout::from_size_align($size, $align).unwrap();
101                     let Excess(ptr, _) = Jemalloc.alloc_excess(layout.clone()).unwrap();
102                     test::black_box(ptr);
103                     Jemalloc.dealloc(ptr, layout);
104                 });
105             }
106 
107             #[bench]
108             fn [<rt_alloc_excess_used_size_ $size _align_ $align>](b: &mut Bencher) {
109                 b.iter(|| unsafe {
110                     let layout = Layout::from_size_align($size, $align).unwrap();
111                     let Excess(ptr, excess) = Jemalloc.alloc_excess(layout.clone()).unwrap();
112                     test::black_box(ptr);
113                     test::black_box(excess);
114                     Jemalloc.dealloc(ptr, layout);
115                 });
116             }
117 
118             #[bench]
119             fn [<rt_mallocx_zeroed_size_ $size _align_ $align>](b: &mut Bencher) {
120                 b.iter(|| unsafe {
121                     use jemalloc_sys as jemalloc;
122                     let flags = layout_to_flags(&Layout::from_size_align($size, $align).unwrap());
123                     let ptr = jemalloc::mallocx($size, flags | jemalloc::MALLOCX_ZERO);
124                     test::black_box(ptr);
125                     jemalloc::sdallocx(ptr, $size, flags);
126                 });
127             }
128 
129             #[bench]
130             fn [<rt_calloc_size_ $size _align_ $align>](b: &mut Bencher) {
131                 b.iter(|| unsafe {
132                     use jemalloc_sys as jemalloc;
133                     let flags = layout_to_flags(&Layout::from_size_align($size, $align).unwrap());
134                     test::black_box(flags);
135                     let ptr = jemalloc::calloc(1, $size);
136                     test::black_box(ptr);
137                     jemalloc::sdallocx(ptr, $size, 0);
138                 });
139             }
140 
141             #[bench]
142             fn [<rt_realloc_naive_size_ $size _align_ $align>](b: &mut Bencher) {
143                 b.iter(|| unsafe {
144                     let layout = Layout::from_size_align($size, $align).unwrap();
145                     let ptr = Jemalloc.alloc(layout.clone()).unwrap();
146                     test::black_box(ptr);
147 
148                     // navie realloc:
149                     let new_layout = Layout::from_size_align(2 * $size, $align).unwrap();
150                     let ptr = {
151                         let new_ptr = Jemalloc.alloc(new_layout.clone()).unwrap();
152                         ptr::copy_nonoverlapping(ptr.as_ptr() as *const u8, new_ptr.as_ptr(), layout.size());
153                         Jemalloc.dealloc(ptr, layout);
154                         new_ptr
155                     };
156                     test::black_box(ptr);
157 
158                     Jemalloc.dealloc(ptr, new_layout);
159                 });
160             }
161 
162             #[bench]
163             fn [<rt_realloc_size_ $size _align_ $align>](b: &mut Bencher) {
164                 b.iter(|| unsafe {
165                     let layout = Layout::from_size_align($size, $align).unwrap();
166                     let ptr = Jemalloc.alloc(layout.clone()).unwrap();
167                     test::black_box(ptr);
168 
169                     let new_layout = Layout::from_size_align(2 * $size, $align).unwrap();
170                     let ptr = Jemalloc.realloc(ptr, layout, new_layout.size()).unwrap();
171                     test::black_box(ptr);
172 
173                     Jemalloc.dealloc(ptr, new_layout);
174                 });
175             }
176 
177             #[bench]
178             fn [<rt_realloc_excess_unused_size_ $size _align_ $align>](b: &mut Bencher) {
179                 b.iter(|| unsafe {
180                     let layout = Layout::from_size_align($size, $align).unwrap();
181                     let ptr = Jemalloc.alloc(layout.clone()).unwrap();
182                     test::black_box(ptr);
183 
184                     let new_layout = Layout::from_size_align(2 * $size, $align).unwrap();
185                     let Excess(ptr, _) = Jemalloc
186                         .realloc_excess(ptr, layout, new_layout.size())
187                         .unwrap();
188                     test::black_box(ptr);
189 
190                     Jemalloc.dealloc(ptr, new_layout);
191                 });
192             }
193 
194             #[bench]
195             fn [<rt_realloc_excess_used_size_ $size _align_ $align>](b: &mut Bencher) {
196                 b.iter(|| unsafe {
197                     let layout = Layout::from_size_align($size, $align).unwrap();
198                     let ptr = Jemalloc.alloc(layout.clone()).unwrap();
199                     test::black_box(ptr);
200 
201                     let new_layout = Layout::from_size_align(2 * $size, $align).unwrap();
202                     let Excess(ptr, excess) = Jemalloc
203                         .realloc_excess(ptr, layout, new_layout.size())
204                         .unwrap();
205                     test::black_box(ptr);
206                     test::black_box(excess);
207 
208                     Jemalloc.dealloc(ptr, new_layout);
209                 });
210             }
211 
212         }
213     };
214     ([$($size:expr),*]) => {
215         $(
216             rt!($size, 1);
217             rt!($size, 2);
218             rt!($size, 4);
219             rt!($size, 8);
220             rt!($size, 16);
221             rt!($size, 32);
222         )*
223     }
224 }
225 
226 // Powers of two
227 mod pow2 {
228     use super::*;
229 
230     rt!([
231         1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072,
232         4194304
233     ]);
234 }
235 
236 mod even {
237     use super::*;
238 
239     rt!([10, 100, 1000, 10000, 100000, 1000000]);
240 }
241 
242 mod odd {
243     use super::*;
244     rt!([9, 99, 999, 9999, 99999, 999999]);
245 }
246 
247 mod primes {
248     use super::*;
249     rt!([
250         3, 7, 13, 17, 31, 61, 96, 127, 257, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65537,
251         131071, 4194301
252     ]);
253 }
254