proxygen
MemoryIdler.h
Go to the documentation of this file.
1 /*
2  * Copyright 2014-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <algorithm>
20 #include <atomic>
21 #include <chrono>
22 
23 #include <folly/detail/Futex.h>
24 #include <folly/hash/Hash.h>
26 #include <folly/system/ThreadId.h>
27 
28 namespace folly {
29 namespace detail {
30 
38 struct MemoryIdler {
42  static void flushLocalMallocCaches();
43 
44  enum {
52  };
53 
57  static void unmapUnusedStack(size_t retain = kDefaultStackToRetain);
58 
65 
69  template <typename IdleTime = std::chrono::steady_clock::duration>
70  static IdleTime getVariationTimeout(
71  IdleTime const& idleTimeout =
72  defaultIdleTimeout.load(std::memory_order_acquire),
73  float timeoutVariationFrac = 0.5) {
74  if (idleTimeout <= IdleTime::zero() || timeoutVariationFrac <= 0) {
75  return idleTimeout;
76  }
77 
78  // hash the pthread_t and the time to get the adjustment
79  // Standard hash func isn't very good, so bit mix the result
82  std::chrono::system_clock::now().time_since_epoch().count()));
83 
84  // multiplying the duration by a floating point doesn't work, grr
85  auto extraFrac = timeoutVariationFrac /
86  static_cast<float>(std::numeric_limits<uint64_t>::max()) * h;
87  auto tics = uint64_t(idleTimeout.count() * (1 + extraFrac));
88  return IdleTime(tics);
89  }
90 
99  template <
100  typename Futex,
101  typename IdleTime = std::chrono::steady_clock::duration>
103  Futex& fut,
104  uint32_t expected,
105  uint32_t waitMask = -1,
106  IdleTime const& idleTimeout =
107  defaultIdleTimeout.load(std::memory_order_acquire),
108  size_t stackToRetain = kDefaultStackToRetain,
109  float timeoutVariationFrac = 0.5) {
110  FutexResult pre;
111  if (futexWaitPreIdle(
112  pre,
113  fut,
114  expected,
116  waitMask,
117  idleTimeout,
118  stackToRetain,
119  timeoutVariationFrac)) {
120  return pre;
121  }
122 
124  return futexWait(&fut, expected, waitMask);
125  }
126 
135  template <
136  typename Futex,
137  typename Deadline,
138  typename IdleTime = std::chrono::steady_clock::duration>
140  Futex& fut,
141  uint32_t expected,
142  Deadline const& deadline,
143  uint32_t waitMask = -1,
144  IdleTime const& idleTimeout =
145  defaultIdleTimeout.load(std::memory_order_acquire),
146  size_t stackToRetain = kDefaultStackToRetain,
147  float timeoutVariationFrac = 0.5) {
148  FutexResult pre;
149  if (futexWaitPreIdle(
150  pre,
151  fut,
152  expected,
153  deadline,
154  waitMask,
155  idleTimeout,
156  stackToRetain,
157  timeoutVariationFrac)) {
158  return pre;
159  }
160 
162  return futexWaitUntil(&fut, expected, deadline, waitMask);
163  }
164 
165  private:
166  template <typename Futex, typename Deadline, typename IdleTime>
167  static bool futexWaitPreIdle(
168  FutexResult& _ret,
169  Futex& fut,
170  uint32_t expected,
171  Deadline const& deadline,
172  uint32_t waitMask,
173  IdleTime idleTimeout,
174  size_t stackToRetain,
175  float timeoutVariationFrac) {
176  // idleTimeout < 0 means no flush behavior
177  if (idleTimeout < IdleTime::zero()) {
178  return false;
179  }
180 
181  // idleTimeout == 0 means flush immediately, without variation
182  // idleTimeout > 0 means flush after delay, with variation
183  if (idleTimeout > IdleTime::zero()) {
184  idleTimeout = std::max(
185  IdleTime::zero(),
186  getVariationTimeout(idleTimeout, timeoutVariationFrac));
187  }
188  if (idleTimeout > IdleTime::zero()) {
189  auto idleDeadline = Deadline::clock::now() + idleTimeout;
190  if (idleDeadline < deadline) {
192  auto rv = futexWaitUntil(&fut, expected, idleDeadline, waitMask);
193  if (rv != FutexResult::TIMEDOUT) {
194  // finished before timeout hit, no flush
195  _ret = rv;
196  return true;
197  }
198  }
199  }
200 
201  // flush, then wait
203  unmapUnusedStack(stackToRetain);
204  return false;
205  }
206 };
207 
208 } // namespace detail
209 } // namespace folly
static FutexResult futexWaitUntil(Futex &fut, uint32_t expected, Deadline const &deadline, uint32_t waitMask=-1, IdleTime const &idleTimeout=defaultIdleTimeout.load(std::memory_order_acquire), size_t stackToRetain=kDefaultStackToRetain, float timeoutVariationFrac=0.5)
Definition: MemoryIdler.h:139
*than *hazptr_holder h
Definition: Hazptr.h:116
static void unmapUnusedStack(size_t retain=kDefaultStackToRetain)
LogLevel max
Definition: LogLevel.cpp:31
static FutexResult futexWait(Futex &fut, uint32_t expected, uint32_t waitMask=-1, IdleTime const &idleTimeout=defaultIdleTimeout.load(std::memory_order_acquire), size_t stackToRetain=kDefaultStackToRetain, float timeoutVariationFrac=0.5)
Definition: MemoryIdler.h:102
static IdleTime getVariationTimeout(IdleTime const &idleTimeout=defaultIdleTimeout.load(std::memory_order_acquire), float timeoutVariationFrac=0.5)
Definition: MemoryIdler.h:70
std::chrono::steady_clock::time_point now()
Atom< std::uint32_t > Futex
Definition: Futex.h:51
T load(std::memory_order mo=std::memory_order_seq_cst) const noexcept
Definition: AtomicStruct.h:141
—— Concurrent Priority Queue Implementation ——
Definition: AtomicBitSet.h:29
FutexResult futexWait(const Futex *futex, uint32_t expected, uint32_t waitMask)
Definition: Futex-inl.h:100
static bool futexWaitPreIdle(FutexResult &_ret, Futex &fut, uint32_t expected, Deadline const &deadline, uint32_t waitMask, IdleTime idleTimeout, size_t stackToRetain, float timeoutVariationFrac)
Definition: MemoryIdler.h:167
size_t hash_combine(const T &t, const Ts &...ts) noexcept(noexcept(hash_combine_generic(StdHasher{}, t, ts...)))
Definition: Hash.h:669
FutexResult futexWaitUntil(const Futex *futex, uint32_t expected, std::chrono::time_point< Clock, Duration > const &deadline, uint32_t waitMask)
Definition: Futex-inl.h:112
int * count
uint64_t twang_mix64(uint64_t key) noexcept
Definition: Hash.h:49
uint64_t getCurrentThreadID()
Definition: ThreadId.h:42
static AtomicStruct< std::chrono::steady_clock::duration > defaultIdleTimeout
Definition: MemoryIdler.h:64
static void flushLocalMallocCaches()
Definition: MemoryIdler.cpp:41