Skip to content

Commit 92b0926

Browse files
committed
micro-optimize dynamic allocation alignment
Previously, some parts of this optimization were impossible because the alignment passed to the free function was not correct. That was fully fixed by #17012. Closes #17092
1 parent b625d43 commit 92b0926

File tree

2 files changed

+65
-35
lines changed

2 files changed

+65
-35
lines changed

Diff for: src/liballoc/heap.rs

+64-34
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,24 @@ unsafe fn closure_exchange_malloc(drop_glue: fn(*mut u8), size: uint,
149149
alloc as *mut u8
150150
}
151151

152+
// The minimum alignment guaranteed by the architecture. This value is used to
153+
// add fast paths for low alignment values. In practice, the alignment is a
154+
// constant at the call site and the branch will be optimized out.
155+
#[cfg(target_arch = "arm")]
156+
#[cfg(target_arch = "mips")]
157+
#[cfg(target_arch = "mipsel")]
158+
static MIN_ALIGN: uint = 8;
159+
#[cfg(target_arch = "x86")]
160+
#[cfg(target_arch = "x86_64")]
161+
static MIN_ALIGN: uint = 16;
162+
152163
#[cfg(jemalloc)]
153164
mod imp {
154165
use core::option::{None, Option};
155166
use core::ptr::{RawPtr, mut_null, null};
156167
use core::num::Int;
157168
use libc::{c_char, c_int, c_void, size_t};
169+
use super::MIN_ALIGN;
158170

159171
#[link(name = "jemalloc", kind = "static")]
160172
#[cfg(not(test))]
@@ -183,9 +195,15 @@ mod imp {
183195
#[inline(always)]
184196
fn mallocx_align(a: uint) -> c_int { a.trailing_zeros() as c_int }
185197

198+
#[inline(always)]
199+
fn align_to_flags(align: uint) -> c_int {
200+
if align <= MIN_ALIGN { 0 } else { mallocx_align(align) }
201+
}
202+
186203
#[inline]
187204
pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
188-
let ptr = je_mallocx(size as size_t, mallocx_align(align)) as *mut u8;
205+
let flags = align_to_flags(align);
206+
let ptr = je_mallocx(size as size_t, flags) as *mut u8;
189207
if ptr.is_null() {
190208
::oom()
191209
}
@@ -195,8 +213,8 @@ mod imp {
195213
#[inline]
196214
pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
197215
_old_size: uint) -> *mut u8 {
198-
let ptr = je_rallocx(ptr as *mut c_void, size as size_t,
199-
mallocx_align(align)) as *mut u8;
216+
let flags = align_to_flags(align);
217+
let ptr = je_rallocx(ptr as *mut c_void, size as size_t, flags) as *mut u8;
200218
if ptr.is_null() {
201219
::oom()
202220
}
@@ -206,18 +224,20 @@ mod imp {
206224
#[inline]
207225
pub unsafe fn reallocate_inplace(ptr: *mut u8, size: uint, align: uint,
208226
_old_size: uint) -> bool {
209-
je_xallocx(ptr as *mut c_void, size as size_t, 0,
210-
mallocx_align(align)) == size as size_t
227+
let flags = align_to_flags(align);
228+
je_xallocx(ptr as *mut c_void, size as size_t, 0, flags) == size as size_t
211229
}
212230

213231
#[inline]
214232
pub unsafe fn deallocate(ptr: *mut u8, _size: uint, align: uint) {
215-
je_dallocx(ptr as *mut c_void, mallocx_align(align))
233+
let flags = align_to_flags(align);
234+
je_dallocx(ptr as *mut c_void, flags)
216235
}
217236

218237
#[inline]
219238
pub fn usable_size(size: uint, align: uint) -> uint {
220-
unsafe { je_nallocx(size as size_t, mallocx_align(align)) as uint }
239+
let flags = align_to_flags(align);
240+
unsafe { je_nallocx(size as size_t, flags) as uint }
221241
}
222242

223243
pub fn stats_print() {
@@ -234,6 +254,7 @@ mod imp {
234254
use core::ptr;
235255
use libc;
236256
use libc_heap;
257+
use super::MIN_ALIGN;
237258

238259
extern {
239260
fn posix_memalign(memptr: *mut *mut libc::c_void,
@@ -243,16 +264,7 @@ mod imp {
243264

244265
#[inline]
245266
pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
246-
// The posix_memalign manpage states
247-
//
248-
// alignment [...] must be a power of and a multiple of
249-
// sizeof(void *)
250-
//
251-
// The `align` parameter to this function is the *minimum* alignment for
252-
// a block of memory, so we special case everything under `*uint` to
253-
// just pass it to malloc, which is guaranteed to align to at least the
254-
// size of `*uint`.
255-
if align < mem::size_of::<uint>() {
267+
if align <= MIN_ALIGN {
256268
libc_heap::malloc_raw(size)
257269
} else {
258270
let mut out = 0 as *mut libc::c_void;
@@ -269,10 +281,14 @@ mod imp {
269281
#[inline]
270282
pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
271283
old_size: uint) -> *mut u8 {
272-
let new_ptr = allocate(size, align);
273-
ptr::copy_memory(new_ptr, ptr as *const u8, cmp::min(size, old_size));
274-
deallocate(ptr, old_size, align);
275-
return new_ptr;
284+
if align <= MIN_ALIGN {
285+
libc_heap::realloc_raw(ptr, size)
286+
} else {
287+
let new_ptr = allocate(size, align);
288+
ptr::copy_memory(new_ptr, ptr as *const u8, cmp::min(size, old_size));
289+
deallocate(ptr, old_size, align);
290+
new_ptr
291+
}
276292
}
277293

278294
#[inline]
@@ -291,14 +307,16 @@ mod imp {
291307
size
292308
}
293309

294-
pub fn stats_print() {
295-
}
310+
pub fn stats_print() {}
296311
}
297312

298313
#[cfg(not(jemalloc), windows)]
299314
mod imp {
300315
use libc::{c_void, size_t};
316+
use libc;
317+
use libc_heap;
301318
use core::ptr::RawPtr;
319+
use super::MIN_ALIGN;
302320

303321
extern {
304322
fn _aligned_malloc(size: size_t, align: size_t) -> *mut c_void;
@@ -309,22 +327,30 @@ mod imp {
309327

310328
#[inline]
311329
pub unsafe fn allocate(size: uint, align: uint) -> *mut u8 {
312-
let ptr = _aligned_malloc(size as size_t, align as size_t);
313-
if ptr.is_null() {
314-
::oom();
330+
if align <= MIN_ALIGN {
331+
libc_heap::malloc_raw(size)
332+
} else {
333+
let ptr = _aligned_malloc(size as size_t, align as size_t);
334+
if ptr.is_null() {
335+
::oom();
336+
}
337+
ptr as *mut u8
315338
}
316-
ptr as *mut u8
317339
}
318340

319341
#[inline]
320342
pub unsafe fn reallocate(ptr: *mut u8, size: uint, align: uint,
321343
_old_size: uint) -> *mut u8 {
322-
let ptr = _aligned_realloc(ptr as *mut c_void, size as size_t,
323-
align as size_t);
324-
if ptr.is_null() {
325-
::oom();
344+
if align <= MIN_ALIGN {
345+
libc_heap::realloc_raw(ptr, size)
346+
} else {
347+
let ptr = _aligned_realloc(ptr as *mut c_void, size as size_t,
348+
align as size_t);
349+
if ptr.is_null() {
350+
::oom();
351+
}
352+
ptr as *mut u8
326353
}
327-
ptr as *mut u8
328354
}
329355

330356
#[inline]
@@ -334,8 +360,12 @@ mod imp {
334360
}
335361

336362
#[inline]
337-
pub unsafe fn deallocate(ptr: *mut u8, _size: uint, _align: uint) {
338-
_aligned_free(ptr as *mut c_void)
363+
pub unsafe fn deallocate(ptr: *mut u8, _size: uint, align: uint) {
364+
if align <= MIN_ALIGN {
365+
libc::free(ptr as *mut libc::c_void)
366+
} else {
367+
_aligned_free(ptr as *mut c_void)
368+
}
339369
}
340370

341371
#[inline]

0 commit comments

Comments
 (0)