| author | |
| committer | |
| log | 63dfca97159fd66563693039606c0bca30aa1f85 |
| tree | 7975692d2f2934f19d13a1784db87619c525bcaf |
| parent | e42d86b657c2fae093fb2545e8b4b85614a0c906 |
| parent | 4e985123447dba40e282e9663e3ca669d3f9243a |
| signature |
add -DZIG_ENABLE_MEM_PROFILE option and -fmem-report flag13 files changed, 315 insertions(+), 83 deletions(-)
CMakeLists.txt+2| ... | ... | @@ -46,6 +46,7 @@ message("Configuring zig version ${ZIG_VERSION}") |
| 46 | 46 | set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)") |
| 47 | 47 | set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries") |
| 48 | 48 | set(ZIG_SKIP_INSTALL_LIB_FILES off CACHE BOOL "Disable copying lib/ files to install prefix") |
| 49 | set(ZIG_ENABLE_MEM_PROFILE off CACHE BOOL "Activate memory usage instrumentation") | |
| 49 | 50 | |
| 50 | 51 | if(ZIG_STATIC) |
| 51 | 52 | set(ZIG_STATIC_LLVM "on") |
| ... | ... | @@ -455,6 +456,7 @@ set(ZIG_SOURCES |
| 455 | 456 | "${CMAKE_SOURCE_DIR}/src/ir_print.cpp" |
| 456 | 457 | "${CMAKE_SOURCE_DIR}/src/libc_installation.cpp" |
| 457 | 458 | "${CMAKE_SOURCE_DIR}/src/link.cpp" |
| 459 | "${CMAKE_SOURCE_DIR}/src/memory_profiling.cpp" | |
| 458 | 460 | "${CMAKE_SOURCE_DIR}/src/os.cpp" |
| 459 | 461 | "${CMAKE_SOURCE_DIR}/src/parser.cpp" |
| 460 | 462 | "${CMAKE_SOURCE_DIR}/src/range_set.cpp" |
src/all_types.hpp+3-3| ... | ... | @@ -2569,12 +2569,12 @@ enum IrInstructionId { |
| 2569 | 2569 | struct IrInstruction { |
| 2570 | 2570 | Scope *scope; |
| 2571 | 2571 | AstNode *source_node; |
| 2572 | ConstExprValue value; | |
| 2573 | size_t debug_id; | |
| 2574 | 2572 | LLVMValueRef llvm_value; |
| 2573 | ConstExprValue value; | |
| 2574 | uint32_t debug_id; | |
| 2575 | 2575 | // if ref_count is zero and the instruction has no side effects, |
| 2576 | 2576 | // the instruction can be omitted in codegen |
| 2577 | size_t ref_count; | |
| 2577 | uint32_t ref_count; | |
| 2578 | 2578 | // When analyzing IR, instructions that point to this instruction in the "old ir" |
| 2579 | 2579 | // can find the instruction that corresponds to this value in the "new ir" |
| 2580 | 2580 | // with this child field. |
src/analyze.cpp+2-2| ... | ... | @@ -5783,8 +5783,8 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_ |
| 5783 | 5783 | |
| 5784 | 5784 | |
| 5785 | 5785 | ConstExprValue *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"); | |
| 5788 | 5788 | for (size_t i = 0; i < count; i += 1) { |
| 5789 | 5789 | vals[i].global_refs = &global_refs[i]; |
| 5790 | 5790 | } |
src/config.h.in+2-3| ... | ... | @@ -13,9 +13,6 @@ |
| 13 | 13 | #define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@ |
| 14 | 14 | #define ZIG_VERSION_STRING "@ZIG_VERSION@" |
| 15 | 15 | |
| 16 | // Only used for running tests before installing. | |
| 17 | #define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test" | |
| 18 | ||
| 19 | 16 | // Used for communicating build information to self hosted build. |
| 20 | 17 | #define ZIG_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@" |
| 21 | 18 | #define ZIG_CXX_COMPILER "@CMAKE_CXX_COMPILER@" |
| ... | ... | @@ -24,4 +21,6 @@ |
| 24 | 21 | #define ZIG_LLVM_CONFIG_EXE "@LLVM_CONFIG_EXE@" |
| 25 | 22 | #define ZIG_DIA_GUIDS_LIB "@ZIG_DIA_GUIDS_LIB_ESCAPED@" |
| 26 | 23 | |
| 24 | #cmakedefine ZIG_ENABLE_MEM_PROFILE | |
| 25 | ||
| 27 | 26 | #endif |
src/dump_analysis.cpp+1-18| ... | ... | @@ -240,23 +240,6 @@ static void jw_string(JsonWriter *jw, const char *s) { |
| 240 | 240 | |
| 241 | 241 | static void tree_print(FILE *f, ZigType *ty, size_t indent); |
| 242 | 242 | |
| 243 | static 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 | ||
| 260 | 243 | static int compare_type_abi_sizes_desc(const void *a, const void *b) { |
| 261 | 244 | uint64_t size_a = (*(ZigType * const*)(a))->abi_size; |
| 262 | 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 | 305 | |
| 323 | 306 | start_peer(f, indent); |
| 324 | 307 | fprintf(f, "\"sizef\": \""); |
| 325 | pretty_print_bytes(f, ty->abi_size); | |
| 308 | zig_pretty_print_bytes(f, ty->abi_size); | |
| 326 | 309 | fprintf(f, "\""); |
| 327 | 310 | |
| 328 | 311 | start_peer(f, indent); |
src/ir.cpp+35-24| ... | ... | @@ -413,7 +413,7 @@ ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) { |
| 413 | 413 | } |
| 414 | 414 | |
| 415 | 415 | static 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 | 417 | result->scope = scope; |
| 418 | 418 | result->name_hint = name_hint; |
| 419 | 419 | result->debug_id = exec_next_debug_id(irb->exec); |
| ... | ... | @@ -1085,13 +1085,18 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSpillEnd *) { |
| 1085 | 1085 | |
| 1086 | 1086 | template<typename T> |
| 1087 | 1087 | static 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 | 1094 | special_instruction->base.id = ir_instruction_id(special_instruction); |
| 1090 | 1095 | special_instruction->base.scope = scope; |
| 1091 | 1096 | special_instruction->base.source_node = source_node; |
| 1092 | 1097 | special_instruction->base.debug_id = exec_next_debug_id(irb->exec); |
| 1093 | 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 | 1100 | return special_instruction; |
| 1096 | 1101 | } |
| 1097 | 1102 | |
| ... | ... | @@ -3569,7 +3574,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3569 | 3574 | switch (node->data.return_expr.kind) { |
| 3570 | 3575 | case ReturnKindUnconditional: |
| 3571 | 3576 | { |
| 3572 | ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1); | |
| 3577 | ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1, "ResultLocReturn"); | |
| 3573 | 3578 | result_loc_ret->base.id = ResultLocIdReturn; |
| 3574 | 3579 | ir_build_reset_result(irb, scope, node, &result_loc_ret->base); |
| 3575 | 3580 | |
| ... | ... | @@ -3664,7 +3669,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, |
| 3664 | 3669 | ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, node, err_val, nullptr)); |
| 3665 | 3670 | IrInstructionSpillBegin *spill_begin = ir_build_spill_begin(irb, scope, node, err_val, |
| 3666 | 3671 | SpillIdRetErrCode); |
| 3667 | ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1); | |
| 3672 | ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1, "ResultLocReturn"); | |
| 3668 | 3673 | result_loc_ret->base.id = ResultLocIdReturn; |
| 3669 | 3674 | ir_build_reset_result(irb, scope, node, &result_loc_ret->base); |
| 3670 | 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 | 3697 | Buf *name, bool src_is_const, bool gen_is_const, bool is_shadowable, IrInstruction *is_comptime, |
| 3693 | 3698 | bool skip_name_check) |
| 3694 | 3699 | { |
| 3695 | ZigVar *variable_entry = allocate<ZigVar>(1); | |
| 3700 | ZigVar *variable_entry = allocate<ZigVar>(1, "ZigVar"); | |
| 3696 | 3701 | variable_entry->parent_scope = parent_scope; |
| 3697 | 3702 | variable_entry->shadowable = is_shadowable; |
| 3698 | 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 | 3772 | } |
| 3768 | 3773 | |
| 3769 | 3774 | static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) { |
| 3770 | ResultLocPeer *result = allocate<ResultLocPeer>(1); | |
| 3775 | ResultLocPeer *result = allocate<ResultLocPeer>(1, "ResultLocPeer"); | |
| 3771 | 3776 | result->base.id = ResultLocIdPeer; |
| 3772 | 3777 | result->base.source_instruction = peer_parent->base.source_instruction; |
| 3773 | 3778 | result->parent = peer_parent; |
| ... | ... | @@ -3806,7 +3811,7 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode |
| 3806 | 3811 | scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, |
| 3807 | 3812 | ir_should_inline(irb->exec, parent_scope)); |
| 3808 | 3813 | |
| 3809 | scope_block->peer_parent = allocate<ResultLocPeerParent>(1); | |
| 3814 | scope_block->peer_parent = allocate<ResultLocPeerParent>(1, "ResultLocPeerParent"); | |
| 3810 | 3815 | scope_block->peer_parent->base.id = ResultLocIdPeerParent; |
| 3811 | 3816 | scope_block->peer_parent->base.source_instruction = scope_block->is_comptime; |
| 3812 | 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 | 3938 | if (lvalue == irb->codegen->invalid_instruction) |
| 3934 | 3939 | return irb->codegen->invalid_instruction; |
| 3935 | 3940 | |
| 3936 | ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1); | |
| 3941 | ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1, "ResultLocInstruction"); | |
| 3937 | 3942 | result_loc_inst->base.id = ResultLocIdInstruction; |
| 3938 | 3943 | result_loc_inst->base.source_instruction = lvalue; |
| 3939 | 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 | 4010 | |
| 4006 | 4011 | ir_set_cursor_at_end_and_append_block(irb, true_block); |
| 4007 | 4012 | |
| 4008 | IrInstruction **incoming_values = allocate<IrInstruction *>(2); | |
| 4013 | IrInstruction **incoming_values = allocate<IrInstruction *>(2, "IrInstruction *"); | |
| 4009 | 4014 | incoming_values[0] = val1; |
| 4010 | 4015 | incoming_values[1] = val2; |
| 4011 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); | |
| 4016 | IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2, "IrBasicBlock *"); | |
| 4012 | 4017 | incoming_blocks[0] = post_val1_block; |
| 4013 | 4018 | incoming_blocks[1] = post_val2_block; |
| 4014 | 4019 | |
| ... | ... | @@ -8017,7 +8022,8 @@ static IrInstruction *ir_gen_err_set_decl(IrBuilder *irb, Scope *parent_scope, A |
| 8017 | 8022 | err_set_type->abi_size = irb->codegen->builtin_types.entry_global_error_set->abi_size; |
| 8018 | 8023 | err_set_type->data.error_set.errors = allocate<ErrorTableEntry *>(err_count); |
| 8019 | 8024 | |
| 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 *"); | |
| 8021 | 8027 | |
| 8022 | 8028 | for (uint32_t i = 0; i < err_count; i += 1) { |
| 8023 | 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 | 8054 | } |
| 8049 | 8055 | errors[err->value] = err; |
| 8050 | 8056 | } |
| 8051 | free(errors); | |
| 8057 | deallocate(errors, errors_count, "ErrorTableEntry *"); | |
| 8052 | 8058 | return ir_build_const_type(irb, parent_scope, node, err_set_type); |
| 8053 | 8059 | } |
| 8054 | 8060 | |
| ... | ... | @@ -9574,7 +9580,8 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp |
| 9574 | 9580 | if (type_is_global_error_set(set2)) { |
| 9575 | 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 | 9585 | populate_error_set_table(errors, set1); |
| 9579 | 9586 | ZigList<ErrorTableEntry *> intersection_list = {}; |
| 9580 | 9587 | |
| ... | ... | @@ -9595,7 +9602,7 @@ static ZigType *get_error_set_intersection(IrAnalyze *ira, ZigType *set1, ZigTyp |
| 9595 | 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 *"); | |
| 9599 | 9606 | |
| 9600 | 9607 | err_set_type->data.error_set.err_count = intersection_list.length; |
| 9601 | 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 | 9799 | return result; |
| 9793 | 9800 | } |
| 9794 | 9801 | |
| 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 | 9804 | for (uint32_t i = 0; i < container_set->data.error_set.err_count; i += 1) { |
| 9797 | 9805 | ErrorTableEntry *error_entry = container_set->data.error_set.errors[i]; |
| 9798 | 9806 | assert(errors[error_entry->value] == nullptr); |
| ... | ... | @@ -9809,7 +9817,7 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted |
| 9809 | 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 | 9821 | return result; |
| 9814 | 9822 | } |
| 9815 | 9823 | |
| ... | ... | @@ -10814,7 +10822,8 @@ static IrInstruction *ira_suspend(IrAnalyze *ira, IrInstruction *old_instruction |
| 10814 | 10822 | IrSuspendPosition *suspend_pos) |
| 10815 | 10823 | { |
| 10816 | 10824 | if (ira->codegen->verbose_ir) { |
| 10817 | fprintf(stderr, "suspend %s_%zu %s_%zu #%zu (%zu,%zu)\n", ira->old_irb.current_basic_block->name_hint, | |
| 10825 | fprintf(stderr, "suspend %s_%zu %s_%zu #%" PRIu32 " (%zu,%zu)\n", | |
| 10826 | ira->old_irb.current_basic_block->name_hint, | |
| 10818 | 10827 | ira->old_irb.current_basic_block->debug_id, |
| 10819 | 10828 | ira->old_irb.exec->basic_block_list.at(ira->old_bb_index)->name_hint, |
| 10820 | 10829 | ira->old_irb.exec->basic_block_list.at(ira->old_bb_index)->debug_id, |
| ... | ... | @@ -10852,7 +10861,7 @@ static IrInstruction *ira_resume(IrAnalyze *ira) { |
| 10852 | 10861 | ira->instruction_index = pos.instruction_index; |
| 10853 | 10862 | assert(pos.instruction_index < ira->old_irb.current_basic_block->instruction_list.length); |
| 10854 | 10863 | if (ira->codegen->verbose_ir) { |
| 10855 | fprintf(stderr, "%s_%zu #%zu\n", ira->old_irb.current_basic_block->name_hint, | |
| 10864 | fprintf(stderr, "%s_%zu #%" PRIu32 "\n", ira->old_irb.current_basic_block->name_hint, | |
| 10856 | 10865 | ira->old_irb.current_basic_block->debug_id, |
| 10857 | 10866 | ira->old_irb.current_basic_block->instruction_list.at(pos.instruction_index)->debug_id); |
| 10858 | 10867 | } |
| ... | ... | @@ -14686,14 +14695,15 @@ static IrInstruction *ir_analyze_instruction_merge_err_sets(IrAnalyze *ira, |
| 14686 | 14695 | return ira->codegen->invalid_instruction; |
| 14687 | 14696 | } |
| 14688 | 14697 | |
| 14689 | ErrorTableEntry **errors = allocate<ErrorTableEntry *>(ira->codegen->errors_by_index.length); | |
| 14698 | size_t errors_count = ira->codegen->errors_by_index.length; | |
| 14699 | ErrorTableEntry **errors = allocate<ErrorTableEntry *>(errors_count, "ErrorTableEntry *"); | |
| 14690 | 14700 | for (uint32_t i = 0, count = op1_type->data.error_set.err_count; i < count; i += 1) { |
| 14691 | 14701 | ErrorTableEntry *error_entry = op1_type->data.error_set.errors[i]; |
| 14692 | 14702 | assert(errors[error_entry->value] == nullptr); |
| 14693 | 14703 | errors[error_entry->value] = error_entry; |
| 14694 | 14704 | } |
| 14695 | 14705 | ZigType *result_type = get_error_set_union(ira->codegen, errors, op1_type, op2_type, instruction->type_name); |
| 14696 | free(errors); | |
| 14706 | deallocate(errors, errors_count, "ErrorTableEntry *"); | |
| 14697 | 14707 | |
| 14698 | 14708 | return ir_const_type(ira, &instruction->base, result_type); |
| 14699 | 14709 | } |
| ... | ... | @@ -24034,7 +24044,8 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, |
| 24034 | 24044 | return ira->codegen->invalid_instruction; |
| 24035 | 24045 | } |
| 24036 | 24046 | |
| 24037 | AstNode **field_prev_uses = allocate<AstNode *>(ira->codegen->errors_by_index.length); | |
| 24047 | size_t field_prev_uses_count = ira->codegen->errors_by_index.length; | |
| 24048 | AstNode **field_prev_uses = allocate<AstNode *>(field_prev_uses_count, "AstNode *"); | |
| 24038 | 24049 | |
| 24039 | 24050 | for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { |
| 24040 | 24051 | IrInstructionCheckSwitchProngsRange *range = &instruction->ranges[range_i]; |
| ... | ... | @@ -24091,7 +24102,7 @@ static IrInstruction *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, |
| 24091 | 24102 | } |
| 24092 | 24103 | } |
| 24093 | 24104 | |
| 24094 | free(field_prev_uses); | |
| 24105 | deallocate(field_prev_uses, field_prev_uses_count, "AstNode *"); | |
| 24095 | 24106 | } else if (switch_type->id == ZigTypeIdInt) { |
| 24096 | 24107 | RangeSet rs = {0}; |
| 24097 | 24108 | for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { |
| ... | ... | @@ -26318,7 +26329,7 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ |
| 26318 | 26329 | } |
| 26319 | 26330 | |
| 26320 | 26331 | if (ira->codegen->verbose_ir) { |
| 26321 | fprintf(stderr, "analyze #%zu\n", old_instruction->debug_id); | |
| 26332 | fprintf(stderr, "analyze #%" PRIu32 "\n", old_instruction->debug_id); | |
| 26322 | 26333 | } |
| 26323 | 26334 | IrInstruction *new_instruction = ir_analyze_instruction_base(ira, old_instruction); |
| 26324 | 26335 | if (new_instruction != nullptr) { |
src/ir_print.cpp+6-6| ... | ... | @@ -38,8 +38,8 @@ struct IrPrint { |
| 38 | 38 | |
| 39 | 39 | static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction); |
| 40 | 40 | |
| 41 | static const char* ir_instruction_type_str(IrInstruction* instruction) { | |
| 42 | switch (instruction->id) { | |
| 41 | const char* ir_instruction_type_str(IrInstructionId id) { | |
| 42 | switch (id) { | |
| 43 | 43 | case IrInstructionIdInvalid: |
| 44 | 44 | return "Invalid"; |
| 45 | 45 | case IrInstructionIdShuffleVector: |
| ... | ... | @@ -385,9 +385,9 @@ static void ir_print_prefix(IrPrint *irp, IrInstruction *instruction, bool trail |
| 385 | 385 | const char mark = trailing ? ':' : '#'; |
| 386 | 386 | const char *type_name = instruction->value.type ? buf_ptr(&instruction->value.type->name) : "(unknown)"; |
| 387 | 387 | const char *ref_count = ir_has_side_effects(instruction) ? |
| 388 | "-" : buf_ptr(buf_sprintf("%" ZIG_PRI_usize "", instruction->ref_count)); | |
| 389 | fprintf(irp->f, "%c%-3zu| %-22s| %-12s| %-2s| ", mark, instruction->debug_id, | |
| 390 | ir_instruction_type_str(instruction), type_name, ref_count); | |
| 388 | "-" : buf_ptr(buf_sprintf("%" PRIu32 "", instruction->ref_count)); | |
| 389 | fprintf(irp->f, "%c%-3" PRIu32 "| %-22s| %-12s| %-2s| ", mark, instruction->debug_id, | |
| 390 | ir_instruction_type_str(instruction->id), type_name, ref_count); | |
| 391 | 391 | } |
| 392 | 392 | |
| 393 | 393 | static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { |
| ... | ... | @@ -398,7 +398,7 @@ static void ir_print_const_value(IrPrint *irp, ConstExprValue *const_val) { |
| 398 | 398 | } |
| 399 | 399 | |
| 400 | 400 | static void ir_print_var_instruction(IrPrint *irp, IrInstruction *instruction) { |
| 401 | fprintf(irp->f, "#%" ZIG_PRI_usize "", instruction->debug_id); | |
| 401 | fprintf(irp->f, "#%" PRIu32 "", instruction->debug_id); | |
| 402 | 402 | if (irp->pass != IrPassSrc && irp->printed.maybe_get(instruction) == nullptr) { |
| 403 | 403 | irp->printed.put(instruction, 0); |
| 404 | 404 | irp->pending.append(instruction); |
src/ir_print.hpp+2| ... | ... | @@ -15,4 +15,6 @@ |
| 15 | 15 | void ir_print(CodeGen *codegen, FILE *f, IrExecutable *executable, int indent_size, IrPass pass); |
| 16 | 16 | void ir_print_instruction(CodeGen *codegen, FILE *f, IrInstruction *instruction, int indent_size, IrPass pass); |
| 17 | 17 | |
| 18 | const char* ir_instruction_type_str(IrInstructionId id); | |
| 19 | ||
| 18 | 20 | #endif |
src/main.cpp+52-23| ... | ... | @@ -64,6 +64,9 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { |
| 64 | 64 | " -fno-PIC disable Position Independent Code\n" |
| 65 | 65 | " -ftime-report print timing diagnostics\n" |
| 66 | 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 | 70 | " -fdump-analysis write analysis.json file with type information\n" |
| 68 | 71 | " -femit-docs create a docs/ dir with html documentation\n" |
| 69 | 72 | " -fno-emit-bin skip emitting machine code\n" |
| ... | ... | @@ -306,9 +309,29 @@ static int zig_error_no_build_file(void) { |
| 306 | 309 | |
| 307 | 310 | extern "C" int ZigClang_main(int argc, char **argv); |
| 308 | 311 | |
| 312 | #ifdef ZIG_ENABLE_MEM_PROFILE | |
| 313 | bool mem_report = false; | |
| 314 | #endif | |
| 315 | ||
| 316 | int 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 | ||
| 309 | 328 | int main(int argc, char **argv) { |
| 310 | 329 | stage2_attach_segfault_handler(); |
| 311 | 330 | |
| 331 | #ifdef ZIG_ENABLE_MEM_PROFILE | |
| 332 | memprof_init(); | |
| 333 | #endif | |
| 334 | ||
| 312 | 335 | char *arg0 = argv[0]; |
| 313 | 336 | Error err; |
| 314 | 337 | |
| ... | ... | @@ -670,6 +693,13 @@ int main(int argc, char **argv) { |
| 670 | 693 | timing_info = true; |
| 671 | 694 | } else if (strcmp(arg, "-fstack-report") == 0) { |
| 672 | 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 | 703 | } else if (strcmp(arg, "-fdump-analysis") == 0) { |
| 674 | 704 | enable_dump_analysis = true; |
| 675 | 705 | } else if (strcmp(arg, "-femit-docs") == 0) { |
| ... | ... | @@ -1038,16 +1068,14 @@ int main(int argc, char **argv) { |
| 1038 | 1068 | if (in_file) { |
| 1039 | 1069 | ZigLibCInstallation libc; |
| 1040 | 1070 | 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); | |
| 1044 | 1073 | } |
| 1045 | 1074 | ZigLibCInstallation libc; |
| 1046 | 1075 | if ((err = zig_libc_find_native(&libc, true))) |
| 1047 | return EXIT_FAILURE; | |
| 1076 | return main_exit(root_progress_node, EXIT_FAILURE); | |
| 1048 | 1077 | 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); | |
| 1051 | 1079 | } |
| 1052 | 1080 | case CmdBuiltin: { |
| 1053 | 1081 | CodeGen *g = codegen_create(main_pkg_path, nullptr, &target, |
| ... | ... | @@ -1065,10 +1093,9 @@ int main(int argc, char **argv) { |
| 1065 | 1093 | Buf *builtin_source = codegen_generate_builtin_source(g); |
| 1066 | 1094 | if (fwrite(buf_ptr(builtin_source), 1, buf_len(builtin_source), stdout) != buf_len(builtin_source)) { |
| 1067 | 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); | |
| 1071 | return EXIT_SUCCESS; | |
| 1098 | return main_exit(root_progress_node, EXIT_SUCCESS); | |
| 1072 | 1099 | } |
| 1073 | 1100 | case CmdRun: |
| 1074 | 1101 | case CmdBuild: |
| ... | ... | @@ -1142,7 +1169,7 @@ int main(int argc, char **argv) { |
| 1142 | 1169 | libc = allocate<ZigLibCInstallation>(1); |
| 1143 | 1170 | if ((err = zig_libc_parse(libc, buf_create_from_str(libc_txt), &target, true))) { |
| 1144 | 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 | 1175 | Buf *cache_dir_buf; |
| ... | ... | @@ -1219,7 +1246,7 @@ int main(int argc, char **argv) { |
| 1219 | 1246 | codegen_set_rdynamic(g, rdynamic); |
| 1220 | 1247 | if (mmacosx_version_min && mios_version_min) { |
| 1221 | 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 | } |
| 1224 | 1251 | |
| 1225 | 1252 | if (mmacosx_version_min) { |
| ... | ... | @@ -1259,6 +1286,11 @@ int main(int argc, char **argv) { |
| 1259 | 1286 | zig_print_stack_report(g, stdout); |
| 1260 | 1287 | |
| 1261 | 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 | 1294 | const char *exec_path = buf_ptr(&g->output_file_path); |
| 1263 | 1295 | ZigList<const char*> args = {0}; |
| 1264 | 1296 | |
| ... | ... | @@ -1282,10 +1314,9 @@ int main(int argc, char **argv) { |
| 1282 | 1314 | buf_replace(&g->output_file_path, '/', '\\'); |
| 1283 | 1315 | #endif |
| 1284 | 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); | |
| 1288 | return EXIT_SUCCESS; | |
| 1319 | return main_exit(root_progress_node, EXIT_SUCCESS); | |
| 1289 | 1320 | } else { |
| 1290 | 1321 | zig_unreachable(); |
| 1291 | 1322 | } |
| ... | ... | @@ -1293,8 +1324,7 @@ int main(int argc, char **argv) { |
| 1293 | 1324 | codegen_translate_c(g, in_file_buf, stdout, cmd == CmdTranslateCUserland); |
| 1294 | 1325 | if (timing_info) |
| 1295 | 1326 | 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); | |
| 1298 | 1328 | } else if (cmd == CmdTest) { |
| 1299 | 1329 | codegen_set_emit_file_type(g, emit_file_type); |
| 1300 | 1330 | |
| ... | ... | @@ -1314,7 +1344,7 @@ int main(int argc, char **argv) { |
| 1314 | 1344 | |
| 1315 | 1345 | if (g->disable_bin_generation) { |
| 1316 | 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 | } |
| 1319 | 1349 | |
| 1320 | 1350 | Buf *test_exe_path_unresolved = &g->output_file_path; |
| ... | ... | @@ -1324,7 +1354,7 @@ int main(int argc, char **argv) { |
| 1324 | 1354 | if (emit_file_type != EmitFileTypeBinary) { |
| 1325 | 1355 | fprintf(stderr, "Created %s but skipping execution because it is non executable.\n", |
| 1326 | 1356 | buf_ptr(test_exe_path)); |
| 1327 | return 0; | |
| 1357 | return main_exit(root_progress_node, EXIT_SUCCESS); | |
| 1328 | 1358 | } |
| 1329 | 1359 | |
| 1330 | 1360 | for (size_t i = 0; i < test_exec_args.length; i += 1) { |
| ... | ... | @@ -1336,7 +1366,7 @@ int main(int argc, char **argv) { |
| 1336 | 1366 | if (!target_can_exec(&native, &target) && test_exec_args.length == 0) { |
| 1337 | 1367 | fprintf(stderr, "Created %s but skipping execution because it is non-native.\n", |
| 1338 | 1368 | buf_ptr(test_exe_path)); |
| 1339 | return 0; | |
| 1369 | return main_exit(root_progress_node, EXIT_SUCCESS); | |
| 1340 | 1370 | } |
| 1341 | 1371 | |
| 1342 | 1372 | Termination term; |
| ... | ... | @@ -1348,21 +1378,20 @@ int main(int argc, char **argv) { |
| 1348 | 1378 | fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n"); |
| 1349 | 1379 | fprintf(stderr, "%s\n", buf_ptr(test_exe_path)); |
| 1350 | 1380 | } |
| 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); | |
| 1353 | 1382 | } else { |
| 1354 | 1383 | zig_unreachable(); |
| 1355 | 1384 | } |
| 1356 | 1385 | } |
| 1357 | 1386 | case CmdVersion: |
| 1358 | 1387 | printf("%s\n", ZIG_VERSION_STRING); |
| 1359 | return EXIT_SUCCESS; | |
| 1388 | return main_exit(root_progress_node, EXIT_SUCCESS); | |
| 1360 | 1389 | case CmdZen: { |
| 1361 | 1390 | const char *ptr; |
| 1362 | 1391 | size_t len; |
| 1363 | 1392 | stage2_zen(&ptr, &len); |
| 1364 | 1393 | fwrite(ptr, len, 1, stdout); |
| 1365 | return EXIT_SUCCESS; | |
| 1394 | return main_exit(root_progress_node, EXIT_SUCCESS); | |
| 1366 | 1395 | } |
| 1367 | 1396 | case CmdTargets: |
| 1368 | 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 | ||
| 9 | static bool str_eql_str(const char *a, const char *b) { | |
| 10 | return strcmp(a, b) == 0; | |
| 11 | } | |
| 12 | ||
| 13 | static 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 | ||
| 23 | struct CountAndSize { | |
| 24 | size_t item_count; | |
| 25 | size_t type_size; | |
| 26 | }; | |
| 27 | ||
| 28 | ZigList<const char *> unknown_names = {}; | |
| 29 | HashMap<const char *, CountAndSize, str_hash, str_eql_str> usage_table = {}; | |
| 30 | bool table_active = false; | |
| 31 | ||
| 32 | ||
| 33 | static 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 | ||
| 48 | void 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 | ||
| 62 | void 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 | ||
| 76 | void memprof_init(void) { | |
| 77 | usage_table.init(1024); | |
| 78 | table_active = true; | |
| 79 | } | |
| 80 | ||
| 81 | struct MemItem { | |
| 82 | const char *type_name; | |
| 83 | CountAndSize count_and_size; | |
| 84 | }; | |
| 85 | ||
| 86 | static size_t get_bytes(const MemItem *item) { | |
| 87 | return item->count_and_size.item_count * item->count_and_size.type_size; | |
| 88 | } | |
| 89 | ||
| 90 | static 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 | ||
| 100 | void 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 | ||
| 16 | void memprof_init(void); | |
| 17 | ||
| 18 | void memprof_alloc(const char *name, size_t item_count, size_t type_size); | |
| 19 | void memprof_dealloc(const char *name, size_t item_count, size_t type_size); | |
| 20 | ||
| 21 | void memprof_dump_stats(FILE *file); | |
| 22 | #endif |
src/util.cpp+18| ... | ... | @@ -119,3 +119,21 @@ Slice<uint8_t> SplitIterator_rest(SplitIterator *self) { |
| 119 | 119 | SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes) { |
| 120 | 120 | return SplitIterator{0, buffer, split_bytes}; |
| 121 | 121 | } |
| 122 | ||
| 123 | void 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 | 8 | #ifndef ZIG_UTIL_HPP |
| 9 | 9 | #define ZIG_UTIL_HPP |
| 10 | 10 | |
| 11 | #include "memory_profiling.hpp" | |
| 12 | ||
| 11 | 13 | #include <stdlib.h> |
| 12 | 14 | #include <stdint.h> |
| 13 | 15 | #include <string.h> |
| ... | ... | @@ -96,7 +98,10 @@ static inline int ctzll(unsigned long long mask) { |
| 96 | 98 | |
| 97 | 99 | |
| 98 | 100 | template<typename T> |
| 99 | ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count) { | |
| 101 | ATTRIBUTE_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 | 105 | #ifndef NDEBUG |
| 101 | 106 | // make behavior when size == 0 portable |
| 102 | 107 | if (count == 0) |
| ... | ... | @@ -109,7 +114,10 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate_nonzero(size_t count) { |
| 109 | 114 | } |
| 110 | 115 | |
| 111 | 116 | template<typename T> |
| 112 | ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) { | |
| 117 | ATTRIBUTE_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 | 121 | #ifndef NDEBUG |
| 114 | 122 | // make behavior when size == 0 portable |
| 115 | 123 | if (count == 0) |
| ... | ... | @@ -122,7 +130,7 @@ ATTRIBUTE_RETURNS_NOALIAS static inline T *allocate(size_t count) { |
| 122 | 130 | } |
| 123 | 131 | |
| 124 | 132 | template<typename T> |
| 125 | static inline T *reallocate(T *old, size_t old_count, size_t new_count) { | |
| 133 | static inline T *reallocate(T *old, size_t old_count, size_t new_count, const char *name = nullptr) { | |
| 126 | 134 | T *ptr = reallocate_nonzero(old, old_count, new_count); |
| 127 | 135 | if (new_count > old_count) { |
| 128 | 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 | 139 | } |
| 132 | 140 | |
| 133 | 141 | template<typename T> |
| 134 | static inline T *reallocate_nonzero(T *old, size_t old_count, size_t new_count) { | |
| 142 | static 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 | 147 | #ifndef NDEBUG |
| 136 | 148 | // make behavior when size == 0 portable |
| 137 | 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 | 155 | return ptr; |
| 144 | 156 | } |
| 145 | 157 | |
| 158 | template<typename T> | |
| 159 | static 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 | ||
| 166 | template<typename T> | |
| 167 | static inline void destroy(T *old, const char *name = nullptr) { | |
| 168 | return deallocate(old, 1); | |
| 169 | } | |
| 170 | ||
| 146 | 171 | template <typename T, size_t n> |
| 147 | 172 | constexpr size_t array_length(const T (&)[n]) { |
| 148 | 173 | return n; |
| ... | ... | @@ -225,6 +250,8 @@ static inline double zig_f16_to_double(float16_t x) { |
| 225 | 250 | return z; |
| 226 | 251 | } |
| 227 | 252 | |
| 253 | void zig_pretty_print_bytes(FILE *f, double n); | |
| 254 | ||
| 228 | 255 | template<typename T> |
| 229 | 256 | struct Optional { |
| 230 | 257 | T value; |