MySQL 8.0.40
Source Code Documentation
large_page_alloc.h
Go to the documentation of this file.
1/*****************************************************************************
2
3Copyright (c) 2021, 2024, Oracle and/or its affiliates.
4
5This program is free software; you can redistribute it and/or modify it under
6the terms of the GNU General Public License, version 2.0, as published by the
7Free Software Foundation.
8
9This program is designed to work with certain software (including
10but not limited to OpenSSL) that is licensed under separate terms,
11as designated in a particular file or component or in included license
12documentation. The authors of MySQL hereby grant you an additional
13permission to link the program and your derivative works with the
14separately licensed software that they have either included with
15the program or referenced in the documentation.
16
17This program is distributed in the hope that it will be useful, but WITHOUT
18ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
19FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
20for more details.
21
22You should have received a copy of the GNU General Public License along with
23this program; if not, write to the Free Software Foundation, Inc.,
2451 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25
26*****************************************************************************/
27
28/** @file include/detail/ut/large_page_alloc.h
29 Implementation bits and pieces for large (huge) page allocations. */
30
31#ifndef detail_ut_large_page_alloc_h
32#define detail_ut_large_page_alloc_h
33
34#include <cstddef>
35#include <fstream>
36
37#include "my_compiler.h"
38#ifdef _WIN32
40#elif defined(__APPLE__)
42#elif defined(__sun)
44#else
46#endif
51
52extern const size_t large_page_default_size;
53
54namespace ut {
55namespace detail {
56
57/** Allocation routines which are purposed for allocating memory through the
58 means of what is known as large (huge) pages.
59
60 large_page_aligned_alloc() and large_page_aligned_free() are taking care of
61 OS specific details and Large_page_alloc is a convenience wrapper which only
62 makes the use of large pages more ergonomic so that it serializes the actual
63 size being allocated into the raw memory. This size is then automagically
64 deduced when large page memory is being freed. Otherwise, client code would
65 have been responsible to store and keep that value somewhere until it frees
66 the large page memory segment. Additionally, information on type of page
67 used to back up requested allocation is also serialized into the memory
68 allowing to build higher-kinded abstractions more easily. See
69 ut::malloc_large_page with option to fallback to regular pages through
70 ut::malloc_page.
71
72 Cost associated with this abstraction is the size of a single CPU page. In
73 terms of virtual memory, especially in 64-bit address space, this cost is
74 negligible. In practice this means that for each N huge-page sized
75 allocation request, application code will get to use CPU_PAGE_SIZE bytes
76 less. In other words, for a request that is backed up by three 2MiB
77 huge-pages, application code will get to use 3 * 2MiB - CPU_PAGE_SIZE of
78 total bytes. CPU_PAGE_SIZE is normally 4K but some architectures such as
79 SPARC have it set to 8K. ARM64 can be set to 4K, 8K or 64K.
80
81 Memory layout representation looks like the following:
82
83 -------------------------------------------
84 | PAGE-ALLOC-METADATA | ... DATA ... |
85 -------------------------------------------
86 ^ ^
87 | |
88 | |
89 | ptr (large-page) to be returned to call-site
90 |
91 --------------------------------
92 | DATALEN | PAGE-TYPE | VARLEN |
93 --------------------------------
94 \ \
95 0 \
96 CPU_PAGE_SIZE - 1
97
98 For details on DATALEN, PAGE-TYPE and VARLEN fields see Page_alloc_metadata.
99
100 DATA is an actual page-aligned (!) segment backed by large (huge) page
101 memory that will be returned to the call-site and which the client code will
102 be able to use for the application data.
103 */
104struct Large_page_alloc : public allocator_traits<false> {
106
107 /** Allocates memory through large-page support.
108
109 @param[in] size Size of storage (in bytes) requested to be allocated.
110 @return Pointer to the allocated storage. nullptr if allocation failed.
111 */
112 static inline void *alloc(std::size_t size) {
113 auto total_len = round_to_next_multiple(
115 auto mem = large_page_aligned_alloc(total_len);
116 if (unlikely(!mem)) return nullptr;
119 return static_cast<uint8_t *>(mem) + page_allocation_metadata::len;
120 }
121
122 /** Releases storage allocated through
123 Large_page_alloc::alloc().
124
125 @param[in] data Pointer to storage allocated through
126 Large_page_alloc::alloc()
127 @return True if releasing the memory was successful.
128 */
129 static inline bool free(void *data) noexcept {
130 if (unlikely(!data)) return false;
132 return large_page_aligned_free(deduce(data),
134 }
135
136 /** Returns the number of bytes that have been allocated.
137
138 @param[in] data Pointer to storage allocated through
139 Large_page_alloc::alloc()
140 @return Number of bytes.
141 */
146 }
147
148 /** Returns the type of the page.
149
150 @param[in] data Pointer to storage allocated through
151 Large_page_alloc::alloc()
152 @return Page type.
153 */
154 static inline Page_type page_type(void *data) {
156 }
157
158 /** Retrieves the pointer and size of the allocation provided by the OS. It is
159 a low level information, and is needed only to call low level
160 memory-related OS functions.
161
162 @param[in] data Pointer to storage allocated through
163 Large_page_alloc::alloc()
164 @return Low level allocation info.
165 */
166 static inline allocation_low_level_info low_level_info(void *data) {
168 return {deduce(data), page_allocation_metadata::datalen(data)};
169 }
170
171 private:
172 /** Helper function which deduces the original pointer returned by
173 Large_page_alloc from a pointer which is passed to us by the call-site.
174 */
175 static inline void *deduce(void *data) noexcept {
177 const auto res = reinterpret_cast<void *>(static_cast<uint8_t *>(data) -
179 ut_ad(reinterpret_cast<std::uintptr_t>(res) % large_page_size() == 0);
180 return res;
181 }
182};
183
184/** Allocation routines which are purposed for allocating memory through the
185 means of what is known as large (huge) pages. This is a PFS
186 (performance-schema) variant of Large_page_alloc. Implemented in terms
187 of Page_alloc_metadata_pfs.
188
189 large_page_aligned_alloc() and large_page_aligned_free() are taking care of
190 OS specific details and Large_page_alloc is a convenience wrapper which only
191 makes the use of large pages more ergonomic so that it serializes all the
192 relevant PFS details into the raw memory. Otherwise, client code would have
193 been responsible to store and keep those details somewhere until the memory
194 segment is freed. Additionally, information on type of page used to back up
195 requested allocation is also serialized into the memory allowing to build
196 higher-kinded abstractions more easily. See ut::malloc_large_page with
197 option to fallback to regular pages through ut::malloc_page.
198
199 Cost associated with this abstraction is the size of a single CPU page. In
200 terms of virtual memory, especially in 64-bit address space, this cost is
201 negligible. In practice this means that for each N huge-page sized
202 allocation request, application code will get to use CPU_PAGE_SIZE bytes
203 less. In other words, for a request that is backed up by three 2MiB
204 huge-pages, application code will get to use 3 * 2MiB - CPU_PAGE_SIZE of
205 total bytes. CPU_PAGE_SIZE is normally 4K but some architectures such as
206 SPARC have it set to 8K. ARM64 can be set to 4K, 8K or 64K.
207
208 Memory layout representation looks like the following:
209
210 ----------------------------------------------
211 | PAGE-ALLOC-METADATA-PFS | ... DATA ... |
212 ----------------------------------------------
213 ^ ^
214 | |
215 | |
216 | ptr (large-page) to be
217 | returned to call-site
218 |
219 ---------------------------------------------------
220 | PFS-META | PAGE-TYPE | VARLEN | PFS-META-OFFSET |
221 ---------------------------------------------------
222 ^ ^
223 | |
224 | ---------------------------
225 | | OWNER | DATALEN | KEY |
226 | ---------------------------
227 |
228 ptr returned by
229 large_page_aligned_alloc
230
231 For details on PFS-META, PAGE-TYPE, VARLEN and PFS-META-OFFSET fields
232 see Page_alloc_metadata_pfs.
233
234 DATA is an actual page-aligned (!) segment backed by large (huge) page
235 memory that will be returned to the call-site and which the client code will
236 be able to use for the application data.
237 */
240
241 /** Allocates memory through large-page support.
242
243 @param[in] size Size of storage (in bytes) requested to be allocated.
244 @param[in] key PSI memory key to be used for PFS memory instrumentation.
245 @return Pointer to the allocated storage. nullptr if allocation failed.
246 */
247 static inline void *alloc(
248 std::size_t size,
250 auto total_len = round_to_next_multiple(
252 auto mem = large_page_aligned_alloc(total_len);
253 if (unlikely(!mem)) return nullptr;
254
255#ifdef HAVE_PSI_MEMORY_INTERFACE
256 // The point of this allocator variant is to trace the memory allocations
257 // through PFS (PSI) so do it.
259 key = PSI_MEMORY_CALL(memory_alloc)(key, total_len, &owner);
260 // To be able to do the opposite action of tracing when we are releasing the
261 // memory, we need right about the same data we passed to the tracing
262 // memory_alloc function. Let's encode this it into our allocator so we
263 // don't have to carry and keep this data around.
270#endif
271
272 return static_cast<uint8_t *>(mem) + page_allocation_metadata::len;
273 }
274
275 /** Releases storage allocated through Large_page_alloc_pfs::alloc().
276
277 @param[in] data Pointer to storage allocated through
278 Large_page_alloc_pfs::alloc()
279 @return True if releasing the memory was successful.
280 */
281 static inline bool free(PFS_metadata::data_segment_ptr data) noexcept {
282 if (unlikely(!data)) return false;
284
285 PFS_metadata::pfs_datalen_t total_len = {};
286#ifdef HAVE_PSI_MEMORY_INTERFACE
287 // Deduce the PFS data we encoded in Large_page_alloc_pfs::alloc()
289 auto owner =
292 // With the deduced PFS data, now trace the memory release action.
294 (key, total_len, owner);
295#endif
296
297 return large_page_aligned_free(deduce(data), total_len);
298 }
299
300 /** Returns the number of bytes that have been allocated.
301
302 @param[in] data Pointer to storage allocated through
303 Large_page_alloc_pfs::alloc()
304 @return Number of bytes.
305 */
306 static inline size_t datalen(PFS_metadata::data_segment_ptr data) {
310 }
311
312 /** Returns the Page_type.
313
314 @param[in] data Pointer to storage allocated through
315 Large_page_alloc_pfs::alloc()
316 @return Page type.
317 */
320 }
321
322 /** Retrieves the pointer and size of the allocation provided by the OS. It is
323 a low level information, and is needed only to call low level
324 memory-related OS functions.
325
326 @param[in] data Pointer to storage allocated through
327 Large_page_alloc_pfs::alloc()
328 @return Low level allocation info.
329 */
330 static inline allocation_low_level_info low_level_info(void *data) {
332 return {deduce(data),
334 }
335
336 private:
337 /** Helper function which deduces the original pointer returned by
338 Large_page_alloc_pfs from a pointer which is passed to us by the
339 call-site.
340 */
341 static inline void *deduce(PFS_metadata::data_segment_ptr data) noexcept {
343 const auto res =
345 ut_ad(reinterpret_cast<std::uintptr_t>(res) % large_page_size() == 0);
346 return res;
347 }
348};
349
350/** Simple utility metafunction which selects appropriate allocator variant
351 (implementation) depending on the input parameter(s).
352 */
353template <bool Pfs_memory_instrumentation_on>
355 using type =
356 Large_page_alloc; // When PFS is OFF, pick ordinary, non-PFS, variant
357};
358
359template <>
361 using type = Large_page_alloc_pfs; // Otherwise, pick PFS variant
362};
363
364/** Just a small helper type which saves us some keystrokes. */
365template <bool Pfs_memory_instrumentation_on>
368
369/** Small wrapper which utilizes SFINAE to dispatch the call to appropriate
370 aligned allocator implementation.
371 */
372template <typename Impl>
374 template <typename T = Impl>
376 alloc(size_t size, PSI_memory_key key) {
377 return Impl::alloc(size, key);
378 }
379 template <typename T = Impl>
381 alloc(size_t size, PSI_memory_key /*key*/) {
382 return Impl::alloc(size);
383 }
384 static inline bool free(void *ptr) { return Impl::free(ptr); }
385 static inline size_t datalen(void *ptr) { return Impl::datalen(ptr); }
386 static inline Page_type page_type(void *ptr) { return Impl::page_type(ptr); }
387 static inline allocation_low_level_info low_level_info(void *ptr) {
388 return Impl::low_level_info(ptr);
389 }
390};
391
392} // namespace detail
393} // namespace ut
394
395#endif
Simple allocator traits.
#define PSI_MEMORY_CALL(M)
Definition: psi_memory.h:36
unsigned int PSI_memory_key
Instrumented memory key.
Definition: psi_memory_bits.h:49
Small helper functions.
Linux-specific implementation bits and pieces for large (huge) page allocations.
OSX-specific implementation bits and pieces for large (huge) page allocations.
Solaris-specific implementation bits and pieces for large (huge) page allocations.
Windows-specific implementation bits and pieces for large (huge) page allocations.
const size_t large_page_default_size
System-default huge (large) page setting.
Definition: ut0new.cc:40
#define free(A)
Definition: lexyy.cc:915
Header for compiler-dependent features.
constexpr bool unlikely(bool expr)
Definition: my_compiler.h:56
Definition: ut0tuple.h:57
static PSI_memory_key memory_alloc(PSI_memory_key, size_t, struct PSI_thread **owner)
Definition: psi_memory_v2_empty.cc:35
static void memory_free(PSI_memory_key, size_t, struct PSI_thread *)
Definition: psi_memory_v2_empty.cc:53
void * large_page_aligned_alloc(size_t n_bytes)
Allocates memory backed by large (huge) pages.
Definition: large_page_alloc-linux.h:52
Page_type
Types of pages currently supported by ut:: library functions.
Definition: page_metadata.h:43
typename select_large_page_alloc_impl< Pfs_memory_instrumentation_on >::type select_large_page_alloc_impl_t
Just a small helper type which saves us some keystrokes.
Definition: large_page_alloc.h:367
constexpr size_t round_to_next_multiple(size_t n, size_t m)
Calculates the next multiple of m that is bigger or equal to n.
Definition: helper.h:68
bool large_page_aligned_free(void *ptr, size_t n_bytes)
Releases memory backed by large (huge) pages.
Definition: large_page_alloc-linux.h:75
size_t large_page_size()
Queries the current size of large (huge) pages on running system.
Definition: large_page_alloc-linux.h:95
This file contains a set of libraries providing overloads for regular dynamic allocation routines whi...
Definition: aligned_alloc.h:48
Implementation bits and pieces for metadata for normal and large (huge) page allocations.
required string key
Definition: replication_asynchronous_connection_failover.proto:60
required string type
Definition: replication_group_member_actions.proto:34
static MEM_ROOT mem
Definition: sql_servers.cc:99
Implementation bits and pieces for PFS metadata handling.
Can be used to extract pointer and size of the allocation provided by the OS.
Definition: ut0new.h:140
Small wrapper which utilizes SFINAE to dispatch the call to appropriate aligned allocator implementat...
Definition: large_page_alloc.h:373
static bool free(void *ptr)
Definition: large_page_alloc.h:384
static std::enable_if<!T::is_pfs_instrumented_v, void * >::type alloc(size_t size, PSI_memory_key)
Definition: large_page_alloc.h:381
static Page_type page_type(void *ptr)
Definition: large_page_alloc.h:386
static std::enable_if< T::is_pfs_instrumented_v, void * >::type alloc(size_t size, PSI_memory_key key)
Definition: large_page_alloc.h:376
static size_t datalen(void *ptr)
Definition: large_page_alloc.h:385
static allocation_low_level_info low_level_info(void *ptr)
Definition: large_page_alloc.h:387
Allocation routines which are purposed for allocating memory through the means of what is known as la...
Definition: large_page_alloc.h:238
static allocation_low_level_info low_level_info(void *data)
Retrieves the pointer and size of the allocation provided by the OS.
Definition: large_page_alloc.h:330
static void * deduce(PFS_metadata::data_segment_ptr data) noexcept
Helper function which deduces the original pointer returned by Large_page_alloc_pfs from a pointer wh...
Definition: large_page_alloc.h:341
static void * alloc(std::size_t size, page_allocation_metadata::pfs_metadata::pfs_memory_key_t key)
Allocates memory through large-page support.
Definition: large_page_alloc.h:247
static size_t datalen(PFS_metadata::data_segment_ptr data)
Returns the number of bytes that have been allocated.
Definition: large_page_alloc.h:306
static Page_type page_type(PFS_metadata::data_segment_ptr data)
Returns the Page_type.
Definition: large_page_alloc.h:318
static bool free(PFS_metadata::data_segment_ptr data) noexcept
Releases storage allocated through Large_page_alloc_pfs::alloc().
Definition: large_page_alloc.h:281
Allocation routines which are purposed for allocating memory through the means of what is known as la...
Definition: large_page_alloc.h:104
static bool free(void *data) noexcept
Releases storage allocated through Large_page_alloc::alloc().
Definition: large_page_alloc.h:129
static void * deduce(void *data) noexcept
Helper function which deduces the original pointer returned by Large_page_alloc from a pointer which ...
Definition: large_page_alloc.h:175
static void * alloc(std::size_t size)
Allocates memory through large-page support.
Definition: large_page_alloc.h:112
static Page_type page_type(void *data)
Returns the type of the page.
Definition: large_page_alloc.h:154
static page_allocation_metadata::datalen_t datalen(void *data)
Returns the number of bytes that have been allocated.
Definition: large_page_alloc.h:142
static allocation_low_level_info low_level_info(void *data)
Retrieves the pointer and size of the allocation provided by the OS.
Definition: large_page_alloc.h:166
void * data_segment_ptr
Definition: pfs.h:94
std::size_t pfs_datalen_t
Definition: pfs.h:91
static void pfs_datalen(data_segment_ptr data, size_t datalen) noexcept
Helper function which stores the PFS datalen info into the DATALEN field.
Definition: pfs.h:109
static void pfs_key(data_segment_ptr data, pfs_memory_key_t key) noexcept
Helper function which stores the PFS key info into the KEY field.
Definition: pfs.h:115
PSI_thread * pfs_owning_thread_t
Convenience types that we will be using to serialize necessary details into the Aligned_alloc metadat...
Definition: pfs.h:90
static void pfs_owning_thread(data_segment_ptr data, pfs_owning_thread_t thread) noexcept
Helper function which stores the PFS thread info into the OWNER field.
Definition: pfs.h:103
static void pfs_metaoffset(data_segment_ptr data, std::size_t alignment) noexcept
Helper function which stores the offset to PFS metadata segment into the PFS-META-OFFSET field.
Definition: pfs.h:122
PSI_memory_key pfs_memory_key_t
Definition: pfs.h:92
static void * deduce_pfs_meta(data_segment_ptr data) noexcept
Helper function which deduces the pointer to the beginning of PFS metadata segment given the pointer ...
Definition: pfs.h:156
Helper struct implementing the type which represents the metadata for all types of PFS-aware page-ali...
Definition: page_metadata.h:198
static constexpr auto len
This is how much this metadata segment will be big.
Definition: page_metadata.h:203
static Page_type page_type(void *data)
Sanity check so that we can be sure that the size of our metadata segment is such so that the pointer...
Definition: page_metadata.h:221
Helper struct implementing the type which represents the metadata for all types of page-aligned alloc...
Definition: page_metadata.h:75
static constexpr auto len
This is how much tise metadata segment will be big.
Definition: page_metadata.h:77
static Page_type page_type(void *data)
Accessor to the page_type_t field.
Definition: page_metadata.h:110
static datalen_t datalen(void *data)
Sanity check so that we can be sure that the size of our metadata segment is such so that the next se...
Definition: page_metadata.h:101
size_t datalen_t
These are the types representing our memory fields.
Definition: page_metadata.h:80
Simple allocator traits.
Definition: allocator_traits.h:82
Simple utility metafunction which selects appropriate allocator variant (implementation) depending on...
Definition: large_page_alloc.h:354
#define ut_ad(EXPR)
Debug assertion.
Definition: ut0dbg.h:69