Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I wanted to time a few functions' execution and I've written myself a helper:

using namespace std;
template<int N = 1, class Fun, class... Args>
void timeExec(string name, Fun fun, Args... args) {

    auto start = chrono::steady_clock::now();

    for(int i = 0; i < N; ++i) {
        fun(args...);
    }

    auto end = chrono::steady_clock::now();

    auto diff = end - start;
    cout << name << ": "<< chrono::duration<double, milli>(diff).count() << " ms. << endl;
}

I figured that for timing member functions this way I'd have to use bind or lambda and I wanted to see which would impact the performance less, so I did:

const int TIMES = 10000;
timeExec<TIMES>("Bind evaluation", bind(&decltype(result)::eval, &result));
timeExec<1>("Lambda evaluation", [&]() {
    for(int i = 0; i < TIMES; ++i) {
        result.eval();
    }
});

The results are:

Bind evaluation: 0.355158 ms.
Lambda evaluation: 0.014414 ms.

I don't know the internals, but I assume that lambda cannot be that better than bind. The only plausible explanation I can think of is the compiler optimizing-out subsequent function evaluations in the lambda's loop.

How would you explain it?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
149 views
Welcome To Ask or Share your Answers For Others

1 Answer

I assume that lambda cannot be that better than bind.

That's quite a preconception.

Lambdas are tied into the compiler internals, so extra optimization opportunities may be found. Moreover, they're designed to avoid inefficiency.

However, there are probably no compiler optimization tricks happening here. The likely culprit is the argument to bind, bind(&decltype(result)::eval, &result). You are passing a pointer-to-member-function (PTMF) and an object. Unlike the lambda type, the PTMF does not capture what function actually gets called; it only contains the function signature (parameter and return types). The slow loop is using an indirect branch function call, because the compiler failed to resolve the function pointer through constant propagation.

If you rename the member eval() to operator () () and get rid of bind, then the explicit object will essentially behave like the lambda and the performance difference should disappear.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...