Commit 9ee00d31 authored by Sven Over's avatar Sven Over Committed by Facebook Github Bot

Fast-path destructor

Summary:
Optimise the destruction of default-constructed and moved-out Function objects. Instead of calling a function pointer that is set to a no-op function, use `nullptr` to signal emptyness of that function pointer and check if it is `nullptr` before invoking.
This adds additional branching in a few places: not only in the destructor, but also in the move constructor, as well as in the little used `hasAllocatedMemory`. The effect of getting rid of calls to a no-op function pointer should outweigh that.

Reviewed By: djwatson

Differential Revision: D8694003

fbshipit-source-id: 42972805b2ade255cf1dcc98e54985b1524daa73
parent 73a507a2
...@@ -247,7 +247,7 @@ Function<ReturnType(Args...) const noexcept> constCastFunction( ...@@ -247,7 +247,7 @@ Function<ReturnType(Args...) const noexcept> constCastFunction(
namespace detail { namespace detail {
namespace function { namespace function {
enum class Op { MOVE, NUKE, FULL, HEAP }; enum class Op { MOVE, NUKE, HEAP };
union Data { union Data {
Data() {} Data() {}
...@@ -282,10 +282,6 @@ std::false_type isNullPtrFn(T&&) { ...@@ -282,10 +282,6 @@ std::false_type isNullPtrFn(T&&) {
return {}; return {};
} }
inline bool uninitNoop(Op, Data*, Data*) {
return false;
}
template <typename F, typename... Args> template <typename F, typename... Args>
using CallableResult = decltype(std::declval<F>()(std::declval<Args>()...)); using CallableResult = decltype(std::declval<F>()(std::declval<Args>()...));
...@@ -493,8 +489,6 @@ bool execSmall(Op o, Data* src, Data* dst) { ...@@ -493,8 +489,6 @@ bool execSmall(Op o, Data* src, Data* dst) {
case Op::NUKE: case Op::NUKE:
static_cast<Fun*>(static_cast<void*>(&src->tiny))->~Fun(); static_cast<Fun*>(static_cast<void*>(&src->tiny))->~Fun();
break; break;
case Op::FULL:
return true;
case Op::HEAP: case Op::HEAP:
break; break;
} }
...@@ -511,7 +505,6 @@ bool execBig(Op o, Data* src, Data* dst) { ...@@ -511,7 +505,6 @@ bool execBig(Op o, Data* src, Data* dst) {
case Op::NUKE: case Op::NUKE:
delete static_cast<Fun*>(src->big); delete static_cast<Fun*>(src->big);
break; break;
case Op::FULL:
case Op::HEAP: case Op::HEAP:
break; break;
} }
...@@ -545,7 +538,11 @@ class Function final : private detail::function::FunctionTraits<FunctionType> { ...@@ -545,7 +538,11 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
// is the result of calling `constCastFunction`. // is the result of calling `constCastFunction`.
mutable Data data_{}; mutable Data data_{};
Call call_{&Traits::uninitCall}; Call call_{&Traits::uninitCall};
Exec exec_{&detail::function::uninitNoop}; Exec exec_{nullptr};
bool exec(Op o, Data* src, Data* dst) const {
return exec_ && exec_(o, src, dst);
}
friend Traits; friend Traits;
friend Function<typename Traits::ConstSignature> folly::constCastFunction<>( friend Function<typename Traits::ConstSignature> folly::constCastFunction<>(
...@@ -577,7 +574,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> { ...@@ -577,7 +574,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
Function( Function(
Function<typename Traits::OtherSignature>&& that, Function<typename Traits::OtherSignature>&& that,
CoerceTag) noexcept { CoerceTag) noexcept {
that.exec_(Op::MOVE, &that.data_, &data_); that.exec(Op::MOVE, &that.data_, &data_);
std::swap(call_, that.call_); std::swap(call_, that.call_);
std::swap(exec_, that.exec_); std::swap(exec_, that.exec_);
} }
...@@ -603,7 +600,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> { ...@@ -603,7 +600,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
* Move constructor * Move constructor
*/ */
Function(Function&& that) noexcept { Function(Function&& that) noexcept {
that.exec_(Op::MOVE, &that.data_, &data_); that.exec(Op::MOVE, &that.data_, &data_);
std::swap(call_, that.call_); std::swap(call_, that.call_);
std::swap(exec_, that.exec_); std::swap(exec_, that.exec_);
} }
...@@ -674,7 +671,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> { ...@@ -674,7 +671,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
} }
~Function() { ~Function() {
exec_(Op::NUKE, &data_, nullptr); exec(Op::NUKE, &data_, nullptr);
} }
Function& operator=(const Function&) = delete; Function& operator=(const Function&) = delete;
...@@ -782,7 +779,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> { ...@@ -782,7 +779,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
* non-empty. * non-empty.
*/ */
explicit operator bool() const noexcept { explicit operator bool() const noexcept {
return exec_(Op::FULL, nullptr, nullptr); return exec_ != nullptr;
} }
/** /**
...@@ -792,7 +789,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> { ...@@ -792,7 +789,7 @@ class Function final : private detail::function::FunctionTraits<FunctionType> {
* object itself. * object itself.
*/ */
bool hasAllocatedMemory() const noexcept { bool hasAllocatedMemory() const noexcept {
return exec_(Op::HEAP, nullptr, nullptr); return exec(Op::HEAP, nullptr, nullptr);
} }
using typename Traits::SharedProxy; using typename Traits::SharedProxy;
......
...@@ -417,54 +417,54 @@ int main(int argc, char** argv) { ...@@ -417,54 +417,54 @@ int main(int argc, char** argv) {
============================================================================ ============================================================================
folly/test/function_benchmark/main.cpp relative time/iter iters/s folly/test/function_benchmark/main.cpp relative time/iter iters/s
============================================================================ ============================================================================
fn_invoke 1.02ns 980.05M fn_invoke 1.21ns 825.86M
fn_ptr_invoke 1.22ns 822.98M fn_ptr_invoke 1.24ns 809.24M
std_function_invoke 2.73ns 365.78M std_function_invoke 2.76ns 362.09M
Function_invoke 2.73ns 365.80M Function_invoke 2.75ns 364.02M
mem_fn_invoke 1.37ns 731.32M mem_fn_invoke 1.22ns 821.10M
fn_ptr_invoke_through_inline 1.22ns 822.98M fn_ptr_invoke_through_inline 1.21ns 826.38M
lambda_invoke_fn 1.22ns 822.96M lambda_invoke_fn 1.22ns 821.00M
lambda_noop 0.00fs Infinity lambda_noop 0.00fs Infinity
lambda_local_var 182.45ps 5.48G lambda_local_var 195.77ps 5.11G
fn_ptr_invoke_through_template 911.58ps 1.10G fn_ptr_invoke_through_template 1.22ns 819.76M
virtual_fn_invoke 1.22ns 822.99M virtual_fn_invoke 1.21ns 826.17M
fn_ptr_create_invoke 1.22ns 822.97M fn_ptr_create_invoke 1.21ns 826.90M
std_function_create_invoke 3.92ns 255.32M std_function_create_invoke 3.72ns 268.86M
Function_create_invoke 2.84ns 351.67M Function_create_invoke 2.80ns 357.04M
mem_fn_create_invoke 1.22ns 822.99M mem_fn_create_invoke 1.21ns 826.38M
std_bind_create_invoke 18.92ns 52.85M std_bind_create_invoke 19.03ns 52.55M
std_bind_direct_invoke 1.22ns 822.99M std_bind_direct_invoke 1.21ns 824.20M
scope_guard_std_function 7.36ns 135.87M scope_guard_std_function 7.28ns 137.42M
scope_guard_std_function_rvalue 6.46ns 154.70M scope_guard_std_function_rvalue 6.60ns 151.52M
scope_guard_Function_rvalue 4.94ns 202.59M scope_guard_Function_rvalue 4.93ns 202.65M
scope_guard_fn_ptr 1.22ns 822.97M scope_guard_fn_ptr 1.23ns 815.68M
scope_guard_lambda_noop 0.00fs Infinity scope_guard_lambda_noop 0.00fs Infinity
scope_guard_lambda_function 1.22ns 822.99M scope_guard_lambda_function 1.24ns 807.24M
scope_guard_lambda_local_var 101.27ps 9.87G scope_guard_lambda_local_var 89.99ps 11.11G
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
throw_exception 1.88us 531.42K throw_exception 1.91us 523.99K
catch_no_exception 1.22ns 822.98M catch_no_exception 1.22ns 820.79M
return_exc_ptr 1.39us 717.63K return_exc_ptr 1.40us 713.05K
exc_ptr_param_return 1.40us 712.23K exc_ptr_param_return 1.42us 704.62K
exc_ptr_param_return_null 1.22ns 823.00M exc_ptr_param_return_null 1.21ns 826.90M
return_string 2.43ns 411.48M return_string 2.75ns 364.14M
return_string_noexcept 2.43ns 411.48M return_string_noexcept 2.74ns 365.15M
return_code 961.88ps 1.04G return_code 903.47ps 1.11G
return_code_noexcept 1.22ns 822.99M return_code_noexcept 1.21ns 823.26M
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
std_function_create_move_invoke 47.37ns 21.11M std_function_create_move_invoke 53.45ns 18.71M
Function_create_move_invoke 53.55ns 18.67M Function_create_move_invoke 50.59ns 19.77M
std_function_create_move_invoke_small 6.76ns 147.82M std_function_create_move_invoke_small 6.89ns 145.19M
Function_create_move_invoke_small 7.75ns 129.08M Function_create_move_invoke_small 7.04ns 141.96M
std_function_create_move_invoke_ref 6.67ns 150.02M std_function_create_move_invoke_ref 6.74ns 148.43M
Function_create_move_invoke_ref 7.63ns 131.09M Function_create_move_invoke_ref 6.93ns 144.39M
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
function_ptr_move 1.21ns 823.06M function_ptr_move 1.21ns 825.65M
std_function_move_small 5.77ns 173.20M std_function_move_small 5.82ns 171.96M
Function_move_small 10.17ns 98.31M Function_move_small 8.34ns 119.90M
std_function_move_small_trivial 5.77ns 173.27M std_function_move_small_trivial 5.79ns 172.70M
Function_move_small_trivial 8.78ns 113.85M Function_move_small_trivial 6.68ns 149.72M
std_function_move_large 5.77ns 173.23M std_function_move_large 5.79ns 172.59M
Function_move_large 8.21ns 121.85M Function_move_large 6.00ns 166.78M
============================================================================ ============================================================================
*/ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment