1 /*****************************************************************************
2
3 Copyright (c) 2014, 2021, Oracle and/or its affiliates.
4 Copyright (c) 2016, Percona Inc. All Rights Reserved.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License, version 2.0,
8 as published by the Free Software Foundation.
9
10 This program is also distributed with certain software (including
11 but not limited to OpenSSL) that is licensed under separate terms,
12 as designated in a particular file or component or in included license
13 documentation. The authors of MySQL hereby grant you an additional
14 permission to link the program and your derivative works with the
15 separately licensed software that they have included with MySQL.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License, version 2.0, for more details.
21
22 You should have received a copy of the GNU General Public License along with
23 this program; if not, write to the Free Software Foundation, Inc.,
24 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
25
26 *****************************************************************************/
27
28 /**************************************************//**
29 @file ut/ut0new.cc
30 Instrumented memory allocator.
31
32 Created May 26, 2014 Vasil Dimov
33 *******************************************************/
34
35 #include "univ.i"
36
37 #include "ut0new.h"
38
39 /** Maximum number of retries to allocate memory. */
40 const size_t alloc_max_retries = 60;
41
42 /** Keys for registering allocations with performance schema.
43 Keep this list alphabetically sorted. */
44 PSI_memory_key mem_key_ahi;
45 PSI_memory_key mem_key_buf_buf_pool;
46 PSI_memory_key mem_key_dict_stats_bg_recalc_pool_t;
47 PSI_memory_key mem_key_dict_stats_index_map_t;
48 PSI_memory_key mem_key_dict_stats_n_diff_on_level;
49 PSI_memory_key mem_key_other;
50 PSI_memory_key mem_key_row_log_buf;
51 PSI_memory_key mem_key_row_merge_sort;
52 PSI_memory_key mem_key_std;
53 PSI_memory_key mem_key_trx_sys_t_rw_trx_ids;
54 PSI_memory_key mem_key_partitioning;
55
56 PSI_memory_key mem_key_log_online_modified_pages;
57 PSI_memory_key mem_key_log_online_sys;
58 PSI_memory_key mem_key_log_online_read_buf;
59 PSI_memory_key mem_key_log_online_iterator_files;
60 PSI_memory_key mem_key_log_online_iterator_page;
61 PSI_memory_key mem_key_parallel_doublewrite;
62
63 #ifdef UNIV_PFS_MEMORY
64
65 /** Auxiliary array of performance schema 'PSI_memory_info'.
66 Each allocation appears in
67 performance_schema.memory_summary_global_by_event_name (and alike) in the form
68 of e.g. 'memory/innodb/NAME' where the last component NAME is picked from
69 the list below:
70 1. If key is specified, then the respective name is used
71 2. Without a specified key, allocations from inside std::* containers use
72 mem_key_std
73 3. Without a specified key, allocations from outside std::* pick up the key
74 based on the file name, and if file name is not found in the predefined list
75 (in ut_new_boot()) then mem_key_other is used.
76 Keep this list alphabetically sorted. */
77 static PSI_memory_info pfs_info[] = {
78 {&mem_key_ahi, "adaptive hash index", 0},
79 {&mem_key_buf_buf_pool, "buf_buf_pool", 0},
80 {&mem_key_dict_stats_bg_recalc_pool_t, "dict_stats_bg_recalc_pool_t", 0},
81 {&mem_key_dict_stats_index_map_t, "dict_stats_index_map_t", 0},
82 {&mem_key_dict_stats_n_diff_on_level, "dict_stats_n_diff_on_level", 0},
83 {&mem_key_other, "other", 0},
84 {&mem_key_row_log_buf, "row_log_buf", 0},
85 {&mem_key_row_merge_sort, "row_merge_sort", 0},
86 {&mem_key_std, "std", 0},
87 {&mem_key_trx_sys_t_rw_trx_ids, "trx_sys_t::rw_trx_ids", 0},
88 {&mem_key_log_online_modified_pages, "log_online_modified_pages", 0},
89 {&mem_key_log_online_sys, "log_online_sys", 0},
90 {&mem_key_log_online_read_buf, "log_online_read_buf", 0},
91 {&mem_key_log_online_iterator_files, "log_online_iterator_files", 0},
92 {&mem_key_log_online_iterator_page, "log_online_iterator_page", 0},
93 {&mem_key_partitioning, "partitioning", 0},
94 {&mem_key_parallel_doublewrite, "parallel_doublewrite", 0},
95 };
96
97 /** Map used for default performance schema keys, based on file name of the
98 caller. The key is the file name of the caller and the value is a pointer
99 to a PSI_memory_key variable to be passed to performance schema methods.
100 We use ut_strcmp_functor because by default std::map will compare the pointers
101 themselves (cont char*) and not do strcmp(). */
102 typedef std::map<const char*, PSI_memory_key*, ut_strcmp_functor>
103 mem_keys_auto_t;
104
105 /** Map of filename/pfskey, used for tracing allocations that have not
106 provided a manually created pfs key. This map is only ever modified (bulk
107 insert) at startup in a single-threaded environment by ut_new_boot().
108 Later it is only read (only std::map::find() is called) from multithreaded
109 environment, thus it is not protected by any latch. */
110 static mem_keys_auto_t mem_keys_auto;
111
112 #endif /* UNIV_PFS_MEMORY */
113
114 /** Setup the internal objects needed for UT_NEW() to operate.
115 This must be called before the first call to UT_NEW(). */
116 void
ut_new_boot()117 ut_new_boot()
118 {
119 #ifdef UNIV_PFS_MEMORY
120 static const char* auto_event_names[] = {
121 /* Keep this list alphabetically sorted. */
122 "api0api",
123 "btr0btr",
124 "btr0bulk",
125 "btr0cur",
126 "btr0pcur",
127 "btr0sea",
128 "buf0buf",
129 "buf0dblwr",
130 "buf0dump",
131 "buf0flu",
132 "buf0lru",
133 "dict0dict",
134 "dict0mem",
135 "dict0stats",
136 "dict0stats_bg",
137 "eval0eval",
138 "fil0fil",
139 "fsp0file",
140 "fsp0space",
141 "fsp0sysspace",
142 "fts0ast",
143 "fts0config",
144 "fts0fts",
145 "fts0opt",
146 "fts0pars",
147 "fts0que",
148 "fts0sql",
149 "gis0sea",
150 "ha0ha",
151 "ha_innodb",
152 "handler0alter",
153 "hash0hash",
154 "i_s",
155 "ibuf0ibuf",
156 "lexyy",
157 "lock0lock",
158 "log0log",
159 "log0recv",
160 "mem0mem",
161 "os0event",
162 "os0file",
163 "page0cur",
164 "page0zip",
165 "pars0lex",
166 "read0read",
167 "rem0rec",
168 "row0ftsort",
169 "row0import",
170 "row0log",
171 "row0merge",
172 "row0mysql",
173 "row0sel",
174 "row0trunc",
175 "srv0conc",
176 "srv0srv",
177 "srv0start",
178 "sync0arr",
179 "sync0debug",
180 "sync0rw",
181 "sync0types",
182 "trx0i_s",
183 "trx0purge",
184 "trx0roll",
185 "trx0rseg",
186 "trx0sys",
187 "trx0trx",
188 "trx0undo",
189 "usr0sess",
190 "ut0list",
191 "ut0mem",
192 "ut0mutex",
193 "ut0pool",
194 "ut0rbt",
195 "ut0wqueue",
196 };
197 static const size_t n_auto = UT_ARR_SIZE(auto_event_names);
198 static PSI_memory_key auto_event_keys[n_auto];
199 static PSI_memory_info pfs_info_auto[n_auto];
200
201 for (size_t i = 0; i < n_auto; i++) {
202
203 const std::pair<mem_keys_auto_t::iterator, bool> ret
204 MY_ATTRIBUTE((unused))
205 = mem_keys_auto.insert(
206 mem_keys_auto_t::value_type(auto_event_names[i],
207 &auto_event_keys[i]));
208
209 /* ret.second is true if new element has been inserted */
210 ut_a(ret.second);
211
212 /* e.g. "btr0btr" */
213 pfs_info_auto[i].m_name = auto_event_names[i];
214
215 /* a pointer to the pfs key */
216 pfs_info_auto[i].m_key = &auto_event_keys[i];
217
218 pfs_info_auto[i].m_flags = 0;
219 }
220
221 PSI_MEMORY_CALL(register_memory)("innodb",
222 pfs_info,
223 UT_ARR_SIZE(pfs_info));
224 PSI_MEMORY_CALL(register_memory)("innodb",
225 pfs_info_auto,
226 n_auto);
227 #endif /* UNIV_PFS_MEMORY */
228 }
229
230 #ifdef UNIV_PFS_MEMORY
231
232 /** Retrieve a memory key (registered with PFS), given a portion of the file
233 name of the caller.
234 @param[in] file portion of the filename - basename without an extension
235 @return registered memory key or PSI_NOT_INSTRUMENTED if not found */
236 PSI_memory_key
ut_new_get_key_by_file(const char * file)237 ut_new_get_key_by_file(
238 const char* file)
239 {
240 mem_keys_auto_t::const_iterator el = mem_keys_auto.find(file);
241
242 if (el != mem_keys_auto.end()) {
243 return(*(el->second));
244 }
245
246 return(PSI_NOT_INSTRUMENTED);
247 }
248
249 #endif /* UNIV_PFS_MEMORY */
250