Skip to content

Commit 1178f57

Browse files
NHDalySacha0vchuravy
committed
Add ccalls to enable dumping LLVM_OPT time per method instance.
Adds these functions to toggle the output: - ccall(:jl_dump_emitted_mi_name, Nothing, (Ptr{Nothing},), e_io.handle) - ccall(:jl_dump_llvm_opt, Nothing, (Ptr{Nothing},), l_io.handle) This will then be controlled from SnoopCompileCore, via JuliaDebug/SnoopCompile.jl#135. This logs a CSV file with mappings from C function name to Julia MethodInstance name, and a YAML file with timings statistics about the LLVM module being optimized, including: - Total time to optimize the llvm module - The `optlevel` used for the llvm module - The name of each function in the module, before and after - Number of instructions for each function, before and after - Number of basic blocks for each function, before and after Co-Authored-By: Sacha Verweij <[email protected]> Co-Authored-By: Valentin Churavy <[email protected]>
1 parent 2697800 commit 1178f57

File tree

2 files changed

+78
-0
lines changed

2 files changed

+78
-0
lines changed

src/codegen.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ typedef Instruction TerminatorInst;
9595
#include "processor.h"
9696
#include "julia_assert.h"
9797

98+
JL_STREAM *dump_emitted_mi_name_stream = NULL;
99+
extern "C" JL_DLLEXPORT
100+
void jl_dump_emitted_mi_name(void *s)
101+
{
102+
dump_emitted_mi_name_stream = (JL_STREAM*)s;
103+
}
104+
98105
extern "C" {
99106

100107
#include "builtin_proto.h"
@@ -7149,6 +7156,16 @@ jl_compile_result_t jl_emit_code(
71497156
"functions compiled with custom codegen params must not be cached");
71507157
JL_TRY {
71517158
std::tie(m, decls) = emit_function(li, src, jlrettype, params);
7159+
if (dump_emitted_mi_name_stream != NULL) {
7160+
jl_printf(dump_emitted_mi_name_stream, "%s\t", decls.specFunctionObject.c_str());
7161+
// NOTE: We print the Type Tuple without surrounding quotes, because the quotes
7162+
// break CSV parsing if there are any internal quotes in the Type name (e.g. in
7163+
// Symbol("...")). The \t delineator should be enough to ensure whitespace is
7164+
// handled correctly. (And we don't need to worry about any tabs in the printed
7165+
// string, because tabs are printed as "\t" by `show`.)
7166+
jl_static_show(dump_emitted_mi_name_stream, li->specTypes);
7167+
jl_printf(dump_emitted_mi_name_stream, "\n");
7168+
}
71527169
}
71537170
JL_CATCH {
71547171
// Something failed! This is very, very bad.

src/jitlayers.cpp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ void jl_dump_compiles(void *s)
3838
{
3939
dump_compiles_stream = (JL_STREAM*)s;
4040
}
41+
JL_STREAM *dump_llvm_opt_stream = NULL;
42+
extern "C" JL_DLLEXPORT
43+
void jl_dump_llvm_opt(void *s)
44+
{
45+
dump_llvm_opt_stream = (JL_STREAM*)s;
46+
}
4147

4248
static void jl_add_to_ee(std::unique_ptr<Module> m);
4349
static void jl_add_to_ee(std::unique_ptr<Module> &M, StringMap<std::unique_ptr<Module>*> &NewExports);
@@ -523,7 +529,36 @@ static void addPassesForOptLevel(legacy::PassManager &PM, TargetMachine &TM, raw
523529

524530
CompilerResultT JuliaOJIT::CompilerT::operator()(Module &M)
525531
{
532+
uint64_t start_time = 0;
533+
if (dump_llvm_opt_stream != NULL) {
534+
// Print LLVM function statistics _before_ optimization
535+
// Print all the information about this invocation as a YAML object
536+
jl_printf(dump_llvm_opt_stream, "- \n");
537+
// We print the name and some statistics for each function in the module, both
538+
// before optimization and again afterwards.
539+
jl_printf(dump_llvm_opt_stream, " before: \n");
540+
for (auto &F : M.functions()) {
541+
if (F.isDeclaration() || F.getName().startswith("jfptr_")) {
542+
continue;
543+
}
544+
// Count number of Basic Blocks
545+
int bbs = 0;
546+
for (auto &B : F.getBasicBlockList()) {
547+
std::ignore = B;
548+
++bbs;
549+
}
550+
551+
// Each function is printed as a YAML object with several attributes
552+
jl_printf(dump_llvm_opt_stream, " \"%s\":\n", F.getName().str().c_str());
553+
jl_printf(dump_llvm_opt_stream, " instructions: %u\n", F.getInstructionCount());
554+
jl_printf(dump_llvm_opt_stream, " basicblocks: %u\n", bbs);
555+
}
556+
557+
start_time = jl_hrtime();
558+
}
559+
526560
JL_TIMING(LLVM_OPT);
561+
527562
int optlevel;
528563
if (jl_generating_output()) {
529564
optlevel = 0;
@@ -565,6 +600,32 @@ CompilerResultT JuliaOJIT::CompilerT::operator()(Module &M)
565600
"The module's content was printed above. Please file a bug report");
566601
}
567602

603+
uint64_t end_time = 0;
604+
if (dump_llvm_opt_stream != NULL) {
605+
end_time = jl_hrtime();
606+
jl_printf(dump_llvm_opt_stream, " time_ns: %" PRIu64 "\n", end_time - start_time);
607+
jl_printf(dump_llvm_opt_stream, " optlevel: %d\n", optlevel);
608+
609+
// Print LLVM function statistics _after_ optimization
610+
jl_printf(dump_llvm_opt_stream, " after: \n");
611+
for (auto &F : M.functions()) {
612+
if (F.isDeclaration() || F.getName().startswith("jfptr_")) {
613+
continue;
614+
}
615+
616+
// Count number of Basic Blocks
617+
int bbs = 0;
618+
for (auto &B : F.getBasicBlockList()) {
619+
std::ignore = B;
620+
++bbs;
621+
}
622+
623+
jl_printf(dump_llvm_opt_stream, " \"%s\":\n", F.getName().str().c_str());
624+
jl_printf(dump_llvm_opt_stream, " instructions: %u\n", F.getInstructionCount());
625+
jl_printf(dump_llvm_opt_stream, " basicblocks: %u\n", bbs);
626+
}
627+
}
628+
568629
return CompilerResultT(std::move(ObjBuffer));
569630
}
570631

0 commit comments

Comments
 (0)