MySQL 8.3.0
Source Code Documentation
ut0new.h
Go to the documentation of this file.
1/*****************************************************************************
2
3Copyright (c) 2014, 2023, 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 also distributed with certain software (including but not
10limited to OpenSSL) that is licensed under separate terms, as designated in a
11particular file or component or in included license documentation. The authors
12of MySQL hereby grant you an additional permission to link the program and
13your derivative works with the separately licensed software that they have
14included with MySQL.
15
16This program is distributed in the hope that it will be useful, but WITHOUT
17ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18FOR A PARTICULAR PURPOSE. See the GNU General Public License, version 2.0,
19for more details.
20
21You should have received a copy of the GNU General Public License along with
22this program; if not, write to the Free Software Foundation, Inc.,
2351 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
25*****************************************************************************/
26
27/** @file include/ut0new.h
28 Dynamic memory allocation routines and custom allocators specifically
29 crafted to support memory instrumentation through performance schema memory
30 engine (PFS).
31 */
32
33/** This file contains a set of libraries providing overloads for regular
34 dynamic allocation routines which allow for opt-in memory instrumentation
35 through performance schema memory engine (PFS).
36
37 In particular, _no_ regular dynamic allocation routines shall be used given
38 that the end goal of instrumentation through PFS is system observability
39 and resource control. In practice this means that we are off the chances to
40 use _any_ standard means of allocating the memory and that we have to
41 provide and re-implement our own PFS-aware variants ourselves.
42
43 This does not only apply to direct memory allocation through malloc or new
44 but also to data structures that may allocate dynamic memory under the hood,
45 like the ones from STL. For that reason, STL data structures shall always
46 be used with PFS-enabled custom memory allocator. STL algorithms OTOH
47 also _may_ allocate dynamic memory but they do not provide customization
48 point for user-code to provide custom memory allocation mechanism so there's
49 nothing that we can do about it.
50
51 Furthermore, facilities that allow safer memory management such as
52 std::unique_ptr, std::shared_ptr and their respective std::make_unique and
53 std::make_shared functions also have to be re-implemented as such so that
54 they become PFS-aware.
55
56 Following is the list of currently implemented PFS-enabled dynamic
57 allocation overloads and associated facilities:
58 * Primitive allocation functions:
59 * ut::malloc
60 * ut::zalloc
61 * ut::realloc
62 * ut::free
63 * ut::{malloc | zalloc | realloc}_withkey
64 * Primitive allocation functions for types with extended alignment:
65 * ut::aligned_alloc
66 * ut::aligned_zalloc
67 * ut::aligned_free
68 * ut::{aligned_alloc | aligned_zalloc}_withkey
69 * Primitive allocation functions for page-aligned allocations:
70 * ut::malloc_page
71 * ut::malloc_page_withkey
72 * ut::free_page
73 * Primitive allocation functions for large (huge) page aligned
74 allocations:
75 * ut::malloc_large_page
76 * ut::malloc_large_page_withkey
77 * ut::free_large_page
78 * Primitive allocation functions for large (huge) aligned allocations with
79 fallback to page-aligned allocations:
80 * ut::malloc_large_page(fallback_to_normal_page_t)
81 * ut::malloc_large_page_withkey(fallback_to_normal_page_t)
82 * ut::free_large_page(fallback_to_normal_page_t)
83 * Overloads for C++ new and delete syntax:
84 * ut::new_
85 * ut::new_arr
86 * ut::{new_ | new_arr_}_withkey
87 * ut::delete_
88 * ut::delete_arr
89 * Overloads for C++ new and delete syntax for types with extended
90 alignment:
91 * ut::aligned_new
92 * ut::aligned_new_arr
93 * ut::{aligned_new_ | aligned_new_arr_}_withkey
94 * ut::aligned_delete
95 * ut::aligned_delete_arr
96 * Custom memory allocators:
97 * ut::allocator
98 * Overloads for std::unique_ptr and std::shared_ptr factory functions
99 * ut::make_unique
100 * ut::make_unique_aligned
101 * ut::make_shared
102 * ut::make_shared_aligned
103 _withkey variants from above are the PFS-enabled dynamic allocation
104 overloads.
105
106 Usages of PFS-enabled library functions are trying to resemble already
107 familiar syntax as close as possible. For concrete examples please see
108 particular function documentation but in general it applies that ::foo(x)
109 becomes ut::foo(x) or ut::foo_withkey(key, x) where foo is some allocation
110 function listed above and key is PFS key to instrument the allocation with.
111*/
112
113#ifndef ut0new_h
114#define ut0new_h
115
116#include <algorithm>
117#include <cerrno>
118#include <cstddef>
119#include <cstdlib>
120#include <cstring>
121#include <limits>
122#include <list>
123#include <map>
124#include <memory>
125#include <set>
126#include <type_traits> /* std::is_trivially_default_constructible */
127#include <unordered_map>
128#include <unordered_set>
129
130#include "my_basename.h"
133#include "mysql/psi/psi_memory.h"
134
135namespace ut {
136/** Can be used to extract pointer and size of the allocation provided by the
137OS. It is a low level information, and is needed only to call low level
138memory-related OS functions. */
140 /** A pointer returned by the OS allocator. */
141 void *base_ptr;
142 /** The size of allocation that OS performed. */
144};
145} // namespace ut
146
147#include "detail/ut0new.h"
148#include "os0proc.h"
149#include "os0thread.h"
150#include "univ.i"
151#include "ut0byte.h" /* ut_align */
152#include "ut0cpu_cache.h"
153#include "ut0dbg.h"
154#include "ut0ut.h"
155
156namespace ut {
157
158/** Light-weight and type-safe wrapper around the PSI_memory_key
159 that eliminates the possibility of introducing silent bugs
160 through the course of implicit conversions and makes them
161 show up as compile-time errors.
162
163 Without this wrapper it was possible to say:
164 aligned_alloc_withkey(10*sizeof(int), key, 64))
165 Which would unfortunately compile just fine but it would silently
166 introduce a bug because it confuses the order of 10*sizeof(int) and
167 key input arguments. Both of them are unsigned types.
168
169 With the wrapper, aligned_alloc_withkey(10*sizeof(int), key, 64)) now
170 results with a compile-time error and the only proper way to accomplish
171 the original intent is to use PSI_memory_key_t wrapper like so:
172 aligned_alloc_withkey(PSI_memory_key_t{key}, 10*sizeof(int), 64))
173
174 Or by making use of the convenience function to create one:
175 aligned_alloc_withkey(make_psi_memory_key(key), 10*sizeof(int), 64))
176*/
179 PSI_memory_key operator()() const { return m_key; }
181};
182
183/** Convenience helper function to create type-safe representation of
184 PSI_memory_key.
185
186 @param[in] key PSI memory key to be held in type-safe PSI_memory_key_t.
187 @return PSI_memory_key_t which wraps the given PSI_memory_key
188 */
190 return PSI_memory_key_t(key);
191}
192
193} // namespace ut
194
195/** Maximum number of retries to allocate memory. */
196extern const size_t alloc_max_retries;
197
198/** Keys for registering allocations with performance schema.
199Pointers to these variables are supplied to PFS code via the pfs_info[]
200array and the PFS code initializes them via PSI_MEMORY_CALL(register_memory)().
201mem_key_other and mem_key_std are special in the following way.
202* If the caller has not provided a key and the file name of the caller is
203 unknown, then mem_key_std will be used. This happens only when called from
204 within std::* containers.
205* If the caller has not provided a key and the file name of the caller is
206 known, but is not amongst the predefined names (see ut_new_boot()) then
207 mem_key_other will be used. Generally this should not happen and if it
208 happens then that means that the list of predefined names must be extended.
209Keep this list alphabetically sorted. */
214/** Memory key for clone */
229/* Please obey alphabetical order in the definitions above. */
230
231/** Setup the internal objects needed for ut::*_withkey() to operate.
232This must be called before the first call to ut::*_withkey(). */
233void ut_new_boot();
234
235/** Setup the internal objects needed for ut::*_withkey() to operate.
236This must be called before the first call to ut::*_withkey(). This
237version of function might be called several times and it will
238simply skip all calls except the first one, during which the
239initialization will happen. */
240void ut_new_boot_safe();
241
242#ifdef UNIV_PFS_MEMORY
243
244/** List of filenames that allocate memory and are instrumented via PFS. */
245static constexpr const char *auto_event_names[] = {
246 /* Keep this list alphabetically sorted. */
247 "api0api",
248 "api0misc",
249 "btr0btr",
250 "btr0cur",
251 "btr0load",
252 "btr0pcur",
253 "btr0sea",
254 "btr0types",
255 "buf",
256 "buf0buddy",
257 "buf0buf",
258 "buf0checksum",
259 "buf0dblwr",
260 "buf0dump",
261 "buf0flu",
262 "buf0lru",
263 "buf0rea",
264 "buf0stats",
265 "buf0types",
266 "checksum",
267 "crc32",
268 "create",
269 "data0data",
270 "data0type",
271 "data0types",
272 "db0err",
273 "ddl0buffer",
274 "ddl0builder",
275 "ddl0ctx",
276 "ddl0ddl",
277 "ddl0file-reader",
278 "ddl0loader",
279 "ddl0merge",
280 "ddl0rtree",
281 "ddl0par-scan",
282 "dict",
283 "dict0boot",
284 "dict0crea",
285 "dict0dd",
286 "dict0dict",
287 "dict0load",
288 "dict0mem",
289 "dict0priv",
290 "dict0sdi",
291 "dict0stats",
292 "dict0stats_bg",
293 "dict0types",
294 "dyn0buf",
295 "dyn0types",
296 "eval0eval",
297 "eval0proc",
298 "fil0fil",
299 "fil0types",
300 "file",
301 "fsp0file",
302 "fsp0fsp",
303 "fsp0space",
304 "fsp0sysspace",
305 "fsp0types",
306 "fts0ast",
307 "fts0blex",
308 "fts0config",
309 "fts0fts",
310 "fts0opt",
311 "fts0pars",
312 "fts0plugin",
313 "fts0priv",
314 "fts0que",
315 "fts0sql",
316 "fts0tlex",
317 "fts0tokenize",
318 "fts0types",
319 "fts0vlc",
320 "fut0fut",
321 "fut0lst",
322 "gis0geo",
323 "gis0rtree",
324 "gis0sea",
325 "gis0type",
326 "ha0ha",
327 "ha0storage",
328 "ha_innodb",
329 "ha_innopart",
330 "ha_prototypes",
331 "handler0alter",
332 "hash0hash",
333 "i_s",
334 "ib0mutex",
335 "ibuf0ibuf",
336 "ibuf0types",
337 "lexyy",
338 "lob0lob",
339 "lock0iter",
340 "lock0lock",
341 "lock0prdt",
342 "lock0priv",
343 "lock0types",
344 "lock0wait",
345 "log0log",
346 "log0recv",
347 "log0write",
348 "mach0data",
349 "mem",
350 "mem0mem",
351 "memory",
352 "mtr0log",
353 "mtr0mtr",
354 "mtr0types",
355 "os0atomic",
356 "os0event",
357 "os0file",
358 "os0numa",
359 "os0once",
360 "os0proc",
361 "os0thread",
362 "page",
363 "page0cur",
364 "page0page",
365 "page0size",
366 "page0types",
367 "page0zip",
368 "pars0grm",
369 "pars0lex",
370 "pars0opt",
371 "pars0pars",
372 "pars0sym",
373 "pars0types",
374 "que0que",
375 "que0types",
376 "read0read",
377 "read0types",
378 "rec",
379 "rem0cmp",
380 "rem0rec",
381 "rem0types",
382 "row0ext",
383 "row0ft",
384 "row0import",
385 "row0ins",
386 "row0log",
387 "row0mysql",
388 "row0purge",
389 "row0quiesce",
390 "row0row",
391 "row0sel",
392 "row0types",
393 "row0uins",
394 "row0umod",
395 "row0undo",
396 "row0upd",
397 "row0vers",
398 "sess0sess",
399 "srv0conc",
400 "srv0mon",
401 "srv0srv",
402 "srv0start",
403 "srv0tmp",
404 "sync0arr",
405 "sync0debug",
406 "sync0policy",
407 "sync0sharded_rw",
408 "sync0rw",
409 "sync0sync",
410 "sync0types",
411 "trx0i_s",
412 "trx0purge",
413 "trx0rec",
414 "trx0roll",
415 "trx0rseg",
416 "trx0sys",
417 "trx0trx",
418 "trx0types",
419 "trx0undo",
420 "trx0xa",
421 "usr0sess",
422 "usr0types",
423 "ut",
424 "ut0byte",
425 "ut0counter",
426 "ut0crc32",
427 "ut0dbg",
428 "ut0link_buf",
429 "ut0list",
430 "ut0lock_free_hash",
431 "ut0lst",
432 "ut0mem",
433 "ut0mutex",
434 "ut0new",
435 "ut0pool",
436 "ut0rbt",
437 "ut0rnd",
438 "ut0sort",
439 "ut0stage",
440 "ut0ut",
441 "ut0vec",
442 "ut0wqueue",
443 "zipdecompress",
444};
445
446static constexpr size_t n_auto = UT_ARR_SIZE(auto_event_names);
449
450/** gcc 5 fails to evaluate costexprs at compile time. */
451#if defined(__GNUG__) && (__GNUG__ == 5)
452
453/** Compute whether a string begins with a given prefix, compile-time.
454@param[in] a first string, taken to be zero-terminated
455@param[in] b second string (prefix to search for)
456@param[in] b_len length in bytes of second string
457@param[in] index character index to start comparing at
458@return whether b is a prefix of a */
459constexpr bool ut_string_begins_with(const char *a, const char *b, size_t b_len,
460 size_t index = 0) {
461 return (index == b_len || (a[index] == b[index] &&
462 ut_string_begins_with(a, b, b_len, index + 1)));
463}
464
465/** Find the length of the filename without its file extension.
466@param[in] file filename, with extension but without directory
467@param[in] index character index to start scanning for extension
468 separator at
469@return length, in bytes */
470constexpr size_t ut_len_without_extension(const char *file, size_t index = 0) {
471 return ((file[index] == '\0' || file[index] == '.')
472 ? index
473 : ut_len_without_extension(file, index + 1));
474}
475
476/** Retrieve a memory key (registered with PFS), given the file name of the
477caller.
478@param[in] file portion of the filename - basename, with extension
479@param[in] len length of the filename to check for
480@param[in] index index of first PSI key to check
481@return registered memory key or PSI_NOT_INSTRUMENTED if not found */
483 size_t len,
484 size_t index = 0) {
485 return ((index == n_auto)
488 ? auto_event_keys[index]
489 : ut_new_get_key_by_base_file(file, len, index + 1)));
490}
491
492/** Retrieve a memory key (registered with PFS), given the file name of
493the caller.
494@param[in] file portion of the filename - basename, with extension
495@return registered memory key or PSI_NOT_INSTRUMENTED if not found */
496constexpr PSI_memory_key ut_new_get_key_by_file(const char *file) {
498}
499
500#define UT_NEW_THIS_FILE_PSI_KEY ut_new_get_key_by_file(MY_BASENAME)
501
502#else /* __GNUG__ == 5 */
503
504/** Compute whether a string begins with a given prefix, compile-time.
505@param[in] a first string, taken to be zero-terminated
506@param[in] b second string (prefix to search for)
507@param[in] b_len length in bytes of second string
508@return whether b is a prefix of a */
509constexpr bool ut_string_begins_with(const char *a, const char *b,
510 size_t b_len) {
511 for (size_t i = 0; i < b_len; ++i) {
512 if (a[i] != b[i]) {
513 return false;
514 }
515 }
516 return true;
517}
518
519/** Find the length of the filename without its file extension.
520@param[in] file filename, with extension but without directory
521@return length, in bytes */
522constexpr size_t ut_len_without_extension(const char *file) {
523 for (size_t i = 0;; ++i) {
524 if (file[i] == '\0' || file[i] == '.') {
525 return i;
526 }
527 }
528}
529
530/** Retrieve a memory key (registered with PFS), given the file name of the
531caller.
532@param[in] file portion of the filename - basename, with extension
533@param[in] len length of the filename to check for
534@return index to registered memory key or -1 if not found */
535constexpr int ut_new_get_key_by_base_file(const char *file, size_t len) {
536 for (size_t i = 0; i < n_auto; ++i) {
538 return static_cast<int>(i);
539 }
540 }
541 return -1;
542}
543
544/** Retrieve a memory key (registered with PFS), given the file name of
545the caller.
546@param[in] file portion of the filename - basename, with extension
547@return index to memory key or -1 if not found */
548constexpr int ut_new_get_key_by_file(const char *file) {
550}
551
552// Sending an expression through a template variable forces the compiler to
553// evaluate the expression at compile time (constexpr in itself has no such
554// guarantee, only that the compiler is allowed).
555template <int Value>
557 static constexpr int value = Value;
558};
559
560#define UT_NEW_THIS_FILE_PSI_INDEX \
561 (force_constexpr<ut_new_get_key_by_file(MY_BASENAME)>::value)
562
563#define UT_NEW_THIS_FILE_PSI_KEY \
564 (UT_NEW_THIS_FILE_PSI_INDEX == -1 \
565 ? ut::make_psi_memory_key(PSI_NOT_INSTRUMENTED) \
566 : ut::make_psi_memory_key(auto_event_keys[UT_NEW_THIS_FILE_PSI_INDEX]))
567
568#endif /* __GNUG__ == 5 */
569
570#else
571
572#define UT_NEW_THIS_FILE_PSI_KEY ut::make_psi_memory_key(PSI_NOT_INSTRUMENTED)
573
574#endif /* UNIV_PFS_MEMORY */
575
576namespace ut {
577
578#ifdef HAVE_PSI_MEMORY_INTERFACE
579constexpr bool WITH_PFS_MEMORY = true;
580#else
581constexpr bool WITH_PFS_MEMORY = false;
582#endif
583
584/** Dynamically allocates storage of given size. Instruments the memory with
585 given PSI memory key in case PFS memory support is enabled.
586
587 @param[in] key PSI memory key to be used for PFS memory instrumentation.
588 @param[in] size Size of storage (in bytes) requested to be allocated.
589 @return Pointer to the allocated storage. nullptr if dynamic storage
590 allocation failed.
591
592 Example:
593 int *x = static_cast<int*>(ut::malloc_withkey(key, 10*sizeof(int)));
594 */
595inline void *malloc_withkey(PSI_memory_key_t key, std::size_t size) noexcept {
597 using malloc_impl = detail::Alloc_<impl>;
598 return malloc_impl::alloc<false>(size, key());
599}
600
601/** Dynamically allocates storage of given size.
602
603 NOTE: Given that this function will _NOT_ be instrumenting the allocation
604 through PFS, observability for particular parts of the system which want to
605 use it will be lost or in best case inaccurate. Please have a strong reason
606 to do so.
607
608 @param[in] size Size of storage (in bytes) requested to be allocated.
609 @return Pointer to the allocated storage. nullptr if dynamic storage
610 allocation failed.
611
612 Example:
613 int *x = static_cast<int*>(ut::malloc_withkey(UT_NEW_THIS_FILE_PSI_KEY,
614 10*sizeof(int)));
615 */
616inline void *malloc(std::size_t size) noexcept {
618}
619
620/** Dynamically allocates zero-initialized storage of given size. Instruments
621 the memory with given PSI memory key in case PFS memory support is enabled.
622
623 @param[in] key PSI memory key to be used for PFS memory instrumentation.
624 @param[in] size Size of storage (in bytes) requested to be allocated.
625 @return Pointer to the zero-initialized allocated storage. nullptr if
626 dynamic storage allocation failed.
627
628 Example:
629 int *x = static_cast<int*>(ut::zalloc_withkey(key, 10*sizeof(int)));
630 */
631inline void *zalloc_withkey(PSI_memory_key_t key, std::size_t size) noexcept {
633 using malloc_impl = detail::Alloc_<impl>;
634 return malloc_impl::alloc<true>(size, key());
635}
636
637/** Dynamically allocates zero-initialized storage of given size.
638
639 NOTE: Given that this function will _NOT_ be instrumenting the allocation
640 through PFS, observability for particular parts of the system which want to
641 use it will be lost or in best case inaccurate. Please have a strong reason
642 to do so.
643
644 @param[in] size Size of storage (in bytes) requested to be allocated.
645 @return Pointer to the zero-initialized allocated storage. nullptr if
646 dynamic storage allocation failed.
647
648 Example:
649 int *x = static_cast<int*>(ut::zalloc_withkey(UT_NEW_THIS_FILE_PSI_KEY,
650 10*sizeof(int)));
651 */
652inline void *zalloc(std::size_t size) noexcept {
654}
655
656/** Upsizes or downsizes already dynamically allocated storage to the new size.
657 Instruments the memory with given PSI memory key in case PFS memory support
658 is enabled.
659
660 It also supports standard realloc() semantics by:
661 * allocating size bytes of memory when passed ptr is nullptr
662 * freeing the memory pointed by ptr if passed size is 0
663
664 @param[in] key PSI memory key to be used for PFS memory instrumentation.
665 @param[in] ptr Pointer to the memory area to be reallocated.
666 @param[in] size New size of storage (in bytes) requested to be reallocated.
667 @return Pointer to the reallocated storage. nullptr if dynamic storage
668 allocation failed.
669
670 Example:
671 int *x = static_cast<int*>(ut::malloc_withkey(key, 10*sizeof(int));
672 x = static_cast<int*>(ut::realloc_withkey(key, ptr, 100*sizeof(int)));
673 */
674inline void *realloc_withkey(PSI_memory_key_t key, void *ptr,
675 std::size_t size) noexcept {
677 using malloc_impl = detail::Alloc_<impl>;
678 return malloc_impl::realloc(ptr, size, key());
679}
680
681/** Upsizes or downsizes already dynamically allocated storage to the new size.
682
683 It also supports standard realloc() semantics by:
684 * allocating size bytes of memory when passed ptr is nullptr
685 * freeing the memory pointed by ptr if passed size is 0
686
687 NOTE: Given that this function will _NOT_ be instrumenting the allocation
688 through PFS, observability for particular parts of the system which want to
689 use it will be lost or in best case inaccurate. Please have a strong reason
690 to do so.
691
692 @param[in] ptr Pointer to the memory area to be reallocated.
693 @param[in] size New size of storage (in bytes) requested to be reallocated.
694 @return Pointer to the reallocated storage. nullptr if dynamic storage
695 allocation failed.
696
697 Example:
698 int *x = static_cast<int*>(ut::malloc_withkey(UT_NEW_THIS_FILE_PSI_KEY,
699 10*sizeof(int)); x = static_cast<int*>(ut::realloc(key, ptr,
700 100*sizeof(int)));
701 */
702inline void *realloc(void *ptr, std::size_t size) noexcept {
704 size);
705}
706
707/** Releases storage which has been dynamically allocated through any of
708 the ut::malloc*(), ut::realloc* or ut::zalloc*() variants.
709
710 @param[in] ptr Pointer which has been obtained through any of the
711 ut::malloc*(), ut::realloc* or ut::zalloc*() variants.
712
713 Example:
714 ut::free(ptr);
715 */
716inline void free(void *ptr) noexcept {
718 using malloc_impl = detail::Alloc_<impl>;
720}
721
722/** Dynamically allocates storage for an object of type T. Constructs the object
723 of type T with provided Args. Instruments the memory with given PSI memory
724 key in case PFS memory support is enabled.
725
726 @param[in] key PSI memory key to be used for PFS memory instrumentation.
727 @param[in] args Arguments one wishes to pass over to T constructor(s)
728 @return Pointer to the allocated storage. Throws std::bad_alloc exception
729 if dynamic storage allocation could not be fulfilled. Re-throws whatever
730 exception that may have occurred during the construction of T, in which case
731 it automatically cleans up the raw memory allocated for it.
732
733 Example 1:
734 int *ptr = ut::new_withkey<int>(key);
735
736 Example 2:
737 int *ptr = ut::new_withkey<int>(key, 10);
738 assert(*ptr == 10);
739
740 Example 3:
741 struct A {
742 A(int x, int y) : _x(x), _y(y) {}
743 int _x, _y;
744 };
745 A *ptr = ut::new_withkey<A>(key, 1, 2);
746 assert(ptr->_x == 1);
747 assert(ptr->_y == 2);
748 */
749template <typename T, typename... Args>
750inline T *new_withkey(PSI_memory_key_t key, Args &&... args) {
751 auto mem = ut::malloc_withkey(key, sizeof(T));
752 if (unlikely(!mem)) throw std::bad_alloc();
753 try {
754 new (mem) T(std::forward<Args>(args)...);
755 } catch (...) {
756 ut::free(mem);
757 throw;
758 }
759 return static_cast<T *>(mem);
760}
761
762/** Dynamically allocates storage for an object of type T. Constructs the object
763 of type T with provided Args.
764
765 NOTE: Given that this function will _NOT_ be instrumenting the allocation
766 through PFS, observability for particular parts of the system which want to
767 use it will be lost or in best case inaccurate. Please have a strong reason
768 to do so.
769
770 @param[in] args Arguments one wishes to pass over to T constructor(s)
771 @return Pointer to the allocated storage. Throws std::bad_alloc exception
772 if dynamic storage allocation could not be fulfilled. Re-throws whatever
773 exception that may have occurred during the construction of T, in which case
774 it automatically cleans up the raw memory allocated for it.
775
776 Example 1:
777 int *ptr = ut::new_withkey<int>(UT_NEW_THIS_FILE_PSI_KEY);
778
779 Example 2:
780 int *ptr = ut::new_withkey<int>(UT_NEW_THIS_FILE_PSI_KEY, 10);
781 assert(*ptr == 10);
782
783 Example 3:
784 struct A {
785 A(int x, int y) : _x(x), _y(y) {}
786 int _x, _y;
787 };
788 A *ptr = ut::new_withkey<A>(UT_NEW_THIS_FILE_PSI_KEY, 1, 2);
789 assert(ptr->_x == 1);
790 assert(ptr->_y == 2);
791 */
792template <typename T, typename... Args>
793inline T *new_(Args &&... args) {
794 return ut::new_withkey<T>(make_psi_memory_key(PSI_NOT_INSTRUMENTED),
795 std::forward<Args>(args)...);
796}
797
798/** Releases storage which has been dynamically allocated through any of
799 the ut::new*() variants. Destructs the object of type T.
800
801 @param[in] ptr Pointer which has been obtained through any of the
802 ut::new*() variants
803
804 Example:
805 ut::delete_(ptr);
806 */
807template <typename T>
808inline void delete_(T *ptr) noexcept {
809 if (unlikely(!ptr)) return;
810 ptr->~T();
811 ut::free(ptr);
812}
813
814/** Dynamically allocates storage for an array of T's. Constructs objects of
815 type T with provided Args. Arguments that are to be used to construct some
816 respective instance of T shall be wrapped into a std::tuple. See examples
817 down below. Instruments the memory with given PSI memory key in case PFS
818 memory support is enabled.
819
820 To create an array of default-intialized T's, one can use this function
821 template but for convenience purposes one can achieve the same by using
822 the ut::new_arr_withkey with ut::Count overload.
823
824 @param[in] key PSI memory key to be used for PFS memory instrumentation.
825 @param[in] args Tuples of arguments one wishes to pass over to T
826 constructor(s).
827 @return Pointer to the first element of allocated storage. Throws
828 std::bad_alloc exception if dynamic storage allocation could not be
829 fulfilled. Re-throws whatever exception that may have occurred during the
830 construction of any instance of T, in which case it automatically destroys
831 successfully constructed objects till that moment (if any), and finally
832 cleans up the raw memory allocated for T instances.
833
834 Example 1:
835 int *ptr = ut::new_arr_withkey<int>(key,
836 std::forward_as_tuple(1),
837 std::forward_as_tuple(2));
838 assert(ptr[0] == 1);
839 assert(ptr[1] == 2);
840
841 Example 2:
842 struct A {
843 A(int x, int y) : _x(x), _y(y) {}
844 int _x, _y;
845 };
846 A *ptr = ut::new_arr_withkey<A>(key,
847 std::forward_as_tuple(0, 1), std::forward_as_tuple(2, 3),
848 std::forward_as_tuple(4, 5), std::forward_as_tuple(6, 7),
849 std::forward_as_tuple(8, 9));
850 assert(ptr[0]->_x == 0 && ptr[0]->_y == 1);
851 assert(ptr[1]->_x == 2 && ptr[1]->_y == 3);
852 assert(ptr[2]->_x == 4 && ptr[2]->_y == 5);
853 assert(ptr[3]->_x == 6 && ptr[3]->_y == 7);
854 assert(ptr[4]->_x == 8 && ptr[4]->_y == 9);
855
856 Example 3:
857 struct A {
858 A() : _x(10), _y(100) {}
859 A(int x, int y) : _x(x), _y(y) {}
860 int _x, _y;
861 };
862 A *ptr = ut::new_arr_withkey<A>(key,
863 std::forward_as_tuple(0, 1), std::forward_as_tuple(2, 3),
864 std::forward_as_tuple(), std::forward_as_tuple(6, 7),
865 std::forward_as_tuple());
866 assert(ptr[0]->_x == 0 && ptr[0]->_y == 1);
867 assert(ptr[1]->_x == 2 && ptr[1]->_y == 3);
868 assert(ptr[2]->_x == 10 && ptr[2]->_y == 100);
869 assert(ptr[3]->_x == 6 && ptr[3]->_y == 7);
870 assert(ptr[4]->_x == 10 && ptr[4]->_y == 100);
871 */
872template <typename T, typename... Args>
873inline T *new_arr_withkey(PSI_memory_key_t key, Args &&... args) {
875 using malloc_impl = detail::Alloc_<impl>;
876 auto mem = malloc_impl::alloc<false>(sizeof(T) * sizeof...(args), key());
877 if (unlikely(!mem)) throw std::bad_alloc();
878
879 size_t idx = 0;
880 try {
881 (...,
882 detail::construct<T>(mem, sizeof(T) * idx++, std::forward<Args>(args)));
883 } catch (...) {
884 for (size_t offset = (idx - 1) * sizeof(T); offset != 0;
885 offset -= sizeof(T)) {
886 reinterpret_cast<T *>(reinterpret_cast<std::uintptr_t>(mem) + offset -
887 sizeof(T))
888 ->~T();
889 }
891 throw;
892 }
893 return static_cast<T *>(mem);
894}
895
896/** Dynamically allocates storage for an array of T's. Constructs objects of
897 type T with provided Args. Arguments that are to be used to construct some
898 respective instance of T shall be wrapped into a std::tuple. See examples
899 down below.
900
901 To create an array of default-intialized T's, one can use this function
902 template but for convenience purposes one can achieve the same by using
903 the ut::new_arr_withkey with ut::Count overload.
904
905 NOTE: Given that this function will _NOT_ be instrumenting the allocation
906 through PFS, observability for particular parts of the system which want to
907 use it will be lost or in best case inaccurate. Please have a strong reason
908 to do so.
909
910 @param[in] args Tuples of arguments one wishes to pass over to T
911 constructor(s).
912 @return Pointer to the first element of allocated storage. Throws
913 std::bad_alloc exception if dynamic storage allocation could not be
914 fulfilled. Re-throws whatever exception that may have occurred during the
915 construction of any instance of T, in which case it automatically destroys
916 successfully constructed objects till that moment (if any), and finally
917 cleans up the raw memory allocated for T instances.
918
919 Example 1:
920 int *ptr = ut::new_arr_withkey<int>(UT_NEW_THIS_FILE_PSI_KEY,
921 std::forward_as_tuple(1),
922 std::forward_as_tuple(2));
923 assert(ptr[0] == 1);
924 assert(ptr[1] == 2);
925
926 Example 2:
927 struct A {
928 A(int x, int y) : _x(x), _y(y) {}
929 int _x, _y;
930 };
931 A *ptr = ut::new_arr_withkey<A>(UT_NEW_THIS_FILE_PSI_KEY,
932 std::forward_as_tuple(0, 1), std::forward_as_tuple(2, 3),
933 std::forward_as_tuple(4, 5), std::forward_as_tuple(6, 7),
934 std::forward_as_tuple(8, 9));
935 assert(ptr[0]->_x == 0 && ptr[0]->_y == 1);
936 assert(ptr[1]->_x == 2 && ptr[1]->_y == 3);
937 assert(ptr[2]->_x == 4 && ptr[2]->_y == 5);
938 assert(ptr[3]->_x == 6 && ptr[3]->_y == 7);
939 assert(ptr[4]->_x == 8 && ptr[4]->_y == 9);
940
941 Example 3:
942 struct A {
943 A() : _x(10), _y(100) {}
944 A(int x, int y) : _x(x), _y(y) {}
945 int _x, _y;
946 };
947 A *ptr = ut::new_arr_withkey<A>(UT_NEW_THIS_FILE_PSI_KEY,
948 std::forward_as_tuple(0, 1), std::forward_as_tuple(2, 3),
949 std::forward_as_tuple(), std::forward_as_tuple(6, 7),
950 std::forward_as_tuple());
951 assert(ptr[0]->_x == 0 && ptr[0]->_y == 1);
952 assert(ptr[1]->_x == 2 && ptr[1]->_y == 3);
953 assert(ptr[2]->_x == 10 && ptr[2]->_y == 100);
954 assert(ptr[3]->_x == 6 && ptr[3]->_y == 7);
955 assert(ptr[4]->_x == 10 && ptr[4]->_y == 100);
956 */
957template <typename T, typename... Args>
958inline T *new_arr(Args &&... args) {
959 return ut::new_arr_withkey<T>(make_psi_memory_key(PSI_NOT_INSTRUMENTED),
960 std::forward<Args>(args)...);
961}
962
963/** Light-weight and type-safe wrapper which serves a purpose of
964 being able to select proper ut::new_arr* overload.
965
966 Without having a separate overload with this type, creating an array of
967 default-initialized instances of T through the ut::new_arr*(Args &&... args)
968 overload would have been impossible because:
969 int *ptr = ut::new_arr_withkey<int>(UT_NEW_THIS_FILE_PSI_KEY, 5);
970 wouldn't even compile and
971 int *ptr = ut::new_arr_withkey<int>(UT_NEW_THIS_FILE_PSI_KEY,
972 std::forward_as_tuple(5)); would compile but would not have intended effect.
973 It would create an array holding 1 integer element that is initialized to 5.
974
975 Given that function templates cannot be specialized, having an overload
976 crafted specifically for given case solves the problem:
977 int *ptr = ut::new_arr_withkey<int>(UT_NEW_THIS_FILE_PSI_KEY,
978 ut::Count{5});
979*/
980struct Count {
981 explicit Count(size_t count) : m_count(count) {}
982 size_t operator()() const { return m_count; }
983 size_t m_count;
984};
985
986/** Dynamically allocates storage for an array of T's. Constructs objects of
987 type T using default constructor. If T cannot be default-initialized (e.g.
988 default constructor does not exist), then this interface cannot be used for
989 constructing such an array. ut::new_arr_withkey overload with user-provided
990 initialization must be used then. Instruments the memory with given PSI
991 memory key in case PFS memory support is enabled.
992
993 @param[in] key PSI memory key to be used for PFS memory instrumentation.
994 @param[in] count Number of T elements in an array.
995 @return Pointer to the first element of allocated storage. Throws
996 std::bad_alloc exception if dynamic storage allocation could not be
997 fulfilled. Re-throws whatever exception that may have occurred during the
998 construction of any instance of T, in which case it automatically destroys
999 successfully constructed objects till that moment (if any), and finally
1000 cleans up the raw memory allocated for T instances.
1001
1002 Example 1:
1003 int *ptr = ut::new_arr_withkey<int>(key, ut::Count{2});
1004
1005 Example 2:
1006 struct A {
1007 A() : _x(10), _y(100) {}
1008 int _x, _y;
1009 };
1010 A *ptr = ut::new_arr_withkey<A>(key, ut::Count{5});
1011 assert(ptr[0]->_x == 10 && ptr[0]->_y == 100);
1012 assert(ptr[1]->_x == 10 && ptr[1]->_y == 100);
1013 assert(ptr[2]->_x == 10 && ptr[2]->_y == 100);
1014 assert(ptr[3]->_x == 10 && ptr[3]->_y == 100);
1015 assert(ptr[4]->_x == 10 && ptr[4]->_y == 100);
1016
1017 Example 3:
1018 struct A {
1019 A(int x, int y) : _x(x), _y(y) {}
1020 int _x, _y;
1021 };
1022 // Following cannot compile because A is not default-constructible
1023 A *ptr = ut::new_arr_withkey<A>(key, ut::Count{5});
1024 */
1025template <typename T>
1028 using malloc_impl = detail::Alloc_<impl>;
1029 auto mem = malloc_impl::alloc<false>(sizeof(T) * count(), key());
1030 if (unlikely(!mem)) throw std::bad_alloc();
1031
1032 size_t offset = 0;
1033 try {
1034 for (; offset < sizeof(T) * count(); offset += sizeof(T)) {
1035 new (reinterpret_cast<uint8_t *>(mem) + offset) T{};
1036 }
1037 } catch (...) {
1038 for (; offset != 0; offset -= sizeof(T)) {
1039 reinterpret_cast<T *>(reinterpret_cast<std::uintptr_t>(mem) + offset -
1040 sizeof(T))
1041 ->~T();
1042 }
1044 throw;
1045 }
1046 return static_cast<T *>(mem);
1047}
1048
1049/** Dynamically allocates storage for an array of T's. Constructs objects of
1050 type T using default constructor. If T cannot be default-initialized (e.g.
1051 default constructor does not exist), then this interface cannot be used for
1052 constructing such an array. ut::new_arr overload with user-provided
1053 initialization must be used then.
1054
1055 NOTE: Given that this function will _NOT_ be instrumenting the allocation
1056 through PFS, observability for particular parts of the system which want to
1057 use it will be lost or in best case inaccurate. Please have a strong reason
1058 to do so.
1059
1060 @param[in] count Number of T elements in an array.
1061 @return Pointer to the first element of allocated storage. Throws
1062 std::bad_alloc exception if dynamic storage allocation could not be
1063 fulfilled. Re-throws whatever exception that may have occurred during the
1064 construction of any instance of T, in which case it automatically destroys
1065 successfully constructed objects till that moment (if any), and finally
1066 cleans up the raw memory allocated for T instances.
1067
1068 Example 1:
1069 int *ptr = ut::new_arr_withkey<int>(UT_NEW_THIS_FILE_PSI_KEY,
1070 ut::Count{2});
1071
1072 Example 2:
1073 struct A {
1074 A() : _x(10), _y(100) {}
1075 int _x, _y;
1076 };
1077 A *ptr = ut::new_arr_withkey<A>(UT_NEW_THIS_FILE_PSI_KEY, ut::Count{5});
1078 assert(ptr[0]->_x == 10 && ptr[0]->_y == 100);
1079 assert(ptr[1]->_x == 10 && ptr[1]->_y == 100);
1080 assert(ptr[2]->_x == 10 && ptr[2]->_y == 100);
1081 assert(ptr[3]->_x == 10 && ptr[3]->_y == 100);
1082 assert(ptr[4]->_x == 10 && ptr[4]->_y == 100);
1083
1084 Example 3:
1085 struct A {
1086 A(int x, int y) : _x(x), _y(y) {}
1087 int _x, _y;
1088 };
1089 // Following cannot compile because A is not default-constructible
1090 A *ptr = ut::new_arr_withkey<A>(UT_NEW_THIS_FILE_PSI_KEY, ut::Count{5});
1091 */
1092template <typename T>
1093inline T *new_arr(Count count) {
1094 return ut::new_arr_withkey<T>(make_psi_memory_key(PSI_NOT_INSTRUMENTED),
1095 count);
1096}
1097
1098/** Releases storage which has been dynamically allocated through any of
1099 the ut::new_arr*() variants. Destructs all objects of type T.
1100
1101 @param[in] ptr Pointer which has been obtained through any of the
1102 ut::new_arr*() variants
1103
1104 Example:
1105 ut::delete_arr(ptr);
1106 */
1107template <typename T>
1108inline void delete_arr(T *ptr) noexcept {
1109 if (unlikely(!ptr)) return;
1111 using malloc_impl = detail::Alloc_<impl>;
1112 const auto data_len = malloc_impl::datalen(ptr);
1113 for (size_t offset = 0; offset < data_len; offset += sizeof(T)) {
1114 reinterpret_cast<T *>(reinterpret_cast<std::uintptr_t>(ptr) + offset)->~T();
1115 }
1116 malloc_impl::free(ptr);
1117}
1118
1119/** Returns number of bytes that ut::malloc_*, ut::zalloc_*, ut::realloc_* and
1120 ut::new_* variants will be using to store the necessary metadata for PFS.
1121
1122 @return Size of the PFS metadata.
1123*/
1124inline size_t pfs_overhead() noexcept {
1126 using malloc_impl = detail::Alloc_<impl>;
1128}
1129
1130/** Dynamically allocates system page-aligned storage of given size. Instruments
1131 the memory with given PSI memory key in case PFS memory support is enabled.
1132
1133 Actual page-alignment, and thus page-size, will depend on CPU architecture
1134 but in general page is traditionally mostly 4K large. In contrast to Unices,
1135 Windows do make an exception here and implement 64K granularity on top of
1136 regular page-size for some legacy reasons. For more details see:
1137 https://devblogs.microsoft.com/oldnewthing/20031008-00/?p=42223
1138
1139 @param[in] key PSI memory key to be used for PFS memory instrumentation.
1140 @param[in] size Size of storage (in bytes) requested to be allocated.
1141 @return Pointer to the page-aligned storage. nullptr if dynamic storage
1142 allocation failed.
1143
1144 Example:
1145 int *x = static_cast<int*>(ut::malloc_page_withkey(key, 10*sizeof(int)));
1146 */
1148 std::size_t size) noexcept {
1150 using page_alloc_impl = detail::Page_alloc_<impl>;
1151 return page_alloc_impl::alloc(size, key());
1152}
1153
1154/** Dynamically allocates system page-aligned storage of given size.
1155
1156 Actual page-alignment, and thus page-size, will depend on CPU architecture
1157 but in general page is traditionally mostly 4K large. In contrast to Unices,
1158 Windows do make an exception here and implement 64K granularity on top of
1159 regular page-size for some legacy reasons. For more details see:
1160 https://devblogs.microsoft.com/oldnewthing/20031008-00/?p=42223
1161
1162 NOTE: Given that this function will _NOT_ be instrumenting the allocation
1163 through PFS, observability for particular parts of the system which want to
1164 use it will be lost or in best case inaccurate. Please have a strong reason
1165 to do so.
1166
1167 @param[in] size Size of storage (in bytes) requested to be allocated.
1168 @return Pointer to the page-aligned storage. nullptr if dynamic storage
1169 allocation failed.
1170
1171 Example:
1172 int *x = static_cast<int*>(ut::malloc_page(10*sizeof(int)));
1173 */
1174inline void *malloc_page(std::size_t size) noexcept {
1176 size);
1177}
1178
1179/** Retrieves the total amount of bytes that are available for application code
1180 to use.
1181
1182 Amount of bytes returned does _not_ have to match bytes requested
1183 through ut::malloc_page*(). This is so because bytes requested will always
1184 be implicitly rounded up to the next regular page size (e.g. 4K).
1185
1186 @param[in] ptr Pointer which has been obtained through any of the
1187 ut::malloc_page*() variants.
1188 @return Number of bytes available.
1189
1190 Example:
1191 int *x = static_cast<int*>(ut::malloc_page(10*sizeof(int)));
1192 assert(page_allocation_size(x) == CPU_PAGE_SIZE);
1193 */
1194inline size_t page_allocation_size(void *ptr) noexcept {
1196 using page_alloc_impl = detail::Page_alloc_<impl>;
1197 return page_alloc_impl::datalen(ptr);
1198}
1199
1200/** Retrieves the pointer and size of the allocation provided by the OS. It is a
1201 low level information, and is needed only to call low level memory-related
1202 OS functions.
1203
1204 @param[in] ptr Pointer which has been obtained through any of the
1205 ut::malloc_page*() variants.
1206 @return Low level OS allocation info.
1207 */
1210 using page_alloc_impl = detail::Page_alloc_<impl>;
1211 return page_alloc_impl::low_level_info(ptr);
1212}
1213
1214/** Releases storage which has been dynamically allocated through any of
1215 the ut::malloc_page*() variants.
1216
1217 @param[in] ptr Pointer which has been obtained through any of the
1218 ut::malloc_page*() variants.
1219 @return True if releasing the page-aligned memory was successful.
1220
1221 Example:
1222 ut::free_page(ptr);
1223 */
1224inline bool free_page(void *ptr) noexcept {
1226 using page_alloc_impl = detail::Page_alloc_<impl>;
1227 return page_alloc_impl::free(ptr);
1228}
1229
1230/** Dynamically allocates memory backed up by large (huge) pages. Instruments
1231 the memory with given PSI memory key in case PFS memory support is enabled.
1232
1233 For large (huge) pages to be functional, usually some steps in system admin
1234 preparation is required. Exact steps vary from system to system.
1235
1236 @param[in] key PSI memory key to be used for PFS memory instrumentation.
1237 @param[in] size Size of storage (in bytes) requested to be allocated.
1238 @return Pointer to the page-aligned storage. nullptr if dynamic storage
1239 allocation failed.
1240
1241 Example:
1242 int *x = static_cast<int*>(
1243 ut::malloc_large_page_withkey(key, 10*sizeof(int))
1244 );
1245 */
1247 std::size_t size) noexcept {
1249 using large_page_alloc_impl = detail::Large_alloc_<impl>;
1250 return large_page_alloc_impl::alloc(size, key());
1251}
1252
1253/** Dynamically allocates memory backed up by large (huge) pages.
1254
1255 For large (huge) pages to be functional, usually some steps in system admin
1256 preparation is required. Exact steps vary from system to system.
1257
1258 NOTE: Given that this function will _NOT_ be instrumenting the allocation
1259 through PFS, observability for particular parts of the system which want to
1260 use it will be lost or in best case inaccurate. Please have a strong reason
1261 to do so.
1262
1263 @param[in] size Size of storage (in bytes) requested to be allocated.
1264 @return Pointer to the page-aligned storage. nullptr if dynamic storage
1265 allocation failed.
1266
1267 Example:
1268 int *x = static_cast<int*>(ut::malloc_large_page(10*sizeof(int)));
1269 */
1270inline void *malloc_large_page(std::size_t size) noexcept {
1273}
1274
1275/** Retrieves the total amount of bytes that are available for application code
1276 to use.
1277
1278 Amount of bytes returned does _not_ have to match bytes requested
1279 through ut::malloc_large_page*(). This is so because bytes requested will
1280 always be implicitly rounded up to the next multiple of huge-page size (e.g.
1281 2MiB). Exact huge-page size value that is going to be used will be stored
1282 in large_page_default_size.
1283
1284 @param[in] ptr Pointer which has been obtained through any of the
1285 ut::malloc_large_page*() variants.
1286 @return Number of bytes available.
1287
1288 Example:
1289 int *x = static_cast<int*>(ut::malloc_large_page(10*sizeof(int)));
1290 assert(large_page_allocation_size(x) == HUGE_PAGE_SIZE);
1291 */
1292inline size_t large_page_allocation_size(void *ptr) noexcept {
1294 using large_page_alloc_impl = detail::Large_alloc_<impl>;
1295 return large_page_alloc_impl::datalen(ptr);
1296}
1297
1298/** Retrieves the pointer and size of the allocation provided by the OS. It is a
1299 low level information, and is needed only to call low level memory-related
1300 OS functions.
1301
1302 @param[in] ptr Pointer which has been obtained through any of the
1303 ut::malloc_large_page*() variants.
1304 @return Low level OS allocation info.
1305 */
1308 using large_page_alloc_impl = detail::Large_alloc_<impl>;
1309 return large_page_alloc_impl::low_level_info(ptr);
1310}
1311
1312/** Releases storage which has been dynamically allocated through any of
1313 the ut::malloc_large_page*() variants.
1314
1315 @param[in] ptr Pointer which has been obtained through any of the
1316 ut::malloc_large_page*() variants.
1317 @return True if releasing the large (huge) page-aligned memory was
1318 successful.
1319
1320 Example:
1321 ut::free_large_page(ptr);
1322 */
1323inline bool free_large_page(void *ptr) noexcept {
1325 using large_page_alloc_impl = detail::Large_alloc_<impl>;
1326 return large_page_alloc_impl::free(ptr);
1327}
1328
1329/* Helper type for tag-dispatch */
1331
1332/** Dynamically allocates memory backed up by large (huge) pages. In the event
1333 that large (huge) pages are unavailable or disabled explicitly through
1334 os_use_large_pages, it will fallback to dynamic allocation backed by
1335 page-aligned memory. Instruments the memory with given PSI memory key in
1336 case PFS memory support is enabled.
1337
1338 @param[in] key PSI memory key to be used for PFS memory instrumentation.
1339 @param[in] size Size of storage (in bytes) requested to be allocated.
1340 @param[in] large_pages_enabled If true, the large pages will be tried to be
1341 used.
1342 @return Pointer to the page-aligned storage. nullptr if dynamic storage
1343 allocation failed.
1344
1345 Example:
1346 int *x = static_cast<int*>(
1347 ut::malloc_large_page_withkey(
1348 key,
1349 10*sizeof(int),
1350 fallback_to_normal_page_t{}
1351 )
1352 );
1353 */
1356 bool large_pages_enabled = os_use_large_pages) noexcept {
1357 void *large_page_mem = nullptr;
1358 if (large_pages_enabled) {
1359 large_page_mem = malloc_large_page_withkey(key, size);
1360 }
1361 return large_page_mem ? large_page_mem : malloc_page_withkey(key, size);
1362}
1363
1364/** Dynamically allocates memory backed up by large (huge) pages. In the event
1365 that large (huge) pages are unavailable or disabled explicitly through
1366 os_use_large_pages, it will fallback to dynamic allocation backed by
1367 page-aligned memory.
1368
1369 NOTE: Given that this function will _NOT_ be instrumenting the allocation
1370 through PFS, observability for particular parts of the system which want to
1371 use it will be lost or in best case inaccurate. Please have a strong reason
1372 to do so.
1373
1374 @param[in] size Size of storage (in bytes) requested to be allocated.
1375 @param[in] large_pages_enabled If true, the large pages will be tried to be
1376 used.
1377 @return Pointer to the page-aligned storage. nullptr if dynamic storage
1378 allocation failed.
1379
1380 Example:
1381 int *x = static_cast<int*>(
1382 ut::malloc_large_page(
1383 10*sizeof(int),
1384 fallback_to_normal_page_t{}
1385 )
1386 );
1387 */
1389 std::size_t size, fallback_to_normal_page_t,
1390 bool large_pages_enabled = os_use_large_pages) noexcept {
1393 fallback_to_normal_page_t{}, large_pages_enabled);
1394}
1395
1396/** Retrieves the total amount of bytes that are available for application code
1397 to use.
1398
1399 Amount of bytes returned does _not_ have to match bytes requested
1400 through ut::malloc_large_page*(fallback_to_normal_page_t). This is so
1401 because bytes requested will always be implicitly rounded up to the next
1402 multiple of either huge-page size (e.g. 2MiB) or regular page size (e.g.
1403 4K).
1404
1405 @param[in] ptr Pointer which has been obtained through any of the
1406 ut::malloc_large_page*(fallback_to_normal_page_t) variants.
1407 @return Number of bytes available for use.
1408 */
1409inline size_t large_page_allocation_size(void *ptr,
1410 fallback_to_normal_page_t) noexcept {
1411 assert(ptr);
1413 using large_page_alloc_impl = detail::Large_alloc_<impl>;
1414 if (large_page_alloc_impl::page_type(ptr) == detail::Page_type::system_page)
1415 return ut::page_allocation_size(ptr);
1416 ut_a(large_page_alloc_impl::page_type(ptr) == detail::Page_type::large_page);
1418}
1419
1420/** Retrieves the pointer and size of the allocation provided by the OS. It is a
1421 low level information, and is needed only to call low level memory-related
1422 OS functions.
1423
1424 @param[in] ptr Pointer which has been obtained through any of the
1425 ut::malloc_large_page*(fallback_to_normal_page_t) variants.
1426 @return Low level OS allocation info.
1427 */
1429 void *ptr, fallback_to_normal_page_t) noexcept {
1430 assert(ptr);
1432 using large_page_alloc_impl = detail::Large_alloc_<impl>;
1433 if (large_page_alloc_impl::page_type(ptr) == detail::Page_type::system_page)
1434 return ut::page_low_level_info(ptr);
1435 ut_a(large_page_alloc_impl::page_type(ptr) == detail::Page_type::large_page);
1437}
1438
1439/** Releases storage which has been dynamically allocated through any of
1440 the ut::malloc_large_page*(fallback_to_normal_page_t) variants.
1441
1442 Whether the pointer is representing area backed up by regular or huge-pages,
1443 this function will know the difference and therefore act accordingly.
1444
1445 @param[in] ptr Pointer which has been obtained through any of the
1446 ut::malloc_large_page*(fallback_to_normal_page_t) variants.
1447 @return True if releasing the memory was successful.
1448
1449 Example:
1450 ut::free_large_page(ptr);
1451 */
1452inline bool free_large_page(void *ptr, fallback_to_normal_page_t) noexcept {
1454 using large_page_alloc_impl = detail::Large_alloc_<impl>;
1455
1456 if (!ptr) return false;
1457
1458 bool success;
1459 if (large_page_alloc_impl::page_type(ptr) == detail::Page_type::system_page) {
1460 success = free_page(ptr);
1461 } else {
1462 ut_a(large_page_alloc_impl::page_type(ptr) ==
1464 success = free_large_page(ptr);
1465 }
1466 assert(success);
1467 return success;
1468}
1469
1470/** Dynamically allocates storage of given size and at the address aligned to
1471 the requested alignment. Instruments the memory with given PSI memory key
1472 in case PFS memory support is enabled.
1473
1474 @param[in] key PSI memory key to be used for PFS memory instrumentation.
1475 @param[in] size Size of storage (in bytes) requested to be allocated.
1476 @param[in] alignment Alignment requirement for storage to be allocated.
1477 @return Pointer to the allocated storage. nullptr if dynamic storage
1478 allocation failed.
1479
1480 Example:
1481 int* x = static_cast<int*>(aligned_alloc_withkey(key, 10*sizeof(int), 64));
1482 */
1483inline void *aligned_alloc_withkey(PSI_memory_key_t key, std::size_t size,
1484 std::size_t alignment) noexcept {
1486 using aligned_alloc_impl = detail::Aligned_alloc_<impl>;
1487 return aligned_alloc_impl::alloc<false>(size, alignment, key());
1488}
1489
1490/** Dynamically allocates storage of given size and at the address aligned to
1491 the requested alignment.
1492
1493 NOTE: Given that this function will _NOT_ be instrumenting the allocation
1494 through PFS, observability for particular parts of the system which want to
1495 use it will be lost or in best case inaccurate. Please have a strong reason
1496 to do so.
1497
1498 @param[in] size Size of storage (in bytes) requested to be allocated.
1499 @param[in] alignment Alignment requirement for storage to be allocated.
1500 @return Pointer to the allocated storage. nullptr if dynamic storage
1501 allocation failed.
1502
1503 Example:
1504 int* x = static_cast<int*>(aligned_alloc(10*sizeof(int), 64));
1505 */
1506inline void *aligned_alloc(std::size_t size, std::size_t alignment) noexcept {
1508 alignment);
1509}
1510
1511/** Dynamically allocates zero-initialized storage of given size and at the
1512 address aligned to the requested alignment. Instruments the memory with
1513 given PSI memory key in case PFS memory support is enabled.
1514
1515 @param[in] key PSI memory key to be used for PFS memory instrumentation.
1516 @param[in] size Size of storage (in bytes) requested to be allocated.
1517 @param[in] alignment Alignment requirement for storage to be allocated.
1518 @return Pointer to the zero-initialized allocated storage. nullptr if
1519 dynamic storage allocation failed.
1520
1521 Example:
1522 int* x =
1523 static_cast<int*>(aligned_zalloc_withkey(key, 10*sizeof(int), 64));
1524 */
1525inline void *aligned_zalloc_withkey(PSI_memory_key_t key, std::size_t size,
1526 std::size_t alignment) noexcept {
1528 using aligned_alloc_impl = detail::Aligned_alloc_<impl>;
1529 return aligned_alloc_impl::alloc<true>(size, alignment, key());
1530}
1531
1532/** Dynamically allocates zero-initialized storage of given size and at the
1533 address aligned to the requested alignment.
1534
1535 NOTE: Given that this function will _NOT_ be instrumenting the allocation
1536 through PFS, observability for particular parts of the system which want to
1537 use it will be lost or in best case inaccurate. Please have a strong reason
1538 to do so.
1539
1540 @param[in] size Size of storage (in bytes) requested to be allocated.
1541 @param[in] alignment Alignment requirement for storage to be allocated.
1542 @return Pointer to the zero-initialized allocated storage. nullptr if
1543 dynamic storage allocation failed.
1544
1545 Example:
1546 int* x = static_cast<int*>(aligned_zalloc(10*sizeof(int), 64));
1547 */
1548inline void *aligned_zalloc(std::size_t size, std::size_t alignment) noexcept {
1550 alignment);
1551}
1552
1553/** Releases storage which has been dynamically allocated through any of
1554 the aligned_alloc_*() or aligned_zalloc_*() variants.
1555
1556 @param[in] ptr Pointer which has been obtained through any of the
1557 aligned_alloc_*() or aligned_zalloc_*() variants.
1558
1559 Example:
1560 aligned_free(ptr);
1561 */
1562inline void aligned_free(void *ptr) noexcept {
1564 using aligned_alloc_impl = detail::Aligned_alloc_<impl>;
1566}
1567
1568/** Dynamically allocates storage for an object of type T at address aligned
1569 to the requested alignment. Constructs the object of type T with provided
1570 Args. Instruments the memory with given PSI memory key in case PFS memory
1571 support is enabled.
1572
1573 @param[in] key PSI memory key to be used for PFS memory instrumentation.
1574 @param[in] alignment Alignment requirement for storage to be allocated.
1575 @param[in] args Arguments one wishes to pass over to T constructor(s)
1576 @return Pointer to the allocated storage. Throws std::bad_alloc exception
1577 if dynamic storage allocation could not be fulfilled.
1578
1579 Example 1:
1580 int *ptr = aligned_new_withkey<int>(key, 2);
1581
1582 Example 2:
1583 int *ptr = aligned_new_withkey<int>(key, 2, 10);
1584 assert(*ptr == 10);
1585
1586 Example 3:
1587 struct A { A(int x, int y) : _x(x), _y(y) {} int x, y; }
1588 A *ptr = aligned_new_withkey<A>(key, 2, 1, 2);
1589 assert(ptr->x == 1);
1590 assert(ptr->y == 2);
1591 */
1592template <typename T, typename... Args>
1593inline T *aligned_new_withkey(PSI_memory_key_t key, std::size_t alignment,
1594 Args &&... args) {
1595 auto mem = aligned_alloc_withkey(key, sizeof(T), alignment);
1596 if (unlikely(!mem)) throw std::bad_alloc();
1597 try {
1598 new (mem) T(std::forward<Args>(args)...);
1599 } catch (...) {
1601 throw;
1602 }
1603 return static_cast<T *>(mem);
1604}
1605
1606/** Dynamically allocates storage for an object of type T at address aligned
1607 to the requested alignment. Constructs the object of type T with provided
1608 Args.
1609
1610 NOTE: Given that this function will _NOT_ be instrumenting the allocation
1611 through PFS, observability for particular parts of the system which want to
1612 use it will be lost or in best case inaccurate. Please have a strong reason
1613 to do so.
1614
1615 @param[in] alignment Alignment requirement for storage to be allocated.
1616 @param[in] args Arguments one wishes to pass over to T constructor(s)
1617 @return Pointer to the allocated storage. Throws std::bad_alloc exception
1618 if dynamic storage allocation could not be fulfilled.
1619
1620 Example 1:
1621 int *ptr = aligned_new<int>(2);
1622
1623 Example 2:
1624 int *ptr = aligned_new<int>(2, 10);
1625 assert(*ptr == 10);
1626
1627 Example 3:
1628 struct A { A(int x, int y) : _x(x), _y(y) {} int x, y; }
1629 A *ptr = aligned_new<A>(2, 1, 2);
1630 assert(ptr->x == 1);
1631 assert(ptr->y == 2);
1632 */
1633template <typename T, typename... Args>
1634inline T *aligned_new(std::size_t alignment, Args &&... args) {
1635 return aligned_new_withkey<T>(make_psi_memory_key(PSI_NOT_INSTRUMENTED),
1636 alignment, std::forward<Args>(args)...);
1637}
1638
1639/** Releases storage which has been dynamically allocated through any of
1640 the aligned_new_*() variants. Destructs the object of type T.
1641
1642 @param[in] ptr Pointer which has been obtained through any of the
1643 aligned_new_*() variants
1644
1645 Example:
1646 aligned_delete(ptr);
1647 */
1648template <typename T>
1649inline void aligned_delete(T *ptr) noexcept {
1650 ptr->~T();
1651 aligned_free(ptr);
1652}
1653
1654/** Dynamically allocates storage for an array of T's at address aligned to the
1655 requested alignment. Constructs objects of type T with provided Args.
1656 Arguments that are to be used to construct some respective instance of T
1657 shall be wrapped into a std::tuple. See examples down below. Instruments the
1658 memory with given PSI memory key in case PFS memory support is enabled.
1659
1660 To create an array of default-initialized T's, one can use this function
1661 template but for convenience purposes one can achieve the same by using
1662 the ut::aligned_new_arr_withkey with ut::Count overload.
1663
1664 @param[in] key PSI memory key to be used for PFS memory instrumentation.
1665 @param[in] alignment Alignment requirement for storage to be allocated.
1666 @param[in] args Tuples of arguments one wishes to pass over to T
1667 constructor(s).
1668 @return Pointer to the first element of allocated storage. Throws
1669 std::bad_alloc exception if dynamic storage allocation could not be
1670 fulfilled. Re-throws whatever exception that may have occurred during the
1671 construction of any instance of T, in which case it automatically destroys
1672 successfully constructed objects till that moment (if any), and finally
1673 cleans up the raw memory allocated for T instances.
1674
1675 Example 1:
1676 int *ptr = ut::aligned_new_arr_withkey<int>(key, 32,
1677 std::forward_as_tuple(1),
1678 std::forward_as_tuple(2));
1679 assert(ptr[0] == 1);
1680 assert(ptr[1] == 2);
1681
1682 Example 2:
1683 struct A {
1684 A(int x, int y) : _x(x), _y(y) {}
1685 int _x, _y;
1686 };
1687 A *ptr = ut::aligned_new_arr_withkey<A>(key, 32,
1688 std::forward_as_tuple(0, 1), std::forward_as_tuple(2, 3),
1689 std::forward_as_tuple(4, 5), std::forward_as_tuple(6, 7),
1690 std::forward_as_tuple(8, 9));
1691 assert(ptr[0]->_x == 0 && ptr[0]->_y == 1);
1692 assert(ptr[1]->_x == 2 && ptr[1]->_y == 3);
1693 assert(ptr[2]->_x == 4 && ptr[2]->_y == 5);
1694 assert(ptr[3]->_x == 6 && ptr[3]->_y == 7);
1695 assert(ptr[4]->_x == 8 && ptr[4]->_y == 9);
1696
1697 Example 3:
1698 struct A {
1699 A() : _x(10), _y(100) {}
1700 A(int x, int y) : _x(x), _y(y) {}
1701 int _x, _y;
1702 };
1703 A *ptr = ut::aligned_new_arr_withkey<A>(key, 32,
1704 std::forward_as_tuple(0, 1), std::forward_as_tuple(2, 3),
1705 std::forward_as_tuple(), std::forward_as_tuple(6, 7),
1706 std::forward_as_tuple());
1707 assert(ptr[0]->_x == 0 && ptr[0]->_y == 1);
1708 assert(ptr[1]->_x == 2 && ptr[1]->_y == 3);
1709 assert(ptr[2]->_x == 10 && ptr[2]->_y == 100);
1710 assert(ptr[3]->_x == 6 && ptr[3]->_y == 7);
1711 assert(ptr[4]->_x == 10 && ptr[4]->_y == 100);
1712 */
1713template <typename T, typename... Args>
1714inline T *aligned_new_arr_withkey(PSI_memory_key_t key, std::size_t alignment,
1715 Args &&... args) {
1716 auto mem = aligned_alloc_withkey(key, sizeof(T) * sizeof...(args), alignment);
1717 if (unlikely(!mem)) throw std::bad_alloc();
1718
1719 size_t idx = 0;
1720 try {
1721 (...,
1722 detail::construct<T>(mem, sizeof(T) * idx++, std::forward<Args>(args)));
1723 } catch (...) {
1724 for (size_t offset = (idx - 1) * sizeof(T); offset != 0;
1725 offset -= sizeof(T)) {
1726 reinterpret_cast<T *>(reinterpret_cast<std::uintptr_t>(mem) + offset -
1727 sizeof(T))
1728 ->~T();
1729 }
1731 throw;
1732 }
1733 return static_cast<T *>(mem);
1734}
1735
1736/** Dynamically allocates storage for an array of T's at address aligned to the
1737 requested alignment. Constructs objects of type T using default constructor.
1738 If T cannot be default-initialized (e.g. default constructor does not
1739 exist), then this interface cannot be used for constructing such an array.
1740 ut::new_arr_withkey overload with user-provided initialization must be used
1741 then. Instruments the memory with given PSI memory key in case PFS memory
1742 support is enabled.
1743
1744 @param[in] key PSI memory key to be used for PFS memory instrumentation.
1745 @param[in] alignment Alignment requirement for storage to be allocated.
1746 @param[in] count Number of T elements in an array.
1747 @return Pointer to the first element of allocated storage. Throws
1748 std::bad_alloc exception if dynamic storage allocation could not be
1749 fulfilled. Re-throws whatever exception that may have occurred during the
1750 construction of any instance of T, in which case it automatically destroys
1751 successfully constructed objects till that moment (if any), and finally
1752 cleans up the raw memory allocated for T instances.
1753
1754 Example 1:
1755 int *ptr = ut::aligned_new_arr_withkey<int>(key, 32, ut::Count{2});
1756
1757 Example 2:
1758 struct A {
1759 A() : _x(10), _y(100) {}
1760 int _x, _y;
1761 };
1762 A *ptr = ut::aligned_new_arr_withkey<A>(key, 32, ut::Count{5});
1763 assert(ptr[0]->_x == 10 && ptr[0]->_y == 100);
1764 assert(ptr[1]->_x == 10 && ptr[1]->_y == 100);
1765 assert(ptr[2]->_x == 10 && ptr[2]->_y == 100);
1766 assert(ptr[3]->_x == 10 && ptr[3]->_y == 100);
1767 assert(ptr[4]->_x == 10 && ptr[4]->_y == 100);
1768
1769 Example 3:
1770 struct A {
1771 A(int x, int y) : _x(x), _y(y) {}
1772 int _x, _y;
1773 };
1774 // Following cannot compile because A is not default-constructible
1775 A *ptr = ut::aligned_new_arr_withkey<A>(key, 32, ut::Count{5});
1776 */
1777template <typename T>
1778inline T *aligned_new_arr_withkey(PSI_memory_key_t key, std::size_t alignment,
1779 Count count) {
1780 auto mem = aligned_alloc_withkey(key, sizeof(T) * count(), alignment);
1781 if (unlikely(!mem)) throw std::bad_alloc();
1782
1783 size_t offset = 0;
1784 try {
1785 for (; offset < sizeof(T) * count(); offset += sizeof(T)) {
1786 new (reinterpret_cast<uint8_t *>(mem) + offset) T{};
1787 }
1788 } catch (...) {
1789 for (; offset != 0; offset -= sizeof(T)) {
1790 reinterpret_cast<T *>(reinterpret_cast<std::uintptr_t>(mem) + offset -
1791 sizeof(T))
1792 ->~T();
1793 }
1795 throw;
1796 }
1797 return static_cast<T *>(mem);
1798}
1799
1800/** Dynamically allocates storage for an array of T's at address aligned to
1801 the requested alignment. Constructs objects of type T with provided Args.
1802
1803 NOTE: Given that this function will _NOT_ be instrumenting the allocation
1804 through PFS, observability for particular parts of the system which want to
1805 use it will be lost or in best case inaccurate. Please have a strong reason
1806 to do so.
1807
1808 @param[in] alignment Alignment requirement for storage to be allocated.
1809 @param[in] args Arguments one wishes to pass over to T constructor(s)
1810 @return Pointer to the first element of allocated storage. Throws
1811 std::bad_alloc exception if dynamic storage allocation could not be
1812 fulfilled.
1813
1814 Example 1:
1815 int *ptr = aligned_new_arr<int, 5>(2);
1816 ptr[0] ... ptr[4]
1817
1818 Example 2:
1819 int *ptr = aligned_new_arr<int, 5>(2, 1, 2, 3, 4, 5);
1820 assert(*ptr[0] == 1);
1821 assert(*ptr[1] == 2);
1822 ...
1823 assert(*ptr[4] == 5);
1824
1825 Example 3:
1826 struct A { A(int x, int y) : _x(x), _y(y) {} int x, y; }
1827 A *ptr = aligned_new_arr<A, 5>(2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
1828 assert(ptr[0]->x == 1);
1829 assert(ptr[0]->y == 2);
1830 assert(ptr[1]->x == 3);
1831 assert(ptr[1]->y == 4);
1832 ...
1833 assert(ptr[4]->x == 9);
1834 assert(ptr[4]->y == 10);
1835 */
1836template <typename T, typename... Args>
1837inline T *aligned_new_arr(std::size_t alignment, Args &&... args) {
1838 return aligned_new_arr_withkey<T>(make_psi_memory_key(PSI_NOT_INSTRUMENTED),
1839 alignment, std::forward<Args>(args)...);
1840}
1841
1842/** Dynamically allocates storage for an array of T's at address aligned to
1843 the requested alignment. Constructs objects of type T using default
1844 constructor.
1845
1846 NOTE: Given that this function will _NOT_ be instrumenting the allocation
1847 through PFS, observability for particular parts of the system which want to
1848 use it will be lost or in best case inaccurate. Please have a strong reason
1849 to do so.
1850
1851 @param[in] alignment Alignment requirement for storage to be allocated.
1852 @param[in] count Number of T elements in an array.
1853 @return Pointer to the first element of allocated storage. Throws
1854 std::bad_alloc exception if dynamic storage allocation could not be
1855 fulfilled.
1856
1857 Example 1:
1858 int *ptr = aligned_new_arr<int>(2, 5);
1859 assert(*ptr[0] == 0);
1860 assert(*ptr[1] == 0);
1861 ...
1862 assert(*ptr[4] == 0);
1863
1864 Example 2:
1865 struct A { A) : x(1), y(2) {} int x, y; }
1866 A *ptr = aligned_new_arr<A>(2, 5);
1867 assert(ptr[0].x == 1);
1868 assert(ptr[0].y == 2);
1869 ...
1870 assert(ptr[4].x == 1);
1871 assert(ptr[4].y == 2);
1872
1873 Example 3:
1874 struct A { A(int x, int y) : _x(x), _y(y) {} int x, y; }
1875 A *ptr = aligned_new_arr<A>(2, 5);
1876 // will not compile, no default constructor
1877 */
1878template <typename T>
1879inline T *aligned_new_arr(std::size_t alignment, Count count) {
1880 return aligned_new_arr_withkey<T>(make_psi_memory_key(PSI_NOT_INSTRUMENTED),
1881 alignment, count);
1882}
1883
1884/** Releases storage which has been dynamically allocated through any of the
1885 aligned_new_arr_*() variants. Destructs all objects of type T.
1886
1887 @param[in] ptr Pointer which has been obtained through any of the
1888 aligned_new_arr_*() variants.
1889
1890 Example:
1891 aligned_delete_arr(ptr);
1892 */
1893template <typename T>
1894inline void aligned_delete_arr(T *ptr) noexcept {
1896 using aligned_alloc_impl = detail::Aligned_alloc_<impl>;
1897 const auto data_len = aligned_alloc_impl::datalen(ptr);
1898 for (size_t offset = 0; offset < data_len; offset += sizeof(T)) {
1899 reinterpret_cast<T *>(reinterpret_cast<std::uintptr_t>(ptr) + offset)->~T();
1900 }
1901 aligned_free(ptr);
1902}
1903
1904/** Lightweight convenience wrapper which manages dynamically allocated
1905 over-aligned type. Wrapper makes use of RAII to do the resource cleanup.
1906
1907 Example usage:
1908 struct My_fancy_type {
1909 My_fancy_type(int x, int y) : _x(x), _y(y) {}
1910 int _x, _y;
1911 };
1912
1913 aligned_pointer<My_fancy_type, 32> ptr;
1914 ptr.alloc(10, 5);
1915 My_fancy_type *p = ptr;
1916 assert(p->_x == 10 && p->_y == 5);
1917
1918 @tparam T Type to be managed.
1919 @tparam Alignment Number of bytes to align the type T to.
1920 */
1921template <typename T, size_t Alignment>
1923 T *ptr = nullptr;
1924
1925 public:
1926 /** Destructor. Invokes destructor of the underlying instance of
1927 type T. Releases dynamically allocated resources, if there had been
1928 left any.
1929 */
1931 if (ptr) dealloc();
1932 }
1933
1934 /** Allocates sufficiently large memory of dynamic storage duration to fit
1935 the instance of type T at the address which is aligned to Alignment bytes.
1936 Constructs the instance of type T with given Args.
1937
1938 Underlying instance of type T is accessed through the conversion operator.
1939
1940 @param[in] args Any number and type of arguments that type T can be
1941 constructed with.
1942 */
1943 template <typename... Args>
1944 void alloc(Args &&... args) {
1945 ut_ad(ptr == nullptr);
1946 ptr = ut::aligned_new<T>(Alignment, args...);
1947 }
1948
1949 /** Allocates sufficiently large memory of dynamic storage duration to fit
1950 the instance of type T at the address which is aligned to Alignment bytes.
1951 Constructs the instance of type T with given Args. Instruments the memory
1952 with given PSI memory key in case PFS memory support is enabled.
1953
1954 Underlying instance of type T is accessed through the conversion operator.
1955
1956 @param[in] key PSI memory key to be used for PFS memory instrumentation.
1957 @param[in] args Any number and type of arguments that type T can be
1958 constructed with.
1959 */
1960 template <typename... Args>
1961 void alloc_withkey(PSI_memory_key_t key, Args &&... args) {
1962 ut_ad(ptr == nullptr);
1963 ptr =
1964 ut::aligned_new_withkey<T>(key, Alignment, std::forward<Args>(args)...);
1965 }
1966
1967 /** Invokes the destructor of instance of type T, if applicable.
1968 Releases the resources previously allocated with alloc().
1969 */
1970 void dealloc() {
1971 ut_ad(ptr != nullptr);
1973 ptr = nullptr;
1974 }
1975
1976 /** Conversion operator. Used for accessing the underlying instance of
1977 type T.
1978 */
1979 operator T *() const {
1980 ut_ad(ptr != nullptr);
1981 return ptr;
1982 }
1983};
1984
1985/** Lightweight convenience wrapper which manages a dynamically
1986 allocated array of over-aligned types. Only the first element of an array is
1987 guaranteed to be aligned to the requested Alignment. Wrapper makes use of
1988 RAII to do the resource cleanup.
1989
1990 Example usage 1:
1991 struct My_fancy_type {
1992 My_fancy_type() : _x(0), _y(0) {}
1993 My_fancy_type(int x, int y) : _x(x), _y(y) {}
1994 int _x, _y;
1995 };
1996
1997 aligned_array_pointer<My_fancy_type, 32> ptr;
1998 ptr.alloc(3);
1999 My_fancy_type *p = ptr;
2000 assert(p[0]._x == 0 && p[0]._y == 0);
2001 assert(p[1]._x == 0 && p[1]._y == 0);
2002 assert(p[2]._x == 0 && p[2]._y == 0);
2003
2004 Example usage 2:
2005 aligned_array_pointer<My_fancy_type, 32> ptr;
2006 ptr.alloc<3>(1, 2, 3, 4, 5, 6);
2007 My_fancy_type *p = ptr;
2008 assert(p[0]._x == 1 && p[0]._y == 2);
2009 assert(p[1]._x == 3 && p[1]._y == 4);
2010 assert(p[2]._x == 5 && p[2]._y == 6);
2011
2012 @tparam T Type to be managed.
2013 @tparam Alignment Number of bytes to align the first element of array to.
2014 */
2015template <typename T, size_t Alignment>
2017 T *ptr = nullptr;
2018
2019 public:
2020 /** Destructor. Invokes destructors of the underlying instances of
2021 type T. Releases dynamically allocated resources, if there had been
2022 left any.
2023 */
2025 if (ptr) dealloc();
2026 }
2027
2028 /** Allocates sufficiently large memory of dynamic storage duration to fit
2029 the array of size number of elements of type T at the address which is
2030 aligned to Alignment bytes. Constructs the size number of instances of
2031 type T, each being initialized through the means of default constructor.
2032
2033 Underlying instances of type T are accessed through the conversion
2034 operator.
2035
2036 @param[in] count Number of T elements in an array.
2037 */
2039 ut_ad(ptr == nullptr);
2040 ptr = ut::aligned_new_arr<T>(Alignment, count);
2041 }
2042
2043 /** Allocates sufficiently large memory of dynamic storage duration to fit
2044 the array of size number of elements of type T at the address which is
2045 aligned to Alignment bytes. Constructs the size number of instances of
2046 type T, each being initialized through the means of provided Args and
2047 corresponding constructors.
2048
2049 Underlying instances of type T are accessed through the conversion
2050 operator.
2051
2052 @param[in] args Any number and type of arguments that type T can be
2053 constructed with.
2054 */
2055 template <typename... Args>
2056 void alloc(Args &&... args) {
2057 ut_ad(ptr == nullptr);
2058 ptr = ut::aligned_new_arr<T>(Alignment, std::forward<Args>(args)...);
2059 }
2060
2061 /** Allocates sufficiently large memory of dynamic storage duration to fit
2062 the array of size number of elements of type T at the address which is
2063 aligned to Alignment bytes. Constructs the size number of instances of
2064 type T, each being initialized through the means of default constructor.
2065 Instruments the memory with given PSI memory key in case PFS memory
2066 support is enabled.
2067
2068 Underlying instances of type T are accessed through the conversion
2069 operator.
2070
2071 @param[in] key PSI memory key to be used for PFS memory instrumentation.
2072 @param[in] count Number of T elements in an array.
2073 */
2075 ut_ad(ptr == nullptr);
2076 ptr = ut::aligned_new_arr_withkey<T>(key, Alignment, count);
2077 }
2078
2079 /** Allocates sufficiently large memory of dynamic storage duration to fit
2080 the array of size number of elements of type T at the address which is
2081 aligned to Alignment bytes. Constructs the size number of instances of
2082 type T, each being initialized through the means of provided Args and
2083 corresponding constructors. Instruments the memory with given PSI memory
2084 key in case PFS memory support is enabled.
2085
2086 Underlying instances of type T are accessed through the conversion
2087 operator.
2088
2089 @param[in] key PSI memory key to be used for PFS memory instrumentation.
2090 @param[in] args Any number and type of arguments that type T can be
2091 constructed with.
2092 */
2093 template <typename... Args>
2094 void alloc_withkey(PSI_memory_key_t key, Args &&... args) {
2095 ut_ad(ptr == nullptr);
2096 ptr = ut::aligned_new_arr_withkey<T>(key, Alignment,
2097 std::forward<Args>(args)...);
2098 }
2099
2100 /** Invokes destructors of instances of type T, if applicable.
2101 Releases the resources previously allocated with any variant of
2102 alloc().
2103 */
2104 void dealloc() {
2106 ptr = nullptr;
2107 }
2108
2109 /** Conversion operator. Used for accessing the underlying instances of
2110 type T.
2111 */
2112 operator T *() const {
2113 ut_ad(ptr != nullptr);
2114 return ptr;
2115 }
2116};
2117
2118namespace detail {
2119template <typename T>
2121 explicit allocator_base(PSI_memory_key /*key*/) {}
2122
2123 template <typename U>
2124 allocator_base(const allocator_base<U> & /*other*/) {}
2125
2126 void *allocate_impl(size_t n_bytes) { return ut::malloc(n_bytes); }
2127};
2128
2129template <typename T>
2132
2133 template <typename U>
2135 : allocator_base_pfs(other.get_mem_key()) {}
2136
2138
2139 void *allocate_impl(size_t n_bytes) {
2141 }
2142
2143 private:
2145};
2146} // namespace detail
2147
2148/** Allocator that allows std::* containers to manage their memory through
2149 ut::malloc* and ut::free library functions.
2150
2151 Main purpose of this custom allocator is to instrument all of the memory
2152 allocations and deallocations that are being done by std::* containers under
2153 the hood, and have them recorded through the PFS (memory) engine.
2154
2155 Other than std::* containers, this allocator is of course also suitable for
2156 use in any other allocator-aware containers and/or code.
2157
2158 Given that ut::malloc* and ut::free library functions already handle all
2159 the PFS and non-PFS implementation bits and pieces, this allocator is a mere
2160 wrapper around them.
2161
2162 Example which uses default PFS key (mem_key_std) to trace all std::vector
2163 allocations and deallocations:
2164 std::vector<int, ut::allocator<int>> vec;
2165 vec.push_back(...);
2166 ...
2167 vec.push_back(...);
2168
2169 Example which uses user-provided PFS key to trace std::vector allocations
2170 and deallocations:
2171 ut::allocator<int> allocator(some_other_psi_key);
2172 std::vector<int, ut::allocator<int>> vec(allocator);
2173 vec.push_back(...);
2174 ...
2175 vec.push_back(...);
2176 */
2177template <typename T, typename Allocator_base = std::conditional_t<
2180class allocator : public Allocator_base {
2181 public:
2182 using pointer = T *;
2183 using const_pointer = const T *;
2184 using reference = T &;
2185 using const_reference = const T &;
2186 using value_type = T;
2187 using size_type = size_t;
2188 using difference_type = ptrdiff_t;
2189
2190 static_assert(alignof(T) <= alignof(std::max_align_t),
2191 "ut::allocator does not support over-aligned types. Use "
2192 "ut::aligned_* API to handle such types.");
2193
2194 /** Default constructor.
2195 @param[in] key performance schema key.
2196 */
2197 explicit allocator(PSI_memory_key key = mem_key_std) : Allocator_base(key) {}
2198
2199 /* Rule-of-five */
2202 const allocator<T, Allocator_base> &) = default;
2205 default;
2206 ~allocator() = default;
2207
2208 /** Copy-construct a new instance of allocator with type T by using existing
2209 instance of allocator constructed with a different type U.
2210 @param[in] other the allocator to copy from.
2211 */
2212 template <typename U>
2214 : Allocator_base(other) {}
2215
2216 /* NOTE: rebind is deprecated in C++17 and to be removed in C++20 but one of
2217 our toolchains, when used in 32-bit setting, still does not support custom
2218 allocators that do not provide rebind support explicitly. In future, this
2219 part will become redundant and can be removed.
2220 */
2221 template <typename U>
2222 struct rebind {
2224 };
2225
2226 /** Equality of allocators instantiated with same types T. */
2228 return true;
2229 }
2230 /** Non-equality of allocators instantiated with same types T. */
2231 inline bool operator!=(const ut::allocator<T, Allocator_base> &other) const {
2232 return !(*this == other);
2233 }
2234
2235 /** Return the maximum number of objects that can be allocated by
2236 this allocator. This number is somewhat lower for PFS-enabled
2237 builds because of extra few bytes needed for PFS.
2238 */
2240 const size_type s_max = std::numeric_limits<size_type>::max();
2241 return (s_max - ut::pfs_overhead()) / sizeof(T);
2242 }
2243
2244 /** Allocates chunk of memory that can hold n_elements objects of
2245 type T. Returned pointer is always valid. In case underlying
2246 allocation function was not able to fulfill the allocation request,
2247 this function will throw std::bad_alloc exception. After successful
2248 allocation, returned pointer must be passed back to
2249 ut::allocator<T>::deallocate() when no longer needed.
2250
2251 @param[in] n_elements number of elements
2252 @param[in] hint pointer to a nearby memory location,
2253 not used by this implementation
2254 @return pointer to the allocated memory
2255 */
2257 const_pointer hint [[maybe_unused]] = nullptr) {
2258 if (unlikely(n_elements > max_size())) {
2259 throw std::bad_array_new_length();
2260 }
2261
2262 auto ptr = Allocator_base::allocate_impl(n_elements * sizeof(T));
2263
2264 if (unlikely(!ptr)) {
2265 throw std::bad_alloc();
2266 }
2267
2268 return static_cast<pointer>(ptr);
2269 }
2270
2271 /** Releases the memory allocated through ut::allocator<T>::allocate().
2272
2273 @param[in,out] ptr pointer to memory to free
2274 @param[in] n_elements number of elements allocated (unused)
2275 */
2276 void deallocate(pointer ptr, size_type n_elements [[maybe_unused]] = 0) {
2277 ut::free(ptr);
2278 }
2279};
2280
2281namespace detail {
2282template <typename>
2283constexpr bool is_unbounded_array_v = false;
2284template <typename T>
2285constexpr bool is_unbounded_array_v<T[]> = true;
2286
2287template <typename>
2288constexpr bool is_bounded_array_v = false;
2289template <typename T, std::size_t N>
2290constexpr bool is_bounded_array_v<T[N]> = true;
2291
2292template <typename>
2293constexpr size_t bounded_array_size_v = 0;
2294template <typename T, std::size_t N>
2296
2297template <typename T>
2298struct Deleter {
2299 void operator()(T *ptr) { ut::delete_(ptr); }
2300};
2301
2302template <typename T>
2304 void operator()(T *ptr) { ut::delete_arr(ptr); }
2305};
2306
2307template <typename T>
2309 void operator()(T *ptr) { ut::aligned_delete(ptr); }
2310};
2311
2312template <typename T>
2314 void operator()(T *ptr) { ut::aligned_delete_arr(ptr); }
2315};
2316
2317} // namespace detail
2318
2319/** Dynamically allocates storage for an object of type T. Constructs the object
2320 of type T with provided Args. Wraps the pointer to T instance into the
2321 std::unique_ptr.
2322
2323 This overload participates in overload resolution only if T
2324 is not an array type.
2325
2326 NOTE: Given that this function will _NOT_ be instrumenting the allocation
2327 through PFS, observability for particular parts of the system which want to
2328 use it will be lost or in best case inaccurate. Please have a strong reason
2329 to do so.
2330
2331 @param[in] args Arguments one wishes to pass over to T constructor(s) .
2332 @return std::unique_ptr holding a pointer to instance of T.
2333 */
2334template <typename T, typename Deleter = detail::Deleter<T>, typename... Args>
2335std::enable_if_t<!std::is_array<T>::value, std::unique_ptr<T, Deleter>>
2336make_unique(Args &&... args) {
2337 return std::unique_ptr<T, Deleter>(ut::new_<T>(std::forward<Args>(args)...));
2338}
2339
2340/** Dynamically allocates storage for an object of type T. Constructs the object
2341 of type T with provided Args. Wraps the pointer to T instance into the
2342 std::unique_ptr with custom deleter which knows how to handle PFS-enabled
2343 dynamic memory allocations. Instruments the memory with given PSI memory key
2344 in case PFS memory support is enabled.
2345
2346 This overload participates in overload resolution only if T
2347 is not an array type.
2348
2349 @param[in] key PSI memory key to be used for PFS memory instrumentation.
2350 @param[in] args Arguments one wishes to pass over to T constructor(s) .
2351 @return std::unique_ptr holding a pointer to instance of T.
2352 */
2353template <typename T, typename Deleter = detail::Deleter<T>, typename... Args>
2354std::enable_if_t<!std::is_array<T>::value, std::unique_ptr<T, Deleter>>
2356 return std::unique_ptr<T, Deleter>(
2357 ut::new_withkey<T>(key, std::forward<Args>(args)...));
2358}
2359
2360/** Dynamically allocates storage for an object of type T. Constructs the object
2361 of type T with provided Args. Wraps the pointer to an array of T instance
2362 into the std::unique_ptr.
2363
2364 This overload participates in overload resolution only if T
2365 is an array type with unknown compile-time bound.
2366
2367 NOTE: Given that this function will _NOT_ be instrumenting the allocation
2368 through PFS, observability for particular parts of the system which want to
2369 use it will be lost or in best case inaccurate. Please have a strong reason
2370 to do so.
2371
2372 @return std::unique_ptr holding a pointer to an array of size instances of
2373 T.
2374 */
2375template <typename T,
2376 typename Deleter = detail::Array_deleter<std::remove_extent_t<T>>>
2377std::enable_if_t<detail::is_unbounded_array_v<T>, std::unique_ptr<T, Deleter>>
2378make_unique(size_t size) {
2379 return std::unique_ptr<T, Deleter>(
2380 ut::new_arr<std::remove_extent_t<T>>(ut::Count{size}));
2381}
2382
2383/** Dynamically allocates storage for an object of type T. Constructs the object
2384 of type T with provided Args. Wraps the pointer to an array of T instances
2385 into the std::unique_ptr with custom deleter which knows how to handle
2386 PFS-enabled dynamic memory allocations. Instruments the memory with given
2387 PSI memory key in case PFS memory support is enabled.
2388
2389 This overload participates in overload resolution only if T
2390 is an array type with unknown compile-time bound.
2391
2392 @return std::unique_ptr holding a pointer to an array of size instances of
2393 T.
2394 */
2395template <typename T,
2396 typename Deleter = detail::Array_deleter<std::remove_extent_t<T>>>
2397std::enable_if_t<detail::is_unbounded_array_v<T>, std::unique_ptr<T, Deleter>>
2399 return std::unique_ptr<T, Deleter>(
2400 ut::new_arr_withkey<std::remove_extent_t<T>>(key, ut::Count{size}));
2401}
2402
2403/** std::unique_ptr for arrays of known compile-time bound are disallowed.
2404
2405 For more details see 4.3 paragraph from
2406 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3588.txt
2407 */
2408template <typename T, typename... Args>
2409std::enable_if_t<detail::is_bounded_array_v<T>> make_unique(Args &&...) =
2410 delete;
2411
2412/** std::unique_ptr in PFS-enabled builds for arrays of known compile-time bound
2413 are disallowed.
2414
2415 For more details see 4.3 paragraph from
2416 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3588.txt
2417 */
2418template <typename T, typename... Args>
2419std::enable_if_t<detail::is_bounded_array_v<T>> make_unique(
2420 PSI_memory_key_t key, Args &&...) = delete;
2421
2422/** The following is a common type that is returned by all the ut::make_unique
2423 (non-aligned) specializations listed above. This is effectively a if-ladder
2424 for the following list of conditions on the input type:
2425 !std::is_array<T>::value -> std::unique_ptr<T, detail::Deleter<T>>
2426 detail::is_unbounded_array_v<T> ->
2427 std::unique_ptr<T,detail::Array_deleter<std::remove_extent_t<T>>> else (or
2428 else if detail::is_bounded_array_v<T>) -> void (we do not support bounded
2429 array ut::make_unique)
2430 */
2431template <typename T>
2432using unique_ptr = std::conditional_t<
2433 !std::is_array<T>::value, std::unique_ptr<T, detail::Deleter<T>>,
2434 std::conditional_t<
2435 detail::is_unbounded_array_v<T>,
2436 std::unique_ptr<T, detail::Array_deleter<std::remove_extent_t<T>>>,
2437 void>>;
2438
2439/** Dynamically allocates storage for an object of type T at address aligned to
2440 the requested alignment. Constructs the object of type T with provided Args.
2441 Wraps the pointer to T instance into the std::unique_ptr.
2442
2443 This overload participates in overload resolution only if T
2444 is not an array type.
2445
2446 NOTE: Given that this function will _NOT_ be instrumenting the allocation
2447 through PFS, observability for particular parts of the system which want to
2448 use it will be lost or in best case inaccurate. Please have a strong reason
2449 to do so.
2450
2451 @param[in] alignment Alignment requirement for storage to be allocated.
2452 @param[in] args Arguments one wishes to pass over to T constructor(s) .
2453 @return std::unique_ptr holding a pointer to instance of T.
2454 */
2455template <typename T, typename Deleter = detail::Aligned_deleter<T>,
2456 typename... Args>
2457std::enable_if_t<!std::is_array<T>::value, std::unique_ptr<T, Deleter>>
2458make_unique_aligned(size_t alignment, Args &&... args) {
2459 return std::unique_ptr<T, Deleter>(
2460 ut::aligned_new<T>(alignment, std::forward<Args>(args)...));
2461}
2462
2463/** Dynamically allocates storage for an array of objects of type T at address
2464 aligned to the requested alignment. Constructs the object of type T with
2465 provided Args. Wraps the pointer to T instance into the std::unique_ptr with
2466 custom deleter which knows how to handle PFS-enabled dynamic memory
2467 allocations. Instruments the memory with given PSI memory key in case PFS
2468 memory support is enabled.
2469
2470 This overload participates in overload resolution only if T is not an array
2471 type.
2472
2473 @param[in] key PSI memory key to be used for PFS memory instrumentation.
2474 @param[in] alignment Alignment requirement for storage to be allocated.
2475 @param[in] args Arguments one wishes to pass over to T constructor(s) .
2476 @return std::unique_ptr holding a pointer to instance of T.
2477 */
2478template <typename T, typename Deleter = detail::Aligned_deleter<T>,
2479 typename... Args>
2480std::enable_if_t<!std::is_array<T>::value, std::unique_ptr<T, Deleter>>
2481make_unique_aligned(PSI_memory_key_t key, size_t alignment, Args &&... args) {
2482 return std::unique_ptr<T, Deleter>(
2483 ut::aligned_new_withkey<T>(key, alignment, std::forward<Args>(args)...));
2484}
2485
2486/** Dynamically allocates storage for an array of requested size of objects of
2487 type T at address aligned to the requested alignment. Constructs the object
2488 of type T with provided Args. Wraps the pointer to an array of T instance
2489 into the std::unique_ptr.
2490
2491 This overload participates in overload resolution only if T
2492 is an array type with unknown compile-time bound.
2493
2494 NOTE: Given that this function will _NOT_ be instrumenting the allocation
2495 through PFS, observability for particular parts of the system which want to
2496 use it will be lost or in best case inaccurate. Please have a strong reason
2497 to do so.
2498
2499 @param[in] alignment Alignment requirement for storage to be allocated.
2500 @param[in] size Size of the array of objects T to allocate.
2501 @return std::unique_ptr holding a pointer to an array of size instances of
2502 T.
2503 */
2504template <typename T, typename Deleter = detail::Aligned_array_deleter<
2505 std::remove_extent_t<T>>>
2506std::enable_if_t<detail::is_unbounded_array_v<T>, std::unique_ptr<T, Deleter>>
2507make_unique_aligned(size_t alignment, size_t size) {
2508 return std::unique_ptr<T, Deleter>(
2509 ut::aligned_new_arr<std::remove_extent_t<T>>(alignment, ut::Count{size}));
2510}
2511
2512/** Dynamically allocates storage for an array of requested size of objects of
2513 type T at address aligned to the requested alignment. Constructs the object
2514 of type T with provided Args. Wraps the pointer to an array of T instances
2515 into the std::unique_ptr with custom deleter which knows how to handle
2516 PFS-enabled dynamic memory allocations. Instruments the memory with given
2517 PSI memory key in case PFS memory support is enabled.
2518
2519 This overload participates in overload resolution only if T
2520 is an array type with unknown compile-time bound.
2521
2522 @param[in] key PSI memory key to be used for PFS memory instrumentation.
2523 @param[in] alignment Alignment requirement for storage to be allocated.
2524 @param[in] size Size of the array of objects T to allocate.
2525 @return std::unique_ptr holding a pointer to an array of size instances of
2526 T.
2527 */
2528template <typename T, typename Deleter = detail::Aligned_array_deleter<
2529 std::remove_extent_t<T>>>
2530std::enable_if_t<detail::is_unbounded_array_v<T>, std::unique_ptr<T, Deleter>>
2531make_unique_aligned(PSI_memory_key_t key, size_t alignment, size_t size) {
2532 return std::unique_ptr<T, Deleter>(
2533 ut::aligned_new_arr_withkey<std::remove_extent_t<T>>(key, alignment,
2534 ut::Count{size}));
2535}
2536
2537/** std::unique_ptr for arrays of known compile-time bound are disallowed.
2538
2539 For more details see 4.3 paragraph from
2540 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3588.txt
2541 */
2542template <typename T, typename... Args>
2543std::enable_if_t<detail::is_bounded_array_v<T>> make_unique_aligned(
2544 Args &&...) = delete;
2545
2546/** std::unique_ptr in PFS-enabled builds for arrays of known compile-time bound
2547 are disallowed.
2548
2549 For more details see 4.3 paragraph from
2550 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3588.txt
2551 */
2552template <typename T, typename... Args>
2553std::enable_if_t<detail::is_bounded_array_v<T>> make_unique_aligned(
2554 PSI_memory_key_t key, Args &&...) = delete;
2555
2556/** The following is a common type that is returned by all the
2557 ut::make_unique_aligned (non-aligned) specializations listed above. This is
2558 effectively a if-ladder for the following list of conditions on the input
2559 type: !std::is_array<T>::value -> std::unique_ptr<T,
2560 detail::Aligned_deleter<T>> detail::is_unbounded_array_v<T> ->
2561 std::unique_ptr<T,detail::Aligned_array_deleter<std::remove_extent_t<T>>>
2562 else (or else if detail::is_bounded_array_v<T>) -> void (we do not support
2563 bounded array ut::make_unique)
2564 */
2565template <typename T>
2566using unique_ptr_aligned = std::conditional_t<
2567 !std::is_array<T>::value, std::unique_ptr<T, detail::Aligned_deleter<T>>,
2568 std::conditional_t<detail::is_unbounded_array_v<T>,
2570 std::remove_extent_t<T>>>,
2571 void>>;
2572
2573/** Dynamically allocates storage for an object of type T. Constructs the object
2574 of type T with provided Args. Wraps the pointer to T instance into the
2575 std::shared_ptr.
2576
2577 This overload participates in overload resolution only if T
2578 is not an array type.
2579
2580 NOTE: Given that this function will _NOT_ be instrumenting the allocation
2581 through PFS, observability for particular parts of the system which want to
2582 use it will be lost or in best case inaccurate. Please have a strong reason
2583 to do so.
2584
2585 @param[in] args Arguments one wishes to pass over to T constructor(s) .
2586 @return std::shared_ptr holding a pointer to instance of T.
2587 */
2588template <typename T, typename Deleter = detail::Deleter<T>, typename... Args>
2589std::enable_if_t<!std::is_array<T>::value, std::shared_ptr<T>> make_shared(
2590 Args &&... args) {
2591 return std::shared_ptr<T>(ut::new_<T>(std::forward<Args>(args)...),
2592 Deleter{});
2593}
2594
2595/** Dynamically allocates storage for an object of type T. Constructs the object
2596 of type T with provided Args. Wraps the pointer to T instance into the
2597 std::shared_ptr with custom deleter which knows how to handle PFS-enabled
2598 dynamic memory allocations. Instruments the memory with given PSI memory key
2599 in case PFS memory support is enabled.
2600
2601 This overload participates in overload resolution only if T
2602 is not an array type.
2603
2604 @param[in] key PSI memory key to be used for PFS memory instrumentation.
2605 @param[in] args Arguments one wishes to pass over to T constructor(s) .
2606 @return std::shared_ptr holding a pointer to instance of T.
2607 */
2608template <typename T, typename Deleter = detail::Deleter<T>, typename... Args>
2609std::enable_if_t<!std::is_array<T>::value, std::shared_ptr<T>> make_shared(
2610 PSI_memory_key_t key, Args &&... args) {
2611 return std::shared_ptr<T>(
2612 ut::new_withkey<T>(key, std::forward<Args>(args)...), Deleter{});
2613}
2614
2615/** Dynamically allocates storage for an array of requested size of objects of
2616 type T. Constructs the object of type T with provided Args. Wraps the
2617 pointer to an array of T instance into the std::shared_ptr.
2618
2619 This overload participates in overload resolution only if T
2620 is an array type with unknown compile-time bound.
2621
2622 NOTE: Given that this function will _NOT_ be instrumenting the allocation
2623 through PFS, observability for particular parts of the system which want to
2624 use it will be lost or in best case inaccurate. Please have a strong reason
2625 to do so.
2626
2627 @param[in] size Size of the array of objects T to allocate.
2628 @return std::shared_ptr holding a pointer to an array of size instances of
2629 T.
2630 */
2631template <typename T,
2632 typename Deleter = detail::Array_deleter<std::remove_extent_t<T>>>
2633std::enable_if_t<detail::is_unbounded_array_v<T>, std::shared_ptr<T>>
2634make_shared(size_t size) {
2635 return std::shared_ptr<T>(
2636 ut::new_arr<std::remove_extent_t<T>>(ut::Count{size}), Deleter{});
2637}
2638
2639/** Dynamically allocates storage for an array of requested size of objects of
2640 type T. Constructs the object of type T with provided Args. Wraps the
2641 pointer to an array of T instances into the std::shared_ptr with custom
2642 deleter which knows how to handle PFS-enabled dynamic memory allocations.
2643 Instruments the memory with given PSI memory key in case PFS memory support
2644 is enabled.
2645
2646 This overload participates in overload resolution only if T
2647 is an array type with unknown compile-time bound.
2648
2649 @param[in] key PSI memory key to be used for PFS memory instrumentation.
2650 @param[in] size Size of the array of objects T to allocate.
2651 @return std::shared_ptr holding a pointer to an array of size instances of
2652 T.
2653 */
2654template <typename T,
2655 typename Deleter = detail::Array_deleter<std::remove_extent_t<T>>>
2656std::enable_if_t<detail::is_unbounded_array_v<T>, std::shared_ptr<T>>
2658 return std::shared_ptr<T>(
2659 ut::new_arr_withkey<std::remove_extent_t<T>>(key, ut::Count{size}),
2660 Deleter{});
2661}
2662
2663/** Dynamically allocates storage for an array of objects of type T. Constructs
2664 the object of type T with provided Args. Wraps the pointer to an array of T
2665 instance into the std::shared_ptr.
2666
2667 This overload participates in overload resolution only if T
2668 is an array type with known compile-time bound.
2669
2670 NOTE: Given that this function will _NOT_ be instrumenting the allocation
2671 through PFS, observability for particular parts of the system which want to
2672 use it will be lost or in best case inaccurate. Please have a strong reason
2673 to do so.
2674
2675 @return std::shared_ptr holding a pointer to an array of size instances of
2676 T.
2677 */
2678template <typename T,
2679 typename Deleter = detail::Array_deleter<std::remove_extent_t<T>>>
2680std::enable_if_t<detail::is_bounded_array_v<T>, std::shared_ptr<T>>
2682 return std::shared_ptr<T>(ut::new_arr<std::remove_extent_t<T>>(
2683 ut::Count{detail::bounded_array_size_v<T>}),
2684 Deleter{});
2685}
2686
2687/** Dynamically allocates storage for an array of objects of type T. Constructs
2688 the object of type T with provided Args. Wraps the pointer to an array of T
2689 instances into the std::shared_ptr with custom deleter which knows how to
2690 handle PFS-enabled dynamic memory allocations. Instruments the memory with
2691 given PSI memory key in case PFS memory support is enabled.
2692
2693 This overload participates in overload resolution only if T
2694 is an array type with known compile-time bound.
2695
2696 @param[in] key PSI memory key to be used for PFS memory instrumentation.
2697 @return std::shared_ptr holding a pointer to an array of size instances of
2698 T.
2699 */
2700template <typename T,
2701 typename Deleter = detail::Array_deleter<std::remove_extent_t<T>>>
2702std::enable_if_t<detail::is_bounded_array_v<T>, std::shared_ptr<T>> make_shared(
2704 return std::shared_ptr<T>(
2705 ut::new_arr_withkey<std::remove_extent_t<T>>(
2706 key, ut::Count{detail::bounded_array_size_v<T>}),
2707 Deleter{});
2708}
2709
2710/** Dynamically allocates storage for an object of type T at address aligned to
2711 the requested alignment. Constructs the object of type T with provided Args.
2712 Wraps the pointer to T instance into the std::shared_ptr.
2713
2714 This overload participates in overload resolution only if T
2715 is not an array type.
2716
2717 NOTE: Given that this function will _NOT_ be instrumenting the allocation
2718 through PFS, observability for particular parts of the system which want to
2719 use it will be lost or in best case inaccurate. Please have a strong reason
2720 to do so.
2721
2722 @param[in] alignment Alignment requirement for storage to be allocated.
2723 @param[in] args Arguments one wishes to pass over to T constructor(s) .
2724 @return std::shared_ptr holding a pointer to instance of T.
2725 */
2726template <typename T, typename Deleter = detail::Aligned_deleter<T>,
2727 typename... Args>
2728std::enable_if_t<!std::is_array<T>::value, std::shared_ptr<T>>
2729make_shared_aligned(size_t alignment, Args &&... args) {
2730 return std::shared_ptr<T>(
2731 ut::aligned_new<T>(alignment, std::forward<Args>(args)...), Deleter{});
2732}
2733
2734/** Dynamically allocates storage for an object of type T at address aligned to
2735 the requested alignment. Constructs the object of type T with provided Args.
2736 Wraps the pointer to T instance into the std::shared_ptr with custom deleter
2737 which knows how to handle PFS-enabled dynamic memory allocations.
2738 Instruments the memory with given PSI memory key in case PFS memory support
2739 is enabled.
2740
2741 This overload participates in overload resolution only if T
2742 is not an array type.
2743
2744 @param[in] key PSI memory key to be used for PFS memory instrumentation.
2745 @param[in] alignment Alignment requirement for storage to be allocated.
2746 @param[in] args Arguments one wishes to pass over to T constructor(s) .
2747 @return std::shared_ptr holding a pointer to instance of T.
2748 */
2749template <typename T, typename Deleter = detail::Aligned_deleter<T>,
2750 typename... Args>
2751std::enable_if_t<!std::is_array<T>::value, std::shared_ptr<T>>
2752make_shared_aligned(PSI_memory_key_t key, size_t alignment, Args &&... args) {
2753 return std::shared_ptr<T>(
2754 ut::aligned_new_withkey<T>(key, alignment, std::forward<Args>(args)...),
2755 Deleter{});
2756}
2757
2758/** Dynamically allocates storage for an array of requested size of objects of
2759 type T at address aligned to the requested alignment. Constructs the object
2760 of type T with provided Args. Wraps the pointer to an array of T instance
2761 into the std::shared_ptr.
2762
2763 This overload participates in overload resolution only if T
2764 is an array type with unknown compile-time bound.
2765
2766 NOTE: Given that this function will _NOT_ be instrumenting the allocation
2767 through PFS, observability for particular parts of the system which want to
2768 use it will be lost or in best case inaccurate. Please have a strong reason
2769 to do so.
2770
2771 @param[in] alignment Alignment requirement for storage to be allocated.
2772 @param[in] size Size of the array of objects T to allocate.
2773 @return std::shared_ptr holding a pointer to an array of size instances of
2774 T.
2775 */
2776template <typename T, typename Deleter = detail::Aligned_array_deleter<
2777 std::remove_extent_t<T>>>
2778std::enable_if_t<detail::is_unbounded_array_v<T>, std::shared_ptr<T>>
2779make_shared_aligned(size_t alignment, size_t size) {
2780 return std::shared_ptr<T>(
2781 ut::aligned_new_arr<std::remove_extent_t<T>>(alignment, ut::Count{size}),
2782 Deleter{});
2783}
2784
2785/** Dynamically allocates storage for an array of requested size of objects of
2786 type T at address aligned to the requested alignment. Constructs the object
2787 of type T with provided Args. Wraps the pointer to an array of T instances
2788 into the std::shared_ptr with custom deleter which knows how to handle
2789 PFS-enabled dynamic memory allocations. Instruments the memory with given
2790 PSI memory key in case PFS memory support is enabled.
2791
2792 This overload participates in overload resolution only if T
2793 is an array type with unknown compile-time bound.
2794
2795 @param[in] key PSI memory key to be used for PFS memory instrumentation.
2796 @param[in] alignment Alignment requirement for storage to be allocated.
2797 @param[in] size Size of the array of objects T to allocate.
2798 @return std::shared_ptr holding a pointer to an array of size instances of
2799 T.
2800 */
2801template <typename T, typename Deleter = detail::Aligned_array_deleter<
2802 std::remove_extent_t<T>>>
2803std::enable_if_t<detail::is_unbounded_array_v<T>, std::shared_ptr<T>>
2804make_shared_aligned(PSI_memory_key_t key, size_t alignment, size_t size) {
2805 return std::shared_ptr<T>(
2806 ut::aligned_new_arr_withkey<std::remove_extent_t<T>>(key, alignment,
2807 ut::Count{size}),
2808 Deleter{});
2809}
2810
2811/** Dynamically allocates storage for an array of objects of type T at address
2812 aligned to the requested alignment. Constructs the object of type T with
2813 provided Args. Wraps the pointer to an array of T instance into the
2814 std::shared_ptr.
2815
2816 This overload participates in overload resolution only if T
2817 is an array type with known compile-time bound.
2818
2819 NOTE: Given that this function will _NOT_ be instrumenting the allocation
2820 through PFS, observability for particular parts of the system which want to
2821 use it will be lost or in best case inaccurate. Please have a strong reason
2822 to do so.
2823
2824 @param[in] alignment Alignment requirement for storage to be allocated.
2825 @return std::shared_ptr holding a pointer to an array of size instances of
2826 T.
2827 */
2828template <typename T, typename Deleter = detail::Aligned_array_deleter<
2829 std::remove_extent_t<T>>>
2830std::enable_if_t<detail::is_bounded_array_v<T>, std::shared_ptr<T>>
2831make_shared_aligned(size_t alignment) {
2832 return std::shared_ptr<T>(
2833 ut::aligned_new_arr<std::remove_extent_t<T>>(
2834 alignment, ut::Count{detail::bounded_array_size_v<T>}),
2835 Deleter{});
2836}
2837
2838/** Dynamically allocates storage for an array of objects of type T at address
2839 aligned to the requested alignment. Constructs the object of type T with
2840 provided Args. Wraps the pointer to an array of T instances into the
2841 std::shared_ptr with custom deleter which knows how to handle PFS-enabled
2842 dynamic memory allocations. Instruments the memory with given PSI memory key
2843 in case PFS memory support is enabled.
2844
2845 This overload participates in overload resolution only if T
2846 is an array type with known compile-time bound.
2847
2848 @param[in] key PSI memory key to be used for PFS memory instrumentation.
2849 @param[in] alignment Alignment requirement for storage to be allocated.
2850 @return std::shared_ptr holding a pointer to an array of size instances of
2851 T.
2852 */
2853template <typename T, typename Deleter = detail::Aligned_array_deleter<
2854 std::remove_extent_t<T>>>
2855std::enable_if_t<detail::is_bounded_array_v<T>, std::shared_ptr<T>>
2857 return std::shared_ptr<T>(
2858 ut::aligned_new_arr_withkey<std::remove_extent_t<T>>(
2859 key, alignment, ut::Count{detail::bounded_array_size_v<T>}),
2860 Deleter{});
2861}
2862
2863/** Specialization of basic_ostringstream which uses ut::allocator. Please note
2864 that it's .str() method returns std::basic_string which is not std::string,
2865 so it has similar API (in particular .c_str()), but you can't assign it to
2866 regular, std::string.
2867 */
2869 std::basic_ostringstream<char, std::char_traits<char>, ut::allocator<char>>;
2870
2871/** Specialization of vector which uses allocator. */
2872template <typename T>
2873using vector = std::vector<T, ut::allocator<T>>;
2874
2875/** Specialization of list which uses ut_allocator. */
2876template <typename T>
2877using list = std::list<T, ut::allocator<T>>;
2878
2879/** Specialization of set which uses ut_allocator. */
2880template <typename Key, typename Compare = std::less<Key>>
2881using set = std::set<Key, Compare, ut::allocator<Key>>;
2882
2883template <typename Key>
2885 std::unordered_set<Key, std::hash<Key>, std::equal_to<Key>,
2887
2888/** Specialization of map which uses ut_allocator. */
2889template <typename Key, typename Value, typename Compare = std::less<Key>>
2890using map =
2891 std::map<Key, Value, Compare, ut::allocator<std::pair<const Key, Value>>>;
2892
2893template <typename Key, typename Value, typename Hash = std::hash<Key>,
2894 typename Key_equal = std::equal_to<Key>>
2896 std::unordered_map<Key, Value, Hash, Key_equal,
2898
2899} // namespace ut
2900
2901#endif /* ut0new_h */
Definition: tls_cipher.cc:36
a nullable SQL value.
Definition: sql_value.h:39
Lightweight convenience wrapper which manages a dynamically allocated array of over-aligned types.
Definition: ut0new.h:2016
void dealloc()
Invokes destructors of instances of type T, if applicable.
Definition: ut0new.h:2104
void alloc(Count count)
Allocates sufficiently large memory of dynamic storage duration to fit the array of size number of el...
Definition: ut0new.h:2038
T * ptr
Definition: ut0new.h:2017
void alloc_withkey(PSI_memory_key_t key, Count count)
Allocates sufficiently large memory of dynamic storage duration to fit the array of size number of el...
Definition: ut0new.h:2074
void alloc_withkey(PSI_memory_key_t key, Args &&... args)
Allocates sufficiently large memory of dynamic storage duration to fit the array of size number of el...
Definition: ut0new.h:2094
~aligned_array_pointer()
Destructor.
Definition: ut0new.h:2024
void alloc(Args &&... args)
Allocates sufficiently large memory of dynamic storage duration to fit the array of size number of el...
Definition: ut0new.h:2056
Lightweight convenience wrapper which manages dynamically allocated over-aligned type.
Definition: ut0new.h:1922
~aligned_pointer()
Destructor.
Definition: ut0new.h:1930
void alloc(Args &&... args)
Allocates sufficiently large memory of dynamic storage duration to fit the instance of type T at the ...
Definition: ut0new.h:1944
void alloc_withkey(PSI_memory_key_t key, Args &&... args)
Allocates sufficiently large memory of dynamic storage duration to fit the instance of type T at the ...
Definition: ut0new.h:1961
T * ptr
Definition: ut0new.h:1923
void dealloc()
Invokes the destructor of instance of type T, if applicable.
Definition: ut0new.h:1970
Allocator that allows std::* containers to manage their memory through ut::malloc* and ut::free libra...
Definition: ut0new.h:2180
T & reference
Definition: ut0new.h:2184
void deallocate(pointer ptr, size_type n_elements=0)
Releases the memory allocated through ut::allocator<T>::allocate().
Definition: ut0new.h:2276
~allocator()=default
const T * const_pointer
Definition: ut0new.h:2183
ptrdiff_t difference_type
Definition: ut0new.h:2188
allocator< T, Allocator_base > & operator=(const allocator< T, Allocator_base > &)=default
allocator< T, Allocator_base > & operator=(allocator< T, Allocator_base > &&)=default
T value_type
Definition: ut0new.h:2186
allocator(const allocator< U, Allocator_base > &other)
Copy-construct a new instance of allocator with type T by using existing instance of allocator constr...
Definition: ut0new.h:2213
pointer allocate(size_type n_elements, const_pointer hint=nullptr)
Allocates chunk of memory that can hold n_elements objects of type T.
Definition: ut0new.h:2256
size_type max_size() const
Return the maximum number of objects that can be allocated by this allocator.
Definition: ut0new.h:2239
const T & const_reference
Definition: ut0new.h:2185
allocator(allocator< T, Allocator_base > &&)=default
bool operator!=(const ut::allocator< T, Allocator_base > &other) const
Non-equality of allocators instantiated with same types T.
Definition: ut0new.h:2231
allocator(PSI_memory_key key=mem_key_std)
Default constructor.
Definition: ut0new.h:2197
allocator(const allocator< T, Allocator_base > &)=default
size_t size_type
Definition: ut0new.h:2187
bool operator==(const ut::allocator< T, Allocator_base > &) const
Equality of allocators instantiated with same types T.
Definition: ut0new.h:2227
T * pointer
Definition: ut0new.h:2182
Implementation bits and pieces of include/ut0new.h.
unsigned int PSI_memory_key
Instrumented memory key.
Definition: psi_memory_bits.h:48
#define realloc(P, A)
Definition: lexyy.cc:916
#define free(A)
Definition: lexyy.cc:915
A macro that gives FILE without the directory name (e.g.
constexpr bool unlikely(bool expr)
Definition: my_compiler.h:57
static int count
Definition: myisam_ftdump.cc:44
Instrumentation helpers for memory allocation.
std::atomic< Type > N
Definition: ut0counter.h:224
std::unordered_map< Key, CHARSET_INFO * > Hash
Definition: collations_internal.cc:547
Definition: ut0tuple.h:56
Definition: os0file.h:88
std::string_view Key
The key type for the hash structure in HashJoinRowBuffer.
Definition: hash_join_buffer.h:102
Definition: authentication.cc:35
Alignment
Enum class describing alignment-requirements.
Definition: lock_free_type.h:38
constexpr bool is_unbounded_array_v< T[]>
Definition: ut0new.h:2285
typename select_alloc_impl< Pfs_memory_instrumentation_on >::type select_alloc_impl_t
Just a small helper type which saves us some keystrokes.
Definition: aligned_alloc.h:690
constexpr size_t bounded_array_size_v< T[N]>
Definition: ut0new.h:2295
constexpr bool is_bounded_array_v
Definition: ut0new.h:2288
constexpr bool is_unbounded_array_v
Definition: ut0new.h:2283
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:366
typename select_page_alloc_impl< Pfs_memory_instrumentation_on >::type select_page_alloc_impl_t
Just a small helper type which saves us some keystrokes.
Definition: page_alloc.h:427
typename select_malloc_impl< Pfs_memory_instrumentation_on, Array_specialization >::type select_malloc_impl_t
Just a small helper type which saves us some keystrokes.
Definition: alloc.h:428
constexpr size_t bounded_array_size_v
Definition: ut0new.h:2293
constexpr bool is_bounded_array_v< T[N]>
Definition: ut0new.h:2290
This file contains a set of libraries providing overloads for regular dynamic allocation routines whi...
Definition: aligned_alloc.h:47
void * aligned_zalloc_withkey(PSI_memory_key_t key, std::size_t size, std::size_t alignment) noexcept
Dynamically allocates zero-initialized storage of given size and at the address aligned to the reques...
Definition: ut0new.h:1525
std::unordered_map< Key, Value, Hash, Key_equal, ut::allocator< std::pair< const Key, Value > > > unordered_map
Definition: ut0new.h:2897
T * new_arr_withkey(PSI_memory_key_t key, Args &&... args)
Dynamically allocates storage for an array of T's.
Definition: ut0new.h:873
size_t pfs_overhead() noexcept
Returns number of bytes that ut::malloc_*, ut::zalloc_*, ut::realloc_* and ut::new_* variants will be...
Definition: ut0new.h:1124
T * aligned_new_withkey(PSI_memory_key_t key, std::size_t alignment, Args &&... args)
Dynamically allocates storage for an object of type T at address aligned to the requested alignment.
Definition: ut0new.h:1593
void * zalloc_withkey(PSI_memory_key_t key, std::size_t size) noexcept
Dynamically allocates zero-initialized storage of given size.
Definition: ut0new.h:631
void * malloc_withkey(PSI_memory_key_t key, std::size_t size) noexcept
Dynamically allocates storage of given size.
Definition: ut0new.h:595
std::enable_if_t<!std::is_array< T >::value, std::unique_ptr< T, Deleter > > make_unique(Args &&... args)
Dynamically allocates storage for an object of type T.
Definition: ut0new.h:2336
T * aligned_new_arr(std::size_t alignment, Args &&... args)
Dynamically allocates storage for an array of T's at address aligned to the requested alignment.
Definition: ut0new.h:1837
void * aligned_zalloc(std::size_t size, std::size_t alignment) noexcept
Dynamically allocates zero-initialized storage of given size and at the address aligned to the reques...
Definition: ut0new.h:1548
void * malloc_large_page(std::size_t size) noexcept
Dynamically allocates memory backed up by large (huge) pages.
Definition: ut0new.h:1270
std::unordered_set< Key, std::hash< Key >, std::equal_to< Key >, ut::allocator< Key > > unordered_set
Definition: ut0new.h:2886
std::basic_ostringstream< char, std::char_traits< char >, ut::allocator< char > > ostringstream
Specialization of basic_ostringstream which uses ut::allocator.
Definition: ut0new.h:2869
T * new_(Args &&... args)
Dynamically allocates storage for an object of type T.
Definition: ut0new.h:793
allocation_low_level_info page_low_level_info(void *ptr) noexcept
Retrieves the pointer and size of the allocation provided by the OS.
Definition: ut0new.h:1208
std::vector< T, ut::allocator< T > > vector
Specialization of vector which uses allocator.
Definition: ut0new.h:2873
void aligned_delete_arr(T *ptr) noexcept
Releases storage which has been dynamically allocated through any of the aligned_new_arr_*() variants...
Definition: ut0new.h:1894
void delete_(T *ptr) noexcept
Releases storage which has been dynamically allocated through any of the ut::new*() variants.
Definition: ut0new.h:808
std::set< Key, Compare, ut::allocator< Key > > set
Specialization of set which uses ut_allocator.
Definition: ut0new.h:2881
void * malloc_page(std::size_t size) noexcept
Dynamically allocates system page-aligned storage of given size.
Definition: ut0new.h:1174
void * realloc_withkey(PSI_memory_key_t key, void *ptr, std::size_t size) noexcept
Upsizes or downsizes already dynamically allocated storage to the new size.
Definition: ut0new.h:674
T * new_withkey(PSI_memory_key_t key, Args &&... args)
Dynamically allocates storage for an object of type T.
Definition: ut0new.h:750
void delete_arr(T *ptr) noexcept
Releases storage which has been dynamically allocated through any of the ut::new_arr*() variants.
Definition: ut0new.h:1108
allocation_low_level_info large_page_low_level_info(void *ptr) noexcept
Retrieves the pointer and size of the allocation provided by the OS.
Definition: ut0new.h:1306
std::enable_if_t<!std::is_array< T >::value, std::unique_ptr< T, Deleter > > make_unique_aligned(size_t alignment, Args &&... args)
Dynamically allocates storage for an object of type T at address aligned to the requested alignment.
Definition: ut0new.h:2458
T * new_arr(Args &&... args)
Dynamically allocates storage for an array of T's.
Definition: ut0new.h:958
bool free_page(void *ptr) noexcept
Releases storage which has been dynamically allocated through any of the ut::malloc_page*() variants.
Definition: ut0new.h:1224
void * malloc_large_page_withkey(PSI_memory_key_t key, std::size_t size) noexcept
Dynamically allocates memory backed up by large (huge) pages.
Definition: ut0new.h:1246
size_t large_page_allocation_size(void *ptr) noexcept
Retrieves the total amount of bytes that are available for application code to use.
Definition: ut0new.h:1292
std::enable_if_t<!std::is_array< T >::value, std::shared_ptr< T > > make_shared_aligned(size_t alignment, Args &&... args)
Dynamically allocates storage for an object of type T at address aligned to the requested alignment.
Definition: ut0new.h:2729
std::map< Key, Value, Compare, ut::allocator< std::pair< const Key, Value > > > map
Specialization of map which uses ut_allocator.
Definition: ut0new.h:2891
void * malloc(std::size_t size) noexcept
Dynamically allocates storage of given size.
Definition: ut0new.h:616
std::conditional_t< !std::is_array< T >::value, std::unique_ptr< T, detail::Deleter< T > >, std::conditional_t< detail::is_unbounded_array_v< T >, std::unique_ptr< T, detail::Array_deleter< std::remove_extent_t< T > > >, void > > unique_ptr
The following is a common type that is returned by all the ut::make_unique (non-aligned) specializati...
Definition: ut0new.h:2437
T * aligned_new(std::size_t alignment, Args &&... args)
Dynamically allocates storage for an object of type T at address aligned to the requested alignment.
Definition: ut0new.h:1634
std::list< T, ut::allocator< T > > list
Specialization of list which uses ut_allocator.
Definition: ut0new.h:2877
void free(void *ptr) noexcept
Releases storage which has been dynamically allocated through any of the ut::malloc*(),...
Definition: ut0new.h:716
PSI_memory_key_t make_psi_memory_key(PSI_memory_key key)
Convenience helper function to create type-safe representation of PSI_memory_key.
Definition: ut0new.h:189
void * aligned_alloc_withkey(PSI_memory_key_t key, std::size_t size, std::size_t alignment) noexcept
Dynamically allocates storage of given size and at the address aligned to the requested alignment.
Definition: ut0new.h:1483
constexpr bool WITH_PFS_MEMORY
Definition: ut0new.h:579
void aligned_delete(T *ptr) noexcept
Releases storage which has been dynamically allocated through any of the aligned_new_*() variants.
Definition: ut0new.h:1649
void * malloc_page_withkey(PSI_memory_key_t key, std::size_t size) noexcept
Dynamically allocates system page-aligned storage of given size.
Definition: ut0new.h:1147
std::conditional_t< !std::is_array< T >::value, std::unique_ptr< T, detail::Aligned_deleter< T > >, std::conditional_t< detail::is_unbounded_array_v< T >, std::unique_ptr< T, detail::Aligned_array_deleter< std::remove_extent_t< T > > >, void > > unique_ptr_aligned
The following is a common type that is returned by all the ut::make_unique_aligned (non-aligned) spec...
Definition: ut0new.h:2571
void * realloc(void *ptr, std::size_t size) noexcept
Upsizes or downsizes already dynamically allocated storage to the new size.
Definition: ut0new.h:702
std::enable_if_t<!std::is_array< T >::value, std::shared_ptr< T > > make_shared(Args &&... args)
Dynamically allocates storage for an object of type T.
Definition: ut0new.h:2589
size_t page_allocation_size(void *ptr) noexcept
Retrieves the total amount of bytes that are available for application code to use.
Definition: ut0new.h:1194
bool free_large_page(void *ptr) noexcept
Releases storage which has been dynamically allocated through any of the ut::malloc_large_page*() var...
Definition: ut0new.h:1323
T * aligned_new_arr_withkey(PSI_memory_key_t key, std::size_t alignment, Args &&... args)
Dynamically allocates storage for an array of T's at address aligned to the requested alignment.
Definition: ut0new.h:1714
void aligned_free(void *ptr) noexcept
Releases storage which has been dynamically allocated through any of the aligned_alloc_*() or aligned...
Definition: ut0new.h:1562
void * aligned_alloc(std::size_t size, std::size_t alignment) noexcept
Dynamically allocates storage of given size and at the address aligned to the requested alignment.
Definition: ut0new.h:1506
void * zalloc(std::size_t size) noexcept
Dynamically allocates zero-initialized storage of given size.
Definition: ut0new.h:652
The interface to the operating system process control primitives.
bool os_use_large_pages
Whether to use large pages in the buffer pool.
Definition: os0proc.cc:50
The interface to the operating system process and thread control primitives.
Performance schema instrumentation interface.
Performance schema instrumentation interface.
required string key
Definition: replication_asynchronous_connection_failover.proto:59
static MEM_ROOT mem
Definition: sql_servers.cc:99
Memory instrument information.
Definition: psi_memory_bits.h:57
Definition: ut0new.h:556
static constexpr int value
Definition: ut0new.h:557
Light-weight and type-safe wrapper which serves a purpose of being able to select proper ut::new_arr*...
Definition: ut0new.h:980
Count(size_t count)
Definition: ut0new.h:981
size_t m_count
Definition: ut0new.h:983
size_t operator()() const
Definition: ut0new.h:982
Light-weight and type-safe wrapper around the PSI_memory_key that eliminates the possibility of intro...
Definition: ut0new.h:177
PSI_memory_key operator()() const
Definition: ut0new.h:179
PSI_memory_key m_key
Definition: ut0new.h:180
PSI_memory_key_t(PSI_memory_key key)
Definition: ut0new.h:178
Can be used to extract pointer and size of the allocation provided by the OS.
Definition: ut0new.h:139
void * base_ptr
A pointer returned by the OS allocator.
Definition: ut0new.h:141
size_t allocation_size
The size of allocation that OS performed.
Definition: ut0new.h:143
Definition: ut0new.h:2222
Small wrapper which utilizes SFINAE to dispatch the call to appropriate aligned allocator implementat...
Definition: aligned_alloc.h:696
Definition: ut0new.h:2313
void operator()(T *ptr)
Definition: ut0new.h:2314
Definition: ut0new.h:2308
void operator()(T *ptr)
Definition: ut0new.h:2309
Small wrapper which utilizes SFINAE to dispatch the call to appropriate allocator implementation.
Definition: alloc.h:434
Definition: ut0new.h:2303
void operator()(T *ptr)
Definition: ut0new.h:2304
Definition: ut0new.h:2298
void operator()(T *ptr)
Definition: ut0new.h:2299
Small wrapper which utilizes SFINAE to dispatch the call to appropriate aligned allocator implementat...
Definition: large_page_alloc.h:372
Small wrapper which utilizes SFINAE to dispatch the call to appropriate aligned allocator implementat...
Definition: page_alloc.h:433
Definition: ut0new.h:2130
void * allocate_impl(size_t n_bytes)
Definition: ut0new.h:2139
const PSI_memory_key m_key
Definition: ut0new.h:2144
PSI_memory_key get_mem_key() const
Definition: ut0new.h:2137
allocator_base_pfs(PSI_memory_key key)
Definition: ut0new.h:2131
allocator_base_pfs(const allocator_base_pfs< U > &other)
Definition: ut0new.h:2134
Definition: ut0new.h:2120
allocator_base(const allocator_base< U > &)
Definition: ut0new.h:2124
void * allocate_impl(size_t n_bytes)
Definition: ut0new.h:2126
allocator_base(PSI_memory_key)
Definition: ut0new.h:2121
Definition: ut0new.h:1330
Version control for database, common definitions, and include files.
#define UT_ARR_SIZE(a)
Definition: univ.i:523
Utilities for byte operations.
Utilities related to CPU cache.
Debug utilities for Innobase.
#define ut_ad(EXPR)
Debug assertion.
Definition: ut0dbg.h:104
#define ut_a(EXPR)
Abort execution if EXPR does not evaluate to nonzero.
Definition: ut0dbg.h:92
PSI_memory_key mem_key_ddl
Definition: ut0new.cc:59
void ut_new_boot_safe()
Setup the internal objects needed for ut::*_withkey() to operate.
Definition: ut0new.cc:136
PSI_memory_key mem_key_redo_log_archive_queue_element
PSI_memory_key mem_key_dict_stats_index_map_t
Definition: ut0new.cc:53
PSI_memory_key mem_key_buf_stat_per_index_t
Definition: ut0new.cc:49
PSI_memory_key mem_key_other
Definition: ut0new.cc:56
PSI_memory_info pfs_info_auto[n_auto]
PSI_memory_key auto_event_keys[n_auto]
constexpr int ut_new_get_key_by_base_file(const char *file, size_t len)
Retrieve a memory key (registered with PFS), given the file name of the caller.
Definition: ut0new.h:535
PSI_memory_key mem_key_fil_space_t
Definition: ut0new.cc:55
constexpr bool ut_string_begins_with(const char *a, const char *b, size_t b_len)
gcc 5 fails to evaluate costexprs at compile time.
Definition: ut0new.h:509
constexpr int ut_new_get_key_by_file(const char *file)
Retrieve a memory key (registered with PFS), given the file name of the caller.
Definition: ut0new.h:548
PSI_memory_key mem_key_ahi
Keys for registering allocations with performance schema.
Definition: ut0new.cc:46
void ut_new_boot()
Setup the internal objects needed for ut::*_withkey() to operate.
Definition: ut0new.cc:117
PSI_memory_key mem_key_partitioning
Definition: ut0new.cc:57
PSI_memory_key mem_key_archive
Definition: ut0new.cc:47
static constexpr const char * auto_event_names[]
List of filenames that allocate memory and are instrumented via PFS.
Definition: ut0new.h:245
PSI_memory_key mem_key_std
Definition: ut0new.cc:60
const size_t alloc_max_retries
Maximum number of retries to allocate memory.
Definition: ut0new.cc:42
PSI_memory_key mem_key_row_log_buf
Definition: ut0new.cc:58
PSI_memory_key mem_key_trx_sys_t_rw_trx_ids
Definition: ut0new.cc:61
static constexpr size_t n_auto
Definition: ut0new.h:446
PSI_memory_key mem_key_buf_buf_pool
Definition: ut0new.cc:48
constexpr size_t ut_len_without_extension(const char *file)
Find the length of the filename without its file extension.
Definition: ut0new.h:522
PSI_memory_key mem_key_undo_spaces
Definition: ut0new.cc:62
PSI_memory_key mem_key_ut_lock_free_hash_t
Definition: ut0new.cc:63
PSI_memory_key mem_key_clone
Memory key for clone.
Definition: ut0new.cc:51
PSI_memory_key mem_key_dict_stats_n_diff_on_level
Definition: ut0new.cc:54
PSI_memory_key mem_key_dict_stats_bg_recalc_pool_t
Definition: ut0new.cc:52
Various utilities.
#define PSI_NOT_INSTRUMENTED
Definition: validate_password_imp.cc:41