Commit 183fc6b4 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Extract WaitOptions

Summary:
[Folly] Extract `WaitOptions` from `SaturatingSemaphore`.

This type may prove useful in the future for a variety of similar cases, and so does not need to be locked up inside `SaturatingSemaphore`.

Additionally:
* Extract and redraft a comment from `Baton`.
* Rename `pre_block` to `spin_max`.

Reviewed By: djwatson, aary

Differential Revision: D6632875

fbshipit-source-id: 6b7faeeb6e1ac2011a037c2b560def0ee2e9f3d4
parent f6ed4a26
/*
* Copyright 2017 Facebook, Inc.
* Copyright 2017-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.
......@@ -19,6 +19,7 @@
#include <folly/Likely.h>
#include <folly/detail/Futex.h>
#include <folly/portability/Asm.h>
#include <folly/synchronization/WaitOptions.h>
#include <glog/logging.h>
......@@ -61,11 +62,10 @@ namespace folly {
/// instruction to the critical path of posters.
///
/// Wait options:
/// The subclass WaitOptions contains optional per call setting for
/// pre-block spin duration: Calls to wait(), try_wait_until(), and
/// try_wait_for() block only after the passage of the pre-block
/// period. The default pre-block duration is 10 microseconds. The
/// pre block option is applicable only if MayBlock is true.
/// WaitOptions contains optional per call setting for spin-max duration:
/// Calls to wait(), try_wait_until(), and try_wait_for() block only after the
/// passage of the spin-max period. The default spin-max duration is 10 usec.
/// The spin-max option is applicable only if MayBlock is true.
///
/// Functions:
/// bool ready():
......@@ -101,11 +101,11 @@ namespace folly {
/// std::chrono::steady_clock::now() + std::chrono::microseconds(1)));
/// ASSERT_FALSE(f.try_wait_until(
/// std::chrono::steady_clock::now() + std::chrono::microseconds(1),
/// f.wait_options().pre_block(std::chrono::microseconds(1))));
/// f.wait_options().spin_max(std::chrono::microseconds(1))));
/// f.post();
/// f.post();
/// f.wait();
/// f.wait(f.wait_options().pre_block(std::chrono::nanoseconds(100)));
/// f.wait(f.wait_options().spin_max(std::chrono::nanoseconds(100)));
/// ASSERT_TRUE(f.try_wait());
/// ASSERT_TRUE(f.try_wait_until(
/// std::chrono::steady_clock::now() + std::chrono::microseconds(1)));
......@@ -125,23 +125,6 @@ class SaturatingSemaphore {
};
public:
/** WaitOptions */
class WaitOptions {
std::chrono::nanoseconds dur_{std::chrono::microseconds(10)};
public:
FOLLY_ALWAYS_INLINE
std::chrono::nanoseconds pre_block() const {
return dur_;
}
FOLLY_ALWAYS_INLINE
WaitOptions& pre_block(std::chrono::nanoseconds dur) {
dur_ = dur;
return *this;
}
};
FOLLY_ALWAYS_INLINE static WaitOptions wait_options() {
return {};
}
......@@ -307,11 +290,11 @@ FOLLY_NOINLINE bool SaturatingSemaphore<MayBlock, Atom>::tryWaitSlow(
if (MayBlock) {
auto tnow = Clock::now();
if (tnow < tbegin) {
// backward time discontinuity in Clock, revise pre_block starting point
// backward time discontinuity in Clock, revise spin_max starting point
tbegin = tnow;
}
auto dur = std::chrono::duration_cast<Duration>(tnow - tbegin);
if (dur >= opt.pre_block()) {
if (dur >= opt.spin_max()) {
if (before == NOTREADY) {
if (!state_.compare_exchange_strong(
before,
......
/*
* 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/synchronization/WaitOptions.h>
namespace folly {
constexpr std::chrono::nanoseconds WaitOptions::Defaults::spin_max;
} // 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.
*/
#pragma once
#include <chrono>
#include <folly/CPortability.h>
namespace folly {
/// WaitOptions
///
/// Various synchronization primitives as well as various concurrent data
/// structures built using them have operations which might wait. This type
/// represents a set of options for controlling such waiting.
class WaitOptions {
public:
struct Defaults {
/// spin_max
///
/// If multiple threads are actively using a synchronization primitive,
/// whether indirectly via a higher-level concurrent data structure or
/// directly, where the synchronization primitive has an operation which
/// waits and another operation which wakes the waiter, it is common for
/// wait and wake events to happen almost at the same time. In this state,
/// we lose big 50% of the time if the wait blocks immediately.
///
/// We can improve our chances of being waked immediately, before blocking,
/// by spinning for a short duration, although we have to balance this
/// against the extra cpu utilization, latency reduction, power consumption,
/// and priority inversion effect if we end up blocking anyway.
///
/// We use a default maximum of 10 usec of spinning. As partial consolation,
/// since spinning as implemented in folly uses the pause instruction where
/// available, we give a small speed boost to the colocated hyperthread.
///
/// On circa-2013 devbox hardware, it costs about 7 usec to FUTEX_WAIT and
/// then be awoken. Spins on this hw take about 7 nsec, where all but 0.5
/// nsec is the pause instruction.
static constexpr std::chrono::nanoseconds spin_max =
std::chrono::microseconds(10);
};
std::chrono::nanoseconds spin_max() const {
return spin_max_;
}
WaitOptions& spin_max(std::chrono::nanoseconds dur) {
spin_max_ = dur;
return *this;
}
private:
std::chrono::nanoseconds spin_max_ = Defaults::spin_max;
};
} // namespace folly
/*
* Copyright 2017 Facebook, Inc.
* Copyright 2017-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.
......@@ -32,11 +32,11 @@ void run_basic_test() {
std::chrono::steady_clock::now() + std::chrono::microseconds(1)));
ASSERT_FALSE(f.try_wait_until(
std::chrono::steady_clock::now() + std::chrono::microseconds(1),
f.wait_options().pre_block(std::chrono::microseconds(1))));
f.wait_options().spin_max(std::chrono::microseconds(1))));
f.post();
f.post();
f.wait();
f.wait(f.wait_options().pre_block(std::chrono::nanoseconds(100)));
f.wait(f.wait_options().spin_max(std::chrono::nanoseconds(100)));
ASSERT_TRUE(f.ready());
ASSERT_TRUE(f.try_wait());
ASSERT_TRUE(f.try_wait_until(
......@@ -98,7 +98,7 @@ void run_multi_poster_multi_waiter_test(int np, int nw) {
std::chrono::steady_clock::now() + std::chrono::microseconds(1)));
ASSERT_FALSE(f.try_wait_until(
std::chrono::steady_clock::now() + std::chrono::microseconds(1),
f.wait_options().pre_block(std::chrono::microseconds(0))));
f.wait_options().spin_max(std::chrono::microseconds(0))));
waited.fetch_add(1);
while (!go_wait.load()) {
/* spin */;
......@@ -110,7 +110,7 @@ void run_multi_poster_multi_waiter_test(int np, int nw) {
std::chrono::steady_clock::now() + std::chrono::microseconds(1)));
ASSERT_TRUE(f.try_wait_until(
std::chrono::steady_clock::now() + std::chrono::microseconds(1),
f.wait_options().pre_block(std::chrono::microseconds(0))));
f.wait_options().spin_max(std::chrono::microseconds(0))));
f.wait();
});
}
......
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