Commit d9df4bf9 authored by Marshall Cline's avatar Marshall Cline Committed by Facebook Github Bot

improve perf of Core::hasResult()

Summary:
Core::hasResult() is called in lots of places:

- future.result()
- future.get()
- future.wait()
- future.within()
- future.hasValue()
- future.hasException()
- future.getTry()
- future.raise()
- future.poll()
- promise.setInterruptHandler()
- etc.

This diff improves that function as follows (source: godbolt, with optimization, on both gcc and clang):

- old: 7 instructions w/ 2 conditional jumps + 1 unconditional jump; fastest path is 4 instructions w/ 2 jumps, slowest is 7 instructions w/ 2 jumps
- new: 3 instructions w/ 0 jumps

Small improvement overall, but to a widely used function.

Reviewed By: yfeldblum

Differential Revision: D8231048

fbshipit-source-id: 83a9f5c602475c2ca7066a45635d807596ecf37d
parent ef22cc7e
...@@ -41,11 +41,23 @@ namespace detail { ...@@ -41,11 +41,23 @@ namespace detail {
/// See `Core` for details /// See `Core` for details
enum class State : uint8_t { enum class State : uint8_t {
Start, Start = 1 << 0,
OnlyResult, OnlyResult = 1 << 1,
OnlyCallback, OnlyCallback = 1 << 2,
Done, Done = 1 << 3,
}; };
constexpr State operator&(State a, State b) {
return State(uint8_t(a) & uint8_t(b));
}
constexpr State operator|(State a, State b) {
return State(uint8_t(a) | uint8_t(b));
}
constexpr State operator^(State a, State b) {
return State(uint8_t(a) ^ uint8_t(b));
}
constexpr State operator~(State a) {
return State(~uint8_t(a));
}
/// SpinLock is and must stay a 1-byte object because of how Core is laid out. /// SpinLock is and must stay a 1-byte object because of how Core is laid out.
struct SpinLock : private MicroSpinLock { struct SpinLock : private MicroSpinLock {
...@@ -203,15 +215,10 @@ class Core final { ...@@ -203,15 +215,10 @@ class Core final {
/// ///
/// Identical to `this->ready()` /// Identical to `this->ready()`
bool hasResult() const noexcept { bool hasResult() const noexcept {
switch (fsm_.getState()) { constexpr auto allowed = State::OnlyResult | State::Done;
case State::OnlyResult: auto const ans = State() != (fsm_.getState() & allowed);
case State::Done: assert(!ans || !!result_); // result_ must exist if hasResult() is true
assert(!!result_); return ans;
return true;
default:
return false;
}
} }
/// May call from any thread /// May call from any thread
......
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