Long
Long

Reputation: 247

Is there a way to check whether C++ lambda functions are inlined by the compiler?

I'm programming with C++ lambdas. For performance reason, I want to make sure that calling to a lambda is inlined by the compiler. For example I have this simplified piece of code:

template <typename T>
auto gen_fn1(T x1, T x2) {
    auto fn1 = [x1, x2]() {
        return x1 + x2;
    };
    return fn1;
}

template <typename T>
auto gen_fn2(T x1, T x2) {
    auto fn2 = [x1, x2]() {
        auto fn1 = gen_fn1(x1, x2);
        return fn1() * fn1();
    };
    return fn2;
}

int test_1() {
    auto fn2 = gen_fn2(1, 2);
    return fn2();
}

I want to make sure there is no extra cost introduced by the lambda generation and invocation in test_1(). I can manually check the assembly code generated by the compile. With '-O2' optimization of clang++8, I can see the desired result: pretty much just a 'return 9' in generated code. So my question is: is there a way to automatically check that I can always get the desired result? In particular, I want to check:

  1. No method invocation for generating the lambdas in 'test_1()', including 'gen_fn2()' and 'gen_fn1()'.
  2. No lambda invocation cost in 'test_1()' or 'gen_fn2()', like 'fn1()' and 'fn2()'. I expect they can be inlined. So how to identify them and check they are inlined?

Question 2 is more interesting to me.   Be able to check it in a programmable way is most appreciated, like 'assert(gen_fn2(1, 2) == ()[]{ return 9; }'. If not possible, check the intermediate file of the compiler is also helpful, or the assembly file. But how?

Upvotes: 7

Views: 931

Answers (3)

Ahmet İbrahim AKSOY
Ahmet İbrahim AKSOY

Reputation: 79

First of all lambda expressions is not actually a function. It's a class. The compiler has written a class for every lambda expression you can see that with using typeid() operator

auto temp = []() {
return true;
};
std::cout << typeid(temp).name() << "\n";

[] -> capture clause, the compiler writes a private data member to class for every capture clause member. () -> parameters, compiler overloading the operator call function for class, and write something like this for this code.

class Temp12343786 {
public:
auto operator()() {
return true;
}
};

and as you can see, this is an inline function for CLASS.

Upvotes: 1

einpoklum
einpoklum

Reputation: 131978

TL;DR: Not without looking at the compilation output.

First, as other answers point out, C++ lambdas are basically anonymous classes with an operator() method; so, your question is no different than "is there a way to check that a certain invocation of an object's method gets inlined?"

Whether your method invocation is inlined or not is a choice of the compiler, and is not mandated by the language specification (although in some cases it's impossible to inline). This fact is therefore not represented in the language itself (nor by compiler extensions of the language).

What you can do is one of two things:

  • Externally examine the compilation output (the easiest way is by compiling without assembling, e.g. gcc -S or clang++ -S, plus whatever optimization flags and other compilation options. Bear in mind, though, that even if inlining has not happened during compilation, it may still theoretically occur at link-time.
  • Internally, try to determine side-effects of the inlining choice. For example, you could have a function which gets the address of a function you want to check; then you read - at run-time - the instructions of that function, to see whether it has any function calls, look up the called addresses in the symbol table, and see whether the symbol name comes from some lambda. This is already rather difficult, error-prone, platform-specific and brittle - and there's the fact that you might have two lambda used in the same function. So I obviously wouldn't recommend doing something like that.

Upvotes: 3

6502
6502

Reputation: 114559

If something has been inlined or not (whatever that means exactly) of course can be detected only by looking at the generated code. For example with g++ you could compile with -S and then grep over what you are looking for in the generated assembly source.

However if you really care about performance the you need to look at performance and not to inlining.

Sometimes inlining is a bad choice because may trash branch prediction or code cache; if you want to know if the code is fast you should not look at the code itself, but measure its speed on real data. As a general rule inlining a big function called in many places is a bad idea, but truth can only be found by actually measuring the speed.

Unfortunately CPUs are today so complex that the execution speed despite being formally deterministic is from a practical point of view more of a black box that must be studied experimentally. Moreover what is faster and what is slower depends on the exact CPU model and the exact machine setup (that it's why for some time critical operations there are OSes that at boot time try different alternatives to measure what is the best approach on the specific computer).

Upvotes: 1

Related Questions