Commit 3d5e5974 authored by Stepan Palamarchuk's avatar Stepan Palamarchuk Committed by Facebook GitHub Bot

Introduce EventBase::Options

Summary:
This API allows for an easier way to configure EventBase without a need to introduce yet another constructor with variable amount of arguments.

In particular, we have an ad-hoc constructor for overriding just the wheel timer interval, but it's not possible to override it in other constructors.

Reviewed By: yfeldblum

Differential Revision: D23511659

fbshipit-source-id: 2f8de3a527ee07dbf2dc19f2e369014793d906c1
parent 8f60f633
...@@ -85,7 +85,11 @@ class EventFD : public EventHandler { ...@@ -85,7 +85,11 @@ class EventFD : public EventHandler {
class BackendEventBase : public EventBase { class BackendEventBase : public EventBase {
public: public:
explicit BackendEventBase(bool useRegisteredFds, size_t capacity = 32 * 1024) explicit BackendEventBase(bool useRegisteredFds, size_t capacity = 32 * 1024)
: EventBase(getBackend(useRegisteredFds, capacity), false) {} : EventBase(EventBase::Options()
.setBackendFactory([useRegisteredFds, capacity] {
return getBackend(useRegisteredFds, capacity);
})
.setSkipTimeMeasurement(true)) {}
private: private:
static std::unique_ptr<folly::EventBaseBackendBase> getBackend( static std::unique_ptr<folly::EventBaseBackendBase> getBackend(
......
...@@ -142,41 +142,23 @@ class EventBase::FunctionRunner ...@@ -142,41 +142,23 @@ class EventBase::FunctionRunner
* EventBase methods * EventBase methods
*/ */
EventBase::EventBase(bool enableTimeMeasurement) EventBase::EventBase(std::chrono::milliseconds tickInterval)
: runOnceCallbacks_(nullptr), : EventBase(Options().setTimerTickInterval(tickInterval)) {}
stop_(false),
loopThread_(),
queue_(nullptr),
fnRunner_(nullptr),
maxLatency_(0),
avgLoopTime_(std::chrono::seconds(2)),
maxLatencyLoopTime_(avgLoopTime_),
enableTimeMeasurement_(enableTimeMeasurement),
nextLoopCnt_(
std::size_t(-40)) // Early wrap-around so bugs will manifest soon
,
latestLoopCnt_(nextLoopCnt_),
startWork_(),
observer_(nullptr),
observerSampleCount_(0),
executionObserver_(nullptr) {
evb_ = getDefaultBackend();
VLOG(5) << "EventBase(): Created."; EventBase::EventBase(bool enableTimeMeasurement)
initNotificationQueue(); : EventBase(Options().setSkipTimeMeasurement(!enableTimeMeasurement)) {}
}
// takes ownership of the event_base // takes ownership of the event_base
EventBase::EventBase(event_base* evb, bool enableTimeMeasurement) EventBase::EventBase(event_base* evb, bool enableTimeMeasurement)
: EventBase( : EventBase(Options()
std::make_unique<EventBaseBackend>(evb), .setBackendFactory([evb] {
enableTimeMeasurement) {} return std::make_unique<EventBaseBackend>(evb);
})
// takes ownership of the backend .setSkipTimeMeasurement(!enableTimeMeasurement)) {}
EventBase::EventBase(
std::unique_ptr<EventBaseBackendBase>&& evb, EventBase::EventBase(Options options)
bool enableTimeMeasurement) : intervalDuration_(options.timerTickInterval),
: runOnceCallbacks_(nullptr), runOnceCallbacks_(nullptr),
stop_(false), stop_(false),
loopThread_(), loopThread_(),
queue_(nullptr), queue_(nullptr),
...@@ -184,7 +166,7 @@ EventBase::EventBase( ...@@ -184,7 +166,7 @@ EventBase::EventBase(
maxLatency_(0), maxLatency_(0),
avgLoopTime_(std::chrono::seconds(2)), avgLoopTime_(std::chrono::seconds(2)),
maxLatencyLoopTime_(avgLoopTime_), maxLatencyLoopTime_(avgLoopTime_),
enableTimeMeasurement_(enableTimeMeasurement), enableTimeMeasurement_(!options.skipTimeMeasurement),
nextLoopCnt_( nextLoopCnt_(
std::size_t(-40)) // Early wrap-around so bugs will manifest soon std::size_t(-40)) // Early wrap-around so bugs will manifest soon
, ,
...@@ -193,7 +175,8 @@ EventBase::EventBase( ...@@ -193,7 +175,8 @@ EventBase::EventBase(
observer_(nullptr), observer_(nullptr),
observerSampleCount_(0), observerSampleCount_(0),
executionObserver_(nullptr) { executionObserver_(nullptr) {
evb_ = evb ? std::move(evb) : getDefaultBackend(); evb_ =
options.backendFactory ? options.backendFactory() : getDefaultBackend();
initNotificationQueue(); initNotificationQueue();
} }
......
...@@ -282,6 +282,47 @@ class EventBase : public TimeoutManager, ...@@ -282,6 +282,47 @@ class EventBase : public TimeoutManager,
Function<void()> f_; Function<void()> f_;
}; };
struct Options {
Options() {}
/**
* Skip measuring event base loop durations.
*
* Disabling it would likely improve performance, but will disable some
* features that rely on time-measurement, including: observer, max latency
* and avg loop time.
*/
bool skipTimeMeasurement{false};
Options& setSkipTimeMeasurement(bool skip) {
skipTimeMeasurement = skip;
return *this;
}
/**
* Factory function for creating the backend.
*/
using BackendFactory =
folly::Function<std::unique_ptr<folly::EventBaseBackendBase>()>;
BackendFactory::SharedProxy backendFactory{nullptr};
Options& setBackendFactory(BackendFactory factoryFn) {
backendFactory = std::move(factoryFn).asSharedProxy();
return *this;
}
/**
* Granularity of the wheel timer in the EventBase.
*/
std::chrono::milliseconds timerTickInterval{
HHWheelTimer::DEFAULT_TICK_INTERVAL};
Options& setTimerTickInterval(std::chrono::milliseconds interval) {
timerTickInterval = interval;
return *this;
}
};
/** /**
* Create a new EventBase object. * Create a new EventBase object.
* *
...@@ -289,9 +330,7 @@ class EventBase : public TimeoutManager, ...@@ -289,9 +330,7 @@ class EventBase : public TimeoutManager,
* except that this also allows the timer granularity to be specified * except that this also allows the timer granularity to be specified
*/ */
explicit EventBase(std::chrono::milliseconds tickInterval) : EventBase(true) { explicit EventBase(std::chrono::milliseconds tickInterval);
intervalDuration_ = tickInterval;
}
/** /**
* Create a new EventBase object. * Create a new EventBase object.
...@@ -328,9 +367,8 @@ class EventBase : public TimeoutManager, ...@@ -328,9 +367,8 @@ class EventBase : public TimeoutManager,
* observer, max latency and avg loop time. * observer, max latency and avg loop time.
*/ */
explicit EventBase(event_base* evb, bool enableTimeMeasurement = true); explicit EventBase(event_base* evb, bool enableTimeMeasurement = true);
explicit EventBase(
std::unique_ptr<EventBaseBackendBase>&& evb, explicit EventBase(Options options);
bool enableTimeMeasurement = true);
~EventBase() override; ~EventBase() override;
/** /**
......
...@@ -66,7 +66,9 @@ EventBase* EventBaseManager::getEventBase() const { ...@@ -66,7 +66,9 @@ EventBase* EventBaseManager::getEventBase() const {
// have one? // have one?
auto* info = localStore_.get(); auto* info = localStore_.get();
if (!info) { if (!info) {
info = func_ ? new EventBaseInfo(func_()) : new EventBaseInfo(); auto evb = std::make_unique<EventBase>(
EventBase::Options().setBackendFactory(func_));
info = new EventBaseInfo(evb.release(), true);
localStore_.reset(info); localStore_.reset(info);
if (observer_) { if (observer_) {
......
...@@ -114,8 +114,6 @@ class EventBaseManager { ...@@ -114,8 +114,6 @@ class EventBaseManager {
private: private:
struct EventBaseInfo { struct EventBaseInfo {
EventBaseInfo(EventBase* evb, bool owned) : eventBase(evb), owned_(owned) {} EventBaseInfo(EventBase* evb, bool owned) : eventBase(evb), owned_(owned) {}
explicit EventBaseInfo(std::unique_ptr<EventBaseBackendBase>&& evb)
: eventBase(new EventBase(std::move(evb))), owned_(true) {}
EventBaseInfo() : eventBase(new EventBase), owned_(true) {} EventBaseInfo() : eventBase(new EventBase), owned_(true) {}
EventBase* eventBase; EventBase* eventBase;
......
...@@ -27,18 +27,14 @@ EventBaseThread::EventBaseThread( ...@@ -27,18 +27,14 @@ EventBaseThread::EventBaseThread(
bool autostart, bool autostart,
EventBaseManager* ebm, EventBaseManager* ebm,
folly::StringPiece threadName) folly::StringPiece threadName)
: ebm_(ebm) { : EventBaseThread(autostart, EventBase::Options(), ebm, threadName) {}
if (autostart) {
start(threadName);
}
}
EventBaseThread::EventBaseThread( EventBaseThread::EventBaseThread(
bool autostart, bool autostart,
std::unique_ptr<EventBaseBackendBase>&& evb, EventBase::Options eventBaseOptions,
EventBaseManager* ebm, EventBaseManager* ebm,
folly::StringPiece threadName) folly::StringPiece threadName)
: ebm_(ebm), evb_(std::move(evb)) { : ebm_(ebm), ebOpts_(std::move(eventBaseOptions)) {
if (autostart) { if (autostart) {
start(threadName); start(threadName);
} }
...@@ -65,8 +61,7 @@ void EventBaseThread::start(folly::StringPiece threadName) { ...@@ -65,8 +61,7 @@ void EventBaseThread::start(folly::StringPiece threadName) {
if (th_) { if (th_) {
return; return;
} }
th_ = std::make_unique<ScopedEventBaseThread>( th_ = std::make_unique<ScopedEventBaseThread>(ebOpts_, ebm_, threadName);
std::move(evb_), ebm_, threadName);
} }
void EventBaseThread::stop() { void EventBaseThread::stop() {
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#pragma once #pragma once
#include <folly/Range.h> #include <folly/Range.h>
#include <folly/io/async/EventBase.h>
#include <memory> #include <memory>
namespace folly { namespace folly {
...@@ -35,7 +36,7 @@ class EventBaseThread { ...@@ -35,7 +36,7 @@ class EventBaseThread {
folly::StringPiece threadName = folly::StringPiece()); folly::StringPiece threadName = folly::StringPiece());
EventBaseThread( EventBaseThread(
bool autostart, bool autostart,
std::unique_ptr<EventBaseBackendBase>&& evb, EventBase::Options eventBaseOptions,
EventBaseManager* ebm = nullptr, EventBaseManager* ebm = nullptr,
folly::StringPiece threadName = folly::StringPiece()); folly::StringPiece threadName = folly::StringPiece());
explicit EventBaseThread(EventBaseManager* ebm); explicit EventBaseThread(EventBaseManager* ebm);
...@@ -54,7 +55,7 @@ class EventBaseThread { ...@@ -54,7 +55,7 @@ class EventBaseThread {
private: private:
EventBaseManager* ebm_; EventBaseManager* ebm_;
std::unique_ptr<EventBaseBackendBase> evb_; EventBase::Options ebOpts_;
std::unique_ptr<ScopedEventBaseThread> th_; std::unique_ptr<ScopedEventBaseThread> th_;
}; };
} // namespace folly } // namespace folly
...@@ -58,17 +58,14 @@ ScopedEventBaseThread::ScopedEventBaseThread(EventBaseManager* ebm) ...@@ -58,17 +58,14 @@ ScopedEventBaseThread::ScopedEventBaseThread(EventBaseManager* ebm)
ScopedEventBaseThread::ScopedEventBaseThread( ScopedEventBaseThread::ScopedEventBaseThread(
EventBaseManager* ebm, EventBaseManager* ebm,
StringPiece name) StringPiece name)
: ScopedEventBaseThread( : ScopedEventBaseThread(EventBase::Options(), ebm, name) {}
std::unique_ptr<EventBaseBackendBase>(),
ebm,
name) {}
ScopedEventBaseThread::ScopedEventBaseThread( ScopedEventBaseThread::ScopedEventBaseThread(
std::unique_ptr<EventBaseBackendBase>&& backend, EventBase::Options eventBaseOptions,
EventBaseManager* ebm, EventBaseManager* ebm,
StringPiece name) StringPiece name)
: ebm_(ebm ? ebm : EventBaseManager::get()) { : ebm_(ebm ? ebm : EventBaseManager::get()) {
new (&eb_) EventBase(std::move(backend)); new (&eb_) EventBase(std::move(eventBaseOptions));
th_ = thread(run, ebm_, &eb_, &stop_, name); th_ = thread(run, ebm_, &eb_, &stop_, name);
eb_.waitUntilRunning(); eb_.waitUntilRunning();
} }
......
...@@ -42,8 +42,8 @@ class ScopedEventBaseThread : public IOExecutor, public SequencedExecutor { ...@@ -42,8 +42,8 @@ class ScopedEventBaseThread : public IOExecutor, public SequencedExecutor {
explicit ScopedEventBaseThread(StringPiece name); explicit ScopedEventBaseThread(StringPiece name);
explicit ScopedEventBaseThread(EventBaseManager* ebm); explicit ScopedEventBaseThread(EventBaseManager* ebm);
explicit ScopedEventBaseThread(EventBaseManager* ebm, StringPiece name); explicit ScopedEventBaseThread(EventBaseManager* ebm, StringPiece name);
explicit ScopedEventBaseThread( ScopedEventBaseThread(
std::unique_ptr<EventBaseBackendBase>&& backend, EventBase::Options eventBaseOptions,
EventBaseManager* ebm, EventBaseManager* ebm,
StringPiece name); StringPiece name);
~ScopedEventBaseThread(); ~ScopedEventBaseThread();
......
...@@ -19,10 +19,24 @@ ...@@ -19,10 +19,24 @@
#include <folly/io/async/test/Util.h> #include <folly/io/async/test/Util.h>
#include <folly/portability/GTest.h> #include <folly/portability/GTest.h>
#define FOLLY_SKIP_IF_NULLPTR_BACKEND(evb) \ #define FOLLY_SKIP_IF_NULLPTR_BACKEND(evb) \
auto backend = TypeParam::getBackend(); \ std::unique_ptr<EventBase> evb##Ptr; \
SKIP_IF(!backend) << "Backend not available"; \ try { \
EventBase evb(std::move(backend)) auto factory = [] { \
auto backend = TypeParam::getBackend(); \
if (!backend) { \
throw std::runtime_error("backend not available"); \
} \
return backend; \
}; \
evb##Ptr = std::make_unique<EventBase>( \
EventBase::Options().setBackendFactory(std::move(factory))); \
} catch (const std::runtime_error& e) { \
if (std::string("backend not available") == e.what()) { \
SKIP() << "Backend not available"; \
} \
} \
EventBase& evb = *evb##Ptr.get()
namespace folly { namespace folly {
namespace test { namespace test {
......
This diff is collapsed.
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