Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

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

Merged
merged 1 commit into from
Feb 25, 2024

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
10 checks passed
@andrewrk andrewrk deleted the raw-c-malloc-size branch February 25, 2024 13:38
# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant