Skip to content

Instantly share code, notes, and snippets.

@zhiguangwang
Last active March 21, 2019 17:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zhiguangwang/6192e8304ca61d18c72350456edcf736 to your computer and use it in GitHub Desktop.
Save zhiguangwang/6192e8304ca61d18c72350456edcf736 to your computer and use it in GitHub Desktop.
Performance cost of passing std::function as parameter.

Environment

  • Intel i7-4790 @ 3.60GHz
  • Ubuntu 14.04.5 LTS (Windows Subsystem Linux)
  • GCC 6.2.0
  • Clang 3.9.1
  • CXXFLAGS -std=c++14 -O2

Output

GCC

TestConstRef: 644 ms
TestRefRef: 436 ms
TestValue: 436 ms

Clang

TestConstRef: 1134 ms
TestRefRef: 754 ms
TestValue: 751 ms

Conclusion

When passing std::function as parameter, always pass by value and move it.

#include <iostream>
#include <functional>
#include <chrono>
#define BIND_THIS(MemFn) \
[this](auto&&... args) { return (this)->MemFn(std::forward<decltype(args)>(args)...); }
#define BIND_REF(ObjectRef, MemFn) \
[&_r = (ObjectRef)](auto&&... args) { return _r.MemFn(std::forward<decltype(args)>(args)...); }
#define BIND_PTR(ObjectPtr, MemFn) \
[_p = (ObjectPtr)](auto&&... args) { return _p->MemFn(std::forward<decltype(args)>(args)...); }
namespace cr = std::chrono;
using my_clock = cr::high_resolution_clock;
using Callback = std::function<void()>;
static const int kIterateCount = 100'000'000;
class CallbackHolder
{
public:
void SetCallbackValue(Callback cb)
{
cb_ = std::move(cb);
}
void SetCallbackConstRef(const Callback& cb)
{
cb_ = cb;
}
void SetCallbackRefRef(Callback&& cb)
{
cb_ = std::move(cb);
}
void DoCallback()
{
cb_();
}
private:
Callback cb_;
};
class CallbackProvider
{
public:
CallbackProvider()
: value_(0)
{
}
void DoSomething()
{
++value_;
}
int GetValue() const { return value_; }
private:
int value_;
};
void TestConstRef()
{
auto start_time = my_clock::now();
CallbackHolder holder;
CallbackProvider provider;
for (int i = 0; i < kIterateCount; ++i)
{
holder.SetCallbackConstRef(BIND_REF(provider, CallbackProvider::DoSomething));
holder.DoCallback();
}
auto end_time = my_clock::now();
auto diff = end_time - start_time;
auto milliseconds = cr::duration_cast<cr::milliseconds>(diff);
auto millisecond_count = milliseconds.count();
std::cout << "TestConstRef: " << millisecond_count << " ms\n";
}
void TestRefRef()
{
auto start_time = my_clock::now();
CallbackHolder holder;
CallbackProvider provider;
for (int i = 0; i < kIterateCount; ++i)
{
holder.SetCallbackRefRef(BIND_REF(provider, CallbackProvider::DoSomething));
holder.DoCallback();
}
auto end_time = my_clock::now();
auto diff = end_time - start_time;
auto milliseconds = cr::duration_cast<cr::milliseconds>(diff);
auto millisecond_count = milliseconds.count();
std::cout << "TestRefRef: " << millisecond_count << " ms\n";
}
void TestValue()
{
auto start_time = my_clock::now();
CallbackHolder holder;
CallbackProvider provider;
for (int i = 0; i < kIterateCount; ++i)
{
holder.SetCallbackValue(BIND_REF(provider, CallbackProvider::DoSomething));
holder.DoCallback();
}
auto end_time = my_clock::now();
auto diff = end_time - start_time;
auto milliseconds = cr::duration_cast<cr::milliseconds>(diff);
auto millisecond_count = milliseconds.count();
std::cout << "TestValue: " << millisecond_count << " ms\n";
}
int main()
{
TestConstRef();
TestRefRef();
TestValue();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment