Commit e0050af293
Changed files (7)
src/all_types.hpp
@@ -1285,6 +1285,11 @@ struct ZigLLVMFnKey {
uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey);
bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b);
+struct TimeEvent {
+ double time;
+ const char *name;
+};
+
struct CodeGen {
LLVMModuleRef module;
ZigList<ErrorMsg*> errors;
@@ -1468,6 +1473,8 @@ struct CodeGen {
Buf *test_filter;
Buf *test_name_prefix;
+
+ ZigList<TimeEvent> timing_events;
};
enum VarLinkage {
src/codegen.cpp
@@ -57,6 +57,9 @@ PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_pa
CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
CodeGen *g = allocate<CodeGen>(1);
+
+ codegen_add_time_event(g, "Initialize");
+
g->import_table.init(32);
g->builtin_fn_table.init(32);
g->primitive_type_table.init(32);
@@ -3654,6 +3657,8 @@ static LLVMValueRef build_alloca(CodeGen *g, TypeTableEntry *type_entry, const c
static void do_code_gen(CodeGen *g) {
assert(!g->errors.length);
+ codegen_add_time_event(g, "Code Generation");
+
delete_unused_builtin_fns(g);
generate_error_name_table(g);
generate_enum_name_tables(g);
@@ -3977,6 +3982,8 @@ static void do_code_gen(CodeGen *g) {
LLVMVerifyModule(g->module, LLVMAbortProcessAction, &error);
#endif
+ codegen_add_time_event(g, "LLVM Emit Object");
+
char *err_msg = nullptr;
Buf *out_file_o = buf_create_from_buf(g->root_out_name);
const char *o_ext = target_o_file_ext(&g->zig_target);
@@ -4730,6 +4737,8 @@ static PackageTableEntry *create_zigrt_pkg(CodeGen *g) {
}
void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *source_code) {
+ codegen_add_time_event(g, "Semantic Analysis");
+
Buf source_path = BUF_INIT;
os_path_join(src_dir, src_basename, &source_path);
@@ -5020,3 +5029,24 @@ void codegen_generate_h_file(CodeGen *g) {
if (fclose(out_h))
zig_panic("unable to close h file: %s", strerror(errno));
}
+
+void codegen_print_timing_report(CodeGen *g, FILE *f) {
+ double start_time = g->timing_events.at(0).time;
+ double end_time = g->timing_events.last().time;
+ double total = end_time - start_time;
+ fprintf(f, "%20s%12s%12s%12s%12s\n", "Name", "Start", "End", "Duration", "Percent");
+ for (size_t i = 0; i < g->timing_events.length - 1; i += 1) {
+ TimeEvent *te = &g->timing_events.at(i);
+ TimeEvent *next_te = &g->timing_events.at(i + 1);
+ fprintf(f, "%20s%12.4f%12.4f%12.4f%12.4f\n", te->name,
+ te->time - start_time,
+ next_te->time - start_time,
+ next_te->time - te->time,
+ (next_te->time - te->time) / total);
+ }
+ fprintf(f, "%20s%12.4f%12.4f%12.4f%12.4f\n", "Total", 0.0, total, total, 1.0);
+}
+
+void codegen_add_time_event(CodeGen *g, const char *name) {
+ g->timing_events.append({os_get_time(), name});
+}
src/codegen.hpp
@@ -47,6 +47,8 @@ void codegen_set_omit_zigrt(CodeGen *g, bool omit_zigrt);
void codegen_set_test_filter(CodeGen *g, Buf *filter);
void codegen_set_test_name_prefix(CodeGen *g, Buf *prefix);
void codegen_set_lib_version(CodeGen *g, size_t major, size_t minor, size_t patch);
+void codegen_add_time_event(CodeGen *g, const char *name);
+void codegen_print_timing_report(CodeGen *g, FILE *f);
PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path);
void codegen_add_root_code(CodeGen *g, Buf *source_dir, Buf *source_basename, Buf *source_code);
src/link.cpp
@@ -732,6 +732,8 @@ static void construct_linker_job(LinkJob *lj) {
}
void codegen_link(CodeGen *g, const char *out_file) {
+ codegen_add_time_event(g, "Build Dependencies");
+
LinkJob lj = {0};
// even though we're calling LLD as a library it thinks the first
@@ -808,10 +810,12 @@ void codegen_link(CodeGen *g, const char *out_file) {
Buf diag = BUF_INIT;
+ codegen_add_time_event(g, "LLVM Link");
if (!ZigLLDLink(g->zig_target.oformat, lj.args.items, lj.args.length, &diag)) {
fprintf(stderr, "%s\n", buf_ptr(&diag));
exit(1);
}
+ codegen_add_time_event(g, "Generate .h");
if (g->out_type == OutTypeLib ||
g->out_type == OutTypeObj)
@@ -819,6 +823,8 @@ void codegen_link(CodeGen *g, const char *out_file) {
codegen_generate_h_file(g);
}
+ codegen_add_time_event(g, "Done");
+
if (g->verbose) {
fprintf(stderr, "OK\n");
}
src/main.cpp
@@ -64,6 +64,7 @@ static int usage(const char *arg0) {
" -mwindows (windows only) --subsystem windows to the linker\n"
" -rdynamic add all symbols to the dynamic symbol table\n"
" -rpath [path] add directory to the runtime library search path\n"
+ " --enable-timing-info print timing diagnostics\n"
"Test Options:\n"
" --test-filter [text] skip tests that do not match filter\n"
" --test-name-prefix [text] add prefix to all tests\n"
@@ -163,6 +164,7 @@ int main(int argc, char **argv) {
size_t ver_major = 0;
size_t ver_minor = 0;
size_t ver_patch = 0;
+ bool timing_info = false;
if (argc >= 2 && strcmp(argv[1], "build") == 0) {
const char *zig_exe_path = arg0;
@@ -292,6 +294,8 @@ int main(int argc, char **argv) {
rdynamic = true;
} else if (strcmp(arg, "--each-lib-rpath") == 0) {
each_lib_rpath = true;
+ } else if (strcmp(arg, "--enable-timing-info") == 0) {
+ timing_info = true;
} else if (arg[1] == 'L' && arg[2] != 0) {
// alias for --library-path
lib_dirs.append(&arg[2]);
@@ -596,20 +600,28 @@ int main(int argc, char **argv) {
if (cmd == CmdBuild) {
codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);
codegen_link(g, out_file);
+ if (timing_info)
+ codegen_print_timing_report(g, stderr);
return EXIT_SUCCESS;
} else if (cmd == CmdLink) {
for (size_t i = 0; i < objects.length; i += 1) {
codegen_add_object(g, buf_create_from_str(objects.at(i)));
}
codegen_link(g, out_file);
+ if (timing_info)
+ codegen_print_timing_report(g, stderr);
return EXIT_SUCCESS;
} else if (cmd == CmdAsm) {
codegen_add_root_assembly(g, &root_source_dir, &root_source_name, &root_source_code);
codegen_link(g, out_file);
+ if (timing_info)
+ codegen_print_timing_report(g, stderr);
return EXIT_SUCCESS;
} else if (cmd == CmdParseH) {
codegen_parseh(g, &root_source_dir, &root_source_name, &root_source_code);
ast_render_decls(g, stdout, 4, g->root_import);
+ if (timing_info)
+ codegen_print_timing_report(g, stderr);
return EXIT_SUCCESS;
} else if (cmd == CmdTest) {
codegen_add_root_code(g, &root_source_dir, &root_source_name, &root_source_code);
@@ -620,6 +632,8 @@ int main(int argc, char **argv) {
if (term.how != TerminationIdClean || term.code != 0) {
fprintf(stderr, "\nTests failed. Use the following command to reproduce the failure:\n");
fprintf(stderr, "./test\n");
+ } else if (timing_info) {
+ codegen_print_timing_report(g, stderr);
}
return (term.how == TerminationIdClean) ? term.code : -1;
} else {
src/os.cpp
@@ -38,6 +38,11 @@
#endif
+#if defined(__MACH__)
+#include <mach/clock.h>
+#include <mach/mach.h>
+#endif
+
#include <stdlib.h>
#include <errno.h>
#include <time.h>
@@ -690,3 +695,27 @@ int os_rename(Buf *src_path, Buf *dest_path) {
}
return 0;
}
+
+double os_get_time(void) {
+#if defined(ZIG_OS_WINDOWS)
+ unsigned __int64 time;
+ QueryPerformanceCounter((LARGE_INTEGER*) &time);
+ return time * win32_time_resolution;
+#elif defined(__MACH__)
+ mach_timespec_t mts;
+
+ kern_return_t err = clock_get_time(cclock, &mts);
+ assert(!err);
+
+ double seconds = (double)mts.tv_sec;
+ seconds += ((double)mts.tv_nsec) / 1000000000.0;
+
+ return seconds;
+#else
+ struct timespec tms;
+ clock_gettime(CLOCK_MONOTONIC, &tms);
+ double seconds = (double)tms.tv_sec;
+ seconds += ((double)tms.tv_nsec) / 1000000000.0;
+ return seconds;
+#endif
+}
src/os.hpp
@@ -56,6 +56,7 @@ int os_delete_file(Buf *path);
int os_file_exists(Buf *full_path, bool *result);
int os_rename(Buf *src_path, Buf *dest_path);
+double os_get_time(void);
#if defined(__APPLE__)
#define ZIG_OS_DARWIN