Merge pull request #7729 from odin-lang/bill/llvm-backend-improvements

LLVM Backend Performance Improvements to Reduce Compile Times Part 2
This commit is contained in:
gingerBill authored and GitHub committed 2026-10-04 19:01:11 +01:00
commit 18aead3ba1
28 files changed
+1266 -941

No files matched your search

+129 -62
View File
@@ -2383,6 +2383,132 @@ gb_internal void show_import_graph(Checker *c) {
gb_printf("}\n\n");
}
gb_internal void add_time_to_tokenize_only(AstFile *f, f64 *time, u64 *cpu_time) {
isize size = f->tokenizer.end - f->tokenizer.start;
if (size <= 0) {
return;
}
Tokenizer t = {};
t.curr_file_id = f->id;
init_tokenizer_with_data(&t, f->fullpath, f->tokenizer.start, size);
u64 start = time_stamp_time_now();
u64 cpu_start = thread_cpu_time_now();
Token token = {};
do {
tokenizer_get_token(&t, &token);
} while (token.kind != Token_EOF && token.kind != Token_Invalid);
*cpu_time += thread_cpu_time_now()-cpu_start;
*time += cast(f64)(time_stamp_time_now()-start)/cast(f64)time_stamp__freq();
}
gb_internal GB_COMPARE_PROC(file_cpu_time_to_parse_cmp) {
AstFile *x = *(AstFile **)a;
AstFile *y = *(AstFile **)b;
if (x->cpu_time_to_parse != y->cpu_time_to_parse) {
return x->cpu_time_to_parse > y->cpu_time_to_parse ? -1 : +1;
}
return string_compare(x->fullpath, y->fullpath);
}
gb_internal void show_parse_timings(Parser *p, Timings *t) {
auto all_files = array_make<AstFile *>(heap_allocator(), 0, p->packages.count*8);
defer (array_free(&all_files));
for (AstPackage *pkg : p->packages) {
for (AstFile *file : pkg->files) {
array_add(&all_files, file);
}
}
f64 cpu_freq = thread_cpu_time_freq();
isize tokens = p->total_token_count;
isize lines = p->total_line_count;
isize total_file_size = 0;
f64 load_time = 0;
f64 load_cpu_time = 0;
f64 parse_time = 0;
f64 parse_cpu_time = 0;
f64 setup_time = 0;
f64 setup_cpu_time = 0;
f64 tokenize_time = 0;
u64 tokenize_cpu_ticks = 0;
for (AstFile *file : all_files) {
total_file_size += file->tokenizer.end - file->tokenizer.start;
load_time += file->time_to_load;
parse_time += file->time_to_parse;
setup_time += file->time_to_setup_decls;
load_cpu_time += cast(f64)file->cpu_time_to_load/cpu_freq;
parse_cpu_time += cast(f64)file->cpu_time_to_parse/cpu_freq;
setup_cpu_time += cast(f64)file->cpu_time_to_setup_decls/cpu_freq;
add_time_to_tokenize_only(file, &tokenize_time, &tokenize_cpu_ticks);
}
f64 tokenize_cpu_time = cast(f64)tokenize_cpu_ticks/cpu_freq;
f64 wall_time = 0;
for (TimeStamp const &s : t->sections) {
if (s.label == "parse files") {
wall_time = time_stamp_as_s(s, t->freq);
break;
}
}
isize thread_count = gb_max(global_thread_pool.threads.count, 1);
f64 task_time = load_time + parse_time + setup_time;
f64 task_cpu_time = load_cpu_time + parse_cpu_time + setup_cpu_time;
f64 mib = cast(f64)total_file_size/(1024.0*1024.0);
auto const &row = [&](char const *label, f64 time, f64 cpu_time, bool rates) {
gb_printf_err(" %s - %9.3f ms %9.3f ms", label, 1.0e3*time, 1.0e3*cpu_time);
if (rates) {
f64 lines_per_second = cast(f64)lines/cpu_time;
char const *loc = " LOC/s";
if (lines_per_second >= 1.0e6) {
lines_per_second /= 1.0e6;
loc = " MLOC/s";
} else if (lines_per_second >= 1.0e3) {
lines_per_second /= 1.0e3;
loc = " kLOC/s";
}
gb_printf_err(" %7.3f us/token %7.3f us/line %8.2f MiB/s %7.2f%s",
1.0e6*cpu_time/cast(f64)tokens, 1.0e6*cpu_time/cast(f64)lines, mib/cpu_time, lines_per_second, loc);
}
gb_printf_err("\n");
};
gb_printf_err("Parsing (%td files, %td lines, %td tokens, %.2f MiB, %td threads)\n", all_files.count, lines, tokens, mib, thread_count);
gb_printf_err(" parse files - %9.3f ms (wall time)\n", 1.0e3*wall_time);
gb_printf_err(" wall time CPU time (rates from the CPU time)\n");
row( "file tasks ", task_time, task_cpu_time, false);
row( " loading files ", load_time, load_cpu_time, false);
row( " tokenizing and parsing ", parse_time, parse_cpu_time, true);
row( " setting up decls and imports ", setup_time, setup_cpu_time, false);
row( "tokenizing alone, 1 thread ", tokenize_time, tokenize_cpu_time, true);
if (build_context.thread_count == 1) {
row( "parsing alone (estimated) ", parse_time-tokenize_time, parse_cpu_time-tokenize_cpu_time, true);
} else {
gb_printf_err(" parsing alone - estimated with -thread-count:1\n");
}
gb_printf_err(" the file tasks kept the threads %.0f%% busy and %.0f%% of their time was spent running\n",
100.0*task_time/(wall_time*cast(f64)thread_count), 100.0*task_cpu_time/task_time);
gb_printf_err("\n");
array_sort(all_files, file_cpu_time_to_parse_cmp);
gb_printf_err("Slowest files to tokenize and parse, by CPU time\n");
for (isize i = 0; i < gb_min(all_files.count, 8); i++) {
AstFile *file = all_files[i];
f64 cpu_time = cast(f64)file->cpu_time_to_parse/cpu_freq;
gb_printf_err(" %9.3f ms %9.3f ms (wall) %8td tokens %7.3f us/token %.*s\n",
1.0e3*cpu_time, 1.0e3*file->time_to_parse, file->token_count,
1.0e6*cpu_time/cast(f64)gb_max(file->token_count, 1), LIT(file->fullpath));
}
gb_printf_err("\n");
}
gb_internal void show_timings(Checker *c, Timings *t) {
Parser *p = c->parser;
isize lines = p->total_line_count;
@@ -2390,13 +2516,9 @@ gb_internal void show_timings(Checker *c, Timings *t) {
isize files = 0;
isize packages = p->packages.count;
isize total_file_size = 0;
f64 total_tokenizing_time = 0;
f64 total_parsing_time = 0;
for (AstPackage *pkg : p->packages) {
files += pkg->files.count;
for (AstFile *file : pkg->files) {
total_tokenizing_time += file->time_to_tokenize;
total_parsing_time += file->time_to_parse;
total_file_size += file->tokenizer.end - file->tokenizer.start;
}
}
@@ -2419,54 +2541,7 @@ gb_internal void show_timings(Checker *c, Timings *t) {
gb_printf_err("Total File Size - %td\n", total_file_size);
gb_printf_err("\n");
}
{
f64 time = total_tokenizing_time;
gb_printf_err("Tokenization Only\n");
gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/time);
gb_printf_err("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/time);
gb_printf_err("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/time);
gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
gb_printf_err("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
gb_printf_err("\n");
}
{
f64 time = total_parsing_time;
gb_printf_err("Parsing Only\n");
gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/time);
gb_printf_err("us/LOC - %.3f\n", 1.0e6*time/cast(f64)lines);
gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/time);
gb_printf_err("us/Token - %.3f\n", 1.0e6*time/cast(f64)tokens);
gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/time);
gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/time)/(1024*1024));
gb_printf_err("us/bytes - %.3f\n", 1.0e6*time/cast(f64)total_file_size);
gb_printf_err("\n");
}
{
TimeStamp ts = {};
for (TimeStamp const &s : t->sections) {
if (s.label == "parse files") {
ts = s;
break;
}
}
GB_ASSERT(ts.label == "parse files");
f64 parse_time = time_stamp_as_s(ts, t->freq);
gb_printf_err("Parse pass\n");
gb_printf_err("LOC/s - %.3f\n", cast(f64)lines/parse_time);
gb_printf_err("us/LOC - %.3f\n", 1.0e6*parse_time/cast(f64)lines);
gb_printf_err("Tokens/s - %.3f\n", cast(f64)tokens/parse_time);
gb_printf_err("us/Token - %.3f\n", 1.0e6*parse_time/cast(f64)tokens);
gb_printf_err("bytes/s - %.3f\n", cast(f64)total_file_size/parse_time);
gb_printf_err("MiB/s - %.3f\n", cast(f64)(total_file_size/parse_time)/(1024*1024));
gb_printf_err("us/bytes - %.3f\n", 1.0e6*parse_time/cast(f64)total_file_size);
gb_printf_err("\n");
}
show_parse_timings(p, t);
{
TimeStamp ts = {};
TimeStamp ts_end = {};
@@ -3634,7 +3709,7 @@ gb_internal gbFileError write_file_with_stripped_tokens(gbFile *f, AstFile *file
u8 const *file_data = file->tokenizer.start;
i32 prev_offset = 0;
i32 const end_offset = cast(i32)(file->tokenizer.end - file->tokenizer.start);
for (Token const &token : file->tokens) {
for (Token const &token : file->token_edits) {
if (token.flags & (TokenFlag_Remove|TokenFlag_Replace)) {
i32 offset = token.pos.offset;
i32 to_write = offset-prev_offset;
@@ -3677,15 +3752,7 @@ gb_internal int strip_semicolons(Parser *parser) {
for (AstPackage *pkg : parser->packages) {
for (AstFile *file : pkg->files) {
bool nothing_to_change = true;
for (Token const &token : file->tokens) {
if (token.flags) {
nothing_to_change = false;
break;
}
}
if (nothing_to_change) {
if (file->token_edits.count == 0) {
continue;
}