Commit dce6e23d authored by James Sedgwick's avatar James Sedgwick Committed by Sara Golemon

optimize makeFuture and Future<T>::Future()

Summary: No reason to go through the whole Promise rigamarole. Add an appropriate Core ctor and use that to make a completed Future with just the core alloc

Note the big win in the `constantFuture` benchmark.

```
Before:
============================================================================
folly/futures/test/Benchmark.cpp                relative  time/iter  iters/s
============================================================================
constantFuture                                             120.50ns    8.30M
promiseAndFuture                                  91.99%   130.98ns    7.63M
withThen                                          28.17%   427.77ns    2.34M
----------------------------------------------------------------------------
oneThen                                                    430.48ns    2.32M
twoThens                                          58.03%   741.86ns    1.35M
fourThens                                         31.85%     1.35us  739.97K
hundredThens                                       1.61%    26.80us   37.32K
----------------------------------------------------------------------------
no_contention                                                4.58ms   218.48
contention                                        83.70%     5.47ms   182.86
----------------------------------------------------------------------------
throwAndCatch                                                8.09us  123.55K
throwAndCatchWrapped                              94.43%     8.57us  116.67K
throwWrappedAndCatch                             154.69%     5.23us  191.12K
throwWrappedAndCatchWrapped                      614.06%     1.32us  758.70K
----------------------------------------------------------------------------
throwAndCatchContended                                     967.54ms     1.03
throwAndCatchWrappedContended                    103.48%   935.04ms     1.07
throwWrappedAndCatchContended                    148.24%   652.70ms     1.53
throwWrappedAndCatchWrappedContended            14313.28%     6.76ms   147.94
============================================================================

After:
============================================================================
folly/futures/test/Benchmark.cpp                relative  time/iter  iters/s
============================================================================
constantFuture                                              69.11ns   14.47M
promiseAndFuture                                  55.12%   125.37ns    7.98M
withThen                                          16.49%   419.18ns    2.39M
----------------------------------------------------------------------------
oneThen                                                    370.39ns    2.70M
twoThens                                          55.11%   672.05ns    1.49M
fourThens                                         29.00%     1.28us  782.89K
hundredThens                                       1.23%    30.22us   33.09K
----------------------------------------------------------------------------
no_contention                                                4.56ms   219.46
contention                                        82.82%     5.50ms   181.77
----------------------------------------------------------------------------
throwAndCatch                                                8.30us  120.42K
throwAndCatchWrapped                              96.40%     8.61us  116.08K
throwWrappedAndCatch                             162.66%     5.11us  195.89K
throwWrappedAndCatchWrapped                      680.39%     1.22us  819.36K
----------------------------------------------------------------------------
throwAndCatchContended                                     979.17ms     1.02
throwAndCatchWrappedContended                    103.09%   949.84ms     1.05
throwWrappedAndCatchContended                    153.55%   637.71ms     1.57
throwWrappedAndCatchWrappedContended            10468.47%     9.35ms   106.91
============================================================================
```

Reviewed By: @fugalh, @​hannesr

Differential Revision: D2144664
parent 86b19dbf
...@@ -45,22 +45,16 @@ Future<T>& Future<T>::operator=(Future<T>&& other) noexcept { ...@@ -45,22 +45,16 @@ Future<T>& Future<T>::operator=(Future<T>&& other) noexcept {
template <class T> template <class T>
template <class T2, typename> template <class T2, typename>
Future<T>::Future(T2&& val) : core_(nullptr) { Future<T>::Future(T2&& val)
Promise<T> p; : core_(new detail::Core<T>(Try<T>(std::forward<T2>(val)))) {}
p.setValue(std::forward<T2>(val));
*this = p.getFuture();
}
template <class T> template <class T>
template <class T2, template <class T2,
typename std::enable_if< typename std::enable_if<
folly::is_void_or_unit<T2>::value, folly::is_void_or_unit<T2>::value,
int>::type> int>::type>
Future<T>::Future() : core_(nullptr) { Future<T>::Future()
Promise<T> p; : core_(new detail::Core<T>(Try<T>())) {}
p.setValue();
*this = p.getFuture();
}
template <class T> template <class T>
...@@ -456,16 +450,12 @@ void Future<T>::raise(exception_wrapper exception) { ...@@ -456,16 +450,12 @@ void Future<T>::raise(exception_wrapper exception) {
template <class T> template <class T>
Future<typename std::decay<T>::type> makeFuture(T&& t) { Future<typename std::decay<T>::type> makeFuture(T&& t) {
Promise<typename std::decay<T>::type> p; return makeFuture(Try<typename std::decay<T>::type>(std::forward<T>(t)));
p.setValue(std::forward<T>(t));
return p.getFuture();
} }
inline // for multiple translation units inline // for multiple translation units
Future<void> makeFuture() { Future<void> makeFuture() {
Promise<void> p; return makeFuture(Try<void>());
p.setValue();
return p.getFuture();
} }
template <class F> template <class F>
...@@ -473,57 +463,37 @@ auto makeFutureWith( ...@@ -473,57 +463,37 @@ auto makeFutureWith(
F&& func, F&& func,
typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf) typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
-> Future<decltype(func())> { -> Future<decltype(func())> {
Promise<decltype(func())> p; return makeFuture(makeTryWith([&func]() {
p.setWith(
[&func]() {
return (func)(); return (func)();
}); }));
return p.getFuture();
} }
template <class F> template <class F>
auto makeFutureWith(F const& func) -> Future<decltype(func())> { auto makeFutureWith(F const& func) -> Future<decltype(func())> {
F copy = func; F copy = func;
return makeFutureWith(std::move(copy)); return makeFuture(makeTryWith(std::move(copy)));
} }
template <class T> template <class T>
Future<T> makeFuture(std::exception_ptr const& e) { Future<T> makeFuture(std::exception_ptr const& e) {
Promise<T> p; return makeFuture(Try<T>(e));
p.setException(e);
return p.getFuture();
} }
template <class T> template <class T>
Future<T> makeFuture(exception_wrapper ew) { Future<T> makeFuture(exception_wrapper ew) {
Promise<T> p; return makeFuture(Try<T>(std::move(ew)));
p.setException(std::move(ew));
return p.getFuture();
} }
template <class T, class E> template <class T, class E>
typename std::enable_if<std::is_base_of<std::exception, E>::value, typename std::enable_if<std::is_base_of<std::exception, E>::value,
Future<T>>::type Future<T>>::type
makeFuture(E const& e) { makeFuture(E const& e) {
Promise<T> p; return makeFuture(Try<T>(make_exception_wrapper<E>(e)));
p.setException(make_exception_wrapper<E>(e));
return p.getFuture();
} }
template <class T> template <class T>
Future<T> makeFuture(Try<T>&& t) { Future<T> makeFuture(Try<T>&& t) {
Promise<typename std::decay<T>::type> p; return Future<T>(new detail::Core<T>(std::move(t)));
p.setTry(std::move(t));
return p.getFuture();
}
template <>
inline Future<void> makeFuture(Try<void>&& t) {
if (t.hasException()) {
return makeFuture<void>(std::move(t.exception()));
} else {
return makeFuture();
}
} }
// via // via
......
...@@ -432,6 +432,9 @@ class Future { ...@@ -432,6 +432,9 @@ class Future {
friend class Promise<T>; friend class Promise<T>;
template <class> friend class Future; template <class> friend class Future;
template <class T2>
friend Future<T2> makeFuture(Try<T2>&&);
// Variant: returns a value // Variant: returns a value
// e.g. f.then([](Try<T> t){ return t.value(); }); // e.g. f.then([](Try<T> t){ return t.value(); });
template <typename F, typename R, bool isTry, typename... Args> template <typename F, typename R, bool isTry, typename... Args>
......
...@@ -79,6 +79,12 @@ class Core { ...@@ -79,6 +79,12 @@ class Core {
/// code but since this is just internal detail code and I don't know how /// code but since this is just internal detail code and I don't know how
/// off-hand, I'm punting. /// off-hand, I'm punting.
Core() {} Core() {}
explicit Core(Try<T>&& t)
: fsm_(State::OnlyResult),
attached_(1),
result_(std::move(t)) {}
~Core() { ~Core() {
assert(attached_ == 0); assert(attached_ == 0);
} }
......
...@@ -46,7 +46,6 @@ BENCHMARK(constantFuture) { ...@@ -46,7 +46,6 @@ BENCHMARK(constantFuture) {
makeFuture(42); makeFuture(42);
} }
// This shouldn't get too far below 100%
BENCHMARK_RELATIVE(promiseAndFuture) { BENCHMARK_RELATIVE(promiseAndFuture) {
Promise<int> p; Promise<int> p;
Future<int> f = p.getFuture(); Future<int> f = p.getFuture();
...@@ -54,7 +53,6 @@ BENCHMARK_RELATIVE(promiseAndFuture) { ...@@ -54,7 +53,6 @@ BENCHMARK_RELATIVE(promiseAndFuture) {
f.value(); f.value();
} }
// The higher the better. At the time of writing, it's only about 40% :(
BENCHMARK_RELATIVE(withThen) { BENCHMARK_RELATIVE(withThen) {
Promise<int> p; Promise<int> p;
Future<int> f = p.getFuture().then(incr<int>); Future<int> f = p.getFuture().then(incr<int>);
......
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