Commit ac744ab3 authored by Dan Melnic's avatar Dan Melnic Committed by Facebook Github Bot

Add timerfd based timers

Summary: Add timerfd based timers

Reviewed By: djwatson

Differential Revision: D13809490

fbshipit-source-id: 9ae70d9cc4d481245623efbc3e74ce5ff8c8f3ca
parent 9f5c7e1e
/*
* Copyright 2019-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/STTimerFDTimeoutManager.h>
#include <folly/io/async/EventUtil.h>
namespace folly {
// STTimerFDTimeoutManager
STTimerFDTimeoutManager::STTimerFDTimeoutManager(folly::EventBase* eventBase)
: TimerFD(eventBase), eventBase_(eventBase) {}
STTimerFDTimeoutManager::~STTimerFDTimeoutManager() {
cancel();
close();
}
void STTimerFDTimeoutManager::setActive(AsyncTimeout* obj, bool active) {
if (obj) {
struct event* ev = obj->getEvent();
if (active) {
event_ref_flags(ev) |= EVLIST_ACTIVE;
} else {
event_ref_flags(ev) &= ~EVLIST_ACTIVE;
}
}
}
void STTimerFDTimeoutManager::attachTimeoutManager(
AsyncTimeout* /*unused*/,
InternalEnum /*unused*/) {}
void STTimerFDTimeoutManager::detachTimeoutManager(AsyncTimeout* obj) {
cancelTimeout(obj);
}
bool STTimerFDTimeoutManager::scheduleTimeout(
AsyncTimeout* obj,
timeout_type timeout) {
timeout_type_high_res high_res_timeout(timeout);
return scheduleTimeoutHighRes(obj, high_res_timeout);
}
bool STTimerFDTimeoutManager::scheduleTimeoutHighRes(
AsyncTimeout* obj,
timeout_type_high_res timeout) {
CHECK(obj_ == nullptr || obj_ == obj)
<< "Scheduling multiple timeouts on a single timeout manager is not allowed!";
// no need to cancel - just reschedule
obj_ = obj;
setActive(obj, true);
schedule(timeout);
return true;
}
void STTimerFDTimeoutManager::cancelTimeout(AsyncTimeout* obj) {
if (obj == obj_) {
setActive(obj, false);
obj_ = nullptr;
cancel();
}
}
void STTimerFDTimeoutManager::bumpHandlingTime() {}
void STTimerFDTimeoutManager::onTimeout() noexcept {
if (obj_) {
auto* obj = obj_;
obj_ = nullptr;
setActive(obj, false);
obj->timeoutExpired();
}
}
} // namespace folly
/*
* Copyright 2019-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <folly/experimental/TimerFD.h>
#include <folly/io/async/TimeoutManager.h>
namespace folly {
// single timeout timerfd based TimeoutManager
class STTimerFDTimeoutManager : public TimeoutManager, TimerFD {
public:
explicit STTimerFDTimeoutManager(folly::EventBase* eventBase);
~STTimerFDTimeoutManager() override;
/**
* Attaches/detaches TimeoutManager to AsyncTimeout
*/
void attachTimeoutManager(AsyncTimeout* obj, InternalEnum internal) final;
void detachTimeoutManager(AsyncTimeout* obj) final;
/**
* Schedules AsyncTimeout to fire after `timeout` milliseconds
*/
bool scheduleTimeout(AsyncTimeout* obj, timeout_type timeout) final;
/**
* Schedules AsyncTimeout to fire after `timeout` microseconds
*/
bool scheduleTimeoutHighRes(AsyncTimeout* obj, timeout_type_high_res timeout)
final;
/**
* Cancels the AsyncTimeout, if scheduled
*/
void cancelTimeout(AsyncTimeout* obj) final;
/**
* This is used to mark the beginning of a new loop cycle by the
* first handler fired within that cycle.
*/
void bumpHandlingTime() final;
/**
* Helper method to know whether we are running in the timeout manager
* thread
*/
bool isInTimeoutManagerThread() final {
return eventBase_->isInEventBaseThread();
}
// from TimerFD
void onTimeout() noexcept final;
private:
static void setActive(AsyncTimeout* obj, bool active);
folly::EventBase* eventBase_{nullptr};
AsyncTimeout* obj_{nullptr};
};
} // namespace folly
/*
* Copyright 2019-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/TimerFD.h>
#ifdef FOLLY_HAVE_TIMERFD
#include <folly/FileUtil.h>
#include <sys/timerfd.h>
#endif
namespace folly {
#ifdef FOLLY_HAVE_TIMERFD
// TimerFD
TimerFD::TimerFD(folly::EventBase* eventBase)
: TimerFD(eventBase, createTimerFd()) {}
TimerFD::TimerFD(folly::EventBase* eventBase, int fd)
: folly::EventHandler(eventBase, fd), fd_(fd) {
if (fd_ > 0) {
registerHandler(folly::EventHandler::READ | folly::EventHandler::PERSIST);
}
}
TimerFD::~TimerFD() {
cancel();
close();
}
void TimerFD::close() {
unregisterHandler();
if (fd_ > 0) {
changeHandlerFD(NetworkSocket());
::close(fd_);
fd_ = -1;
}
}
void TimerFD::schedule(std::chrono::microseconds timeout) {
// schedule(0) will stop the timer otherwise
setTimer(timeout.count() ? timeout : std::chrono::microseconds(1));
}
void TimerFD::cancel() {
setTimer(std::chrono::microseconds(0));
}
bool TimerFD::setTimer(std::chrono::microseconds useconds) {
if (fd_ <= 0) {
return false;
}
struct itimerspec val;
val.it_interval = {0, 0};
val.it_value.tv_sec =
std::chrono::duration_cast<std::chrono::seconds>(useconds).count();
val.it_value.tv_nsec =
std::chrono::duration_cast<std::chrono::nanoseconds>(useconds).count() %
1000000000LL;
return (0 == ::timerfd_settime(fd_, 0, &val, nullptr));
}
void TimerFD::handlerReady(uint16_t events) noexcept {
DestructorGuard dg(this);
uint16_t relevantEvents = uint16_t(events & folly::EventHandler::READ_WRITE);
if (relevantEvents == folly::EventHandler::READ ||
relevantEvents == folly::EventHandler::READ_WRITE) {
uint64_t data = 0;
ssize_t num = folly::readNoInt(fd_, &data, sizeof(data));
if (num == sizeof(data)) {
onTimeout();
}
}
}
int TimerFD::createTimerFd() {
return ::timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
}
#else
TimerFD::TimerFD(folly::EventBase* eventBase) : timeout_(eventBase, this) {}
TimerFD::~TimerFD() {
// cancel has to be called from the derived classes !!!
}
void TimerFD::schedule(std::chrono::microseconds timeout) {
timeout_.scheduleTimeoutHighRes(timeout);
}
void TimerFD::cancel() {
timeout_.cancelTimeout();
}
TimerFD::TimerFDAsyncTimeout::TimerFDAsyncTimeout(
folly::EventBase* eventBase,
TimerFD* timerFd)
: folly::AsyncTimeout(eventBase), timerFd_(timerFd) {}
void TimerFD::TimerFDAsyncTimeout::timeoutExpired() noexcept {
timerFd_->onTimeout();
}
#endif
} // namespace folly
/*
* Copyright 2019-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#if __linux__ && !__ANDROID__
#define FOLLY_HAVE_TIMERFD
#endif
#include <folly/io/async/EventBase.h>
#ifdef FOLLY_HAVE_TIMERFD
#include <folly/io/async/EventHandler.h>
#else
#include <folly/io/async/AsyncTimeout.h>
#endif
#include <chrono>
namespace folly {
#ifdef FOLLY_HAVE_TIMERFD
// timerfd wrapper
class TimerFD : public folly::EventHandler, public DelayedDestruction {
public:
explicit TimerFD(folly::EventBase* eventBase);
~TimerFD() override;
virtual void onTimeout() noexcept = 0;
void schedule(std::chrono::microseconds timeout);
void cancel();
// from folly::EventHandler
void handlerReady(uint16_t events) noexcept override;
protected:
void close();
private:
TimerFD(folly::EventBase* eventBase, int fd);
static int createTimerFd();
// use 0 to stop the timer
bool setTimer(std::chrono::microseconds useconds);
int fd_{-1};
};
#else
// alternative implementation using a folly::AsyncTimeout
class TimerFD {
public:
explicit TimerFD(folly::EventBase* eventBase);
virtual ~TimerFD();
virtual void onTimeout() = 0;
void schedule(std::chrono::microseconds timeout);
void cancel();
protected:
void close() {}
private:
class TimerFDAsyncTimeout : public folly::AsyncTimeout {
public:
TimerFDAsyncTimeout(folly::EventBase* eventBase, TimerFD* timerFd);
~TimerFDAsyncTimeout() override = default;
// from folly::AsyncTimeout
void timeoutExpired() noexcept final;
private:
TimerFD* timerFd_;
};
TimerFDAsyncTimeout timeout_;
};
#endif
} // namespace folly
/*
* Copyright 2019-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/experimental/TimerFDTimeoutManager.h>
namespace folly {
// TimerFDTimeoutManager
TimerFDTimeoutManager::TimerFDTimeoutManager(folly::EventBase* eventBase)
: TimerFD(eventBase) {}
TimerFDTimeoutManager::~TimerFDTimeoutManager() {
cancelAll();
close();
}
void TimerFDTimeoutManager::onTimeout() noexcept {
processExpiredTimers();
scheduleNextTimer();
}
void TimerFDTimeoutManager::scheduleTimeout(
Callback* callback,
std::chrono::microseconds timeout) {
cancelTimeout(callback);
// we cannot schedule a timeout of 0 - this will stop the timer
if (FOLLY_UNLIKELY(!timeout.count())) {
timeout = std::chrono::microseconds(1);
}
auto expirationTime = getCurTime() + timeout;
auto expirationTimeUsec =
std::chrono::duration_cast<std::chrono::microseconds>(
expirationTime.time_since_epoch());
if (callbacks_.empty() || expirationTimeUsec < callbacks_.begin()->first) {
schedule(timeout);
}
// now add the callback
// handle entries that expire at the same time
auto iter = callbacks_.find(expirationTimeUsec);
if (iter != callbacks_.end()) {
iter->second.push_back(*callback);
} else {
CallbackList list;
list.push_back(*callback);
callbacks_.emplace(expirationTimeUsec, std::move(list));
}
callback->setExpirationTime(this, expirationTimeUsec);
}
bool TimerFDTimeoutManager::cancelTimeout(Callback* callback) {
if (!callback->is_linked()) {
return false;
}
callback->unlink();
callback->callbackCanceled();
auto expirationTime = callback->getExpirationTime();
auto iter = callbacks_.find(expirationTime);
if (iter == callbacks_.end()) {
return false;
}
bool removeFirst = (iter == callbacks_.begin());
if (iter->second.empty()) {
callbacks_.erase(iter);
}
// reschedule the timer if needed
if (!processingExpired_ && removeFirst && !callbacks_.empty()) {
auto now = std::chrono::duration_cast<std::chrono::microseconds>(
getCurTime().time_since_epoch());
if (now > callbacks_.begin()->first) {
auto timeout = now - callbacks_.begin()->first;
schedule(timeout);
}
}
if (callbacks_.empty()) {
cancel();
}
return true;
}
size_t TimerFDTimeoutManager::cancelAll() {
size_t ret = 0;
while (!callbacks_.empty()) {
auto iter = callbacks_.begin();
auto callbackList = std::move(iter->second);
callbacks_.erase(iter);
while (!callbackList.empty()) {
++ret;
auto* callback = &callbackList.front();
callbackList.pop_front();
callback->callbackCanceled();
}
}
// and now the in progress list
while (!inProgressList_.empty()) {
++ret;
auto* callback = &inProgressList_.front();
inProgressList_.pop_front();
callback->callbackCanceled();
}
if (ret) {
cancel();
}
return ret;
}
size_t TimerFDTimeoutManager::count() const {
size_t ret = 0;
for (const auto& c : callbacks_) {
ret += c.second.size();
}
return ret;
}
void TimerFDTimeoutManager::processExpiredTimers() {
processingExpired_ = true;
while (true) {
if (callbacks_.empty()) {
break;
}
auto iter = callbacks_.begin();
auto now = std::chrono::duration_cast<std::chrono::microseconds>(
getCurTime().time_since_epoch());
if (now >= iter->first) {
inProgressList_ = std::move(iter->second);
callbacks_.erase(iter);
CHECK(!inProgressList_.empty());
while (!inProgressList_.empty()) {
auto* callback = &inProgressList_.front();
inProgressList_.pop_front();
callback->timeoutExpired();
}
} else {
break;
}
}
processingExpired_ = false;
}
void TimerFDTimeoutManager::scheduleNextTimer() {
if (callbacks_.empty()) {
return;
}
auto iter = callbacks_.begin();
auto now = std::chrono::duration_cast<std::chrono::microseconds>(
getCurTime().time_since_epoch());
if (iter->first > now) {
schedule(iter->first - now);
} else {
// we schedule it here again to avoid the case
// where a timer can cause starvation
// by continuosly rescheduling itlsef
schedule(std::chrono::microseconds(1));
}
}
} // namespace folly
/*
* Copyright 2019-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <folly/experimental/TimerFD.h>
#include <folly/io/async/DelayedDestruction.h>
#include <map>
namespace folly {
// generic TimerFD based timeout manager
class TimerFDTimeoutManager : public TimerFD {
public:
using UniquePtr =
std::unique_ptr<TimerFDTimeoutManager, DelayedDestruction::Destructor>;
using SharedPtr = std::shared_ptr<TimerFDTimeoutManager>;
public:
class Callback
: public boost::intrusive::list_base_hook<
boost::intrusive::link_mode<boost::intrusive::auto_unlink>> {
public:
Callback() = default;
explicit Callback(TimerFDTimeoutManager* mgr) : mgr_(mgr) {}
virtual ~Callback() = default;
virtual void timeoutExpired() noexcept = 0;
virtual void callbackCanceled() noexcept {
timeoutExpired();
}
const std::chrono::microseconds& getExpirationTime() const {
return expirationTime_;
}
void setExpirationTime(
TimerFDTimeoutManager* mgr,
const std::chrono::microseconds& expirationTime) {
mgr_ = mgr;
expirationTime_ = expirationTime;
}
std::chrono::microseconds getTimeRemaining() const {
return getTimeRemaining(std::chrono::steady_clock::now());
}
std::chrono::microseconds getTimeRemaining(
std::chrono::steady_clock::time_point now) const {
auto nowMs = std::chrono::duration_cast<std::chrono::microseconds>(
now.time_since_epoch());
if (expirationTime_ > nowMs) {
return std::chrono::duration_cast<std::chrono::microseconds>(
expirationTime_ - nowMs);
}
return std::chrono::microseconds(0);
}
void scheduleTimeout(std::chrono::microseconds timeout) {
if (mgr_) {
mgr_->scheduleTimeout(this, timeout);
}
}
bool cancelTimeout() {
return mgr_->cancelTimeout(this);
}
private:
TimerFDTimeoutManager* mgr_{nullptr};
std::chrono::microseconds expirationTime_{0};
};
explicit TimerFDTimeoutManager(folly::EventBase* eventBase);
~TimerFDTimeoutManager() override;
// from TimerFD
void onTimeout() noexcept final;
size_t cancelAll();
void scheduleTimeout(Callback* callback, std::chrono::microseconds timeout);
bool cancelTimeout(Callback* callback);
template <class F>
void scheduleTimeoutFn(F fn, std::chrono::microseconds timeout) {
struct Wrapper : Callback {
explicit Wrapper(F f) : fn_(std::move(f)) {}
void timeoutExpired() noexcept override {
try {
fn_();
} catch (std::exception const& e) {
LOG(ERROR) << "HHWheelTimerBase timeout callback threw an exception: "
<< e.what();
} catch (...) {
LOG(ERROR)
<< "HHWheelTimerBase timeout callback threw a non-exception.";
}
delete this;
}
F fn_;
};
Wrapper* w = new Wrapper(std::move(fn));
scheduleTimeout(w, timeout);
}
size_t count() const;
private:
void processExpiredTimers();
void scheduleNextTimer();
std::chrono::steady_clock::time_point getCurTime() {
return std::chrono::steady_clock::now();
}
// we can attempt to schedule new entries while in processExpiredTimers
// we want to reschedule the timers once we're done with the processing
bool processingExpired_{false};
typedef boost::intrusive::
list<Callback, boost::intrusive::constant_time_size<false>>
CallbackList;
std::map<std::chrono::microseconds, CallbackList> callbacks_;
CallbackList inProgressList_;
};
} // namespace folly
/*
* Copyright 2018-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <folly/Benchmark.h>
#include <folly/experimental/STTimerFDTimeoutManager.h>
#include <folly/experimental/TimerFDTimeoutManager.h>
#include <folly/io/async/test/UndelayedDestruction.h>
using namespace folly;
using std::chrono::microseconds;
using std::chrono::milliseconds;
class TestTimeoutMs : public HHWheelTimer::Callback {
public:
TestTimeoutMs() = default;
~TestTimeoutMs() override = default;
void timeoutExpired() noexcept override {}
void callbackCanceled() noexcept override {}
};
typedef UndelayedDestruction<HHWheelTimer> StackWheelTimerMs;
class TestTimeoutUs : public HHWheelTimerHighRes::Callback {
public:
TestTimeoutUs() = default;
~TestTimeoutUs() override = default;
void timeoutExpired() noexcept override {}
void callbackCanceled() noexcept override {}
};
typedef UndelayedDestruction<HHWheelTimerHighRes> StackWheelTimerUs;
class TestTimeoutDirectUs : public TimerFDTimeoutManager::Callback {
public:
TestTimeoutDirectUs() = default;
~TestTimeoutDirectUs() override = default;
void timeoutExpired() noexcept override {}
void callbackCanceled() noexcept override {}
};
unsigned int scheduleCancelTimersMs(unsigned int iters, unsigned int timers) {
BenchmarkSuspender susp;
EventBase evb;
StackWheelTimerMs t(&evb, milliseconds(1));
std::vector<TestTimeoutMs> timeouts(timers);
susp.dismiss();
for (unsigned int i = 0; i < iters; ++i) {
for (unsigned int j = 0; j < timers; ++j) {
t.scheduleTimeout(&timeouts[j], milliseconds(5 * (j + 1)));
}
for (unsigned int j = 0; j < timers; ++j) {
timeouts[j].cancelTimeout();
}
}
susp.rehire();
return iters;
}
unsigned int scheduleCancelTimersUs(unsigned int iters, unsigned int timers) {
BenchmarkSuspender susp;
EventBase evb;
STTimerFDTimeoutManager timeoutMgr(&evb);
StackWheelTimerUs t(&timeoutMgr, microseconds(20));
std::vector<TestTimeoutUs> timeouts(timers);
susp.dismiss();
for (unsigned int i = 0; i < iters; ++i) {
for (unsigned int j = 0; j < timers; ++j) {
t.scheduleTimeout(&timeouts[j], microseconds(5000 * (j + 1)));
}
for (unsigned int j = 0; j < timers; ++j) {
timeouts[j].cancelTimeout();
}
}
susp.rehire();
return iters;
}
unsigned int scheduleCancelTimersDirectUs(
unsigned int iters,
unsigned int timers) {
BenchmarkSuspender susp;
EventBase evb;
TimerFDTimeoutManager t(&evb);
std::vector<TestTimeoutDirectUs> timeouts(timers);
susp.dismiss();
for (unsigned int i = 0; i < iters; ++i) {
for (unsigned int j = 0; j < timers; ++j) {
t.scheduleTimeout(&timeouts[j], microseconds(5000 * (j + 1)));
}
for (unsigned int j = 0; j < timers; ++j) {
timeouts[j].cancelTimeout();
}
}
susp.rehire();
return iters;
}
BENCHMARK_DRAW_LINE();
BENCHMARK_NAMED_PARAM_MULTI(scheduleCancelTimersMs, ms_1, 1)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(scheduleCancelTimersUs, us_1, 1)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(
scheduleCancelTimersDirectUs,
direct_us_1,
1)
BENCHMARK_DRAW_LINE();
BENCHMARK_NAMED_PARAM_MULTI(scheduleCancelTimersMs, ms_16, 16)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(scheduleCancelTimersUs, us_16, 16)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(
scheduleCancelTimersDirectUs,
direct_us_16,
16)
BENCHMARK_DRAW_LINE();
BENCHMARK_NAMED_PARAM_MULTI(scheduleCancelTimersMs, ms_64, 64)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(scheduleCancelTimersUs, us_64, 64)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(
scheduleCancelTimersDirectUs,
direct_us_64,
64)
BENCHMARK_DRAW_LINE();
BENCHMARK_NAMED_PARAM_MULTI(scheduleCancelTimersMs, ms_128, 128)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(scheduleCancelTimersUs, us_128, 128)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(
scheduleCancelTimersDirectUs,
direct_us_128,
128)
BENCHMARK_DRAW_LINE();
BENCHMARK_NAMED_PARAM_MULTI(scheduleCancelTimersMs, ms_512, 512)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(scheduleCancelTimersUs, us_512, 512)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(
scheduleCancelTimersDirectUs,
direct_us_512,
512)
BENCHMARK_DRAW_LINE();
BENCHMARK_NAMED_PARAM_MULTI(scheduleCancelTimersMs, ms_1024, 1024)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(scheduleCancelTimersUs, us_1024, 1024)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(
scheduleCancelTimersDirectUs,
direct_us_1024,
1024)
BENCHMARK_DRAW_LINE();
BENCHMARK_NAMED_PARAM_MULTI(scheduleCancelTimersMs, ms_4096, 4096)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(scheduleCancelTimersUs, us_4096, 4096)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(
scheduleCancelTimersDirectUs,
direct_us_4096,
4096)
BENCHMARK_DRAW_LINE();
BENCHMARK_NAMED_PARAM_MULTI(scheduleCancelTimersMs, ms_8192, 9182)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(scheduleCancelTimersUs, us_8192, 9182)
BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(
scheduleCancelTimersDirectUs,
direct_us_8192,
9182)
BENCHMARK_DRAW_LINE();
int main(int argc, char* argv[]) {
gflags::ParseCommandLineFlags(&argc, &argv, true);
folly::runBenchmarks();
return 0;
}
This diff is collapsed.
This diff is collapsed.
......@@ -21,4 +21,5 @@ namespace folly {
template <class Duration>
class HHWheelTimerBase;
using HHWheelTimer = HHWheelTimerBase<std::chrono::milliseconds>;
using HHWheelTimerHighRes = HHWheelTimerBase<std::chrono::microseconds>;
}
......@@ -375,6 +375,16 @@ int64_t HHWheelTimerBase<Duration>::calcNextTick(
return (curTime - startTime_) / interval_;
}
// std::chrono::microseconds
template <>
void HHWheelTimerBase<std::chrono::microseconds>::scheduleTimeoutInternal(
std::chrono::microseconds timeout) {
this->AsyncTimeout::scheduleTimeoutHighRes(timeout);
}
// std::chrono::milliseconds
template class HHWheelTimerBase<std::chrono::milliseconds>;
// std::chrono::microseconds
template class HHWheelTimerBase<std::chrono::microseconds>;
} // namespace folly
......@@ -346,4 +346,12 @@ class HHWheelTimerBase : private folly::AsyncTimeout,
using HHWheelTimer = HHWheelTimerBase<std::chrono::milliseconds>;
extern template class HHWheelTimerBase<std::chrono::milliseconds>;
// std::chrono::microseconds
template <>
void HHWheelTimerBase<std::chrono::microseconds>::scheduleTimeoutInternal(
std::chrono::microseconds timeout);
using HHWheelTimerHighRes = HHWheelTimerBase<std::chrono::microseconds>;
extern template class HHWheelTimerBase<std::chrono::microseconds>;
} // namespace folly
......@@ -20,6 +20,7 @@
#include <cstdint>
#include <folly/Function.h>
#include <folly/Optional.h>
namespace folly {
......
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