1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 
6 #pragma once
7 
8 #include <chrono>
9 
10 namespace folly {
11 
12 /// WaitOptions
13 ///
14 /// Various synchronization primitives as well as various concurrent data
15 /// structures built using them have operations which might wait. This type
16 /// represents a set of options for controlling such waiting.
17 class WaitOptions {
18  public:
19   struct Defaults {
20     /// spin_max
21     ///
22     /// If multiple threads are actively using a synchronization primitive,
23     /// whether indirectly via a higher-level concurrent data structure or
24     /// directly, where the synchronization primitive has an operation which
25     /// waits and another operation which wakes the waiter, it is common for
26     /// wait and wake events to happen almost at the same time. In this state,
27     /// we lose big 50% of the time if the wait blocks immediately.
28     ///
29     /// We can improve our chances of being waked immediately, before blocking,
30     /// by spinning for a short duration, although we have to balance this
31     /// against the extra cpu utilization, latency reduction, power consumption,
32     /// and priority inversion effect if we end up blocking anyway.
33     ///
34     /// We use a default maximum of 2 usec of spinning. As partial consolation,
35     /// since spinning as implemented in folly uses the pause instruction where
36     /// available, we give a small speed boost to the colocated hyperthread.
37     ///
38     /// On circa-2013 devbox hardware, it costs about 7 usec to FUTEX_WAIT and
39     /// then be awoken. Spins on this hw take about 7 nsec, where all but 0.5
40     /// nsec is the pause instruction.
41     static constexpr std::chrono::nanoseconds spin_max =
42         std::chrono::microseconds(2);
43   };
44 
spin_max()45   std::chrono::nanoseconds spin_max() const {
46     return spin_max_;
47   }
spin_max(std::chrono::nanoseconds dur)48   WaitOptions& spin_max(std::chrono::nanoseconds dur) {
49     spin_max_ = dur;
50     return *this;
51   }
52 
53  private:
54   std::chrono::nanoseconds spin_max_ = Defaults::spin_max;
55 };
56 
57 } // namespace folly
58