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