Seastar
High performance C++ framework for concurrent servers
memory.hh
1 /*
2  * This file is open source software, licensed to you under the terms
3  * of the Apache License, Version 2.0 (the "License"). See the NOTICE file
4  * distributed with this work for additional information regarding copyright
5  * ownership. You may not use this file except in compliance with the License.
6  *
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing,
12  * software distributed under the License is distributed on an
13  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14  * KIND, either express or implied. See the License for the
15  * specific language governing permissions and limitations
16  * under the License.
17  */
18 /*
19  * Copyright (C) 2014 Cloudius Systems, Ltd.
20  */
21 
22 #pragma once
23 
24 #include <seastar/core/resource.hh>
25 #include <seastar/core/bitops.hh>
26 #include <seastar/util/modules.hh>
27 #ifndef SEASTAR_MODULE
28 #include <new>
29 #include <cstdint>
30 #include <functional>
31 #include <optional>
32 #include <string>
33 #include <vector>
34 #endif
35 
36 namespace seastar {
37 
48 
121 namespace memory {
122 
124 
125 #ifdef SEASTAR_OVERRIDE_ALLOCATOR_PAGE_SIZE
126 #define SEASTAR_INTERNAL_ALLOCATOR_PAGE_SIZE (SEASTAR_OVERRIDE_ALLOCATOR_PAGE_SIZE)
127 #else
128 #define SEASTAR_INTERNAL_ALLOCATOR_PAGE_SIZE 4096
129 #endif
130 
131 static constexpr size_t page_size = SEASTAR_INTERNAL_ALLOCATOR_PAGE_SIZE;
132 static constexpr size_t page_bits = log2ceil(page_size);
133 static constexpr size_t huge_page_size =
134 #if defined(__x86_64__) || defined(__i386__) || defined(__s390x__) || defined(__zarch__)
135  1 << 21; // 2M
136 #elif defined(__aarch64__)
137  1 << 21; // 2M
138 #elif defined(__PPC__)
139  1 << 24; // 16M
140 #else
141 #error "Huge page size is not defined for this architecture"
142 #endif
143 
144 
145 namespace internal {
146 
147 struct memory_range {
148  char* start;
149  char* end;
150  unsigned numa_node_id;
151 };
152 
153 struct numa_layout {
154  std::vector<memory_range> ranges;
155 };
156 
157 numa_layout merge(numa_layout one, numa_layout two);
158 
159 }
160 
161 internal::numa_layout configure(std::vector<resource::memory> m, bool mbind,
162  bool transparent_hugepages,
163  std::optional<std::string> hugetlbfs_path = {});
164 
165 // A deprecated alias for set_abort_on_allocation_failure(true).
166 [[deprecated("use set_abort_on_allocation_failure(true) instead")]]
167 void enable_abort_on_allocation_failure();
168 
169 class disable_abort_on_alloc_failure_temporarily {
170 public:
171  disable_abort_on_alloc_failure_temporarily();
172  ~disable_abort_on_alloc_failure_temporarily() noexcept;
173 };
174 
175 // Disables heap profiling as long as this object is alive.
176 // Can be nested, in which case the profiling is re-enabled when all
177 // the objects go out of scope.
178 class disable_backtrace_temporarily {
179  bool _old;
180 public:
181  disable_backtrace_temporarily();
182  ~disable_backtrace_temporarily();
183 };
184 
185 enum class reclaiming_result {
186  reclaimed_nothing,
187  reclaimed_something
188 };
189 
190 // Determines when reclaimer can be invoked
191 enum class reclaimer_scope {
192  //
193  // Reclaimer is only invoked in its own fiber. That fiber will be
194  // given higher priority than regular application fibers.
195  //
196  async,
197 
198  //
199  // Reclaimer may be invoked synchronously with allocation.
200  // It may also be invoked in async scope.
201  //
202  // Reclaimer may invoke allocation, though it is discouraged because
203  // the system may be low on memory and such allocations may fail.
204  // Reclaimers which allocate should be prepared for re-entry.
205  //
206  sync
207 };
208 
209 class reclaimer {
210 public:
211  struct request {
212  // The number of bytes which is needed to be released.
213  // The reclaimer can release a different amount.
214  // If less is released then the reclaimer may be invoked again.
215  size_t bytes_to_reclaim;
216  };
217  using reclaim_fn = std::function<reclaiming_result ()>;
218 private:
219  std::function<reclaiming_result (request)> _reclaim;
220  reclaimer_scope _scope;
221 public:
222  // Installs new reclaimer which will be invoked when system is falling
223  // low on memory. 'scope' determines when reclaimer can be executed.
224  reclaimer(std::function<reclaiming_result ()> reclaim, reclaimer_scope scope = reclaimer_scope::async);
225  reclaimer(std::function<reclaiming_result (request)> reclaim, reclaimer_scope scope = reclaimer_scope::async);
226  ~reclaimer();
227  reclaiming_result do_reclaim(size_t bytes_to_reclaim) { return _reclaim(request{bytes_to_reclaim}); }
228  reclaimer_scope scope() const { return _scope; }
229 };
230 
231 extern std::pmr::polymorphic_allocator<char>* malloc_allocator;
232 
233 // Call periodically to recycle objects that were freed
234 // on cpu other than the one they were allocated on.
235 //
236 // Returns @true if any work was actually performed.
237 bool drain_cross_cpu_freelist();
238 
239 
240 // We don't want the memory code calling back into the rest of
241 // the system, so allow the rest of the system to tell the memory
242 // code how to initiate reclaim.
243 //
244 // When memory is low, calling \c hook(fn) will result in fn being called
245 // in a safe place wrt. allocations.
246 void set_reclaim_hook(
247  std::function<void (std::function<void ()>)> hook);
248 
250 
251 SEASTAR_MODULE_EXPORT_BEGIN
252 
269 
276 
277 class statistics;
278 
281 
283 class statistics {
284  uint64_t _mallocs;
285  uint64_t _frees;
286  uint64_t _cross_cpu_frees;
287  size_t _total_memory;
288  size_t _free_memory;
289  uint64_t _reclaims;
290  uint64_t _large_allocs;
291  uint64_t _failed_allocs;
292 
293  uint64_t _foreign_mallocs;
294  uint64_t _foreign_frees;
295  uint64_t _foreign_cross_frees;
296 private:
297  statistics(uint64_t mallocs, uint64_t frees, uint64_t cross_cpu_frees,
298  uint64_t total_memory, uint64_t free_memory, uint64_t reclaims,
299  uint64_t large_allocs, uint64_t failed_allocs,
300  uint64_t foreign_mallocs, uint64_t foreign_frees, uint64_t foreign_cross_frees)
301  : _mallocs(mallocs), _frees(frees), _cross_cpu_frees(cross_cpu_frees)
302  , _total_memory(total_memory), _free_memory(free_memory), _reclaims(reclaims)
303  , _large_allocs(large_allocs), _failed_allocs(failed_allocs)
304  , _foreign_mallocs(foreign_mallocs), _foreign_frees(foreign_frees)
305  , _foreign_cross_frees(foreign_cross_frees) {}
306 public:
308  uint64_t mallocs() const { return _mallocs; }
310  uint64_t frees() const { return _frees; }
313  uint64_t cross_cpu_frees() const { return _cross_cpu_frees; }
315  size_t live_objects() const { return mallocs() - frees(); }
317  size_t free_memory() const { return _free_memory; }
319  size_t allocated_memory() const { return _total_memory - _free_memory; }
321  size_t total_memory() const { return _total_memory; }
323  uint64_t reclaims() const { return _reclaims; }
325  uint64_t large_allocations() const { return _large_allocs; }
328  uint64_t failed_allocations() const { return _failed_allocs; }
330  uint64_t foreign_mallocs() const { return _foreign_mallocs; }
332  uint64_t foreign_frees() const { return _foreign_frees; }
334  uint64_t foreign_cross_frees() const { return _foreign_cross_frees; }
335  friend statistics stats();
336 };
337 
339  uintptr_t start;
340  uintptr_t end;
341 };
342 
343 // Discover virtual address range used by the allocator on current shard.
344 // Supported only when seastar allocator is enabled.
345 memory::memory_layout get_memory_layout();
346 
348 size_t free_memory();
349 
353 
355 void set_min_free_pages(size_t pages);
356 
363 
366 
369 
372  size_t _old_threshold;
373 public:
374  explicit scoped_large_allocation_warning_threshold(size_t threshold)
375  : _old_threshold(get_large_allocation_warning_threshold()) {
377  }
381  if (_old_threshold) {
383  }
384  }
385  void operator=(const scoped_large_allocation_warning_threshold&) const = delete;
386  void operator=(scoped_large_allocation_warning_threshold&&) = delete;
387 };
388 
391  size_t _old_threshold;
392 public:
394  : _old_threshold(get_large_allocation_warning_threshold()) {
396  }
400  if (_old_threshold) {
402  }
403  }
404  void operator=(const scoped_large_allocation_warning_disable&) const = delete;
405  void operator=(scoped_large_allocation_warning_disable&&) = delete;
406 };
407 
421 
427 public:
428  scoped_heap_profiling() noexcept;
430 };
431 
432 SEASTAR_MODULE_EXPORT_END
433 
434 }
435 }
Disable large allocation warnings for a scope.
Definition: memory.hh:390
Set a different large allocation warning threshold for a scope.
Definition: memory.hh:371
Memory allocation statistics.
Definition: memory.hh:283
uint64_t failed_allocations() const
Definition: memory.hh:328
uint64_t foreign_frees() const
Number of foreign frees.
Definition: memory.hh:332
uint64_t cross_cpu_frees() const
Definition: memory.hh:313
size_t total_memory() const
Total memory (in bytes)
Definition: memory.hh:321
uint64_t large_allocations() const
Number of allocations which violated the large allocation threshold.
Definition: memory.hh:325
uint64_t mallocs() const
Total number of memory allocations calls since the system was started.
Definition: memory.hh:308
uint64_t reclaims() const
Number of reclaims performed due to low memory.
Definition: memory.hh:323
size_t live_objects() const
Total number of objects which were allocated but not freed.
Definition: memory.hh:315
uint64_t frees() const
Total number of memory deallocations calls since the system was started.
Definition: memory.hh:310
friend statistics stats()
Capture a snapshot of memory allocation statistics for this lcore.
uint64_t foreign_mallocs() const
Number of foreign allocations.
Definition: memory.hh:330
size_t free_memory() const
Total free memory (in bytes)
Definition: memory.hh:317
size_t allocated_memory() const
Total allocated memory (in bytes)
Definition: memory.hh:319
uint64_t foreign_cross_frees() const
Number of foreign frees on reactor threads.
Definition: memory.hh:334
futurize_t< std::invoke_result_t< Func, Args... > > async(thread_attributes attr, Func &&func, Args &&... args) noexcept
Definition: thread.hh:247
size_t free_memory()
Returns the size of free memory in bytes.
void set_large_allocation_warning_threshold(size_t threshold)
size_t get_large_allocation_warning_threshold()
Gets the current large allocation warning threshold.
statistics stats()
Capture a snapshot of memory allocation statistics for this lcore.
void set_min_free_pages(size_t pages)
Sets the value of free memory low water mark in memory::page_size units.
size_t min_free_memory()
void set_heap_profiling_enabled(bool)
void set_abort_on_allocation_failure(bool enabled)
Set the global state of the abort on allocation failure behavior.
bool is_abort_on_allocation_failure()
Determine the abort on allocation failure mode.
void disable_large_allocation_warning()
Disable large allocation warnings.
Definition: memory.hh:338
future configure(const options &opts)
set the metrics configuration
Seastar API namespace.
Definition: abort_on_ebadf.hh:26