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}")...@@ -46,6 +46,7 @@ message("Configuring zig version ${ZIG_VERSION}")
46set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")46set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
47set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries")47set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries")
48set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix")48set(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
50if(ZIG_STATIC)51if(ZIG_STATIC)
51 set(ZIG_STATIC_LLVM "on")52 set(ZIG_STATIC_LLVM "on")
...@@ -455,6 +456,7 @@ set(ZIG_SOURCES...@@ -455,6 +456,7 @@ set(ZIG_SOURCES
455 "${CMAKE_SOURCE_DIR}/src/ir_print.cpp"456 "${CMAKE_SOURCE_DIR}/src/ir_print.cpp"
456 "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp"457 "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp"
457 "${CMAKE_SOURCE_DIR}/src/link.cpp"458 "${CMAKE_SOURCE_DIR}/src/link.cpp"
459 "${CMAKE_SOURCE_DIR}/src/memory_profiling.cpp"
458 "${CMAKE_SOURCE_DIR}/src/os.cpp"460 "${CMAKE_SOURCE_DIR}/src/os.cpp"
459 "${CMAKE_SOURCE_DIR}/src/parser.cpp"461 "${CMAKE_SOURCE_DIR}/src/parser.cpp"
460 "${CMAKE_SOURCE_DIR}/src/range_set.cpp"462 "${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_...@@ -5783,8 +5783,8 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_
57835783
57845784
5785ConstExprValue *create_const_vals(size_t count) {5785ConstExprValue *create_const_vals(size_t count) {
5786 ConstGlobalRefs *global_refs = allocate<ConstGlobalRefs>(count);5786 ConstGlobalRefs *global_refs = allocate<ConstGlobalRefs>(count, "ConstGlobalRefs");
5787 ConstExprValue *vals = allocate<ConstExprValue>(count);5787 ConstExprValue *vals = allocate<ConstExprValue>(count, "ConstExprValue");
5788 for (size_t i = 0; i < count; i += 1) {5788 for (size_t i = 0; i < count; i += 1) {
5789 vals[i].global_refs = &global_refs[i];5789 vals[i].global_refs = &global_refs[i];
5790 }5790 }
src/config.h.in+2-3
...@@ -13,9 +13,6 @@...@@ -13,9 +13,6 @@
13#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@13#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@
14#define ZIG_VERSION_STRING "@ZIG_VERSION@"14#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
19// Used for communicating build information to self hosted build.16// Used for communicating build information to self hosted build.
20#define ZIG_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@"17#define ZIG_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@"
21#define ZIG_CXX_COMPILER "@CMAKE_CXX_COMPILER@"18#define ZIG_CXX_COMPILER "@CMAKE_CXX_COMPILER@"
...@@ -24,4 +21,6 @@...@@ -24,4 +21,6 @@
24#define ZIG_LLVM_CONFIG_EXE "@LLVM_CONFIG_EXE@"21#define ZIG_LLVM_CONFIG_EXE "@LLVM_CONFIG_EXE@"
25#define ZIG_DIA_GUIDS_LIB "@ZIG_DIA_GUIDS_LIB_ESCAPED@"22#define ZIG_DIA_GUIDS_LIB "@ZIG_DIA_GUIDS_LIB_ESCAPED@"
2623
24#cmakedefine ZIG_ENABLE_MEM_PROFILE
25
27#endif26#endif
src/dump_analysis.cpp+1-18
...@@ -240,23 +240,6 @@ static void jw_string(JsonWriter *jw, const char *s) {...@@ -240,23 +240,6 @@ static void jw_string(JsonWriter *jw, const char *s) {
240240
241static void tree_print(FILE *f, ZigType *ty, size_t indent);241static 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
260static int compare_type_abi_sizes_desc(const void *a, const void *b) {243static int compare_type_abi_sizes_desc(const void *a, const void *b) {
261 uint64_t size_a = (*(ZigType * const*)(a))->abi_size;244 uint64_t size_a = (*(ZigType * const*)(a))->abi_size;
262 uint64_t size_b = (*(ZigType * const*)(b))->abi_size;245 uint64_t size_b = (*(ZigType * const*)(b))->abi_size;
...@@ -322,7 +305,7 @@ static void tree_print(FILE *f, ZigType *ty, size_t indent) {...@@ -322,7 +305,7 @@ static void tree_print(FILE *f, ZigType *ty, size_t indent) {
322305
323 start_peer(f, indent);306 start_peer(f, indent);
324 fprintf(f, "\"sizef\": \"");307 fprintf(f, "\"sizef\": \"");
325 pretty_print_bytes(f, ty->abi_size);308 zig_pretty_print_bytes(f, ty->abi_size);
326 fprintf(f, "\"");309 fprintf(f, "\"");
327310
328 start_peer(f, indent);311 start_peer(f, indent);
src/ir.cpp+31-21
...@@ -413,7 +413,7 @@ ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) {...@@ -413,7 +413,7 @@ ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) {
413}413}
414414
415static IrBasicBlock *ir_create_basic_block(IrBuilder *irb, Scope *scope, const char *name_hint) {415static 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");
417 result->scope = scope;417 result->scope = scope;
418 result->name_hint = name_hint;418 result->name_hint = name_hint;
419 result->debug_id = exec_next_debug_id(irb->exec);419 result->debug_id = exec_next_debug_id(irb->exec);
...@@ -1085,13 +1085,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillEnd *) {...@@ -1085,13 +1085,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillEnd *) {
10851085
1086template<typename T>1086template<typename T>
1087static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {1087static 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);
1089 special_instruction->base.id = ir_instruction_id(special_instruction);1094 special_instruction->base.id = ir_instruction_id(special_instruction);
1090 special_instruction->base.scope = scope;1095 special_instruction->base.scope = scope;
1091 special_instruction->base.source_node = source_node;1096 special_instruction->base.source_node = source_node;
1092 special_instruction->base.debug_id = exec_next_debug_id(irb->exec);1097 special_instruction->base.debug_id = exec_next_debug_id(irb->exec);
1093 special_instruction->base.owner_bb = irb->current_basic_block;1098 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");
1095 return special_instruction;1100 return special_instruction;
1096}1101}
10971102
...@@ -3569,7 +3574,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -3569,7 +3574,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
3569 switch (node->data.return_expr.kind) {3574 switch (node->data.return_expr.kind) {
3570 case ReturnKindUnconditional:3575 case ReturnKindUnconditional:
3571 {3576 {
3572 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);3577 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1, "ResultLocReturn");
3573 result_loc_ret->base.id = ResultLocIdReturn;3578 result_loc_ret->base.id = ResultLocIdReturn;
3574 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);3579 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,...@@ -3664,7 +3669,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
3664 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val, nullptr));3669 ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val, nullptr));
3665 IrInstructionSpillBegin *spill_begin = ir_build_spill_begin(irb, scope, node, err_val,3670 IrInstructionSpillBegin *spill_begin = ir_build_spill_begin(irb, scope, node, err_val,
3666 SpillIdRetErrCode);3671 SpillIdRetErrCode);
3667 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1);3672 ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1, "ResultLocReturn");
3668 result_loc_ret->base.id = ResultLocIdReturn;3673 result_loc_ret->base.id = ResultLocIdReturn;
3669 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);3674 ir_build_reset_result(irb, scope, node, &result_loc_ret->base);
3670 ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base);3675 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...@@ -3692,7 +3697,7 @@ static ZigVar *create_local_var(CodeGen *codegen, AstNode *node, Scope *parent_s
3692 Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime,3697 Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime,
3693 bool skip_name_check)3698 bool skip_name_check)
3694{3699{
3695 ZigVar *variable_entry = allocate<ZigVar>(1);3700 ZigVar *variable_entry = allocate<ZigVar>(1, "ZigVar");
3696 variable_entry->parent_scope = parent_scope;3701 variable_entry->parent_scope = parent_scope;
3697 variable_entry->shadowable = is_shadowable;3702 variable_entry->shadowable = is_shadowable;
3698 variable_entry->mem_slot_index = SIZE_MAX;3703 variable_entry->mem_slot_index = SIZE_MAX;
...@@ -3767,7 +3772,7 @@ static ZigVar *ir_create_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *n...@@ -3767,7 +3772,7 @@ static ZigVar *ir_create_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *n
3767}3772}
37683773
3769static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) {3774static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) {
3770 ResultLocPeer *result = allocate<ResultLocPeer>(1);3775 ResultLocPeer *result = allocate<ResultLocPeer>(1, "ResultLocPeer");
3771 result->base.id = ResultLocIdPeer;3776 result->base.id = ResultLocIdPeer;
3772 result->base.source_instruction = peer_parent->base.source_instruction;3777 result->base.source_instruction = peer_parent->base.source_instruction;
3773 result->parent = peer_parent;3778 result->parent = peer_parent;
...@@ -3806,7 +3811,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode...@@ -3806,7 +3811,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode
3806 scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node,3811 scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node,
3807 ir_should_inline(irb->exec, parent_scope));3812 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");
3810 scope_block->peer_parent->base.id = ResultLocIdPeerParent;3815 scope_block->peer_parent->base.id = ResultLocIdPeerParent;
3811 scope_block->peer_parent->base.source_instruction = scope_block->is_comptime;3816 scope_block->peer_parent->base.source_instruction = scope_block->is_comptime;
3812 scope_block->peer_parent->end_bb = scope_block->end_block;3817 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)...@@ -3933,7 +3938,7 @@ static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node)
3933 if (lvalue == irb->codegen->invalid_instruction)3938 if (lvalue == irb->codegen->invalid_instruction)
3934 return irb->codegen->invalid_instruction;3939 return irb->codegen->invalid_instruction;
39353940
3936 ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1);3941 ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1, "ResultLocInstruction");
3937 result_loc_inst->base.id = ResultLocIdInstruction;3942 result_loc_inst->base.id = ResultLocIdInstruction;
3938 result_loc_inst->base.source_instruction = lvalue;3943 result_loc_inst->base.source_instruction = lvalue;
3939 ir_ref_instruction(lvalue, irb->current_basic_block);3944 ir_ref_instruction(lvalue, irb->current_basic_block);
...@@ -4005,10 +4010,10 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node...@@ -4005,10 +4010,10 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node
40054010
4006 ir_set_cursor_at_end_and_append_block(irb, true_block);4011 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 *");
4009 incoming_values[0] = val1;4014 incoming_values[0] = val1;
4010 incoming_values[1] = val2;4015 incoming_values[1] = val2;
4011 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2);4016 IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *");
4012 incoming_blocks[0] = post_val1_block;4017 incoming_blocks[0] = post_val1_block;
4013 incoming_blocks[1] = post_val2_block;4018 incoming_blocks[1] = post_val2_block;
40144019
...@@ -8017,7 +8022,8 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A...@@ -8017,7 +8022,8 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A
8017 err_set_type->abi_size = irb->codegen->builtin_types.entry_global_error_set->abi_size;8022 err_set_type->abi_size = irb->codegen->builtin_types.entry_global_error_set->abi_size;
8018 err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count);8023 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
8022 for (uint32_t i = 0; i < err_count; i += 1) {8028 for (uint32_t i = 0; i < err_count; i += 1) {
8023 AstNode *field_node = node->data.err_set_decl.decls.at(i);8029 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...@@ -8048,7 +8054,7 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A
8048 }8054 }
8049 errors[err->value] = err;8055 errors[err->value] = err;
8050 }8056 }
8051 free(errors);8057 deallocate(errors, errors_count, "ErrorTableEntry *");
8052 return ir_build_const_type(irb, parent_scope, node, err_set_type);8058 return ir_build_const_type(irb, parent_scope, node, err_set_type);
8053}8059}
80548060
...@@ -9574,7 +9580,8 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp...@@ -9574,7 +9580,8 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp
9574 if (type_is_global_error_set(set2)) {9580 if (type_is_global_error_set(set2)) {
9575 return set1;9581 return set1;
9576 }9582 }
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 *");
9578 populate_error_set_table(errors, set1);9585 populate_error_set_table(errors, set1);
9579 ZigList<ErrorTableEntry *> intersection_list = {};9586 ZigList<ErrorTableEntry *> intersection_list = {};
95809587
...@@ -9595,7 +9602,7 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp...@@ -9595,7 +9602,7 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp
9595 buf_appendf(&err_set_type->name, "%s%s", comma, buf_ptr(&existing_entry_with_docs->name));9602 buf_appendf(&err_set_type->name, "%s%s", comma, buf_ptr(&existing_entry_with_docs->name));
9596 }9603 }
9597 }9604 }
9598 free(errors);9605 deallocate(errors, errors_count, "ErrorTableEntry *");
95999606
9600 err_set_type->data.error_set.err_count = intersection_list.length;9607 err_set_type->data.error_set.err_count = intersection_list.length;
9601 err_set_type->data.error_set.errors = intersection_list.items;9608 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...@@ -9792,7 +9799,8 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
9792 return result;9799 return result;
9793 }9800 }
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 *");
9796 for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) {9804 for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) {
9797 ErrorTableEntry *error_entry = container_set->data.error_set.errors[i];9805 ErrorTableEntry *error_entry = container_set->data.error_set.errors[i];
9798 assert(errors[error_entry->value] == nullptr);9806 assert(errors[error_entry->value] == nullptr);
...@@ -9809,7 +9817,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted...@@ -9809,7 +9817,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted
9809 result.data.error_set_mismatch->missing_errors.append(contained_error_entry);9817 result.data.error_set_mismatch->missing_errors.append(contained_error_entry);
9810 }9818 }
9811 }9819 }
9812 free(errors);9820 deallocate(errors, errors_count, "ErrorTableEntry *");
9813 return result;9821 return result;
9814 }9822 }
98159823
...@@ -14686,14 +14694,15 @@ static IrInstruction *ir_analyze_instruction_merge_err_sets(IrAnalyze *ira,...@@ -14686,14 +14694,15 @@ static IrInstruction *ir_analyze_instruction_merge_err_sets(IrAnalyze *ira,
14686 return ira->codegen->invalid_instruction;14694 return ira->codegen->invalid_instruction;
14687 }14695 }
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 *");
14690 for (uint32_t i = 0, count = op1_type->data.error_set.err_count; i < count; i += 1) {14699 for (uint32_t i = 0, count = op1_type->data.error_set.err_count; i < count; i += 1) {
14691 ErrorTableEntry *error_entry = op1_type->data.error_set.errors[i];14700 ErrorTableEntry *error_entry = op1_type->data.error_set.errors[i];
14692 assert(errors[error_entry->value] == nullptr);14701 assert(errors[error_entry->value] == nullptr);
14693 errors[error_entry->value] = error_entry;14702 errors[error_entry->value] = error_entry;
14694 }14703 }
14695 ZigType *result_type = get_error_set_union(ira->codegen, errors, op1_type, op2_type, instruction->type_name);14704 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
14698 return ir_const_type(ira, &instruction->base, result_type);14707 return ir_const_type(ira, &instruction->base, result_type);
14699}14708}
...@@ -24034,7 +24043,8 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,...@@ -24034,7 +24043,8 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
24034 return ira->codegen->invalid_instruction;24043 return ira->codegen->invalid_instruction;
24035 }24044 }
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
24039 for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {24049 for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {
24040 IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i];24050 IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i];
...@@ -24091,7 +24101,7 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,...@@ -24091,7 +24101,7 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira,
24091 }24101 }
24092 }24102 }
2409324103
24094 free(field_prev_uses);24104 deallocate(field_prev_uses, field_prev_uses_count, "AstNode *");
24095 } else if (switch_type->id == ZigTypeIdInt) {24105 } else if (switch_type->id == ZigTypeIdInt) {
24096 RangeSet rs = {0};24106 RangeSet rs = {0};
24097 for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) {24107 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 {...@@ -38,8 +38,8 @@ struct IrPrint {
3838
39static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction);39static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction);
4040
41static const char* ir_instruction_type_str(IrInstruction* instruction) {41const char* ir_instruction_type_str(IrInstructionId id) {
42 switch (instruction->id) {42 switch (id) {
43 case IrInstructionIdInvalid:43 case IrInstructionIdInvalid:
44 return "Invalid";44 return "Invalid";
45 case IrInstructionIdShuffleVector:45 case IrInstructionIdShuffleVector:
...@@ -387,7 +387,7 @@ static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction, bool trail...@@ -387,7 +387,7 @@ static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction, bool trail
387 const char *ref_count = ir_has_side_effects(instruction) ?387 const char *ref_count = ir_has_side_effects(instruction) ?
388 "-" : buf_ptr(buf_sprintf("%" ZIG_PRI_usize "", instruction->ref_count));388 "-" : buf_ptr(buf_sprintf("%" ZIG_PRI_usize "", instruction->ref_count));
389 fprintf(irp->f, "%c%-3zu| %-22s| %-12s| %-2s| ", mark, instruction->debug_id,389 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);
391}391}
392392
393static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) {393static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) {
src/ir_print.hpp+2
...@@ -15,4 +15,6 @@...@@ -15,4 +15,6 @@
15void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size, IrPass pass);15void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size, IrPass pass);
16void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size, IrPass pass);16void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size, IrPass pass);
1717
18const char* ir_instruction_type_str(IrInstructionId id);
19
18#endif20#endif
src/main.cpp+52-23
...@@ -64,6 +64,9 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {...@@ -64,6 +64,9 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) {
64 " -fno-PIC disable Position Independent Code\n"64 " -fno-PIC disable Position Independent Code\n"
65 " -ftime-report print timing diagnostics\n"65 " -ftime-report print timing diagnostics\n"
66 " -fstack-report print stack size diagnostics\n"66 " -fstack-report print stack size diagnostics\n"
67#ifdef ZIG_ENABLE_MEM_PROFILE
68 " -fmem-report print memory usage diagnostics\n"
69#endif
67 " -fdump-analysis write analysis.json file with type information\n"70 " -fdump-analysis write analysis.json file with type information\n"
68 " -femit-docs create a docs/ dir with html documentation\n"71 " -femit-docs create a docs/ dir with html documentation\n"
69 " -fno-emit-bin skip emitting machine code\n"72 " -fno-emit-bin skip emitting machine code\n"
...@@ -306,9 +309,29 @@ static int zig_error_no_build_file(void) {...@@ -306,9 +309,29 @@ static int zig_error_no_build_file(void) {
306309
307extern "C" int ZigClang_main(int argc, char **argv);310extern "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
309int main(int argc, char **argv) {328int main(int argc, char **argv) {
310 stage2_attach_segfault_handler();329 stage2_attach_segfault_handler();
311330
331#ifdef ZIG_ENABLE_MEM_PROFILE
332 memprof_init();
333#endif
334
312 char *arg0 = argv[0];335 char *arg0 = argv[0];
313 Error err;336 Error err;
314337
...@@ -670,6 +693,13 @@ int main(int argc, char **argv) {...@@ -670,6 +693,13 @@ int main(int argc, char **argv) {
670 timing_info = true;693 timing_info = true;
671 } else if (strcmp(arg, "-fstack-report") == 0) {694 } else if (strcmp(arg, "-fstack-report") == 0) {
672 stack_report = true;695 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
673 } else if (strcmp(arg, "-fdump-analysis") == 0) {703 } else if (strcmp(arg, "-fdump-analysis") == 0) {
674 enable_dump_analysis = true;704 enable_dump_analysis = true;
675 } else if (strcmp(arg, "-femit-docs") == 0) {705 } else if (strcmp(arg, "-femit-docs") == 0) {
...@@ -1038,16 +1068,14 @@ int main(int argc, char **argv) {...@@ -1038,16 +1068,14 @@ int main(int argc, char **argv) {
1038 if (in_file) {1068 if (in_file) {
1039 ZigLibCInstallation libc;1069 ZigLibCInstallation libc;
1040 if ((err = zig_libc_parse(&libc, buf_create_from_str(in_file), &target, true)))1070 if ((err = zig_libc_parse(&libc, buf_create_from_str(in_file), &target, true)))
1041 return EXIT_FAILURE;1071 return main_exit(root_progress_node, EXIT_FAILURE);
1042 stage2_progress_end(root_progress_node);1072 return main_exit(root_progress_node, EXIT_SUCCESS);
1043 return EXIT_SUCCESS;
1044 }1073 }
1045 ZigLibCInstallation libc;1074 ZigLibCInstallation libc;
1046 if ((err = zig_libc_find_native(&libc, true)))1075 if ((err = zig_libc_find_native(&libc, true)))
1047 return EXIT_FAILURE;1076 return main_exit(root_progress_node, EXIT_FAILURE);
1048 zig_libc_render(&libc, stdout);1077 zig_libc_render(&libc, stdout);
1049 stage2_progress_end(root_progress_node);1078 return main_exit(root_progress_node, EXIT_SUCCESS);
1050 return EXIT_SUCCESS;
1051 }1079 }
1052 case CmdBuiltin: {1080 case CmdBuiltin: {
1053 CodeGen *g = codegen_create(main_pkg_path, nullptr, &target,1081 CodeGen *g = codegen_create(main_pkg_path, nullptr, &target,
...@@ -1065,10 +1093,9 @@ int main(int argc, char **argv) {...@@ -1065,10 +1093,9 @@ int main(int argc, char **argv) {
1065 Buf *builtin_source = codegen_generate_builtin_source(g);1093 Buf *builtin_source = codegen_generate_builtin_source(g);
1066 if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {1094 if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) {
1067 fprintf(stderr, "unable to write to stdout: %s\n", strerror(ferror(stdout)));1095 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);
1069 }1097 }
1070 stage2_progress_end(root_progress_node);1098 return main_exit(root_progress_node, EXIT_SUCCESS);
1071 return EXIT_SUCCESS;
1072 }1099 }
1073 case CmdRun:1100 case CmdRun:
1074 case CmdBuild:1101 case CmdBuild:
...@@ -1142,7 +1169,7 @@ int main(int argc, char **argv) {...@@ -1142,7 +1169,7 @@ int main(int argc, char **argv) {
1142 libc = allocate<ZigLibCInstallation>(1);1169 libc = allocate<ZigLibCInstallation>(1);
1143 if ((err = zig_libc_parse(libc, buf_create_from_str(libc_txt), &target, true))) {1170 if ((err = zig_libc_parse(libc, buf_create_from_str(libc_txt), &target, true))) {
1144 fprintf(stderr, "Unable to parse --libc text file: %s\n", err_str(err));1171 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);
1146 }1173 }
1147 }1174 }
1148 Buf *cache_dir_buf;1175 Buf *cache_dir_buf;
...@@ -1219,7 +1246,7 @@ int main(int argc, char **argv) {...@@ -1219,7 +1246,7 @@ int main(int argc, char **argv) {
1219 codegen_set_rdynamic(g, rdynamic);1246 codegen_set_rdynamic(g, rdynamic);
1220 if (mmacosx_version_min && mios_version_min) {1247 if (mmacosx_version_min && mios_version_min) {
1221 fprintf(stderr, "-mmacosx-version-min and -mios-version-min options not allowed together\n");1248 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);
1223 }1250 }
12241251
1225 if (mmacosx_version_min) {1252 if (mmacosx_version_min) {
...@@ -1259,6 +1286,11 @@ int main(int argc, char **argv) {...@@ -1259,6 +1286,11 @@ int main(int argc, char **argv) {
1259 zig_print_stack_report(g, stdout);1286 zig_print_stack_report(g, stdout);
12601287
1261 if (cmd == CmdRun) {1288 if (cmd == CmdRun) {
1289 stage2_progress_end(root_progress_node);
1290#ifdef ZIG_ENABLE_MEM_PROFILE
1291 memprof_dump_stats(stderr);
1292#endif
1293
1262 const char *exec_path = buf_ptr(&g->output_file_path);1294 const char *exec_path = buf_ptr(&g->output_file_path);
1263 ZigList<const char*> args = {0};1295 ZigList<const char*> args = {0};
12641296
...@@ -1282,10 +1314,9 @@ int main(int argc, char **argv) {...@@ -1282,10 +1314,9 @@ int main(int argc, char **argv) {
1282 buf_replace(&g->output_file_path, '/', '\\');1314 buf_replace(&g->output_file_path, '/', '\\');
1283#endif1315#endif
1284 if (printf("%s\n", buf_ptr(&g->output_file_path)) < 0)1316 if (printf("%s\n", buf_ptr(&g->output_file_path)) < 0)
1285 return EXIT_FAILURE;1317 return main_exit(root_progress_node, EXIT_FAILURE);
1286 }1318 }
1287 stage2_progress_end(root_progress_node);1319 return main_exit(root_progress_node, EXIT_SUCCESS);
1288 return EXIT_SUCCESS;
1289 } else {1320 } else {
1290 zig_unreachable();1321 zig_unreachable();
1291 }1322 }
...@@ -1293,8 +1324,7 @@ int main(int argc, char **argv) {...@@ -1293,8 +1324,7 @@ int main(int argc, char **argv) {
1293 codegen_translate_c(g, in_file_buf, stdout, cmd == CmdTranslateCUserland);1324 codegen_translate_c(g, in_file_buf, stdout, cmd == CmdTranslateCUserland);
1294 if (timing_info)1325 if (timing_info)
1295 codegen_print_timing_report(g, stderr);1326 codegen_print_timing_report(g, stderr);
1296 stage2_progress_end(root_progress_node);1327 return main_exit(root_progress_node, EXIT_SUCCESS);
1297 return EXIT_SUCCESS;
1298 } else if (cmd == CmdTest) {1328 } else if (cmd == CmdTest) {
1299 codegen_set_emit_file_type(g, emit_file_type);1329 codegen_set_emit_file_type(g, emit_file_type);
13001330
...@@ -1314,7 +1344,7 @@ int main(int argc, char **argv) {...@@ -1314,7 +1344,7 @@ int main(int argc, char **argv) {
13141344
1315 if (g->disable_bin_generation) {1345 if (g->disable_bin_generation) {
1316 fprintf(stderr, "Semantic analysis complete. No binary produced due to -fno-emit-bin.\n");1346 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);
1318 }1348 }
13191349
1320 Buf *test_exe_path_unresolved = &g->output_file_path;1350 Buf *test_exe_path_unresolved = &g->output_file_path;
...@@ -1324,7 +1354,7 @@ int main(int argc, char **argv) {...@@ -1324,7 +1354,7 @@ int main(int argc, char **argv) {
1324 if (emit_file_type != EmitFileTypeBinary) {1354 if (emit_file_type != EmitFileTypeBinary) {
1325 fprintf(stderr, "Created %s but skipping execution because it is non executable.\n",1355 fprintf(stderr, "Created %s but skipping execution because it is non executable.\n",
1326 buf_ptr(test_exe_path));1356 buf_ptr(test_exe_path));
1327 return 0;1357 return main_exit(root_progress_node, EXIT_SUCCESS);
1328 }1358 }
13291359
1330 for (size_t i = 0; i < test_exec_args.length; i += 1) {1360 for (size_t i = 0; i < test_exec_args.length; i += 1) {
...@@ -1336,7 +1366,7 @@ int main(int argc, char **argv) {...@@ -1336,7 +1366,7 @@ int main(int argc, char **argv) {
1336 if (!target_can_exec(&native, &target) && test_exec_args.length == 0) {1366 if (!target_can_exec(&native, &target) && test_exec_args.length == 0) {
1337 fprintf(stderr, "Created %s but skipping execution because it is non-native.\n",1367 fprintf(stderr, "Created %s but skipping execution because it is non-native.\n",
1338 buf_ptr(test_exe_path));1368 buf_ptr(test_exe_path));
1339 return 0;1369 return main_exit(root_progress_node, EXIT_SUCCESS);
1340 }1370 }
13411371
1342 Termination term;1372 Termination term;
...@@ -1348,21 +1378,20 @@ int main(int argc, char **argv) {...@@ -1348,21 +1378,20 @@ int main(int argc, char **argv) {
1348 fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n");1378 fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n");
1349 fprintf(stderr, "%s\n", buf_ptr(test_exe_path));1379 fprintf(stderr, "%s\n", buf_ptr(test_exe_path));
1350 }1380 }
1351 stage2_progress_end(root_progress_node);1381 return main_exit(root_progress_node, (term.how == TerminationIdClean) ? term.code : -1);
1352 return (term.how == TerminationIdClean) ? term.code : -1;
1353 } else {1382 } else {
1354 zig_unreachable();1383 zig_unreachable();
1355 }1384 }
1356 }1385 }
1357 case CmdVersion:1386 case CmdVersion:
1358 printf("%s\n", ZIG_VERSION_STRING);1387 printf("%s\n", ZIG_VERSION_STRING);
1359 return EXIT_SUCCESS;1388 return main_exit(root_progress_node, EXIT_SUCCESS);
1360 case CmdZen: {1389 case CmdZen: {
1361 const char *ptr;1390 const char *ptr;
1362 size_t len;1391 size_t len;
1363 stage2_zen(&ptr, &len);1392 stage2_zen(&ptr, &len);
1364 fwrite(ptr, len, 1, stdout);1393 fwrite(ptr, len, 1, stdout);
1365 return EXIT_SUCCESS;1394 return main_exit(root_progress_node, EXIT_SUCCESS);
1366 }1395 }
1367 case CmdTargets:1396 case CmdTargets:
1368 return print_target_list(stdout);1397 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) {...@@ -119,3 +119,21 @@ Slice<uint8_t> SplitIterator_rest(SplitIterator *self) {
119SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes) {119SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes) {
120 return SplitIterator{0, buffer, split_bytes};120 return SplitIterator{0, buffer, split_bytes};
121}121}
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 @@...@@ -8,6 +8,8 @@
8#ifndef ZIG_UTIL_HPP8#ifndef ZIG_UTIL_HPP
9#define ZIG_UTIL_HPP9#define ZIG_UTIL_HPP
1010
11#include "memory_profiling.hpp"
12
11#include <stdlib.h>13#include <stdlib.h>
12#include <stdint.h>14#include <stdint.h>
13#include <string.h>15#include <string.h>
...@@ -96,7 +98,10 @@ static inline int ctzll(unsigned long long mask) {...@@ -96,7 +98,10 @@ static inline int ctzll(unsigned long long mask) {
9698
9799
98template<typename T>100template<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
100#ifndef NDEBUG105#ifndef NDEBUG
101 // make behavior when size == 0 portable106 // make behavior when size == 0 portable
102 if (count == 0)107 if (count == 0)
...@@ -109,7 +114,10 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count) {...@@ -109,7 +114,10 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count) {
109}114}
110115
111template<typename T>116template<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
113#ifndef NDEBUG121#ifndef NDEBUG
114 // make behavior when size == 0 portable122 // make behavior when size == 0 portable
115 if (count == 0)123 if (count == 0)
...@@ -122,7 +130,7 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) {...@@ -122,7 +130,7 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) {
122}130}
123131
124template<typename T>132template<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) {
126 T *ptr = reallocate_nonzero(old, old_count, new_count);134 T *ptr = reallocate_nonzero(old, old_count, new_count);
127 if (new_count > old_count) {135 if (new_count > old_count) {
128 memset(&ptr[old_count], 0, (new_count - old_count) * sizeof(T));136 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) {...@@ -131,7 +139,11 @@ static inline T *reallocate(T *old, size_t old_count, size_t new_count) {
131}139}
132140
133template<typename T>141template<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
135#ifndef NDEBUG147#ifndef NDEBUG
136 // make behavior when size == 0 portable148 // make behavior when size == 0 portable
137 if (new_count == 0 && old == nullptr)149 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)...@@ -143,6 +155,19 @@ static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count)
143 return ptr;155 return ptr;
144}156}
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
146template <typename T, size_t n>171template <typename T, size_t n>
147constexpr size_t array_length(const T (&)[n]) {172constexpr size_t array_length(const T (&)[n]) {
148 return n;173 return n;
...@@ -225,6 +250,8 @@ static inline double zig_f16_to_double(float16_t x) {...@@ -225,6 +250,8 @@ static inline double zig_f16_to_double(float16_t x) {
225 return z;250 return z;
226}251}
227252
253void zig_pretty_print_bytes(FILE *f, double n);
254
228template<typename T>255template<typename T>
229struct Optional {256struct Optional {
230 T value;257 T value;