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