authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-08 12:04:19-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-08-08 12:04:19-07:00
logcb9405cdbdd7c9dc30c84ea9a8a17ced2cae66af
treec78ef93e0540ef438d20bfec29f058dd28822a72
parent051aadd7810de9b68f415ec00a3867f6f783b961

don't collect stack trace frames in release safe mode by default

We don't pass no-omit-frame-pointer in release safe by default, so it also makes sense to not try to collect stack trace frames by default in release safe mode.

1 files changed, 47 insertions(+), 65 deletions(-)

lib/std/heap/general_purpose_allocator.zig+47-65
...@@ -95,6 +95,7 @@...@@ -95,6 +95,7 @@
95const std = @import("std");95const std = @import("std");
96const math = std.math;96const math = std.math;
97const assert = std.debug.assert;97const assert = std.debug.assert;
98const mem = std.mem;
98const Allocator = std.mem.Allocator;99const Allocator = std.mem.Allocator;
99const page_size = std.mem.page_size;100const page_size = std.mem.page_size;
100const StackTrace = std.builtin.StackTrace;101const StackTrace = std.builtin.StackTrace;
...@@ -117,11 +118,15 @@ const sys_can_stack_trace = switch (std.Target.current.cpu.arch) {...@@ -117,11 +118,15 @@ const sys_can_stack_trace = switch (std.Target.current.cpu.arch) {
117118
118 else => true,119 else => true,
119};120};
120const default_stack_trace_frames: usize = if (sys_can_stack_trace) 4 else 0;121const default_sys_stack_trace_frames: usize = if (sys_can_stack_trace) 4 else 0;
122const default_stack_trace_frames: usize = switch (std.builtin.mode) {
123 .Debug => default_sys_stack_trace_frames,
124 else => 0,
125};
121126
122pub const Config = struct {127pub const Config = struct {
123 /// Number of stack frames to capture.128 /// Number of stack frames to capture.
124 stack_trace_frames: usize = if (std.debug.runtime_safety) default_stack_trace_frames else @as(usize, 0),129 stack_trace_frames: usize = default_stack_trace_frames,
125130
126 /// If true, the allocator will have two fields:131 /// If true, the allocator will have two fields:
127 /// * `total_requested_bytes` which tracks the total allocated bytes of memory requested.132 /// * `total_requested_bytes` which tracks the total allocated bytes of memory requested.
...@@ -163,7 +168,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -163,7 +168,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
163 const one_trace_size = @sizeOf(usize) * stack_n;168 const one_trace_size = @sizeOf(usize) * stack_n;
164 const traces_per_slot = 2;169 const traces_per_slot = 2;
165170
166 pub const Error = std.mem.Allocator.Error;171 pub const Error = mem.Allocator.Error;
167172
168 const small_bucket_count = math.log2(page_size);173 const small_bucket_count = math.log2(page_size);
169 const largest_bucket_object_size = 1 << (small_bucket_count - 1);174 const largest_bucket_object_size = 1 << (small_bucket_count - 1);
...@@ -246,7 +251,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -246,7 +251,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
246 }251 }
247252
248 fn bucketStackFramesStart(size_class: usize) usize {253 fn bucketStackFramesStart(size_class: usize) usize {
249 return std.mem.alignForward(254 return mem.alignForward(
250 @sizeOf(BucketHeader) + usedBitsCount(size_class),255 @sizeOf(BucketHeader) + usedBitsCount(size_class),
251 @alignOf(usize),256 @alignOf(usize),
252 );257 );
...@@ -322,7 +327,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -322,7 +327,8 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
322 }327 }
323328
324 fn collectStackTrace(first_trace_addr: usize, addresses: *[stack_n]usize) void {329 fn collectStackTrace(first_trace_addr: usize, addresses: *[stack_n]usize) void {
325 std.mem.set(usize, addresses, 0);330 if (stack_n == 0) return;
331 mem.set(usize, addresses, 0);
326 var stack_trace = StackTrace{332 var stack_trace = StackTrace{
327 .instruction_addresses = addresses,333 .instruction_addresses = addresses,
328 .index = 0,334 .index = 0,
...@@ -679,14 +685,14 @@ test "realloc" {...@@ -679,14 +685,14 @@ test "realloc" {
679 // This reallocation should keep its pointer address.685 // This reallocation should keep its pointer address.
680 const old_slice = slice;686 const old_slice = slice;
681 slice = try allocator.realloc(slice, 2);687 slice = try allocator.realloc(slice, 2);
682 assert(old_slice.ptr == slice.ptr);688 std.testing.expect(old_slice.ptr == slice.ptr);
683 assert(slice[0] == 0x12);689 std.testing.expect(slice[0] == 0x12);
684 slice[1] = 0x34;690 slice[1] = 0x34;
685691
686 // This requires upgrading to a larger size class692 // This requires upgrading to a larger size class
687 slice = try allocator.realloc(slice, 17);693 slice = try allocator.realloc(slice, 17);
688 assert(slice[0] == 0x12);694 std.testing.expect(slice[0] == 0x12);
689 assert(slice[1] == 0x34);695 std.testing.expect(slice[1] == 0x34);
690}696}
691697
692test "shrink" {698test "shrink" {
...@@ -697,18 +703,18 @@ test "shrink" {...@@ -697,18 +703,18 @@ test "shrink" {
697 var slice = try allocator.alloc(u8, 20);703 var slice = try allocator.alloc(u8, 20);
698 defer allocator.free(slice);704 defer allocator.free(slice);
699705
700 std.mem.set(u8, slice, 0x11);706 mem.set(u8, slice, 0x11);
701707
702 slice = allocator.shrink(slice, 17);708 slice = allocator.shrink(slice, 17);
703709
704 for (slice) |b| {710 for (slice) |b| {
705 assert(b == 0x11);711 std.testing.expect(b == 0x11);
706 }712 }
707713
708 slice = allocator.shrink(slice, 16);714 slice = allocator.shrink(slice, 16);
709715
710 for (slice) |b| {716 for (slice) |b| {
711 assert(b == 0x11);717 std.testing.expect(b == 0x11);
712 }718 }
713}719}
714720
...@@ -722,10 +728,10 @@ test "large object - grow" {...@@ -722,10 +728,10 @@ test "large object - grow" {
722728
723 var old = slice1;729 var old = slice1;
724 slice1 = try allocator.realloc(slice1, page_size * 2 - 10);730 slice1 = try allocator.realloc(slice1, page_size * 2 - 10);
725 assert(slice1.ptr == old.ptr);731 std.testing.expect(slice1.ptr == old.ptr);
726732
727 slice1 = try allocator.realloc(slice1, page_size * 2);733 slice1 = try allocator.realloc(slice1, page_size * 2);
728 assert(slice1.ptr == old.ptr);734 std.testing.expect(slice1.ptr == old.ptr);
729735
730 slice1 = try allocator.realloc(slice1, page_size * 2 + 1);736 slice1 = try allocator.realloc(slice1, page_size * 2 + 1);
731}737}
...@@ -743,8 +749,8 @@ test "realloc small object to large object" {...@@ -743,8 +749,8 @@ test "realloc small object to large object" {
743 // This requires upgrading to a large object749 // This requires upgrading to a large object
744 const large_object_size = page_size * 2 + 50;750 const large_object_size = page_size * 2 + 50;
745 slice = try allocator.realloc(slice, large_object_size);751 slice = try allocator.realloc(slice, large_object_size);
746 assert(slice[0] == 0x12);752 std.testing.expect(slice[0] == 0x12);
747 assert(slice[60] == 0x34);753 std.testing.expect(slice[60] == 0x34);
748}754}
749755
750test "shrink large object to large object" {756test "shrink large object to large object" {
...@@ -758,16 +764,16 @@ test "shrink large object to large object" {...@@ -758,16 +764,16 @@ test "shrink large object to large object" {
758 slice[60] = 0x34;764 slice[60] = 0x34;
759765
760 slice = try allocator.resize(slice, page_size * 2 + 1);766 slice = try allocator.resize(slice, page_size * 2 + 1);
761 assert(slice[0] == 0x12);767 std.testing.expect(slice[0] == 0x12);
762 assert(slice[60] == 0x34);768 std.testing.expect(slice[60] == 0x34);
763769
764 slice = allocator.shrink(slice, page_size * 2 + 1);770 slice = allocator.shrink(slice, page_size * 2 + 1);
765 assert(slice[0] == 0x12);771 std.testing.expect(slice[0] == 0x12);
766 assert(slice[60] == 0x34);772 std.testing.expect(slice[60] == 0x34);
767773
768 slice = try allocator.realloc(slice, page_size * 2);774 slice = try allocator.realloc(slice, page_size * 2);
769 assert(slice[0] == 0x12);775 std.testing.expect(slice[0] == 0x12);
770 assert(slice[60] == 0x34);776 std.testing.expect(slice[60] == 0x34);
771}777}
772778
773test "shrink large object to large object with larger alignment" {779test "shrink large object to large object with larger alignment" {
...@@ -783,7 +789,7 @@ test "shrink large object to large object with larger alignment" {...@@ -783,7 +789,7 @@ test "shrink large object to large object with larger alignment" {
783 defer allocator.free(slice);789 defer allocator.free(slice);
784790
785 var stuff_to_free = std.ArrayList([]align(16) u8).init(debug_allocator);791 var stuff_to_free = std.ArrayList([]align(16) u8).init(debug_allocator);
786 while (isAligned(@ptrToInt(slice.ptr), page_size * 2)) {792 while (mem.isAligned(@ptrToInt(slice.ptr), page_size * 2)) {
787 try stuff_to_free.append(slice);793 try stuff_to_free.append(slice);
788 slice = try allocator.alignedAlloc(u8, 16, alloc_size);794 slice = try allocator.alignedAlloc(u8, 16, alloc_size);
789 }795 }
...@@ -794,8 +800,8 @@ test "shrink large object to large object with larger alignment" {...@@ -794,8 +800,8 @@ test "shrink large object to large object with larger alignment" {
794 slice[60] = 0x34;800 slice[60] = 0x34;
795801
796 slice = try allocator.reallocAdvanced(slice, page_size * 2, alloc_size / 2, .exact);802 slice = try allocator.reallocAdvanced(slice, page_size * 2, alloc_size / 2, .exact);
797 assert(slice[0] == 0x12);803 std.testing.expect(slice[0] == 0x12);
798 assert(slice[60] == 0x34);804 std.testing.expect(slice[60] == 0x34);
799}805}
800806
801test "realloc large object to small object" {807test "realloc large object to small object" {
...@@ -809,8 +815,8 @@ test "realloc large object to small object" {...@@ -809,8 +815,8 @@ test "realloc large object to small object" {
809 slice[16] = 0x34;815 slice[16] = 0x34;
810816
811 slice = try allocator.realloc(slice, 19);817 slice = try allocator.realloc(slice, 19);
812 assert(slice[0] == 0x12);818 std.testing.expect(slice[0] == 0x12);
813 assert(slice[16] == 0x34);819 std.testing.expect(slice[16] == 0x34);
814}820}
815821
816test "non-page-allocator backing allocator" {822test "non-page-allocator backing allocator" {
...@@ -834,7 +840,7 @@ test "realloc large object to larger alignment" {...@@ -834,7 +840,7 @@ test "realloc large object to larger alignment" {
834 defer allocator.free(slice);840 defer allocator.free(slice);
835841
836 var stuff_to_free = std.ArrayList([]align(16) u8).init(debug_allocator);842 var stuff_to_free = std.ArrayList([]align(16) u8).init(debug_allocator);
837 while (isAligned(@ptrToInt(slice.ptr), page_size * 2)) {843 while (mem.isAligned(@ptrToInt(slice.ptr), page_size * 2)) {
838 try stuff_to_free.append(slice);844 try stuff_to_free.append(slice);
839 slice = try allocator.alignedAlloc(u8, 16, page_size * 2 + 50);845 slice = try allocator.alignedAlloc(u8, 16, page_size * 2 + 50);
840 }846 }
...@@ -845,40 +851,16 @@ test "realloc large object to larger alignment" {...@@ -845,40 +851,16 @@ test "realloc large object to larger alignment" {
845 slice[16] = 0x34;851 slice[16] = 0x34;
846852
847 slice = try allocator.reallocAdvanced(slice, 32, page_size * 2 + 100, .exact);853 slice = try allocator.reallocAdvanced(slice, 32, page_size * 2 + 100, .exact);
848 assert(slice[0] == 0x12);854 std.testing.expect(slice[0] == 0x12);
849 assert(slice[16] == 0x34);855 std.testing.expect(slice[16] == 0x34);
850856
851 slice = try allocator.reallocAdvanced(slice, 32, page_size * 2 + 25, .exact);857 slice = try allocator.reallocAdvanced(slice, 32, page_size * 2 + 25, .exact);
852 assert(slice[0] == 0x12);858 std.testing.expect(slice[0] == 0x12);
853 assert(slice[16] == 0x34);859 std.testing.expect(slice[16] == 0x34);
854860
855 slice = try allocator.reallocAdvanced(slice, page_size * 2, page_size * 2 + 100, .exact);861 slice = try allocator.reallocAdvanced(slice, page_size * 2, page_size * 2 + 100, .exact);
856 assert(slice[0] == 0x12);862 std.testing.expect(slice[0] == 0x12);
857 assert(slice[16] == 0x34);863 std.testing.expect(slice[16] == 0x34);
858}
859
860fn isAligned(addr: usize, alignment: usize) bool {
861 // 000010000 // example addr
862 // 000001111 // subtract 1
863 // 111110000 // binary not
864 const aligned_addr = (addr & ~(alignment - 1));
865 return aligned_addr == addr;
866}
867
868test "isAligned works" {
869 assert(isAligned(0, 4));
870 assert(isAligned(1, 1));
871 assert(isAligned(2, 1));
872 assert(isAligned(2, 2));
873 assert(!isAligned(2, 4));
874 assert(isAligned(3, 1));
875 assert(!isAligned(3, 2));
876 assert(!isAligned(3, 4));
877 assert(isAligned(4, 4));
878 assert(isAligned(4, 2));
879 assert(isAligned(4, 1));
880 assert(!isAligned(4, 8));
881 assert(!isAligned(4, 16));
882}864}
883865
884test "large object shrinks to small but allocation fails during shrink" {866test "large object shrinks to small but allocation fails during shrink" {
...@@ -895,8 +877,8 @@ test "large object shrinks to small but allocation fails during shrink" {...@@ -895,8 +877,8 @@ test "large object shrinks to small but allocation fails during shrink" {
895 // Next allocation will fail in the backing allocator of the GeneralPurposeAllocator877 // Next allocation will fail in the backing allocator of the GeneralPurposeAllocator
896878
897 slice = allocator.shrink(slice, 4);879 slice = allocator.shrink(slice, 4);
898 assert(slice[0] == 0x12);880 std.testing.expect(slice[0] == 0x12);
899 assert(slice[3] == 0x34);881 std.testing.expect(slice[3] == 0x34);
900}882}
901883
902test "objects of size 1024 and 2048" {884test "objects of size 1024 and 2048" {
...@@ -919,20 +901,20 @@ test "setting a memory cap" {...@@ -919,20 +901,20 @@ test "setting a memory cap" {
919 gpda.setRequestedMemoryLimit(1010);901 gpda.setRequestedMemoryLimit(1010);
920902
921 const small = try allocator.create(i32);903 const small = try allocator.create(i32);
922 assert(gpda.total_requested_bytes == 4);904 std.testing.expect(gpda.total_requested_bytes == 4);
923905
924 const big = try allocator.alloc(u8, 1000);906 const big = try allocator.alloc(u8, 1000);
925 assert(gpda.total_requested_bytes == 1004);907 std.testing.expect(gpda.total_requested_bytes == 1004);
926908
927 std.testing.expectError(error.OutOfMemory, allocator.create(u64));909 std.testing.expectError(error.OutOfMemory, allocator.create(u64));
928910
929 allocator.destroy(small);911 allocator.destroy(small);
930 assert(gpda.total_requested_bytes == 1000);912 std.testing.expect(gpda.total_requested_bytes == 1000);
931913
932 allocator.free(big);914 allocator.free(big);
933 assert(gpda.total_requested_bytes == 0);915 std.testing.expect(gpda.total_requested_bytes == 0);
934916
935 const exact = try allocator.alloc(u8, 1010);917 const exact = try allocator.alloc(u8, 1010);
936 assert(gpda.total_requested_bytes == 1010);918 std.testing.expect(gpda.total_requested_bytes == 1010);
937 allocator.free(exact);919 allocator.free(exact);
938}920}