Skip to content
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

Merged
merged 1 commit into from
Nov 7, 2016
Merged

Conversation

LemonBoy
Copy link
Contributor

Closes #1839.

@@ -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"),
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Member

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?)

Copy link
Contributor Author

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,
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Member

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?

Copy link
Member

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).

Copy link
Contributor Author

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'slibc` that provides the stubs...we might provide such stubs in the druntime, no ?

Copy link
Member

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
Copy link
Member

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

Copy link
Contributor Author

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)
Copy link
Member

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.

@JohanEngelen
Copy link
Member

Great stuff btw :-)

@LemonBoy LemonBoy force-pushed the instr branch 2 times, most recently from 43fa944 to ce07808 Compare October 20, 2016 13:48
@@ -202,6 +202,7 @@ struct Param
OUTPUTFLAG output_bc;
OUTPUTFLAG output_s;
OUTPUTFLAG output_o;
bool instrumentFunctions;
Copy link
Member

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!)

Copy link
Member

@JohanEngelen JohanEngelen Oct 20, 2016

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
Copy link
Member

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
Copy link
Member

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?

@LemonBoy LemonBoy force-pushed the instr branch 3 times, most recently from e0124bf to 01c10c7 Compare October 20, 2016 21:22
Copy link
Member

@JohanEngelen JohanEngelen left a 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);
Copy link
Member

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});
Copy link
Member

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.

@LemonBoy LemonBoy force-pushed the instr branch 2 times, most recently from a283b4c to b41a3f8 Compare November 3, 2016 22:32
@kinke kinke mentioned this pull request Nov 7, 2016
@kinke kinke merged commit e154826 into ldc-developers:master Nov 7, 2016
@JohanEngelen
Copy link
Member

#1961

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants