| author | |
| committer | |
| log | f09386cce9ad99d77978cee0d15ae7dd422ea50c |
| tree | 6828b966db6583bde462ed725f8f039036adf553 |
| parent | 46658257f458b7c3c95d7e10cbde85403f7bdb44 |
The `alignedIndex` function is very hot (literally every single `alloc`
call invokes it at least once) and `std.mem.alignPointerOffset` seems to
be very slow, so this commit replaces this functions with a custom
implementation that doesn't do any unnecessary validation and doesn't have
any branches as a result of that. The validation `std.mem.alignPointerOffset`
does isn't necessary anyway, we're not actually calculating an offset that
we plan to apply to a pointer directly, but an offset into a valid buffer
that we only apply to a pointer if the result is inside of that buffer.
This leads to a ~4% speedup in a synthetic benchmark that just puts a lot
of concurrent load on an `ArenaAllocator`.1 files changed, 4 insertions(+), 2 deletions(-)
lib/std/heap/ArenaAllocator.zig+4-2| ... | ... | @@ -315,8 +315,10 @@ fn pushFreeList(arena: *ArenaAllocator, first: *Node, last: *Node) void { |
| 315 | 315 | } |
| 316 | 316 | |
| 317 | 317 | fn alignedIndex(buf_ptr: [*]u8, end_index: usize, alignment: Alignment) usize { |
| 318 | return end_index + | |
| 319 | mem.alignPointerOffset(buf_ptr + end_index, alignment.toByteUnits()).?; | |
| 318 | // Wrapping arithmetic to avoid overflows since `end_index` isn't bounded by | |
| 319 | // `size`. This is always ok since the max alignment in byte units is also | |
| 320 | // the max value of `usize` so wrapped values are correctly aligned anyway. | |
| 321 | return alignment.forward(@intFromPtr(buf_ptr) +% end_index) -% @intFromPtr(buf_ptr); | |
| 320 | 322 | } |
| 321 | 323 | |
| 322 | 324 | fn alloc(ctx: *anyopaque, n: usize, alignment: Alignment, ret_addr: usize) ?[*]u8 { |