@@ -90,15 +90,12 @@ const mem = std.mem;
9090const Allocator = std .mem .Allocator ;
9191const StackTrace = std .builtin .StackTrace ;
9292
93- const page_size : usize = @max (std .heap .page_size_max , switch (builtin .os .tag ) {
93+ const default_page_size : usize = @max (std .heap .page_size_max , switch (builtin .os .tag ) {
9494 .windows = > 64 * 1024 , // Makes `std.heap.PageAllocator` take the happy path.
9595 .wasi = > 64 * 1024 , // Max alignment supported by `std.heap.WasmAllocator`.
9696 else = > 128 * 1024 , // Avoids too many active mappings when `page_size_max` is low.
9797});
98- const page_align : mem.Alignment = .fromByteUnits (page_size );
9998
100- /// Integer type for pointing to slots in a small allocation
101- const SlotIndex = std .meta .Int (.unsigned , math .log2 (page_size ) + 1 );
10299const Log2USize = std .math .Log2Int (usize );
103100
104101const default_sys_stack_trace_frames : usize = if (std .debug .sys_can_stack_trace ) 6 else 0 ;
@@ -159,6 +156,12 @@ pub const Config = struct {
159156 /// Magic value that distinguishes allocations owned by this allocator from
160157 /// other regions of memory.
161158 canary : usize = @truncate (0x9232a6ff85dff10f ),
159+
160+ /// The size of allocations requested from the backing allocator for
161+ /// subdividing into slots for small allocations.
162+ ///
163+ /// Must be a power of two.
164+ page_size : usize = default_page_size ,
162165};
163166
164167/// Default initialization of this struct is deprecated; use `.init` instead.
@@ -184,6 +187,15 @@ pub fn DebugAllocator(comptime config: Config) type {
184187 break :init result ;
185188 };
186189
190+ comptime {
191+ assert (math .isPowerOfTwo (page_size ));
192+ }
193+
194+ const page_size = config .page_size ;
195+ const page_align : mem.Alignment = .fromByteUnits (page_size );
196+ /// Integer type for pointing to slots in a small allocation
197+ const SlotIndex = std .meta .Int (.unsigned , math .log2 (page_size ) + 1 );
198+
187199 const total_requested_bytes_init = if (config .enable_memory_limit ) @as (usize , 0 ) else {};
188200 const requested_memory_limit_init = if (config .enable_memory_limit ) @as (usize , math .maxInt (usize )) else {};
189201
@@ -1138,17 +1150,17 @@ test "large object - grow" {
11381150 defer std .testing .expect (gpa .deinit () == .ok ) catch @panic ("leak" );
11391151 const allocator = gpa .allocator ();
11401152
1141- var slice1 = try allocator .alloc (u8 , page_size * 2 - 20 );
1153+ var slice1 = try allocator .alloc (u8 , default_page_size * 2 - 20 );
11421154 defer allocator .free (slice1 );
11431155
11441156 const old = slice1 ;
1145- slice1 = try allocator .realloc (slice1 , page_size * 2 - 10 );
1157+ slice1 = try allocator .realloc (slice1 , default_page_size * 2 - 10 );
11461158 try std .testing .expect (slice1 .ptr == old .ptr );
11471159
1148- slice1 = try allocator .realloc (slice1 , page_size * 2 );
1160+ slice1 = try allocator .realloc (slice1 , default_page_size * 2 );
11491161 try std .testing .expect (slice1 .ptr == old .ptr );
11501162
1151- slice1 = try allocator .realloc (slice1 , page_size * 2 + 1 );
1163+ slice1 = try allocator .realloc (slice1 , default_page_size * 2 + 1 );
11521164}
11531165
11541166test "realloc small object to large object" {
@@ -1162,7 +1174,7 @@ test "realloc small object to large object" {
11621174 slice [60 ] = 0x34 ;
11631175
11641176 // This requires upgrading to a large object
1165- const large_object_size = page_size * 2 + 50 ;
1177+ const large_object_size = default_page_size * 2 + 50 ;
11661178 slice = try allocator .realloc (slice , large_object_size );
11671179 try std .testing .expect (slice [0 ] == 0x12 );
11681180 try std .testing .expect (slice [60 ] == 0x34 );
@@ -1173,22 +1185,22 @@ test "shrink large object to large object" {
11731185 defer std .testing .expect (gpa .deinit () == .ok ) catch @panic ("leak" );
11741186 const allocator = gpa .allocator ();
11751187
1176- var slice = try allocator .alloc (u8 , page_size * 2 + 50 );
1188+ var slice = try allocator .alloc (u8 , default_page_size * 2 + 50 );
11771189 defer allocator .free (slice );
11781190 slice [0 ] = 0x12 ;
11791191 slice [60 ] = 0x34 ;
11801192
1181- if (! allocator .resize (slice , page_size * 2 + 1 )) return ;
1182- slice = slice .ptr [0 .. page_size * 2 + 1 ];
1193+ if (! allocator .resize (slice , default_page_size * 2 + 1 )) return ;
1194+ slice = slice .ptr [0 .. default_page_size * 2 + 1 ];
11831195 try std .testing .expect (slice [0 ] == 0x12 );
11841196 try std .testing .expect (slice [60 ] == 0x34 );
11851197
1186- try std .testing .expect (allocator .resize (slice , page_size * 2 + 1 ));
1187- slice = slice [0 .. page_size * 2 + 1 ];
1198+ try std .testing .expect (allocator .resize (slice , default_page_size * 2 + 1 ));
1199+ slice = slice [0 .. default_page_size * 2 + 1 ];
11881200 try std .testing .expect (slice [0 ] == 0x12 );
11891201 try std .testing .expect (slice [60 ] == 0x34 );
11901202
1191- slice = try allocator .realloc (slice , page_size * 2 );
1203+ slice = try allocator .realloc (slice , default_page_size * 2 );
11921204 try std .testing .expect (slice [0 ] == 0x12 );
11931205 try std .testing .expect (slice [60 ] == 0x34 );
11941206}
@@ -1204,13 +1216,13 @@ test "shrink large object to large object with larger alignment" {
12041216 var fba = std .heap .FixedBufferAllocator .init (& debug_buffer );
12051217 const debug_allocator = fba .allocator ();
12061218
1207- const alloc_size = page_size * 2 + 50 ;
1219+ const alloc_size = default_page_size * 2 + 50 ;
12081220 var slice = try allocator .alignedAlloc (u8 , 16 , alloc_size );
12091221 defer allocator .free (slice );
12101222
12111223 const big_alignment : usize = switch (builtin .os .tag ) {
1212- .windows = > page_size * 32 , // Windows aligns to 64K.
1213- else = > page_size * 2 ,
1224+ .windows = > default_page_size * 32 , // Windows aligns to 64K.
1225+ else = > default_page_size * 2 ,
12141226 };
12151227 // This loop allocates until we find a page that is not aligned to the big
12161228 // alignment. Then we shrink the allocation after the loop, but increase the
@@ -1236,7 +1248,7 @@ test "realloc large object to small object" {
12361248 defer std .testing .expect (gpa .deinit () == .ok ) catch @panic ("leak" );
12371249 const allocator = gpa .allocator ();
12381250
1239- var slice = try allocator .alloc (u8 , page_size * 2 + 50 );
1251+ var slice = try allocator .alloc (u8 , default_page_size * 2 + 50 );
12401252 defer allocator .free (slice );
12411253 slice [0 ] = 0x12 ;
12421254 slice [16 ] = 0x34 ;
@@ -1282,34 +1294,34 @@ test "realloc large object to larger alignment" {
12821294 var fba = std .heap .FixedBufferAllocator .init (& debug_buffer );
12831295 const debug_allocator = fba .allocator ();
12841296
1285- var slice = try allocator .alignedAlloc (u8 , 16 , page_size * 2 + 50 );
1297+ var slice = try allocator .alignedAlloc (u8 , 16 , default_page_size * 2 + 50 );
12861298 defer allocator .free (slice );
12871299
12881300 const big_alignment : usize = switch (builtin .os .tag ) {
1289- .windows = > page_size * 32 , // Windows aligns to 64K.
1290- else = > page_size * 2 ,
1301+ .windows = > default_page_size * 32 , // Windows aligns to 64K.
1302+ else = > default_page_size * 2 ,
12911303 };
12921304 // This loop allocates until we find a page that is not aligned to the big alignment.
12931305 var stuff_to_free = std .ArrayList ([]align (16 ) u8 ).init (debug_allocator );
12941306 while (mem .isAligned (@intFromPtr (slice .ptr ), big_alignment )) {
12951307 try stuff_to_free .append (slice );
1296- slice = try allocator .alignedAlloc (u8 , 16 , page_size * 2 + 50 );
1308+ slice = try allocator .alignedAlloc (u8 , 16 , default_page_size * 2 + 50 );
12971309 }
12981310 while (stuff_to_free .popOrNull ()) | item | {
12991311 allocator .free (item );
13001312 }
13011313 slice [0 ] = 0x12 ;
13021314 slice [16 ] = 0x34 ;
13031315
1304- slice = try allocator .reallocAdvanced (slice , 32 , page_size * 2 + 100 );
1316+ slice = try allocator .reallocAdvanced (slice , 32 , default_page_size * 2 + 100 );
13051317 try std .testing .expect (slice [0 ] == 0x12 );
13061318 try std .testing .expect (slice [16 ] == 0x34 );
13071319
1308- slice = try allocator .reallocAdvanced (slice , 32 , page_size * 2 + 25 );
1320+ slice = try allocator .reallocAdvanced (slice , 32 , default_page_size * 2 + 25 );
13091321 try std .testing .expect (slice [0 ] == 0x12 );
13101322 try std .testing .expect (slice [16 ] == 0x34 );
13111323
1312- slice = try allocator .reallocAdvanced (slice , big_alignment , page_size * 2 + 100 );
1324+ slice = try allocator .reallocAdvanced (slice , big_alignment , default_page_size * 2 + 100 );
13131325 try std .testing .expect (slice [0 ] == 0x12 );
13141326 try std .testing .expect (slice [16 ] == 0x34 );
13151327}
@@ -1327,7 +1339,7 @@ test "large object rejects shrinking to small" {
13271339 defer std .testing .expect (gpa .deinit () == .ok ) catch @panic ("leak" );
13281340 const allocator = gpa .allocator ();
13291341
1330- var slice = try allocator .alloc (u8 , page_size * 2 + 50 );
1342+ var slice = try allocator .alloc (u8 , default_page_size * 2 + 50 );
13311343 defer allocator .free (slice );
13321344 slice [0 ] = 0x12 ;
13331345 slice [3 ] = 0x34 ;
@@ -1379,8 +1391,8 @@ test "large allocations count requested size not backing size" {
13791391 var gpa : DebugAllocator (.{ .enable_memory_limit = true }) = .{};
13801392 const allocator = gpa .allocator ();
13811393
1382- var buf = try allocator .alignedAlloc (u8 , 1 , page_size + 1 );
1383- try std .testing .expectEqual (page_size + 1 , gpa .total_requested_bytes );
1394+ var buf = try allocator .alignedAlloc (u8 , 1 , default_page_size + 1 );
1395+ try std .testing .expectEqual (default_page_size + 1 , gpa .total_requested_bytes );
13841396 buf = try allocator .realloc (buf , 1 );
13851397 try std .testing .expectEqual (1 , gpa .total_requested_bytes );
13861398 buf = try allocator .realloc (buf , 2 );
0 commit comments