| 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 | |