Optimizations for latch (#27294)

* Optimizations for latch

* comments
pull/27056/head^2
Craig Tiller 3 years ago committed by GitHub
parent 27eae53d83
commit b51355c691
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 38
      src/core/lib/promise/latch.h

@ -17,6 +17,8 @@
#include <grpc/impl/codegen/port_platform.h> #include <grpc/impl/codegen/port_platform.h>
#include <grpc/support/log.h>
#include "src/core/lib/promise/activity.h" #include "src/core/lib/promise/activity.h"
#include "src/core/lib/promise/intra_activity_waiter.h" #include "src/core/lib/promise/intra_activity_waiter.h"
#include "src/core/lib/promise/poll.h" #include "src/core/lib/promise/poll.h"
@ -34,8 +36,8 @@ class Latch {
class WaitPromise { class WaitPromise {
public: public:
Poll<T*> operator()() const { Poll<T*> operator()() const {
if (latch_->value_.has_value()) { if (latch_->has_value_) {
return &*latch_->value_; return &latch_->value_;
} else { } else {
return latch_->waiter_.pending(); return latch_->waiter_.pending();
} }
@ -50,34 +52,50 @@ class Latch {
Latch() = default; Latch() = default;
Latch(const Latch&) = delete; Latch(const Latch&) = delete;
Latch& operator=(const Latch&) = delete; Latch& operator=(const Latch&) = delete;
Latch(Latch&& other) noexcept : value_(std::move(other.value_)) { Latch(Latch&& other) noexcept
assert(!other.has_had_waiters_); : value_(std::move(other.value_)), has_value_(other.has_value_) {
#ifndef NDEBUG
GPR_DEBUG_ASSERT(!other.has_had_waiters_);
#endif
} }
Latch& operator=(Latch&& other) noexcept { Latch& operator=(Latch&& other) noexcept {
assert(!other.has_had_waiters_); #ifndef NDEBUG
GPR_DEBUG_ASSERT(!other.has_had_waiters_);
#endif
value_ = std::move(other.value_); value_ = std::move(other.value_);
has_value_ = other.has_value_;
return *this; return *this;
} }
// Produce a promise to wait for a value from this latch. // Produce a promise to wait for a value from this latch.
WaitPromise Wait() { WaitPromise Wait() {
#ifndef NDEBUG
has_had_waiters_ = true; has_had_waiters_ = true;
#endif
return WaitPromise(this); return WaitPromise(this);
} }
// Set the value of the latch. Can only be called once. // Set the value of the latch. Can only be called once.
void Set(T value) { void Set(T value) {
assert(!value_.has_value()); GPR_DEBUG_ASSERT(!has_value_);
value_ = std::move(value); value_ = std::move(value);
has_value_ = true;
waiter_.Wake(); waiter_.Wake();
} }
private: private:
// TODO(ctiller): consider ditching optional here and open coding the bool // The value stored (if has_value_ is true), otherwise some random value, we
// and optionally constructed value - because in doing so we likely save a // don't care.
// few bytes per latch, and it's likely we'll have many of these. // Why not absl::optional<>? Writing things this way lets us compress
absl::optional<T> value_; // has_value_ with waiter_ and leads to some significant memory savings for
// some scenarios.
GPR_NO_UNIQUE_ADDRESS T value_;
// True if we have a value set, false otherwise.
bool has_value_ = false;
#ifndef NDEBUG
// Has this latch ever had waiters.
bool has_had_waiters_ = false; bool has_had_waiters_ = false;
#endif
IntraActivityWaiter waiter_; IntraActivityWaiter waiter_;
}; };

Loading…
Cancel
Save