add some timing diagnostics

pass --enable-timing-info to print a nice table like this:

```
                Name       Start         End    Duration     Percent
          Initialize      0.0000      0.0000      0.0000      0.0001
   Semantic Analysis      0.0000      0.0421      0.0420      0.2109
     Code Generation      0.0421      0.0620      0.0200      0.1003
    LLVM Emit Object      0.0620      0.1852      0.1231      0.6180
  Build Dependencies      0.1852      0.1974      0.0122      0.0615
           LLVM Link      0.1974      0.1993      0.0018      0.0093
         Generate .h      0.1993      0.1993      0.0000      0.0000
               Total      0.0000      0.1993      0.1993      1.0000
```
master
Andrew Kelley 2017-04-25 12:29:25 -04:00
parent 4cc2ea1421
commit e0050af293
7 changed files with 89 additions and 0 deletions

View File

@ -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 {

View File

@ -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});
}

View File

@ -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);

View File

@ -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");
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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