From ce3f254526609a9b2088d81070903107c969bb81 Mon Sep 17 00:00:00 2001 From: Justus Klausecker Date: Wed, 25 Mar 2026 14:56:56 +0100 Subject: [PATCH] std.heap.ArenaAllocator: do not cmpxchg in hot path when it would be a noop The cmpxchg is there to recover alignment padding that isn't needed (which can only be determined after the fetch-and-add that reserves it as allocated memory). As cmpxchg tends to be a very expensive operation, it is actually faster to introduce an additional branch here that checks if the cmpxchg would be a noop (because all of the reserved alignment padding was in fact necessary) and skips it if that's the case. This does not measurably regress performance if the arena is only accessed by a single thread and yields slight performance benefits for multi-threaded usage. If the arena is commonly used for unaligned allocations, the perf benefits are quite significant. Co-authored-by: Jacob Young --- lib/std/heap/ArenaAllocator.zig | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/std/heap/ArenaAllocator.zig b/lib/std/heap/ArenaAllocator.zig index ab5febfaadd081b9eefd6e17e4a8f4cf3d09e513..ad6c937c2346a1b6c4a3b97408d1a29fdf83c56f 100644 --- a/lib/std/heap/ArenaAllocator.zig +++ b/lib/std/heap/ArenaAllocator.zig @@ -358,14 +358,16 @@ fn alloc(ctx: *anyopaque, n: usize, alignment: Alignment, ret_addr: usize) ?[*]u const end_index = @atomicRmw(usize, &node.end_index, .Add, alignable, .acquire); // acquire any memory that may have been freed const aligned_index = alignedIndex(buf.ptr, end_index, alignment); assert(end_index + alignable >= aligned_index + n); - _ = @cmpxchgStrong( - usize, - &node.end_index, - end_index + alignable, - aligned_index + n, - .monotonic, // no need to release alignment padding; there's no one accessing it! - .monotonic, - ); + if (end_index + alignable != aligned_index + n) { + _ = @cmpxchgStrong( + usize, + &node.end_index, + end_index + alignable, + aligned_index + n, + .monotonic, // no need to release alignment padding; there's no one accessing it! + .monotonic, + ); + } if (aligned_index + n > buf.len) break :first_node .{ node, buf.len }; return buf[aligned_index..][0..n].ptr; -- 2.54.0