authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-10-19 03:23:23-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-10-19 03:23:23-04:00
logfa9f1d23968d3b9fe3ae35ed1306aec0cbcfd908
tree40b93bf95fa3ff35cb91ebb76c9ccf7d3fc95c70
parente42d86b657c2fae093fb2545e8b4b85614a0c906
signaturelock-open Commit is signed but in an unrecognized format.

add -DZIG_ENABLE_MEM_PROFILE option and -fmem-report flag

This can be used to find what's taking up memory in the compiler. Here's an example of how to use it: ``` ./zig test ../lib/std/std.zig --cache off -fmem-report ``` And here's the output I get for this on x86_64-linux-gnu today: ``` Const: 6462833 items, 152 bytes each, total 936.84 MiB ConstGlobalRefs: 17236534 items, 24 bytes each, total 394.51 MiB ResetResult: 1698108 items, 160 bytes each, total 259.11 MiB ConstExprValue: 3118299 items, 80 bytes each, total 237.91 MiB EndExpr: 1345395 items, 168 bytes each, total 215.56 MiB Unknown_8: 27370821 items, 8 bytes each, total 208.82 MiB VarPtr: 1127866 items, 168 bytes each, total 180.70 MiB IrBasicBlock: 794834 items, 120 bytes each, total 90.96 MiB LoadPtr: 554024 items, 160 bytes each, total 84.54 MiB Unknown_64: 1245715 items, 64 bytes each, total 76.03 MiB Unknown_40: 1879218 items, 40 bytes each, total 71.69 MiB Unknown_72: 989117 items, 72 bytes each, total 67.92 MiB Return: 423783 items, 160 bytes each, total 64.66 MiB Unknown_168: 332480 items, 168 bytes each, total 53.27 MiB Unknown_152: 336890 items, 152 bytes each, total 48.84 MiB AddImplicitReturnType: 230819 items, 168 bytes each, total 36.98 MiB Br: 217835 items, 168 bytes each, total 34.90 MiB Unknown_184: 179529 items, 184 bytes each, total 31.50 MiB FieldPtr: 179388 items, 184 bytes each, total 31.48 MiB BinOp: 171004 items, 176 bytes each, total 28.70 MiB LoadPtrGen: 173287 items, 168 bytes each, total 27.76 MiB CondBr: 137864 items, 192 bytes each, total 25.24 MiB Unknown_720: 30918 items, 720 bytes each, total 21.23 MiB CallSrc: 99320 items, 216 bytes each, total 20.46 MiB Unknown_160: 129243 items, 160 bytes each, total 19.72 MiB Unknown_1: 19339456 items, 1 bytes each, total 18.44 MiB CheckStatementIsVoid: 119838 items, 160 bytes each, total 18.29 MiB Unknown_48: 371178 items, 48 bytes each, total 16.99 MiB TestComptime: 101443 items, 160 bytes each, total 15.48 MiB DeclVarSrc: 72578 items, 184 bytes each, total 12.74 MiB StorePtr: 72776 items, 176 bytes each, total 12.22 MiB ZigVar: 79201 items, 160 bytes each, total 12.09 MiB Unknown_16: 770643 items, 16 bytes each, total 11.76 MiB Phi: 60482 items, 184 bytes each, total 10.61 MiB TestErrSrc: 66177 items, 168 bytes each, total 10.60 MiB Unknown_240: 45164 items, 240 bytes each, total 10.34 MiB ElemPtr: 58232 items, 184 bytes each, total 10.22 MiB AllocaSrc: 60053 items, 176 bytes each, total 10.08 MiB CallGen: 44873 items, 224 bytes each, total 9.59 MiB SaveErrRetAddr: 63787 items, 152 bytes each, total 9.25 MiB Unknown_112: 82283 items, 112 bytes each, total 8.79 MiB AllocaGen: 51909 items, 176 bytes each, total 8.71 MiB Unknown_24: 373599 items, 24 bytes each, total 8.55 MiB ResultLocPeer: 113683 items, 72 bytes each, total 7.81 MiB DeclRef: 36343 items, 168 bytes each, total 5.82 MiB UnwrapErrPayload: 34603 items, 168 bytes each, total 5.54 MiB Ref: 33414 items, 168 bytes each, total 5.35 MiB Unknown_104: 53882 items, 104 bytes each, total 5.34 MiB DeclVarGen: 32540 items, 168 bytes each, total 5.21 MiB StructFieldPtr: 30449 items, 176 bytes each, total 5.11 MiB UnwrapErrCode: 31508 items, 168 bytes each, total 5.05 MiB Unknown_56: 90256 items, 56 bytes each, total 4.82 MiB SpillBegin: 28722 items, 168 bytes each, total 4.60 MiB SpillEnd: 28722 items, 160 bytes each, total 4.38 MiB ResultLocReturn: 64573 items, 48 bytes each, total 2.96 MiB PtrType: 14702 items, 184 bytes each, total 2.58 MiB SliceType: 15005 items, 176 bytes each, total 2.52 MiB Unknown_176: 13326 items, 176 bytes each, total 2.24 MiB RefGen: 12881 items, 168 bytes each, total 2.06 MiB UnOp: 12102 items, 176 bytes each, total 2.03 MiB SwitchBr: 9453 items, 200 bytes each, total 1.80 MiB TestErrGen: 11143 items, 160 bytes each, total 1.70 MiB Unknown_32: 52359 items, 32 bytes each, total 1.60 MiB CheckSwitchProngs: 9094 items, 184 bytes each, total 1.60 MiB TypeOf: 9259 items, 160 bytes each, total 1.41 MiB IntCast: 8772 items, 168 bytes each, total 1.41 MiB OptionalUnwrapPtr: 8755 items, 168 bytes each, total 1.40 MiB SwitchTarget: 9094 items, 160 bytes each, total 1.39 MiB Cast: 8198 items, 176 bytes each, total 1.38 MiB WidenOrShorten: 8448 items, 160 bytes each, total 1.29 MiB ErrorUnion: 7613 items, 176 bytes each, total 1.28 MiB SliceSrc: 6249 items, 192 bytes each, total 1.14 MiB ErrWrapCode: 7133 items, 168 bytes each, total 1.14 MiB TypeName: 7328 items, 160 bytes each, total 1.12 MiB ImplicitCast: 5480 items, 176 bytes each, total 941.88 KiB ResolveResult: 5638 items, 168 bytes each, total 924.98 KiB ResultLocInstruction: 22696 items, 40 bytes each, total 886.56 KiB BitCastSrc: 4947 items, 168 bytes each, total 811.62 KiB CompileErr: 5148 items, 160 bytes each, total 804.38 KiB ReturnPtr: 5305 items, 152 bytes each, total 787.46 KiB Unreachable: 5038 items, 152 bytes each, total 747.83 KiB TestNonNull: 4716 items, 160 bytes each, total 736.88 KiB BitCastGen: 4431 items, 160 bytes each, total 692.34 KiB PtrToInt: 4289 items, 160 bytes each, total 670.16 KiB SliceGen: 3573 items, 192 bytes each, total 669.94 KiB ArrayType: 4081 items, 168 bytes each, total 669.54 KiB IntType: 3868 items, 168 bytes each, total 634.59 KiB Unknown_88: 7213 items, 88 bytes each, total 619.87 KiB Truncate: 3771 items, 168 bytes each, total 618.68 KiB TypeInfo: 3740 items, 160 bytes each, total 584.38 KiB SwitchVar: 3385 items, 176 bytes each, total 581.80 KiB ContainerInitFields: 3223 items, 184 bytes each, total 579.13 KiB ContainerInitList: 2309 items, 192 bytes each, total 432.94 KiB PtrCastGen: 2626 items, 168 bytes each, total 430.83 KiB BoolNot: 2457 items, 160 bytes each, total 383.91 KiB FnProto: 2054 items, 184 bytes each, total 369.08 KiB MergeErrSets: 1927 items, 176 bytes each, total 331.20 KiB Unknown_136: 2486 items, 136 bytes each, total 330.17 KiB Unknown_80: 4059 items, 80 bytes each, total 317.11 KiB Bswap: 1670 items, 168 bytes each, total 273.98 KiB TypeId: 1680 items, 160 bytes each, total 262.50 KiB PtrCastSrc: 1371 items, 176 bytes each, total 235.64 KiB ErrName: 1193 items, 160 bytes each, total 186.41 KiB UnionTag: 1120 items, 160 bytes each, total 175.00 KiB TagName: 1050 items, 160 bytes each, total 164.06 KiB SizeOf: 942 items, 160 bytes each, total 147.19 KiB MemberName: 871 items, 168 bytes each, total 142.90 KiB Import: 881 items, 160 bytes each, total 137.66 KiB PtrOfArrayToSlice: 758 items, 168 bytes each, total 124.36 KiB UnionFieldPtr: 710 items, 176 bytes each, total 122.03 KiB EnumToInt: 778 items, 160 bytes each, total 121.56 KiB CheckRuntimeScope: 700 items, 168 bytes each, total 114.84 KiB FieldParentPtr: 632 items, 184 bytes each, total 113.56 KiB BoolToInt: 719 items, 160 bytes each, total 112.34 KiB ResultLocPeerParent: 904 items, 104 bytes each, total 91.81 KiB IntToPtr: 537 items, 168 bytes each, total 88.10 KiB AlignOf: 561 items, 160 bytes each, total 87.66 KiB AtomicRmw: 356 items, 208 bytes each, total 72.31 KiB MemberCount: 441 items, 160 bytes each, total 68.91 KiB Memset: 342 items, 176 bytes each, total 58.78 KiB PopCount: 321 items, 168 bytes each, total 52.66 KiB AlignCast: 251 items, 168 bytes each, total 41.18 KiB IrInstruction *: 5230 items, 8 bytes each, total 40.86 KiB IrBasicBlock *: 5230 items, 8 bytes each, total 40.86 KiB TagType: 261 items, 160 bytes each, total 40.78 KiB HasDecl: 234 items, 168 bytes each, total 38.39 KiB OverflowOp: 191 items, 200 bytes each, total 37.30 KiB Export: 209 items, 176 bytes each, total 35.92 KiB SetCold: 219 items, 160 bytes each, total 34.22 KiB ReturnAddress: 216 items, 152 bytes each, total 32.06 KiB FromBytes: 178 items, 176 bytes each, total 30.59 KiB SetRuntimeSafety: 188 items, 160 bytes each, total 29.38 KiB OptionalWrap: 151 items, 168 bytes each, total 24.77 KiB Clz: 143 items, 168 bytes each, total 23.46 KiB ResizeSlice: 135 items, 168 bytes each, total 22.15 KiB UnionInitNamedField: 106 items, 184 bytes each, total 19.05 KiB Panic: 102 items, 160 bytes each, total 15.94 KiB SwitchElseVar: 93 items, 168 bytes each, total 15.26 KiB ToBytes: 89 items, 168 bytes each, total 14.60 KiB IntToFloat: 78 items, 168 bytes each, total 12.80 KiB Unknown_4360: 3 items, 4360 bytes each, total 12.77 KiB ErrWrapPayload: 72 items, 168 bytes each, total 11.81 KiB FloatOp: 62 items, 176 bytes each, total 10.66 KiB FloatToInt: 47 items, 168 bytes each, total 7.71 KiB FloatCast: 46 items, 168 bytes each, total 7.55 KiB ErrToInt: 47 items, 160 bytes each, total 7.34 KiB Asm: 33 items, 216 bytes each, total 6.96 KiB ErrSetCast: 40 items, 168 bytes each, total 6.56 KiB Memcpy: 34 items, 176 bytes each, total 5.84 KiB AtomicLoad: 17 items, 184 bytes each, total 3.05 KiB AwaitSrc: 16 items, 168 bytes each, total 2.62 KiB Resume: 14 items, 160 bytes each, total 2.19 KiB AwaitGen: 12 items, 176 bytes each, total 2.06 KiB ArgType: 12 items, 168 bytes each, total 1.97 KiB AnyFrameType: 12 items, 160 bytes each, total 1.88 KiB SuspendFinish: 10 items, 160 bytes each, total 1.56 KiB SuspendBegin: 10 items, 160 bytes each, total 1.56 KiB Ctz: 9 items, 168 bytes each, total 1.48 KiB FrameHandle: 8 items, 152 bytes each, total 1.19 KiB SetEvalBranchQuota: 7 items, 160 bytes each, total 1.09 KiB AssertZero: 7 items, 160 bytes each, total 1.09 KiB UndeclaredIdent: 7 items, 160 bytes each, total 1.09 KiB CmpxchgSrc: 5 items, 216 bytes each, total 1.05 KiB CmpxchgGen: 5 items, 200 bytes each, total 1000.00 bytes IntToEnum: 4 items, 168 bytes each, total 672.00 bytes VectorType: 4 items, 168 bytes each, total 672.00 bytes ErrorReturnTrace: 2 items, 160 bytes each, total 320.00 bytes Breakpoint: 2 items, 152 bytes each, total 304.00 bytes FrameAddress: 2 items, 152 bytes each, total 304.00 bytes Unknown_4: 61 items, 4 bytes each, total 244.00 bytes VectorToArray: 1 items, 168 bytes each, total 168.00 bytes SetAlignStack: 1 items, 160 bytes each, total 160.00 bytes Unknown_12: 2 items, 12 bytes each, total 24.00 bytes ErrorTableEntry *: 0 items, 8 bytes each, total 0.00 bytes AstNode *: 0 items, 8 bytes each, total 0.00 bytes Total bytes used: 3.51 GiB ``` You can see that most of the memory is taken up by IR instructions, as well as comptime values. This points toward 2 changes which will greatly reduce memory usage: * Rework semantic analysis so that IR instructions can be freed. Currently the comptime value struct (ConstExprValue) is embedded directly into the IrInstruction struct. If this is made to be separate, at the very least pass 1 IR instructions can be freed. This includes `Const` which is the largest usage of memory currently. * Rework the ConstExprValue struct to no longer be a tagged union. For example, there's no need for an integer comptime value to be 80 bytes. From this you can also see that this eliminates some things from being the culprit. Before doing this analysis, I considered whether doing string interning would help. From the above output, you can see that all strings in the compiler account for only 18 MiB, so string interning would have been a dead end.

12 files changed, 305 insertions(+), 74 deletions(-)

CMakeLists.txt+2
......@@ -46,6 +46,7 @@ message("Configuring zig version ${ZIG_VERSION}")
4646set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
4747set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries")
4848set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix")
49set(ZIG_ENABLE_MEM_PROFILE off CACHE BOOL "Activate memory usage instrumentation")
4950
5051if(ZIG_STATIC)
5152 set(ZIG_STATIC_LLVM "on")
......@@ -455,6 +456,7 @@ set(ZIG_SOURCES
455456 "${CMAKE_SOURCE_DIR}/src/ir_print.cpp"
456457 "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp"
457458 "${CMAKE_SOURCE_DIR}/src/link.cpp"
459 "${CMAKE_SOURCE_DIR}/src/memory_profiling.cpp"
458460 "${CMAKE_SOURCE_DIR}/src/os.cpp"
459461 "${CMAKE_SOURCE_DIR}/src/parser.cpp"
460462 "${CMAKE_SOURCE_DIR}/src/range_set.cpp"
src/analyze.cpp+2-2
......@@ -5783,8 +5783,8 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_
57835783
57845784
57855785ConstExprValue *create_const_vals(size_t count) {
5786 ConstGlobalRefs *global_refs = allocate<ConstGlobalRefs>(count);
5787 ConstExprValue *vals = allocate<ConstExprValue>(count);
5786 ConstGlobalRefs *global_refs = allocate<ConstGlobalRefs>(count, "ConstGlobalRefs");
5787 ConstExprValue *vals = allocate<ConstExprValue>(count, "ConstExprValue");
57885788 for (size_t i = 0; i < count; i += 1) {
57895789 vals[i].global_refs = &global_refs[i];
57905790 }
src/config.h.in+2-3
......@@ -13,9 +13,6 @@
1313#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@
1414#define ZIG_VERSION_STRING "@ZIG_VERSION@"
1515
16// Only used for running tests before installing.
17#define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test"
18
1916// Used for communicating build information to self hosted build.
2017#define ZIG_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@"
2118#define ZIG_CXX_COMPILER "@CMAKE_CXX_COMPILER@"
......@@ -24,4 +21,6 @@
2421#define ZIG_LLVM_CONFIG_EXE "@LLVM_CONFIG_EXE@"
2522#define ZIG_DIA_GUIDS_LIB "@ZIG_DIA_GUIDS_LIB_ESCAPED@"
2623
24#cmakedefine ZIG_ENABLE_MEM_PROFILE
25
2726#endif
src/dump_analysis.cpp+1-18
......@@ -240,23 +240,6 @@ static void jw_string(JsonWriter *jw, const char *s) {
240240
241241static void tree_print(FILE *f, ZigType *ty, size_t indent);
242242
243static void pretty_print_bytes(FILE *f, double n) {
244 if (n > 1024.0 * 1024.0 * 1024.0) {
245 fprintf(f, "%.02f GiB", n / 1024.0 / 1024.0 / 1024.0);
246 return;
247 }
248 if (n > 1024.0 * 1024.0) {
249 fprintf(f, "%.02f MiB", n / 1024.0 / 1024.0);
250 return;
251 }
252 if (n > 1024.0) {
253 fprintf(f, "%.02f KiB", n / 1024.0);
254 return;
255 }
256 fprintf(f, "%.02f bytes", n );
257 return;
258}
259
260243static int compare_type_abi_sizes_desc(const void *a, const void *b) {
261244 uint64_t size_a = (*(ZigType * const*)(a))->abi_size;
262245 uint64_t size_b = (*(ZigType * const*)(b))->abi_size;
......@@ -322,7 +305,7 @@ static void tree_print(FILE *f, ZigType *ty, size_t indent) {
322305
323306 start_peer(f, indent);
324307 fprintf(f, "\"sizef\": \"");
325 pretty_print_bytes(f, ty->abi_size);
308 zig_pretty_print_bytes(f, ty->abi_size);
326309 fprintf(f, "\"");
327310
328311 start_peer(f, indent);
src/ir.cpp+31-21
......@@ -413,7 +413,7 @@ ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) {
413413}
414414
415415static IrBasicBlock *ir_create_basic_block(IrBuilder *irb, Scope *scope, const char *name_hint) {
416 IrBasicBlock *result = allocate<IrBasicBlock>(1);
416 IrBasicBlock *result = allocate<IrBasicBlock>(1, "IrBasicBlock");
417417 result->scope = scope;
418418 result->name_hint = name_hint;
419419 result->debug_id = exec_next_debug_id(irb->exec);
......@@ -1085,13 +1085,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillEnd *) {
10851085
10861086template<typename T>
10871087static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
1088 T *special_instruction = allocate<T>(1);
1088 const char *name = nullptr;
1089#ifdef ZIG_ENABLE_MEM_PROFILE
1090 T *dummy = nullptr;
1091 name = ir_instruction_type_str(ir_instruction_id(dummy));
1092#endif
1093 T *special_instruction = allocate<T>(1, name);
10891094 special_instruction->base.id = ir_instruction_id(special_instruction);
10901095 special_instruction->base.scope = scope;
10911096 special_instruction->base.source_node = source_node;
10921097 special_instruction->base.debug_id = exec_next_debug_id(irb->exec);
10931098 special_instruction->base.owner_bb = irb->current_basic_block;
1094 special_instruction->base.value.global_refs = allocate<ConstGlobalRefs>(1);
1099 special_instruction->base.value.global_refs = allocate<ConstGlobalRefs>(1, "ConstGlobalRefs");
10951100 return special_instruction;
10961101}
10971102
......@@ -3569,7 +3574,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
35693574 switch (node->data.return_expr.kind) {
35703575 case ReturnKindUnconditional:
35713576 {
3572 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);
3577 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1, "ResultLocReturn");
35733578 result_loc_ret->base.id = ResultLocIdReturn;
35743579 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);
35753580
......@@ -3664,7 +3669,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
36643669 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val, nullptr));
36653670 IrInstructionSpillBegin *spill_begin = ir_build_spill_begin(irb, scope, node, err_val,
36663671 SpillIdRetErrCode);
3667 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);
3672 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1, "ResultLocReturn");
36683673 result_loc_ret->base.id = ResultLocIdReturn;
36693674 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);
36703675 ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base);
......@@ -3692,7 +3697,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s
36923697 Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime,
36933698 bool skip_name_check)
36943699{
3695 ZigVar *variable_entry = allocate<ZigVar>(1);
3700 ZigVar *variable_entry = allocate<ZigVar>(1, "ZigVar");
36963701 variable_entry->parent_scope = parent_scope;
36973702 variable_entry->shadowable = is_shadowable;
36983703 variable_entry->mem_slot_index = SIZE_MAX;
......@@ -3767,7 +3772,7 @@ static ZigVar *ir_create_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *n
37673772}
37683773
37693774static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) {
3770 ResultLocPeer *result = allocate<ResultLocPeer>(1);
3775 ResultLocPeer *result = allocate<ResultLocPeer>(1, "ResultLocPeer");
37713776 result->base.id = ResultLocIdPeer;
37723777 result->base.source_instruction = peer_parent->base.source_instruction;
37733778 result->parent = peer_parent;
......@@ -3806,7 +3811,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
38063811 scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node,
38073812 ir_should_inline(irb->exec, parent_scope));
38083813
3809 scope_block->peer_parent = allocate<ResultLocPeerParent>(1);
3814 scope_block->peer_parent = allocate<ResultLocPeerParent>(1, "ResultLocPeerParent");
38103815 scope_block->peer_parent->base.id = ResultLocIdPeerParent;
38113816 scope_block->peer_parent->base.source_instruction = scope_block->is_comptime;
38123817 scope_block->peer_parent->end_bb = scope_block->end_block;
......@@ -3933,7 +3938,7 @@ static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node)
39333938 if (lvalue == irb->codegen->invalid_instruction)
39343939 return irb->codegen->invalid_instruction;
39353940
3936 ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1);
3941 ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1, "ResultLocInstruction");
39373942 result_loc_inst->base.id = ResultLocIdInstruction;
39383943 result_loc_inst->base.source_instruction = lvalue;
39393944 ir_ref_instruction(lvalue, irb->current_basic_block);
......@@ -4005,10 +4010,10 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node
40054010
40064011 ir_set_cursor_at_end_and_append_block(irb, true_block);
40074012
4008 IrInstruction **incoming_values = allocate<IrInstruction *>(2);
4013 IrInstruction **incoming_values = allocate<IrInstruction *>(2, "IrInstruction *");
40094014 incoming_values[0] = val1;
40104015 incoming_values[1] = val2;
4011 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);
4016 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *");
40124017 incoming_blocks[0] = post_val1_block;
40134018 incoming_blocks[1] = post_val2_block;
40144019
......@@ -8017,7 +8022,8 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A
80178022 err_set_type->abi_size = irb->codegen->builtin_types.entry_global_error_set->abi_size;
80188023 err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count);
80198024
8020 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(irb->codegen->errors_by_index.length + err_count);
8025 size_t errors_count = irb->codegen->errors_by_index.length + err_count;
8026 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(errors_count, "ErrorTableEntry *");
80218027
80228028 for (uint32_t i = 0; i < err_count; i += 1) {
80238029 AstNode *field_node = node->data.err_set_decl.decls.at(i);
......@@ -8048,7 +8054,7 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A
80488054 }
80498055 errors[err->value] = err;
80508056 }
8051 free(errors);
8057 deallocate(errors, errors_count, "ErrorTableEntry *");
80528058 return ir_build_const_type(irb, parent_scope, node, err_set_type);
80538059}
80548060
......@@ -9574,7 +9580,8 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp
95749580 if (type_is_global_error_set(set2)) {
95759581 return set1;
95769582 }
9577 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
9583 size_t errors_count = ira->codegen->errors_by_index.length;
9584 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(errors_count, "ErrorTableEntry *");
95789585 populate_error_set_table(errors, set1);
95799586 ZigList<ErrorTableEntry *> intersection_list = {};
95809587
......@@ -9595,7 +9602,7 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp
95959602 buf_appendf(&err_set_type->name, "%s%s", comma, buf_ptr(&existing_entry_with_docs->name));
95969603 }
95979604 }
9598 free(errors);
9605 deallocate(errors, errors_count, "ErrorTableEntry *");
95999606
96009607 err_set_type->data.error_set.err_count = intersection_list.length;
96019608 err_set_type->data.error_set.errors = intersection_list.items;
......@@ -9792,7 +9799,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
97929799 return result;
97939800 }
97949801
9795 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(g->errors_by_index.length);
9802 size_t errors_count = g->errors_by_index.length;
9803 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(errors_count, "ErrorTableEntry *");
97969804 for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) {
97979805 ErrorTableEntry *error_entry = container_set->data.error_set.errors[i];
97989806 assert(errors[error_entry->value] == nullptr);
......@@ -9809,7 +9817,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
98099817 result.data.error_set_mismatch->missing_errors.append(contained_error_entry);
98109818 }
98119819 }
9812 free(errors);
9820 deallocate(errors, errors_count, "ErrorTableEntry *");
98139821 return result;
98149822 }
98159823
......@@ -14686,14 +14694,15 @@ static IrInstruction *ir_analyze_instruction_merge_err_sets(IrAnalyze *ira,
1468614694 return ira->codegen->invalid_instruction;
1468714695 }
1468814696
14689 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length);
14697 size_t errors_count = ira->codegen->errors_by_index.length;
14698 ErrorTableEntry **errors = allocate<ErrorTableEntry *>(errors_count, "ErrorTableEntry *");
1469014699 for (uint32_t i = 0, count = op1_type->data.error_set.err_count; i < count; i += 1) {
1469114700 ErrorTableEntry *error_entry = op1_type->data.error_set.errors[i];
1469214701 assert(errors[error_entry->value] == nullptr);
1469314702 errors[error_entry->value] = error_entry;
1469414703 }
1469514704 ZigType *result_type = get_error_set_union(ira->codegen, errors, op1_type, op2_type, instruction->type_name);
14696 free(errors);
14705 deallocate(errors, errors_count, "ErrorTableEntry *");
1469714706
1469814707 return ir_const_type(ira, &instruction->base, result_type);
1469914708}
......@@ -24034,7 +24043,8 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
2403424043 return ira->codegen->invalid_instruction;
2403524044 }
2403624045
24037 AstNode **field_prev_uses = allocate<AstNode *>(ira->codegen->errors_by_index.length);
24046 size_t field_prev_uses_count = ira->codegen->errors_by_index.length;
24047 AstNode **field_prev_uses = allocate<AstNode *>(field_prev_uses_count, "AstNode *");
2403824048
2403924049 for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {
2404024050 IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i];
......@@ -24091,7 +24101,7 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
2409124101 }
2409224102 }
2409324103
24094 free(field_prev_uses);
24104 deallocate(field_prev_uses, field_prev_uses_count, "AstNode *");
2409524105 } else if (switch_type->id == ZigTypeIdInt) {
2409624106 RangeSet rs = {0};
2409724107 for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {
src/ir_print.cpp+3-3
......@@ -38,8 +38,8 @@ struct IrPrint {
3838
3939static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction);
4040
41static const char* ir_instruction_type_str(IrInstruction* instruction) {
42 switch (instruction->id) {
41const char* ir_instruction_type_str(IrInstructionId id) {
42 switch (id) {
4343 case IrInstructionIdInvalid:
4444 return "Invalid";
4545 case IrInstructionIdShuffleVector:
......@@ -387,7 +387,7 @@ static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction, bool trail
387387 const char *ref_count = ir_has_side_effects(instruction) ?
388388 "-" : buf_ptr(buf_sprintf("%" ZIG_PRI_usize "", instruction->ref_count));
389389 fprintf(irp->f, "%c%-3zu| %-22s| %-12s| %-2s| ", mark, instruction->debug_id,
390 ir_instruction_type_str(instruction), type_name, ref_count);
390 ir_instruction_type_str(instruction->id), type_name, ref_count);
391391}
392392
393393static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) {
src/ir_print.hpp+2
......@@ -15,4 +15,6 @@
1515void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size, IrPass pass);
1616void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size, IrPass pass);
1717
18const char* ir_instruction_type_str(IrInstructionId id);
19
1820#endif
src/main.cpp+52-23
......@@ -64,6 +64,9 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
6464 " -fno-PIC disable Position Independent Code\n"
6565 " -ftime-report print timing diagnostics\n"
6666 " -fstack-report print stack size diagnostics\n"
67#ifdef ZIG_ENABLE_MEM_PROFILE
68 " -fmem-report print memory usage diagnostics\n"
69#endif
6770 " -fdump-analysis write analysis.json file with type information\n"
6871 " -femit-docs create a docs/ dir with html documentation\n"
6972 " -fno-emit-bin skip emitting machine code\n"
......@@ -306,9 +309,29 @@ static int zig_error_no_build_file(void) {
306309
307310extern "C" int ZigClang_main(int argc, char **argv);
308311
312#ifdef ZIG_ENABLE_MEM_PROFILE
313bool mem_report = false;
314#endif
315
316int main_exit(Stage2ProgressNode *root_progress_node, int exit_code) {
317 if (root_progress_node != nullptr) {
318 stage2_progress_end(root_progress_node);
319 }
320#ifdef ZIG_ENABLE_MEM_PROFILE
321 if (mem_report) {
322 memprof_dump_stats(stderr);
323 }
324#endif
325 return exit_code;
326}
327
309328int main(int argc, char **argv) {
310329 stage2_attach_segfault_handler();
311330
331#ifdef ZIG_ENABLE_MEM_PROFILE
332 memprof_init();
333#endif
334
312335 char *arg0 = argv[0];
313336 Error err;
314337
......@@ -670,6 +693,13 @@ int main(int argc, char **argv) {
670693 timing_info = true;
671694 } else if (strcmp(arg, "-fstack-report") == 0) {
672695 stack_report = true;
696 } else if (strcmp(arg, "-fmem-report") == 0) {
697#ifdef ZIG_ENABLE_MEM_PROFILE
698 mem_report = true;
699#else
700 fprintf(stderr, "-fmem-report requires configuring with -DZIG_ENABLE_MEM_PROFILE=ON\n");
701 return print_error_usage(arg0);
702#endif
673703 } else if (strcmp(arg, "-fdump-analysis") == 0) {
674704 enable_dump_analysis = true;
675705 } else if (strcmp(arg, "-femit-docs") == 0) {
......@@ -1038,16 +1068,14 @@ int main(int argc, char **argv) {
10381068 if (in_file) {
10391069 ZigLibCInstallation libc;
10401070 if ((err = zig_libc_parse(&libc, buf_create_from_str(in_file), &target, true)))
1041 return EXIT_FAILURE;
1042 stage2_progress_end(root_progress_node);
1043 return EXIT_SUCCESS;
1071 return main_exit(root_progress_node, EXIT_FAILURE);
1072 return main_exit(root_progress_node, EXIT_SUCCESS);
10441073 }
10451074 ZigLibCInstallation libc;
10461075 if ((err = zig_libc_find_native(&libc, true)))
1047 return EXIT_FAILURE;
1076 return main_exit(root_progress_node, EXIT_FAILURE);
10481077 zig_libc_render(&libc, stdout);
1049 stage2_progress_end(root_progress_node);
1050 return EXIT_SUCCESS;
1078 return main_exit(root_progress_node, EXIT_SUCCESS);
10511079 }
10521080 case CmdBuiltin: {
10531081 CodeGen *g = codegen_create(main_pkg_path, nullptr, &target,
......@@ -1065,10 +1093,9 @@ int main(int argc, char **argv) {
10651093 Buf *builtin_source = codegen_generate_builtin_source(g);
10661094 if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {
10671095 fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout)));
1068 return EXIT_FAILURE;
1096 return main_exit(root_progress_node, EXIT_FAILURE);
10691097 }
1070 stage2_progress_end(root_progress_node);
1071 return EXIT_SUCCESS;
1098 return main_exit(root_progress_node, EXIT_SUCCESS);
10721099 }
10731100 case CmdRun:
10741101 case CmdBuild:
......@@ -1142,7 +1169,7 @@ int main(int argc, char **argv) {
11421169 libc = allocate<ZigLibCInstallation>(1);
11431170 if ((err = zig_libc_parse(libc, buf_create_from_str(libc_txt), &target, true))) {
11441171 fprintf(stderr, "Unable to parse --libc text file: %s\n", err_str(err));
1145 return EXIT_FAILURE;
1172 return main_exit(root_progress_node, EXIT_FAILURE);
11461173 }
11471174 }
11481175 Buf *cache_dir_buf;
......@@ -1219,7 +1246,7 @@ int main(int argc, char **argv) {
12191246 codegen_set_rdynamic(g, rdynamic);
12201247 if (mmacosx_version_min && mios_version_min) {
12211248 fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n");
1222 return EXIT_FAILURE;
1249 return main_exit(root_progress_node, EXIT_FAILURE);
12231250 }
12241251
12251252 if (mmacosx_version_min) {
......@@ -1259,6 +1286,11 @@ int main(int argc, char **argv) {
12591286 zig_print_stack_report(g, stdout);
12601287
12611288 if (cmd == CmdRun) {
1289 stage2_progress_end(root_progress_node);
1290#ifdef ZIG_ENABLE_MEM_PROFILE
1291 memprof_dump_stats(stderr);
1292#endif
1293
12621294 const char *exec_path = buf_ptr(&g->output_file_path);
12631295 ZigList<const char*> args = {0};
12641296
......@@ -1282,10 +1314,9 @@ int main(int argc, char **argv) {
12821314 buf_replace(&g->output_file_path, '/', '\\');
12831315#endif
12841316 if (printf("%s\n", buf_ptr(&g->output_file_path)) < 0)
1285 return EXIT_FAILURE;
1317 return main_exit(root_progress_node, EXIT_FAILURE);
12861318 }
1287 stage2_progress_end(root_progress_node);
1288 return EXIT_SUCCESS;
1319 return main_exit(root_progress_node, EXIT_SUCCESS);
12891320 } else {
12901321 zig_unreachable();
12911322 }
......@@ -1293,8 +1324,7 @@ int main(int argc, char **argv) {
12931324 codegen_translate_c(g, in_file_buf, stdout, cmd == CmdTranslateCUserland);
12941325 if (timing_info)
12951326 codegen_print_timing_report(g, stderr);
1296 stage2_progress_end(root_progress_node);
1297 return EXIT_SUCCESS;
1327 return main_exit(root_progress_node, EXIT_SUCCESS);
12981328 } else if (cmd == CmdTest) {
12991329 codegen_set_emit_file_type(g, emit_file_type);
13001330
......@@ -1314,7 +1344,7 @@ int main(int argc, char **argv) {
13141344
13151345 if (g->disable_bin_generation) {
13161346 fprintf(stderr, "Semantic analysis complete. No binary produced due to -fno-emit-bin.\n");
1317 return 0;
1347 return main_exit(root_progress_node, EXIT_SUCCESS);
13181348 }
13191349
13201350 Buf *test_exe_path_unresolved = &g->output_file_path;
......@@ -1324,7 +1354,7 @@ int main(int argc, char **argv) {
13241354 if (emit_file_type != EmitFileTypeBinary) {
13251355 fprintf(stderr, "Created %s but skipping execution because it is non executable.\n",
13261356 buf_ptr(test_exe_path));
1327 return 0;
1357 return main_exit(root_progress_node, EXIT_SUCCESS);
13281358 }
13291359
13301360 for (size_t i = 0; i < test_exec_args.length; i += 1) {
......@@ -1336,7 +1366,7 @@ int main(int argc, char **argv) {
13361366 if (!target_can_exec(&native, &target) && test_exec_args.length == 0) {
13371367 fprintf(stderr, "Created %s but skipping execution because it is non-native.\n",
13381368 buf_ptr(test_exe_path));
1339 return 0;
1369 return main_exit(root_progress_node, EXIT_SUCCESS);
13401370 }
13411371
13421372 Termination term;
......@@ -1348,21 +1378,20 @@ int main(int argc, char **argv) {
13481378 fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n");
13491379 fprintf(stderr, "%s\n", buf_ptr(test_exe_path));
13501380 }
1351 stage2_progress_end(root_progress_node);
1352 return (term.how == TerminationIdClean) ? term.code : -1;
1381 return main_exit(root_progress_node, (term.how == TerminationIdClean) ? term.code : -1);
13531382 } else {
13541383 zig_unreachable();
13551384 }
13561385 }
13571386 case CmdVersion:
13581387 printf("%s\n", ZIG_VERSION_STRING);
1359 return EXIT_SUCCESS;
1388 return main_exit(root_progress_node, EXIT_SUCCESS);
13601389 case CmdZen: {
13611390 const char *ptr;
13621391 size_t len;
13631392 stage2_zen(&ptr, &len);
13641393 fwrite(ptr, len, 1, stdout);
1365 return EXIT_SUCCESS;
1394 return main_exit(root_progress_node, EXIT_SUCCESS);
13661395 }
13671396 case CmdTargets:
13681397 return print_target_list(stdout);
src/memory_profiling.cpp created+139
......@@ -0,0 +1,139 @@
1#include "memory_profiling.hpp"
2#include "hash_map.hpp"
3#include "list.hpp"
4#include "util.hpp"
5#include <string.h>
6
7#ifdef ZIG_ENABLE_MEM_PROFILE
8
9static bool str_eql_str(const char *a, const char *b) {
10 return strcmp(a, b) == 0;
11}
12
13static uint32_t str_hash(const char *s) {
14 // FNV 32-bit hash
15 uint32_t h = 2166136261;
16 for (; *s; s += 1) {
17 h = h ^ *s;
18 h = h * 16777619;
19 }
20 return h;
21}
22
23struct CountAndSize {
24 size_t item_count;
25 size_t type_size;
26};
27
28ZigList<const char *> unknown_names = {};
29HashMap<const char *, CountAndSize, str_hash, str_eql_str> usage_table = {};
30bool table_active = false;
31
32
33static const char *get_default_name(const char *name_or_null, size_t type_size) {
34 if (name_or_null != nullptr) return name_or_null;
35 if (type_size >= unknown_names.length) {
36 table_active = false;
37 unknown_names.resize(type_size + 1);
38 table_active = true;
39 }
40 if (unknown_names.at(type_size) == nullptr) {
41 char buf[100];
42 sprintf(buf, "Unknown_%zu%c", type_size, 0);
43 unknown_names.at(type_size) = strdup(buf);
44 }
45 return unknown_names.at(type_size);
46}
47
48void memprof_alloc(const char *name, size_t count, size_t type_size) {
49 if (!table_active) return;
50 if (count == 0) return;
51 // temporarily disable during table put
52 table_active = false;
53 name = get_default_name(name, type_size);
54 auto existing_entry = usage_table.put_unique(name, {count, type_size});
55 if (existing_entry != nullptr) {
56 assert(existing_entry->value.type_size == type_size); // allocated name does not match type
57 existing_entry->value.item_count += count;
58 }
59 table_active = true;
60}
61
62void memprof_dealloc(const char *name, size_t count, size_t type_size) {
63 if (!table_active) return;
64 if (count == 0) return;
65 name = get_default_name(name, type_size);
66 auto existing_entry = usage_table.maybe_get(name);
67 if (existing_entry == nullptr) {
68 zig_panic("deallocated more than allocated; compromised memory usage stats");
69 }
70 if (existing_entry->value.type_size != type_size) {
71 zig_panic("deallocated name '%s' does not match expected type size %zu", name, type_size);
72 }
73 existing_entry->value.item_count -= count;
74}
75
76void memprof_init(void) {
77 usage_table.init(1024);
78 table_active = true;
79}
80
81struct MemItem {
82 const char *type_name;
83 CountAndSize count_and_size;
84};
85
86static size_t get_bytes(const MemItem *item) {
87 return item->count_and_size.item_count * item->count_and_size.type_size;
88}
89
90static int compare_bytes_desc(const void *a, const void *b) {
91 size_t size_a = get_bytes((const MemItem *)(a));
92 size_t size_b = get_bytes((const MemItem *)(b));
93 if (size_a > size_b)
94 return -1;
95 if (size_a < size_b)
96 return 1;
97 return 0;
98}
99
100void memprof_dump_stats(FILE *file) {
101 assert(table_active);
102 // disable modifications from this function
103 table_active = false;
104
105 ZigList<MemItem> list = {};
106
107 auto it = usage_table.entry_iterator();
108 for (;;) {
109 auto *entry = it.next();
110 if (!entry)
111 break;
112
113 list.append({entry->key, entry->value});
114 }
115
116 qsort(list.items, list.length, sizeof(MemItem), compare_bytes_desc);
117
118 size_t total_bytes_used = 0;
119
120 for (size_t i = 0; i < list.length; i += 1) {
121 const MemItem *item = &list.at(i);
122 fprintf(file, "%s: %zu items, %zu bytes each, total ", item->type_name,
123 item->count_and_size.item_count, item->count_and_size.type_size);
124 size_t bytes = get_bytes(item);
125 zig_pretty_print_bytes(file, bytes);
126 fprintf(file, "\n");
127
128 total_bytes_used += bytes;
129 }
130
131 fprintf(stderr, "Total bytes used: ");
132 zig_pretty_print_bytes(file, total_bytes_used);
133 fprintf(file, "\n");
134
135 list.deinit();
136 table_active = true;
137}
138
139#endif
src/memory_profiling.hpp created+22
......@@ -0,0 +1,22 @@
1/*
2 * Copyright (c) 2019 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#ifndef ZIG_MEMORY_PROFILING_HPP
9#define ZIG_MEMORY_PROFILING_HPP
10
11#include "config.h"
12
13#include <stddef.h>
14#include <stdio.h>
15
16void memprof_init(void);
17
18void memprof_alloc(const char *name, size_t item_count, size_t type_size);
19void memprof_dealloc(const char *name, size_t item_count, size_t type_size);
20
21void memprof_dump_stats(FILE *file);
22#endif
src/util.cpp+18
......@@ -119,3 +119,21 @@ Slice<uint8_t> SplitIterator_rest(SplitIterator *self) {
119119SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes) {
120120 return SplitIterator{0, buffer, split_bytes};
121121}
122
123void zig_pretty_print_bytes(FILE *f, double n) {
124 if (n > 1024.0 * 1024.0 * 1024.0) {
125 fprintf(f, "%.02f GiB", n / 1024.0 / 1024.0 / 1024.0);
126 return;
127 }
128 if (n > 1024.0 * 1024.0) {
129 fprintf(f, "%.02f MiB", n / 1024.0 / 1024.0);
130 return;
131 }
132 if (n > 1024.0) {
133 fprintf(f, "%.02f KiB", n / 1024.0);
134 return;
135 }
136 fprintf(f, "%.02f bytes", n );
137 return;
138}
139
src/util.hpp+31-4
......@@ -8,6 +8,8 @@
88#ifndef ZIG_UTIL_HPP
99#define ZIG_UTIL_HPP
1010
11#include "memory_profiling.hpp"
12
1113#include <stdlib.h>
1214#include <stdint.h>
1315#include <string.h>
......@@ -96,7 +98,10 @@ static inline int ctzll(unsigned long long mask) {
9698
9799
98100template<typename T>
99ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count) {
101ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count, const char *name = nullptr) {
102#ifdef ZIG_ENABLE_MEM_PROFILE
103 memprof_alloc(name, count, sizeof(T));
104#endif
100105#ifndef NDEBUG
101106 // make behavior when size == 0 portable
102107 if (count == 0)
......@@ -109,7 +114,10 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count) {
109114}
110115
111116template<typename T>
112ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) {
117ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count, const char *name = nullptr) {
118#ifdef ZIG_ENABLE_MEM_PROFILE
119 memprof_alloc(name, count, sizeof(T));
120#endif
113121#ifndef NDEBUG
114122 // make behavior when size == 0 portable
115123 if (count == 0)
......@@ -122,7 +130,7 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) {
122130}
123131
124132template<typename T>
125static inline T *reallocate(T *old, size_t old_count, size_t new_count) {
133static inline T *reallocate(T *old, size_t old_count, size_t new_count, const char *name = nullptr) {
126134 T *ptr = reallocate_nonzero(old, old_count, new_count);
127135 if (new_count > old_count) {
128136 memset(&ptr[old_count], 0, (new_count - old_count) * sizeof(T));
......@@ -131,7 +139,11 @@ static inline T *reallocate(T *old, size_t old_count, size_t new_count) {
131139}
132140
133141template<typename T>
134static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) {
142static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count, const char *name = nullptr) {
143#ifdef ZIG_ENABLE_MEM_PROFILE
144 memprof_dealloc(name, old_count, sizeof(T));
145 memprof_alloc(name, new_count, sizeof(T));
146#endif
135147#ifndef NDEBUG
136148 // make behavior when size == 0 portable
137149 if (new_count == 0 && old == nullptr)
......@@ -143,6 +155,19 @@ static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count)
143155 return ptr;
144156}
145157
158template<typename T>
159static inline void deallocate(T *old, size_t count, const char *name = nullptr) {
160#ifdef ZIG_ENABLE_MEM_PROFILE
161 memprof_dealloc(name, count, sizeof(T));
162#endif
163 free(old);
164}
165
166template<typename T>
167static inline void destroy(T *old, const char *name = nullptr) {
168 return deallocate(old, 1);
169}
170
146171template <typename T, size_t n>
147172constexpr size_t array_length(const T (&)[n]) {
148173 return n;
......@@ -225,6 +250,8 @@ static inline double zig_f16_to_double(float16_t x) {
225250 return z;
226251}
227252
253void zig_pretty_print_bytes(FILE *f, double n);
254
228255template<typename T>
229256struct Optional {
230257 T value;