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