Skip to content

Comments

std.heap.raw_c_allocator: use malloc_size for resize#19073

Merged
andrewrk merged 1 commit intomasterfrom
raw-c-malloc-size
Feb 25, 2024
Merged

std.heap.raw_c_allocator: use malloc_size for resize#19073
andrewrk merged 1 commit intomasterfrom
raw-c-malloc-size

Conversation

@andrewrk
Copy link
Member

std.heap.c_allocator was already doing this, however, std.heap.raw_c_allocator, which asserts no allocations more than 16 bytes aligned, was not.

The zig compiler uses std.heap.raw_c_allocator, so it is affected by this.

Using this example program:

const std = @import("std");

pub fn main() !void {
    const gpa = std.heap.raw_c_allocator;
    //var general_purpose_allocator: std.heap.GeneralPurposeAllocator(.{}) = .{};
    //const gpa = general_purpose_allocator.allocator();

    const stdout = std.io.getStdOut().writer();
    var slice = try gpa.alloc(u8, 1);
    for (2..100000) |i| {
        if (gpa.resize(slice, i)) {
            slice = slice.ptr[0..i];
            try stdout.print("{d} - resized\n", .{i});
        } else {
            try stdout.print("{d} - reallocated\n", .{i});
            const new_slice = try gpa.alloc(u8, i);
            gpa.free(slice);
            slice = new_slice;
        }
    }
}

Before this, you would observe zig run grow.zig -lc to print "reallocated" for all iterations. After this change it looks more like this:

99967 - resized
99968 - resized
99969 - resized
99970 - resized
99971 - resized
99972 - resized
99973 - resized
99974 - resized
99975 - resized
99976 - resized
99977 - reallocated
99978 - resized
99979 - resized
99980 - resized
99981 - resized
99982 - resized
99983 - resized
99984 - resized
99985 - resized
99986 - resized
99987 - resized
99988 - resized
99989 - resized
99990 - resized
99991 - resized
99992 - resized
99993 - reallocated
99994 - resized
99995 - resized
99996 - resized
99997 - resized
99998 - resized
99999 - resized

Since ArrayList already does superlinear growth, I expect this change to be almost meaningless. However it may perform better for small lists, since apparently glibc malloc allocation can grow up to 25 bytes:

2 - resized
3 - resized
4 - resized
5 - resized
6 - resized
7 - resized
8 - resized
9 - resized
10 - resized
11 - resized
12 - resized
13 - resized
14 - resized
15 - resized
16 - resized
17 - resized
18 - resized
19 - resized
20 - resized
21 - resized
22 - resized
23 - resized
24 - resized
25 - reallocated

On the other hand, looks like musl libc never reports growable memory. 🤷

std.heap.c_allocator was already doing this, however,
std.heap.raw_c_allocator, which asserts no allocations more than 16
bytes aligned, was not.

The zig compiler uses std.heap.raw_c_allocator, so it is affected by
this.
@andrewrk andrewrk enabled auto-merge (rebase) February 25, 2024 01:48
@andrewrk andrewrk merged commit 9d70829 into master Feb 25, 2024
@andrewrk andrewrk deleted the raw-c-malloc-size branch February 25, 2024 13:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant