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