Commit 55fc4b32 authored by Lee Howes's avatar Lee Howes Committed by Facebook GitHub Bot

Add logging for blocking using baton while on an executor

Summary:
Add sampled logging of blocking operations made on folly::Baton from within an executor task.

Relies on thread_local state recording whether we are in a context where blocking is disallowed, which means within a task running on an executor with support for the functionality. Functionality is currently limited to certain executors, and to blocking operations on Baton, but this covers common user-facing APIs like Future.

Reviewed By: andriigrynenko

Differential Revision: D20010963

fbshipit-source-id: c0598e1a3a9c4e3641581e561b678a2b241998ff
parent f6ef5d3c
...@@ -176,8 +176,10 @@ void SingletonHolder<T>::destroyInstance() { ...@@ -176,8 +176,10 @@ void SingletonHolder<T>::destroyInstance() {
instance_copy_.reset(); instance_copy_.reset();
if (destroy_baton_) { if (destroy_baton_) {
constexpr std::chrono::seconds kDestroyWaitTime{5}; constexpr std::chrono::seconds kDestroyWaitTime{5};
auto const wait_options =
destroy_baton_->wait_options().logging_enabled(false);
auto last_reference_released = auto last_reference_released =
destroy_baton_->try_wait_for(kDestroyWaitTime); destroy_baton_->try_wait_for(kDestroyWaitTime, wait_options);
if (last_reference_released) { if (last_reference_released) {
teardown_(instance_ptr_); teardown_(instance_ptr_);
} else { } else {
......
...@@ -28,5 +28,6 @@ FOLLY_ATTR_WEAK void logGetGlobalIOExecutor(IOExecutor*) noexcept {} ...@@ -28,5 +28,6 @@ FOLLY_ATTR_WEAK void logGetGlobalIOExecutor(IOExecutor*) noexcept {}
FOLLY_ATTR_WEAK void logGetImmutableIOExecutor(IOExecutor*) noexcept {} FOLLY_ATTR_WEAK void logGetImmutableIOExecutor(IOExecutor*) noexcept {}
FOLLY_ATTR_WEAK void logSemiFutureVia(Executor*, Executor*) noexcept {} FOLLY_ATTR_WEAK void logSemiFutureVia(Executor*, Executor*) noexcept {}
FOLLY_ATTR_WEAK void logFutureVia(Executor*, Executor*) noexcept {} FOLLY_ATTR_WEAK void logFutureVia(Executor*, Executor*) noexcept {}
FOLLY_ATTR_WEAK void logBlockingOperation(std::chrono::milliseconds) noexcept {}
} // namespace async_tracing } // namespace async_tracing
} // namespace folly } // namespace folly
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
*/ */
#pragma once #pragma once
#include <chrono>
#include <folly/Optional.h> #include <folly/Optional.h>
namespace folly { namespace folly {
...@@ -30,5 +33,6 @@ void logGetGlobalIOExecutor(IOExecutor*) noexcept; ...@@ -30,5 +33,6 @@ void logGetGlobalIOExecutor(IOExecutor*) noexcept;
void logGetImmutableIOExecutor(IOExecutor*) noexcept; void logGetImmutableIOExecutor(IOExecutor*) noexcept;
void logSemiFutureVia(Executor*, Executor*) noexcept; void logSemiFutureVia(Executor*, Executor*) noexcept;
void logFutureVia(Executor*, Executor*) noexcept; void logFutureVia(Executor*, Executor*) noexcept;
void logBlockingOperation(std::chrono::milliseconds) noexcept;
} // namespace async_tracing } // namespace async_tracing
} // namespace folly } // namespace folly
...@@ -34,4 +34,6 @@ TEST(FollyCountersTest, Trivial) { ...@@ -34,4 +34,6 @@ TEST(FollyCountersTest, Trivial) {
folly::async_tracing::logSemiFutureVia(lastExec, exec); folly::async_tracing::logSemiFutureVia(lastExec, exec);
folly::async_tracing::logFutureVia(lastExec, exec); folly::async_tracing::logFutureVia(lastExec, exec);
folly::async_tracing::logBlockingOperation(std::chrono::milliseconds{100});
} }
...@@ -200,7 +200,8 @@ void ThreadPoolExecutor::addThreads(size_t n) { ...@@ -200,7 +200,8 @@ void ThreadPoolExecutor::addThreads(size_t n) {
threadList_.add(thread); threadList_.add(thread);
} }
for (auto& thread : newThreads) { for (auto& thread : newThreads) {
thread->startupBaton.wait(); thread->startupBaton.wait(
folly::Baton<>::wait_options().logging_enabled(false));
} }
for (auto& o : observers_) { for (auto& o : observers_) {
for (auto& thread : newThreads) { for (auto& thread : newThreads) {
......
...@@ -670,7 +670,7 @@ void EventBase::runInEventBaseThreadAndWait(Func fn) noexcept { ...@@ -670,7 +670,7 @@ void EventBase::runInEventBaseThreadAndWait(Func fn) noexcept {
// before posting the baton and waking the waiting thread. // before posting the baton and waking the waiting thread.
copy(std::move(fn))(); copy(std::move(fn))();
}); });
ready.wait(); ready.wait(folly::Baton<>::wait_options().logging_enabled(false));
} }
void EventBase::runImmediatelyOrRunInEventBaseThreadAndWait(Func fn) noexcept { void EventBase::runImmediatelyOrRunInEventBaseThreadAndWait(Func fn) noexcept {
......
...@@ -42,7 +42,7 @@ static void run( ...@@ -42,7 +42,7 @@ static void run(
// must destruct in io thread for on-destruction callbacks // must destruct in io thread for on-destruction callbacks
eb->runOnDestruction([=] { ebm->clearEventBase(); }); eb->runOnDestruction([=] { ebm->clearEventBase(); });
// wait until terminateLoopSoon() is complete // wait until terminateLoopSoon() is complete
stop->wait(); stop->wait(folly::Baton<>::wait_options().logging_enabled(false));
eb->~EventBase(); eb->~EventBase();
} }
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <thread> #include <thread>
#include <folly/Likely.h> #include <folly/Likely.h>
#include <folly/detail/AsyncTrace.h>
#include <folly/detail/Futex.h> #include <folly/detail/Futex.h>
#include <folly/detail/MemoryIdler.h> #include <folly/detail/MemoryIdler.h>
#include <folly/portability/Asm.h> #include <folly/portability/Asm.h>
...@@ -263,6 +264,12 @@ class Baton { ...@@ -263,6 +264,12 @@ class Baton {
FOLLY_NOINLINE bool tryWaitSlow( FOLLY_NOINLINE bool tryWaitSlow(
const std::chrono::time_point<Clock, Duration>& deadline, const std::chrono::time_point<Clock, Duration>& deadline,
const WaitOptions& opt) noexcept { const WaitOptions& opt) noexcept {
if (opt.logging_enabled()) {
folly::async_tracing::logBlockingOperation(
std::chrono::duration_cast<std::chrono::milliseconds>(
deadline - Clock::now()));
}
switch (detail::spin_pause_until(deadline, opt, [=] { return ready(); })) { switch (detail::spin_pause_until(deadline, opt, [=] { return ready(); })) {
case detail::spin_result::success: case detail::spin_result::success:
return true; return true;
......
...@@ -53,6 +53,7 @@ class WaitOptions { ...@@ -53,6 +53,7 @@ class WaitOptions {
/// nsec is the pause instruction. /// nsec is the pause instruction.
static constexpr std::chrono::nanoseconds spin_max = static constexpr std::chrono::nanoseconds spin_max =
std::chrono::microseconds(2); std::chrono::microseconds(2);
static constexpr bool logging_enabled = true;
}; };
constexpr std::chrono::nanoseconds spin_max() const { constexpr std::chrono::nanoseconds spin_max() const {
...@@ -62,9 +63,17 @@ class WaitOptions { ...@@ -62,9 +63,17 @@ class WaitOptions {
spin_max_ = dur; spin_max_ = dur;
return *this; return *this;
} }
constexpr bool logging_enabled() const {
return logging_enabled_;
}
constexpr WaitOptions& logging_enabled(bool enable) {
logging_enabled_ = enable;
return *this;
}
private: private:
std::chrono::nanoseconds spin_max_ = Defaults::spin_max; std::chrono::nanoseconds spin_max_ = Defaults::spin_max;
bool logging_enabled_ = Defaults::logging_enabled;
}; };
} // namespace folly } // 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