Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

c++11

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?

like image 689
Long Avatar asked Apr 11 '20 05:04

Long


People also ask

How do you check if a function has been inlined?

The most reliable way to see if a function is being inlined or not is to look at the output from the compiler. Most compilers have a switch to output assembler code for your inspection.

Are lambda functions inlined?

Python lambda functions, also known as anonymous functions, are inline functions that do not have a name. They are created with the lambda keyword. This is part of the functional paradigm built-in Python. Python lambda functions are restricted to a single expression.

How are lambda functions compiled?

For Lambda expressions, the compiler doesn't translate them into something which is already understood by JVM. Lambda syntax that is written by the developer is desugared into JVM level instructions generated during compilation, which means the actual responsibility of constructing lambda is deferred to runtime.

Can lambdas be Constexpr?

constexpr lambda expressions in C++ Visual Studio 2017 version 15.3 and later (available in /std:c++17 mode and later): A lambda expression may be declared as constexpr or used in a constant expression when the initialization of each data member that it captures or introduces is allowed within a constant expression.


1 Answers

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.
like image 123
einpoklum Avatar answered Oct 21 '22 05:10

einpoklum