diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2025-02-05 19:28:48 -0800 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-02-06 14:23:23 -0800 |
| commit | 960190643ab4fe2227cbc7ab69a3907bf6722a6e (patch) | |
| tree | 2f010a0ee8dbffb256f454e705d36d17b363811a /lib/std/heap/debug_allocator.zig | |
| parent | cd99ab32294a3c22f09615c93d611593a2887cc3 (diff) | |
| download | zig-960190643ab4fe2227cbc7ab69a3907bf6722a6e.tar.gz zig-960190643ab4fe2227cbc7ab69a3907bf6722a6e.zip | |
std.heap.DebugAllocator: make page size configurable
Diffstat (limited to 'lib/std/heap/debug_allocator.zig')
| -rw-r--r-- | lib/std/heap/debug_allocator.zig | 70 |
1 files changed, 41 insertions, 29 deletions
diff --git a/lib/std/heap/debug_allocator.zig b/lib/std/heap/debug_allocator.zig index 9a76a70202..a4ac906703 100644 --- a/lib/std/heap/debug_allocator.zig +++ b/lib/std/heap/debug_allocator.zig @@ -90,15 +90,12 @@ const mem = std.mem; const Allocator = std.mem.Allocator; const StackTrace = std.builtin.StackTrace; -const page_size: usize = @max(std.heap.page_size_max, switch (builtin.os.tag) { +const default_page_size: usize = @max(std.heap.page_size_max, switch (builtin.os.tag) { .windows => 64 * 1024, // Makes `std.heap.PageAllocator` take the happy path. .wasi => 64 * 1024, // Max alignment supported by `std.heap.WasmAllocator`. else => 128 * 1024, // Avoids too many active mappings when `page_size_max` is low. }); -const page_align: mem.Alignment = .fromByteUnits(page_size); -/// Integer type for pointing to slots in a small allocation -const SlotIndex = std.meta.Int(.unsigned, math.log2(page_size) + 1); const Log2USize = std.math.Log2Int(usize); const default_sys_stack_trace_frames: usize = if (std.debug.sys_can_stack_trace) 6 else 0; @@ -159,6 +156,12 @@ pub const Config = struct { /// Magic value that distinguishes allocations owned by this allocator from /// other regions of memory. canary: usize = @truncate(0x9232a6ff85dff10f), + + /// The size of allocations requested from the backing allocator for + /// subdividing into slots for small allocations. + /// + /// Must be a power of two. + page_size: usize = default_page_size, }; /// Default initialization of this struct is deprecated; use `.init` instead. @@ -184,6 +187,15 @@ pub fn DebugAllocator(comptime config: Config) type { break :init result; }; + comptime { + assert(math.isPowerOfTwo(page_size)); + } + + const page_size = config.page_size; + const page_align: mem.Alignment = .fromByteUnits(page_size); + /// Integer type for pointing to slots in a small allocation + const SlotIndex = std.meta.Int(.unsigned, math.log2(page_size) + 1); + const total_requested_bytes_init = if (config.enable_memory_limit) @as(usize, 0) else {}; const requested_memory_limit_init = if (config.enable_memory_limit) @as(usize, math.maxInt(usize)) else {}; @@ -1138,17 +1150,17 @@ test "large object - grow" { defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak"); const allocator = gpa.allocator(); - var slice1 = try allocator.alloc(u8, page_size * 2 - 20); + var slice1 = try allocator.alloc(u8, default_page_size * 2 - 20); defer allocator.free(slice1); const old = slice1; - slice1 = try allocator.realloc(slice1, page_size * 2 - 10); + slice1 = try allocator.realloc(slice1, default_page_size * 2 - 10); try std.testing.expect(slice1.ptr == old.ptr); - slice1 = try allocator.realloc(slice1, page_size * 2); + slice1 = try allocator.realloc(slice1, default_page_size * 2); try std.testing.expect(slice1.ptr == old.ptr); - slice1 = try allocator.realloc(slice1, page_size * 2 + 1); + slice1 = try allocator.realloc(slice1, default_page_size * 2 + 1); } test "realloc small object to large object" { @@ -1162,7 +1174,7 @@ test "realloc small object to large object" { slice[60] = 0x34; // This requires upgrading to a large object - const large_object_size = page_size * 2 + 50; + const large_object_size = default_page_size * 2 + 50; slice = try allocator.realloc(slice, large_object_size); try std.testing.expect(slice[0] == 0x12); try std.testing.expect(slice[60] == 0x34); @@ -1173,22 +1185,22 @@ test "shrink large object to large object" { defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak"); const allocator = gpa.allocator(); - var slice = try allocator.alloc(u8, page_size * 2 + 50); + var slice = try allocator.alloc(u8, default_page_size * 2 + 50); defer allocator.free(slice); slice[0] = 0x12; slice[60] = 0x34; - if (!allocator.resize(slice, page_size * 2 + 1)) return; - slice = slice.ptr[0 .. page_size * 2 + 1]; + if (!allocator.resize(slice, default_page_size * 2 + 1)) return; + slice = slice.ptr[0 .. default_page_size * 2 + 1]; try std.testing.expect(slice[0] == 0x12); try std.testing.expect(slice[60] == 0x34); - try std.testing.expect(allocator.resize(slice, page_size * 2 + 1)); - slice = slice[0 .. page_size * 2 + 1]; + try std.testing.expect(allocator.resize(slice, default_page_size * 2 + 1)); + slice = slice[0 .. default_page_size * 2 + 1]; try std.testing.expect(slice[0] == 0x12); try std.testing.expect(slice[60] == 0x34); - slice = try allocator.realloc(slice, page_size * 2); + slice = try allocator.realloc(slice, default_page_size * 2); try std.testing.expect(slice[0] == 0x12); try std.testing.expect(slice[60] == 0x34); } @@ -1204,13 +1216,13 @@ test "shrink large object to large object with larger alignment" { var fba = std.heap.FixedBufferAllocator.init(&debug_buffer); const debug_allocator = fba.allocator(); - const alloc_size = page_size * 2 + 50; + const alloc_size = default_page_size * 2 + 50; var slice = try allocator.alignedAlloc(u8, 16, alloc_size); defer allocator.free(slice); const big_alignment: usize = switch (builtin.os.tag) { - .windows => page_size * 32, // Windows aligns to 64K. - else => page_size * 2, + .windows => default_page_size * 32, // Windows aligns to 64K. + else => default_page_size * 2, }; // This loop allocates until we find a page that is not aligned to the big // alignment. Then we shrink the allocation after the loop, but increase the @@ -1236,7 +1248,7 @@ test "realloc large object to small object" { defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak"); const allocator = gpa.allocator(); - var slice = try allocator.alloc(u8, page_size * 2 + 50); + var slice = try allocator.alloc(u8, default_page_size * 2 + 50); defer allocator.free(slice); slice[0] = 0x12; slice[16] = 0x34; @@ -1282,18 +1294,18 @@ test "realloc large object to larger alignment" { var fba = std.heap.FixedBufferAllocator.init(&debug_buffer); const debug_allocator = fba.allocator(); - var slice = try allocator.alignedAlloc(u8, 16, page_size * 2 + 50); + var slice = try allocator.alignedAlloc(u8, 16, default_page_size * 2 + 50); defer allocator.free(slice); const big_alignment: usize = switch (builtin.os.tag) { - .windows => page_size * 32, // Windows aligns to 64K. - else => page_size * 2, + .windows => default_page_size * 32, // Windows aligns to 64K. + else => default_page_size * 2, }; // This loop allocates until we find a page that is not aligned to the big alignment. var stuff_to_free = std.ArrayList([]align(16) u8).init(debug_allocator); while (mem.isAligned(@intFromPtr(slice.ptr), big_alignment)) { try stuff_to_free.append(slice); - slice = try allocator.alignedAlloc(u8, 16, page_size * 2 + 50); + slice = try allocator.alignedAlloc(u8, 16, default_page_size * 2 + 50); } while (stuff_to_free.popOrNull()) |item| { allocator.free(item); @@ -1301,15 +1313,15 @@ test "realloc large object to larger alignment" { slice[0] = 0x12; slice[16] = 0x34; - slice = try allocator.reallocAdvanced(slice, 32, page_size * 2 + 100); + slice = try allocator.reallocAdvanced(slice, 32, default_page_size * 2 + 100); try std.testing.expect(slice[0] == 0x12); try std.testing.expect(slice[16] == 0x34); - slice = try allocator.reallocAdvanced(slice, 32, page_size * 2 + 25); + slice = try allocator.reallocAdvanced(slice, 32, default_page_size * 2 + 25); try std.testing.expect(slice[0] == 0x12); try std.testing.expect(slice[16] == 0x34); - slice = try allocator.reallocAdvanced(slice, big_alignment, page_size * 2 + 100); + slice = try allocator.reallocAdvanced(slice, big_alignment, default_page_size * 2 + 100); try std.testing.expect(slice[0] == 0x12); try std.testing.expect(slice[16] == 0x34); } @@ -1327,7 +1339,7 @@ test "large object rejects shrinking to small" { defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak"); const allocator = gpa.allocator(); - var slice = try allocator.alloc(u8, page_size * 2 + 50); + var slice = try allocator.alloc(u8, default_page_size * 2 + 50); defer allocator.free(slice); slice[0] = 0x12; slice[3] = 0x34; @@ -1379,8 +1391,8 @@ test "large allocations count requested size not backing size" { var gpa: DebugAllocator(.{ .enable_memory_limit = true }) = .{}; const allocator = gpa.allocator(); - var buf = try allocator.alignedAlloc(u8, 1, page_size + 1); - try std.testing.expectEqual(page_size + 1, gpa.total_requested_bytes); + var buf = try allocator.alignedAlloc(u8, 1, default_page_size + 1); + try std.testing.expectEqual(default_page_size + 1, gpa.total_requested_bytes); buf = try allocator.realloc(buf, 1); try std.testing.expectEqual(1, gpa.total_requested_bytes); buf = try allocator.realloc(buf, 2); |
