1 | /***************************************************************************** |
2 | |
3 | Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved. |
4 | |
5 | This program is free software; you can redistribute it and/or modify it under |
6 | the terms of the GNU General Public License as published by the Free Software |
7 | Foundation; version 2 of the License. |
8 | |
9 | This program is distributed in the hope that it will be useful, but WITHOUT |
10 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
11 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. |
12 | |
13 | You should have received a copy of the GNU General Public License along with |
14 | this program; if not, write to the Free Software Foundation, Inc., |
15 | 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA |
16 | |
17 | *****************************************************************************/ |
18 | |
19 | /**************************************************//** |
20 | @file ut/ut0new.cc |
21 | Instrumented memory allocator. |
22 | |
23 | Created 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. */ |
31 | const size_t alloc_max_retries = 60; |
32 | |
33 | /** Keys for registering allocations with performance schema. |
34 | Keep this list alphabetically sorted. */ |
35 | #ifdef BTR_CUR_HASH_ADAPT |
36 | PSI_memory_key mem_key_ahi; |
37 | #endif /* BTR_CUR_HASH_ADAPT */ |
38 | PSI_memory_key mem_key_buf_buf_pool; |
39 | PSI_memory_key mem_key_dict_stats_bg_recalc_pool_t; |
40 | PSI_memory_key mem_key_dict_stats_index_map_t; |
41 | PSI_memory_key mem_key_dict_stats_n_diff_on_level; |
42 | PSI_memory_key mem_key_other; |
43 | PSI_memory_key mem_key_row_log_buf; |
44 | PSI_memory_key mem_key_row_merge_sort; |
45 | PSI_memory_key mem_key_std; |
46 | PSI_memory_key mem_key_partitioning; |
47 | |
48 | #ifdef UNIV_PFS_MEMORY |
49 | |
50 | /** Auxiliary array of performance schema 'PSI_memory_info'. |
51 | Each allocation appears in |
52 | performance_schema.memory_summary_global_by_event_name (and alike) in the form |
53 | of e.g. 'memory/innodb/NAME' where the last component NAME is picked from |
54 | the list below: |
55 | 1. If key is specified, then the respective name is used |
56 | 2. Without a specified key, allocations from inside std::* containers use |
57 | mem_key_std |
58 | 3. 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. |
61 | Keep this list alphabetically sorted. */ |
62 | static 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 |
78 | caller. The key is the file name of the caller and the value is a pointer |
79 | to a PSI_memory_key variable to be passed to performance schema methods. |
80 | We use ut_strcmp_functor because by default std::map will compare the pointers |
81 | themselves (cont char*) and not do strcmp(). */ |
82 | typedef 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 |
86 | provided a manually created pfs key. This map is only ever modified (bulk |
87 | insert) at startup in a single-threaded environment by ut_new_boot(). |
88 | Later it is only read (only std::map::find() is called) from multithreaded |
89 | environment, thus it is not protected by any latch. */ |
90 | static 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. |
95 | This must be called before the first call to UT_NEW(). */ |
96 | void |
97 | ut_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 |
211 | name 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 */ |
214 | PSI_memory_key |
215 | ut_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 | |