-
-
Notifications
You must be signed in to change notification settings - Fork 262
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement -finstrument-functions. #1845
Conversation
@@ -455,6 +455,11 @@ cl::opt<std::string> usefileInstrProf( | |||
cl::ValueRequired); | |||
#endif | |||
|
|||
cl::opt<bool, true> instrumentFunctions( | |||
"finstrument-functions", | |||
cl::desc("Instrument function entry and exit with profiling calls"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe say "GCC-compatible profiling calls" to be clear?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's what GCC says in the --help
, verbatim, and Clang also says Generate calls to instrument function entry and exit
, so I think that there's no need to further clarify the description.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding "GCC" may help, because you;d have to link with a GCC-compatible runtime I guess? (On Windows, it would help folks figure out what's wrong?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed, the stubbed out functions are actually defined in libc.so
and it didn't occur to me that the MSVC libc doesn't have those (doesn't it ?).
LLType *VoidTy = LLType::getVoidTy(gIR->context()); | ||
LLType *Tys[] = {VoidPtrTy, VoidPtrTy}; | ||
auto fty = LLFunctionType::get(VoidTy, Tys, false); | ||
fn = LLFunction::Create(fty, LLGlobalValue::ExternalLinkage, fnName, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are there any LLVM attributes that could allow more optimisations here, or do we need to allow arbitrary hook functions?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can't make any assumption about what's done in the functions, better play it safe.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we usually put the definition of these "runtime" functions in runtime.cpp.
Attributes you may think about are "nocapture" "readonly" or something like that. Runtime.cpp has a bunch of that.
I had trouble finding where these cyg_profile functions are defined, did you find a link to an implementation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these profiling functions ever used in a debugging context? What I mean is: is it OK if the compiler reorders things, e.g.:
void foo() {
__cyg_profile_func_start(...);
smth();
__cyg_profile_func_exit(...);
}
optimized (for whatever reason) to:
void foo() {
__cyg_profile_func_start(...);
__cyg_profile_func_exit(...);
smth();
}
To prevent that, perhaps an attribute is needed on the function declarations (or perhaps the absence of attributes means that LLVM assumes the worst).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't 100% sure about where to put this, I can move it to runtime.cpp
if that's deemed a best place. I'll also have a look at what those attributes are for and which ones are applicable.
WRT the definition of the symbols, LD_DEBUG
shows
binding file ./test [0] to /usr/lib/libc.so.6 [0]: normal symbol
__cyg_profile_func_enter' [GLIBC_2.2.5] so it's
libc` that provides the stubs...we might provide such stubs in the druntime, no ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think in runtime.cpp
is best: for example, you forgot to explicitly set the C-calling convention, and there may be other things that end up forgotten. The createFwdDecl
function was invented for this ;-)
|
||
pragma(LDC_profile_instr, false) | ||
void fun1 () { | ||
// CHECK: ret void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this doesn't check for the absense of __cyg_profile calls
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad, I'm still convinced that lit's smarter than it really is :)
// RUN: %ldc -c -output-ll -finstrument-functions -of=%t.ll %s && FileCheck %s < %t.ll | ||
|
||
void fun0 () { | ||
// CHECK: %1 = call i8* @llvm.returnaddress(i32 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could add some simple code to the function to test that the profiling function calls enclose any "body" code.
Also you could add a function with more than one exit path, and a function with an exception throwing exit path, or a non-trivial destructor call. Again to check where the profiling calls are placed.
Great stuff btw :-) |
43fa944
to
ce07808
Compare
@@ -202,6 +202,7 @@ struct Param | |||
OUTPUTFLAG output_bc; | |||
OUTPUTFLAG output_s; | |||
OUTPUTFLAG output_o; | |||
bool instrumentFunctions; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this must be added to the struct in globals.d too. May fix the CI tester failures.
(it'd be so nice if there was a tool to check types that are declared in both C++ and D!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually: better to not add it to globals.param, and to add it to cl_options.h. (similar to linkonceTemplates
)
int fun1 (int x) { | ||
// CHECK: %x = alloca i32, align 4 | ||
// CHECK-NEXT: store i32 %x_arg, i32* %x | ||
// CHECK-NEXT: ret i32 42 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to check the absence of _cyg_profile_func{enter,exit}, you should just do a // CHECK-NOT: __cyg_profile_func_
.
Because you only want to check that for this one particular function, you should add CHECK-LABEL
checks for each function, such that the file is "sectioned".
if (x < 10) | ||
// CHECK: if: | ||
// CHECK-NEXT: %{{.}} = call i8* @llvm.returnaddress(i32 1) | ||
// CHECK-NEXT: call void @__cyg_profile_func_exit |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about
// CHECK: call void @__cyg_profile_func_exit
// CHECK-NEXT: ret
here, and at the end of the functions?
e0124bf
to
01c10c7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good stuff. Please look at the two comments.
@@ -973,6 +973,9 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) { | |||
// debug info - after all allocas, but before any llvm.dbg.declare etc | |||
gIR->DBuilder.EmitFuncStart(fd); | |||
|
|||
if (opts::instrumentFunctions && fd->emitInstrumentation) | |||
emitInstrumentationFn(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a little nitpicky / subjective, but how about adding two helper functions emitInstrumentationFuncStart(FuncDeclaration *fd)
and emitInstrumentationFuncEnd
in runtime.h?
Note that other emitSomething
functions do the check whether to actually do something inside, instead of outside like you do here.
inline void emitInstrumentationFuncStart(FuncDeclaration *fd) {
if (opts::instrumentFunctions && fd->emitInstrumentation)
emitInstrumentationFn(false);
}
// void __cyg_profile_func_exit(void *callee, void *caller) | ||
createFwdDecl(LINKc, voidTy, | ||
{"__cyg_profile_func_exit", "__cyg_profile_func_enter"}, | ||
{voidPtrTy, voidPtrTy}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as we discussed, please add the nounwind attribute here.
a283b4c
to
b41a3f8
Compare
Closes #1839.