if (enableTimeMeasurement_) {
prev = std::chrono::steady_clock::now();
- idleStart = std::chrono::steady_clock::now();
+ idleStart = prev;
}
while (!stop_.load(std::memory_order_relaxed)) {
ranLoopCallbacks = runLoopCallbacks();
if (enableTimeMeasurement_) {
+ auto now = std::chrono::steady_clock::now();
busy = std::chrono::duration_cast<std::chrono::microseconds>(
- std::chrono::steady_clock::now() - startWork_);
+ now - startWork_);
idle = std::chrono::duration_cast<std::chrono::microseconds>(
startWork_ - idleStart);
+ auto loop_time = busy + idle;
- avgLoopTime_.addSample(std::chrono::microseconds(idle),
- std::chrono::microseconds(busy));
- maxLatencyLoopTime_.addSample(std::chrono::microseconds(idle),
- std::chrono::microseconds(busy));
+ avgLoopTime_.addSample(loop_time, busy);
+ maxLatencyLoopTime_.addSample(loop_time, busy);
if (observer_) {
if (observerSampleCount_++ == observer_->getSampleRate()) {
}
}
- VLOG(11) << "EventBase " << this << " did not timeout " <<
- " loop time guess: " << (busy + idle).count() <<
- " idle time: " << idle.count() <<
- " busy time: " << busy.count() <<
- " avgLoopTime: " << avgLoopTime_.get() <<
- " maxLatencyLoopTime: " << maxLatencyLoopTime_.get() <<
- " maxLatency_: " << maxLatency_.count() << "us" <<
- " notificationQueueSize: " << getNotificationQueueSize() <<
- " nothingHandledYet(): " << nothingHandledYet();
+ VLOG(11) << "EventBase " << this << " did not timeout "
+ << " loop time guess: " << loop_time.count()
+ << " idle time: " << idle.count()
+ << " busy time: " << busy.count()
+ << " avgLoopTime: " << avgLoopTime_.get()
+ << " maxLatencyLoopTime: " << maxLatencyLoopTime_.get()
+ << " maxLatency_: " << maxLatency_.count() << "us"
+ << " notificationQueueSize: " << getNotificationQueueSize()
+ << " nothingHandledYet(): " << nothingHandledYet();
// see if our average loop time has exceeded our limit
if ((maxLatency_ > std::chrono::microseconds::zero()) &&
}
// Our loop run did real work; reset the idle timer
- idleStart = std::chrono::steady_clock::now();
+ idleStart = now;
} else {
VLOG(11) << "EventBase " << this << " did not timeout";
}
}
void EventBase::SmoothLoopTime::addSample(
- std::chrono::microseconds idle,
+ std::chrono::microseconds total,
std::chrono::microseconds busy) {
- /*
- * Position at which the busy sample is considered to be taken.
- * (Allows to quickly skew our average without editing much code)
- */
- enum BusySamplePosition {
- RIGHT = 0, // busy sample placed at the end of the iteration
- CENTER = 1, // busy sample placed at the middle point of the iteration
- LEFT = 2, // busy sample placed at the beginning of the iteration
- };
-
- // See http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average
- // and D676020 for more info on this calculation.
- VLOG(11) << "idle " << idle.count() << " oldBusyLeftover_ "
- << oldBusyLeftover_.count() << " idle + oldBusyLeftover_ "
- << (idle + oldBusyLeftover_).count() << " busy " << busy.count()
- << " " << __PRETTY_FUNCTION__;
- idle += oldBusyLeftover_ + busy;
- oldBusyLeftover_ = (busy * BusySamplePosition::CENTER) / 2;
- idle -= oldBusyLeftover_;
-
- double coeff = exp(idle.count() * expCoeff_);
- value_ *= coeff;
- value_ += (1.0 - coeff) * busy.count();
+ if ((buffer_time_ + total) > buffer_interval_ && buffer_cnt_ > 0) {
+ // See https://en.wikipedia.org/wiki/Exponential_smoothing for
+ // more info on this calculation.
+ double coeff = exp(buffer_time_.count() * expCoeff_);
+ value_ =
+ value_ * coeff + (1.0 - coeff) * (busy_buffer_.count() / buffer_cnt_);
+ buffer_time_ = std::chrono::microseconds{0};
+ busy_buffer_ = std::chrono::microseconds{0};
+ buffer_cnt_ = 0;
+ }
+ buffer_time_ += total;
+ busy_buffer_ += busy;
+ buffer_cnt_++;
}
bool EventBase::nothingHandledYet() const noexcept {
return *virtualEventBase_;
}
+constexpr std::chrono::milliseconds EventBase::SmoothLoopTime::buffer_interval_;
} // namespace folly
class SmoothLoopTime {
public:
explicit SmoothLoopTime(std::chrono::microseconds timeInterval)
- : expCoeff_(-1.0 / timeInterval.count()),
- value_(0.0),
- oldBusyLeftover_(0) {
+ : expCoeff_(-1.0 / timeInterval.count()), value_(0.0) {
VLOG(11) << "expCoeff_ " << expCoeff_ << " " << __PRETTY_FUNCTION__;
}
void reset(double value = 0.0);
void addSample(
- std::chrono::microseconds idle,
+ std::chrono::microseconds total,
std::chrono::microseconds busy);
double get() const {
- return value_;
+ // Add the outstanding buffered times linearly, to avoid
+ // expensive exponentiation
+ auto lcoeff = buffer_time_.count() * -expCoeff_;
+ return value_ * (1.0 - lcoeff) + lcoeff * busy_buffer_.count();
}
void dampen(double factor) {
private:
double expCoeff_;
double value_;
- std::chrono::microseconds oldBusyLeftover_;
+ std::chrono::microseconds buffer_time_{0};
+ std::chrono::microseconds busy_buffer_{0};
+ uint64_t buffer_cnt_{0};
+ static constexpr std::chrono::milliseconds buffer_interval_{10};
};
void setObserver(const std::shared_ptr<EventBaseObserver>& observer) {