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 {
class BackendEventBase : public EventBase {
public:
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:
static std::unique_ptr<folly::EventBaseBackendBase> getBackend(
......
......@@ -142,41 +142,23 @@ class EventBase::FunctionRunner
* EventBase methods
*/
EventBase::EventBase(bool enableTimeMeasurement)
: runOnceCallbacks_(nullptr),
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();
EventBase::EventBase(std::chrono::milliseconds tickInterval)
: EventBase(Options().setTimerTickInterval(tickInterval)) {}
VLOG(5) << "EventBase(): Created.";
initNotificationQueue();
}
EventBase::EventBase(bool enableTimeMeasurement)
: EventBase(Options().setSkipTimeMeasurement(!enableTimeMeasurement)) {}
// takes ownership of the event_base
EventBase::EventBase(event_base* evb, bool enableTimeMeasurement)
: EventBase(
std::make_unique<EventBaseBackend>(evb),
enableTimeMeasurement) {}
// takes ownership of the backend
EventBase::EventBase(
std::unique_ptr<EventBaseBackendBase>&& evb,
bool enableTimeMeasurement)
: runOnceCallbacks_(nullptr),
: EventBase(Options()
.setBackendFactory([evb] {
return std::make_unique<EventBaseBackend>(evb);
})
.setSkipTimeMeasurement(!enableTimeMeasurement)) {}
EventBase::EventBase(Options options)
: intervalDuration_(options.timerTickInterval),
runOnceCallbacks_(nullptr),
stop_(false),
loopThread_(),
queue_(nullptr),
......@@ -184,7 +166,7 @@ EventBase::EventBase(
maxLatency_(0),
avgLoopTime_(std::chrono::seconds(2)),
maxLatencyLoopTime_(avgLoopTime_),
enableTimeMeasurement_(enableTimeMeasurement),
enableTimeMeasurement_(!options.skipTimeMeasurement),
nextLoopCnt_(
std::size_t(-40)) // Early wrap-around so bugs will manifest soon
,
......@@ -193,7 +175,8 @@ EventBase::EventBase(
observer_(nullptr),
observerSampleCount_(0),
executionObserver_(nullptr) {
evb_ = evb ? std::move(evb) : getDefaultBackend();
evb_ =
options.backendFactory ? options.backendFactory() : getDefaultBackend();
initNotificationQueue();
}
......
......@@ -282,6 +282,47 @@ class EventBase : public TimeoutManager,
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.
*
......@@ -289,9 +330,7 @@ class EventBase : public TimeoutManager,
* except that this also allows the timer granularity to be specified
*/
explicit EventBase(std::chrono::milliseconds tickInterval) : EventBase(true) {
intervalDuration_ = tickInterval;
}
explicit EventBase(std::chrono::milliseconds tickInterval);
/**
* Create a new EventBase object.
......@@ -328,9 +367,8 @@ class EventBase : public TimeoutManager,
* observer, max latency and avg loop time.
*/
explicit EventBase(event_base* evb, bool enableTimeMeasurement = true);
explicit EventBase(
std::unique_ptr<EventBaseBackendBase>&& evb,
bool enableTimeMeasurement = true);
explicit EventBase(Options options);
~EventBase() override;
/**
......
......@@ -66,7 +66,9 @@ EventBase* EventBaseManager::getEventBase() const {
// have one?
auto* info = localStore_.get();
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);
if (observer_) {
......
......@@ -114,8 +114,6 @@ class EventBaseManager {
private:
struct EventBaseInfo {
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) {}
EventBase* eventBase;
......
......@@ -27,18 +27,14 @@ EventBaseThread::EventBaseThread(
bool autostart,
EventBaseManager* ebm,
folly::StringPiece threadName)
: ebm_(ebm) {
if (autostart) {
start(threadName);
}
}
: EventBaseThread(autostart, EventBase::Options(), ebm, threadName) {}
EventBaseThread::EventBaseThread(
bool autostart,
std::unique_ptr<EventBaseBackendBase>&& evb,
EventBase::Options eventBaseOptions,
EventBaseManager* ebm,
folly::StringPiece threadName)
: ebm_(ebm), evb_(std::move(evb)) {
: ebm_(ebm), ebOpts_(std::move(eventBaseOptions)) {
if (autostart) {
start(threadName);
}
......@@ -65,8 +61,7 @@ void EventBaseThread::start(folly::StringPiece threadName) {
if (th_) {
return;
}
th_ = std::make_unique<ScopedEventBaseThread>(
std::move(evb_), ebm_, threadName);
th_ = std::make_unique<ScopedEventBaseThread>(ebOpts_, ebm_, threadName);
}
void EventBaseThread::stop() {
......
......@@ -17,6 +17,7 @@
#pragma once
#include <folly/Range.h>
#include <folly/io/async/EventBase.h>
#include <memory>
namespace folly {
......@@ -35,7 +36,7 @@ class EventBaseThread {
folly::StringPiece threadName = folly::StringPiece());
EventBaseThread(
bool autostart,
std::unique_ptr<EventBaseBackendBase>&& evb,
EventBase::Options eventBaseOptions,
EventBaseManager* ebm = nullptr,
folly::StringPiece threadName = folly::StringPiece());
explicit EventBaseThread(EventBaseManager* ebm);
......@@ -54,7 +55,7 @@ class EventBaseThread {
private:
EventBaseManager* ebm_;
std::unique_ptr<EventBaseBackendBase> evb_;
EventBase::Options ebOpts_;
std::unique_ptr<ScopedEventBaseThread> th_;
};
} // namespace folly
......@@ -58,17 +58,14 @@ ScopedEventBaseThread::ScopedEventBaseThread(EventBaseManager* ebm)
ScopedEventBaseThread::ScopedEventBaseThread(
EventBaseManager* ebm,
StringPiece name)
: ScopedEventBaseThread(
std::unique_ptr<EventBaseBackendBase>(),
ebm,
name) {}
: ScopedEventBaseThread(EventBase::Options(), ebm, name) {}
ScopedEventBaseThread::ScopedEventBaseThread(
std::unique_ptr<EventBaseBackendBase>&& backend,
EventBase::Options eventBaseOptions,
EventBaseManager* ebm,
StringPiece name)
: ebm_(ebm ? ebm : EventBaseManager::get()) {
new (&eb_) EventBase(std::move(backend));
new (&eb_) EventBase(std::move(eventBaseOptions));
th_ = thread(run, ebm_, &eb_, &stop_, name);
eb_.waitUntilRunning();
}
......
......@@ -42,8 +42,8 @@ class ScopedEventBaseThread : public IOExecutor, public SequencedExecutor {
explicit ScopedEventBaseThread(StringPiece name);
explicit ScopedEventBaseThread(EventBaseManager* ebm);
explicit ScopedEventBaseThread(EventBaseManager* ebm, StringPiece name);
explicit ScopedEventBaseThread(
std::unique_ptr<EventBaseBackendBase>&& backend,
ScopedEventBaseThread(
EventBase::Options eventBaseOptions,
EventBaseManager* ebm,
StringPiece name);
~ScopedEventBaseThread();
......
......@@ -20,9 +20,23 @@
#include <folly/portability/GTest.h>
#define FOLLY_SKIP_IF_NULLPTR_BACKEND(evb) \
std::unique_ptr<EventBase> evb##Ptr; \
try { \
auto factory = [] { \
auto backend = TypeParam::getBackend(); \
SKIP_IF(!backend) << "Backend not available"; \
EventBase evb(std::move(backend))
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 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