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