1 // -*- C++ -*- 2 // 3 // Copyright (C) 2009-2019 Free Software Foundation, Inc. 4 // 5 // This file is part of the GNU ISO C++ Library. This library is free 6 // software; you can redistribute it and/or modify it under the 7 // terms of the GNU General Public License as published by the 8 // Free Software Foundation; either version 3, or (at your option) 9 // any later version. 10 // 11 // This library is distributed in the hope that it will be useful, 12 // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 // GNU General Public License for more details. 15 16 // Under Section 7 of GPL version 3, you are granted additional 17 // permissions described in the GCC Runtime Library Exception, version 18 // 3.1, as published by the Free Software Foundation. 19 20 // You should have received a copy of the GNU General Public License along 21 // with this library; see the file COPYING3. If not see 22 // <http://www.gnu.org/licenses/>. 23 24 /** @file profile/impl/profiler_trace.h 25 * @brief Data structures to represent profiling traces. 26 */ 27 28 // Written by Lixia Liu and Silvius Rus. 29 30 #ifndef _GLIBCXX_PROFILE_PROFILER_TRACE_H 31 #define _GLIBCXX_PROFILE_PROFILER_TRACE_H 1 32 33 #include <cstdio> // fopen, fclose, fprintf, FILE 34 #include <cerrno> 35 #include <cstdlib> // atof, atoi, strtol, getenv, atexit, abort 36 37 #if __cplusplus >= 201103L 38 #include <unordered_map> 39 #define _GLIBCXX_IMPL_UNORDERED_MAP std::_GLIBCXX_STD_C::unordered_map 40 #else 41 #include <tr1/unordered_map> 42 #define _GLIBCXX_IMPL_UNORDERED_MAP std::tr1::unordered_map 43 #endif 44 45 #include <ext/concurrence.h> 46 #include <fstream> 47 #include <string> 48 #include <utility> 49 #include <vector> 50 51 #include "profile/impl/profiler_algos.h" 52 #include "profile/impl/profiler_state.h" 53 #include "profile/impl/profiler_node.h" 54 55 namespace __gnu_profile 56 { 57 /** @brief Internal environment. Values can be set one of two ways: 58 1. In config file "var = value". The default config file path is 59 libstdcxx-profile.conf. 60 2. By setting process environment variables. For instance, in a Bash 61 shell you can set the unit cost of iterating through a map like this: 62 export __map_iterate_cost_factor=5.0. 63 If a value is set both in the input file and through an environment 64 variable, the environment value takes precedence. */ 65 typedef _GLIBCXX_IMPL_UNORDERED_MAP<std::string, std::string> __env_t; 66 67 _GLIBCXX_PROFILE_DEFINE_UNINIT_DATA(__env_t, __env); 68 69 /** @brief Master lock. */ 70 _GLIBCXX_PROFILE_DEFINE_UNINIT_DATA(__gnu_cxx::__mutex, __global_mutex); 71 72 /** @brief Representation of a warning. */ 73 struct __warning_data 74 { 75 float __magnitude; 76 __stack_t __context; 77 const char* __warning_id; 78 std::string __warning_message; 79 __warning_data__warning_data80 __warning_data() 81 : __magnitude(0.0), __context(0), __warning_id(0) { } 82 __warning_data__warning_data83 __warning_data(float __m, __stack_t __c, const char* __id, 84 const std::string& __msg) 85 : __magnitude(__m), __context(__c), __warning_id(__id), 86 __warning_message(__msg) { } 87 88 bool 89 operator<(const __warning_data& __other) const 90 { return __magnitude < __other.__magnitude; } 91 }; 92 93 typedef std::_GLIBCXX_STD_C::vector<__warning_data> __warning_vector_t; 94 95 // Defined in profiler_<diagnostic name>.h. 96 class __trace_hash_func; 97 class __trace_hashtable_size; 98 class __trace_map2umap; 99 class __trace_vector_size; 100 class __trace_vector_to_list; 101 class __trace_list_to_slist; 102 class __trace_list_to_vector; 103 void __trace_vector_size_init(); 104 void __trace_hashtable_size_init(); 105 void __trace_hash_func_init(); 106 void __trace_vector_to_list_init(); 107 void __trace_list_to_slist_init(); 108 void __trace_list_to_vector_init(); 109 void __trace_map_to_unordered_map_init(); 110 void __trace_vector_size_report(FILE*, __warning_vector_t&); 111 void __trace_hashtable_size_report(FILE*, __warning_vector_t&); 112 void __trace_hash_func_report(FILE*, __warning_vector_t&); 113 void __trace_vector_to_list_report(FILE*, __warning_vector_t&); 114 void __trace_list_to_slist_report(FILE*, __warning_vector_t&); 115 void __trace_list_to_vector_report(FILE*, __warning_vector_t&); 116 void __trace_map_to_unordered_map_report(FILE*, __warning_vector_t&); 117 void __trace_vector_size_free(); 118 void __trace_hashtable_size_free(); 119 void __trace_hash_func_free(); 120 void __trace_vector_to_list_free(); 121 void __trace_list_to_slist_free(); 122 void __trace_list_to_vector_free(); 123 void __trace_map_to_unordered_map_free(); 124 125 struct __cost_factor 126 { 127 const char* __env_var; 128 float __value; 129 }; 130 131 typedef std::_GLIBCXX_STD_C::vector<__cost_factor*> __cost_factor_vector; 132 133 _GLIBCXX_PROFILE_DEFINE_DATA(__trace_hash_func*, _S_hash_func, 0); 134 _GLIBCXX_PROFILE_DEFINE_DATA(__trace_hashtable_size*, _S_hashtable_size, 0); 135 _GLIBCXX_PROFILE_DEFINE_DATA(__trace_map2umap*, _S_map2umap, 0); 136 _GLIBCXX_PROFILE_DEFINE_DATA(__trace_vector_size*, _S_vector_size, 0); 137 _GLIBCXX_PROFILE_DEFINE_DATA(__trace_vector_to_list*, _S_vector_to_list, 0); 138 _GLIBCXX_PROFILE_DEFINE_DATA(__trace_list_to_slist*, _S_list_to_slist, 0); 139 _GLIBCXX_PROFILE_DEFINE_DATA(__trace_list_to_vector*, _S_list_to_vector, 0); 140 141 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __vector_shift_cost_factor, 142 {"__vector_shift_cost_factor", 1.0}); 143 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __vector_iterate_cost_factor, 144 {"__vector_iterate_cost_factor", 1.0}); 145 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __vector_resize_cost_factor, 146 {"__vector_resize_cost_factor", 1.0}); 147 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __list_shift_cost_factor, 148 {"__list_shift_cost_factor", 0.0}); 149 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __list_iterate_cost_factor, 150 {"__list_iterate_cost_factor", 10.0}); 151 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __list_resize_cost_factor, 152 {"__list_resize_cost_factor", 0.0}); 153 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_insert_cost_factor, 154 {"__map_insert_cost_factor", 1.5}); 155 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_erase_cost_factor, 156 {"__map_erase_cost_factor", 1.5}); 157 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_find_cost_factor, 158 {"__map_find_cost_factor", 1}); 159 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_iterate_cost_factor, 160 {"__map_iterate_cost_factor", 2.3}); 161 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_insert_cost_factor, 162 {"__umap_insert_cost_factor", 12.0}); 163 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_erase_cost_factor, 164 {"__umap_erase_cost_factor", 12.0}); 165 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_find_cost_factor, 166 {"__umap_find_cost_factor", 10.0}); 167 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_iterate_cost_factor, 168 {"__umap_iterate_cost_factor", 1.7}); 169 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor_vector*, __cost_factors, 0); 170 171 _GLIBCXX_PROFILE_DEFINE_DATA(const char*, _S_trace_file_name, 172 _GLIBCXX_PROFILE_TRACE_PATH_ROOT); 173 _GLIBCXX_PROFILE_DEFINE_DATA(std::size_t, _S_max_warn_count, 174 _GLIBCXX_PROFILE_MAX_WARN_COUNT); 175 _GLIBCXX_PROFILE_DEFINE_DATA(std::size_t, _S_max_stack_depth, 176 _GLIBCXX_PROFILE_MAX_STACK_DEPTH); 177 _GLIBCXX_PROFILE_DEFINE_DATA(std::size_t, _S_max_mem, 178 _GLIBCXX_PROFILE_MEM_PER_DIAGNOSTIC); 179 180 inline std::size_t __stack_max_depth()181 __stack_max_depth() 182 { return _GLIBCXX_PROFILE_DATA(_S_max_stack_depth); } 183 184 inline std::size_t __max_mem()185 __max_mem() 186 { return _GLIBCXX_PROFILE_DATA(_S_max_mem); } 187 188 /** @brief Base class for all trace producers. */ 189 template<typename __object_info, typename __stack_info> 190 class __trace_base 191 { 192 public: 193 // Do not pick the initial size too large, as we don't know which 194 // diagnostics are more active. __trace_base()195 __trace_base() 196 : __objects_byte_size(0), __stack_table(10000), 197 __stack_table_byte_size(0), __id(0) { } 198 ~__trace_base()199 ~__trace_base() 200 { 201 for (typename __stack_table_t::iterator __it 202 = __stack_table.begin(); __it != __stack_table.end(); ++__it) 203 delete __it->first; 204 } 205 206 __object_info* __add_object(__stack_t __stack); 207 void __retire_object(__object_info* __info); 208 void __write(FILE* __f); 209 void __collect_warnings(__warning_vector_t& __warnings); 210 void __free(); 211 212 private: 213 __gnu_cxx::__mutex __trace_mutex; 214 typedef _GLIBCXX_IMPL_UNORDERED_MAP<__stack_t, __stack_info, 215 __stack_hash, 216 __stack_hash> __stack_table_t; 217 std::size_t __objects_byte_size; 218 __stack_table_t __stack_table; 219 std::size_t __stack_table_byte_size; 220 221 protected: 222 const char* __id; 223 }; 224 225 template<typename __object_info, typename __stack_info> 226 __object_info* 227 __trace_base<__object_info, __stack_info>:: __add_object(__stack_t __stack)228 __add_object(__stack_t __stack) 229 { 230 // If we have no backtrace information no need to collect data. 231 if (!__stack) 232 return 0; 233 234 __gnu_cxx::__scoped_lock __lock(this->__trace_mutex); 235 236 if (__max_mem() != 0 && __objects_byte_size >= __max_mem()) 237 { 238 delete __stack; 239 return 0; 240 } 241 242 __object_info* __ret = new(std::nothrow) __object_info(__stack); 243 if (!__ret) 244 { 245 delete __stack; 246 return 0; 247 } 248 249 __objects_byte_size += sizeof(__object_info); 250 return __ret; 251 } 252 253 template<typename __object_info, typename __stack_info> 254 void 255 __trace_base<__object_info, __stack_info>:: __retire_object(__object_info * __obj_info)256 __retire_object(__object_info* __obj_info) 257 { 258 if (!__obj_info) 259 return; 260 261 __gnu_cxx::__scoped_lock __lock(this->__trace_mutex); 262 263 const __object_info& __info = *__obj_info; 264 __stack_t __stack = __info.__stack(); 265 typename __stack_table_t::iterator __stack_it 266 = __stack_table.find(__stack); 267 268 if (__stack_it == __stack_table.end()) 269 { 270 // First occurrence of this call context. 271 if (__max_mem() == 0 || __stack_table_byte_size < __max_mem()) 272 { 273 __stack_table_byte_size 274 += (sizeof(__instruction_address_t) * __size(__stack) 275 + sizeof(__stack) + sizeof(__stack_info)); 276 __stack_table.insert(make_pair(__stack, 277 __stack_info(__info))); 278 } 279 else 280 delete __stack; 281 } 282 else 283 { 284 // Merge object info into info summary for this call context. 285 __stack_it->second.__merge(__info); 286 delete __stack; 287 } 288 289 delete __obj_info; 290 __objects_byte_size -= sizeof(__object_info); 291 } 292 293 template<typename __object_info, typename __stack_info> 294 void 295 __trace_base<__object_info, __stack_info>:: __write(FILE * __f)296 __write(FILE* __f) 297 { 298 for (typename __stack_table_t::iterator __it 299 = __stack_table.begin(); __it != __stack_table.end(); ++__it) 300 if (__it->second.__is_valid()) 301 { 302 std::fprintf(__f, __id); 303 std::fprintf(__f, "|"); 304 __gnu_profile::__write(__f, __it->first); 305 std::fprintf(__f, "|"); 306 __it->second.__write(__f); 307 } 308 } 309 310 template<typename __object_info, typename __stack_info> 311 void 312 __trace_base<__object_info, __stack_info>:: __collect_warnings(__warning_vector_t & __warnings)313 __collect_warnings(__warning_vector_t& __warnings) 314 { 315 for (typename __stack_table_t::iterator __it 316 = __stack_table.begin(); __it != __stack_table.end(); ++__it) 317 __warnings.push_back(__warning_data(__it->second.__magnitude(), 318 __it->first, __id, 319 __it->second.__advice())); 320 } 321 322 template<typename __object_info, typename __stack_info> 323 inline void __trace_report(__trace_base<__object_info,__stack_info> * __cont,FILE * __f,__warning_vector_t & __warnings)324 __trace_report(__trace_base<__object_info, __stack_info>* __cont, 325 FILE* __f, __warning_vector_t& __warnings) 326 { 327 if (__cont) 328 { 329 __cont->__collect_warnings(__warnings); 330 __cont->__write(__f); 331 } 332 } 333 334 inline std::size_t __env_to_size_t(const char * __env_var,std::size_t __default_value)335 __env_to_size_t(const char* __env_var, std::size_t __default_value) 336 { 337 char* __env_value = std::getenv(__env_var); 338 if (__env_value) 339 { 340 errno = 0; 341 long __converted_value = std::strtol(__env_value, 0, 10); 342 if (errno || __converted_value < 0) 343 { 344 std::fprintf(stderr, 345 "Bad value for environment variable '%s'.\n", 346 __env_var); 347 std::abort(); 348 } 349 else 350 return static_cast<std::size_t>(__converted_value); 351 } 352 else 353 return __default_value; 354 } 355 356 inline void __set_max_stack_trace_depth()357 __set_max_stack_trace_depth() 358 { 359 _GLIBCXX_PROFILE_DATA(_S_max_stack_depth) 360 = __env_to_size_t(_GLIBCXX_PROFILE_MAX_STACK_DEPTH_ENV_VAR, 361 _GLIBCXX_PROFILE_DATA(_S_max_stack_depth)); 362 } 363 364 inline void __set_max_mem()365 __set_max_mem() 366 { 367 _GLIBCXX_PROFILE_DATA(_S_max_mem) 368 = __env_to_size_t(_GLIBCXX_PROFILE_MEM_PER_DIAGNOSTIC_ENV_VAR, 369 _GLIBCXX_PROFILE_DATA(_S_max_mem)); 370 } 371 372 inline int __log_magnitude(float __f)373 __log_magnitude(float __f) 374 { 375 const float __log_base = 10.0; 376 int __result = 0; 377 int __sign = 1; 378 379 if (__f < 0) 380 { 381 __f = -__f; 382 __sign = -1; 383 } 384 385 while (__f > __log_base) 386 { 387 ++__result; 388 __f /= 10.0; 389 } 390 return __sign * __result; 391 } 392 393 inline FILE* __open_output_file(const char * __extension)394 __open_output_file(const char* __extension) 395 { 396 // The path is made of _S_trace_file_name + "." + extension. 397 std::size_t __root_len 398 = __builtin_strlen(_GLIBCXX_PROFILE_DATA(_S_trace_file_name)); 399 std::size_t __ext_len = __builtin_strlen(__extension); 400 char* __file_name = new char[__root_len + 1 + __ext_len + 1]; 401 __builtin_memcpy(__file_name, 402 _GLIBCXX_PROFILE_DATA(_S_trace_file_name), 403 __root_len); 404 *(__file_name + __root_len) = '.'; 405 __builtin_memcpy(__file_name + __root_len + 1, 406 __extension, __ext_len + 1); 407 408 FILE* __out_file = std::fopen(__file_name, "w"); 409 if (!__out_file) 410 { 411 std::fprintf(stderr, "Could not open trace file '%s'.\n", 412 __file_name); 413 std::abort(); 414 } 415 416 delete[] __file_name; 417 return __out_file; 418 } 419 420 struct __warn 421 { 422 FILE* __file; 423 __warn__warn424 __warn(FILE* __f) 425 { __file = __f; } 426 427 void operator__warn428 operator()(const __warning_data& __info) 429 { 430 std::fprintf(__file, __info.__warning_id); 431 std::fprintf(__file, ": improvement = %d", 432 __log_magnitude(__info.__magnitude)); 433 std::fprintf(__file, ": call stack = "); 434 __gnu_profile::__write(__file, __info.__context); 435 std::fprintf(__file, ": advice = %s\n", 436 __info.__warning_message.c_str()); 437 } 438 }; 439 440 /** @brief Final report method, registered with @b atexit. 441 * 442 * This can also be called directly by user code, including signal handlers. 443 * It is protected against deadlocks by the reentrance guard in profiler.h. 444 * However, when called from a signal handler that triggers while within 445 * __gnu_profile (under the guarded zone), no output will be produced. 446 */ 447 inline void __report()448 __report() 449 { 450 __gnu_cxx::__scoped_lock __lock(_GLIBCXX_PROFILE_DATA(__global_mutex)); 451 452 __warning_vector_t __warnings, __top_warnings; 453 454 FILE* __raw_file = __open_output_file("raw"); 455 __trace_vector_size_report(__raw_file, __warnings); 456 __trace_hashtable_size_report(__raw_file, __warnings); 457 __trace_hash_func_report(__raw_file, __warnings); 458 __trace_vector_to_list_report(__raw_file, __warnings); 459 __trace_list_to_slist_report(__raw_file, __warnings); 460 __trace_list_to_vector_report(__raw_file, __warnings); 461 __trace_map_to_unordered_map_report(__raw_file, __warnings); 462 std::fclose(__raw_file); 463 464 // Sort data by magnitude, keeping just top N. 465 std::size_t __cutoff = std::min(_GLIBCXX_PROFILE_DATA(_S_max_warn_count), 466 __warnings.size()); 467 __top_n(__warnings, __top_warnings, __cutoff); 468 469 FILE* __warn_file = __open_output_file("txt"); 470 __for_each(__top_warnings.begin(), __top_warnings.end(), 471 __warn(__warn_file)); 472 std::fclose(__warn_file); 473 } 474 475 inline void __report_and_free()476 __report_and_free() 477 { 478 __report(); 479 480 __trace_map_to_unordered_map_free(); 481 __trace_list_to_vector_free(); 482 __trace_list_to_slist_free(); 483 __trace_vector_to_list_free(); 484 __trace_hash_func_free(); 485 __trace_hashtable_size_free(); 486 __trace_vector_size_free(); 487 delete _GLIBCXX_PROFILE_DATA(__cost_factors); 488 } 489 490 inline void __set_trace_path()491 __set_trace_path() 492 { 493 char* __env_trace_file_name = std::getenv(_GLIBCXX_PROFILE_TRACE_ENV_VAR); 494 495 if (__env_trace_file_name) 496 _GLIBCXX_PROFILE_DATA(_S_trace_file_name) = __env_trace_file_name; 497 498 // Make sure early that we can create the trace file. 499 std::fclose(__open_output_file("txt")); 500 } 501 502 inline void __set_max_warn_count()503 __set_max_warn_count() 504 { 505 char* __env_max_warn_count_str 506 = std::getenv(_GLIBCXX_PROFILE_MAX_WARN_COUNT_ENV_VAR); 507 508 if (__env_max_warn_count_str) 509 _GLIBCXX_PROFILE_DATA(_S_max_warn_count) 510 = static_cast<std::size_t>(std::atoi(__env_max_warn_count_str)); 511 } 512 513 inline void __read_cost_factors()514 __read_cost_factors() 515 { 516 std::string __conf_file_name(_GLIBCXX_PROFILE_DATA(_S_trace_file_name)); 517 __conf_file_name += ".conf"; 518 519 std::ifstream __conf_file(__conf_file_name.c_str()); 520 521 if (__conf_file.is_open()) 522 { 523 std::string __line; 524 525 while (std::getline(__conf_file, __line)) 526 { 527 std::string::size_type __i = __line.find_first_not_of(" \t\n\v"); 528 529 if (__line.length() <= 0 || __line[__i] == '#') 530 // Skip empty lines or comments. 531 continue; 532 } 533 534 // Trim. 535 __line.erase(__remove(__line.begin(), __line.end(), ' '), 536 __line.end()); 537 std::string::size_type __pos = __line.find("="); 538 std::string __factor_name = __line.substr(0, __pos); 539 std::string::size_type __end = __line.find_first_of(";\n"); 540 std::string __factor_value = __line.substr(__pos + 1, __end - __pos); 541 542 _GLIBCXX_PROFILE_DATA(__env)[__factor_name] = __factor_value; 543 } 544 } 545 546 struct __cost_factor_writer 547 { 548 FILE* __file; 549 __cost_factor_writer__cost_factor_writer550 __cost_factor_writer(FILE* __f) 551 : __file(__f) { } 552 553 void operator__cost_factor_writer554 operator() (const __cost_factor* __factor) 555 { std::fprintf(__file, "%s = %f\n", __factor->__env_var, 556 __factor->__value); } 557 }; 558 559 inline void __write_cost_factors()560 __write_cost_factors() 561 { 562 FILE* __file = __open_output_file("conf.out"); 563 __for_each(_GLIBCXX_PROFILE_DATA(__cost_factors)->begin(), 564 _GLIBCXX_PROFILE_DATA(__cost_factors)->end(), 565 __cost_factor_writer(__file)); 566 std::fclose(__file); 567 } 568 569 struct __cost_factor_setter 570 { 571 void operator__cost_factor_setter572 operator()(__cost_factor* __factor) 573 { 574 // Look it up in the process environment first. 575 const char* __env_value = std::getenv(__factor->__env_var); 576 577 if (!__env_value) 578 { 579 // Look it up in the config file. 580 __env_t::iterator __it 581 = _GLIBCXX_PROFILE_DATA(__env).find(__factor->__env_var); 582 if (__it != _GLIBCXX_PROFILE_DATA(__env).end()) 583 __env_value = __it->second.c_str(); 584 } 585 586 if (__env_value) 587 __factor->__value = std::atof(__env_value); 588 } 589 }; 590 591 inline void __set_cost_factors()592 __set_cost_factors() 593 { 594 __cost_factor_vector* __factors = new __cost_factor_vector; 595 _GLIBCXX_PROFILE_DATA(__cost_factors) = __factors; 596 __factors->push_back(&_GLIBCXX_PROFILE_DATA(__vector_shift_cost_factor)); 597 __factors->push_back(&_GLIBCXX_PROFILE_DATA(__vector_iterate_cost_factor)); 598 __factors->push_back(&_GLIBCXX_PROFILE_DATA(__vector_resize_cost_factor)); 599 __factors->push_back(&_GLIBCXX_PROFILE_DATA(__list_shift_cost_factor)); 600 __factors->push_back(&_GLIBCXX_PROFILE_DATA(__list_iterate_cost_factor)); 601 __factors->push_back(&_GLIBCXX_PROFILE_DATA(__list_resize_cost_factor)); 602 __factors->push_back(&_GLIBCXX_PROFILE_DATA(__map_insert_cost_factor)); 603 __factors->push_back(&_GLIBCXX_PROFILE_DATA(__map_erase_cost_factor)); 604 __factors->push_back(&_GLIBCXX_PROFILE_DATA(__map_find_cost_factor)); 605 __factors->push_back(&_GLIBCXX_PROFILE_DATA(__map_iterate_cost_factor)); 606 __factors->push_back(&_GLIBCXX_PROFILE_DATA(__umap_insert_cost_factor)); 607 __factors->push_back(&_GLIBCXX_PROFILE_DATA(__umap_erase_cost_factor)); 608 __factors->push_back(&_GLIBCXX_PROFILE_DATA(__umap_find_cost_factor)); 609 __factors->push_back(&_GLIBCXX_PROFILE_DATA(__umap_iterate_cost_factor)); 610 __for_each(__factors->begin(), __factors->end(), __cost_factor_setter()); 611 } 612 613 inline void __profcxx_init_unconditional()614 __profcxx_init_unconditional() 615 { 616 __gnu_cxx::__scoped_lock __lock(_GLIBCXX_PROFILE_DATA(__global_mutex)); 617 618 if (__is_invalid()) 619 { 620 __set_max_warn_count(); 621 622 if (_GLIBCXX_PROFILE_DATA(_S_max_warn_count) == 0) 623 __turn_off(); 624 else 625 { 626 __set_max_stack_trace_depth(); 627 __set_max_mem(); 628 __set_trace_path(); 629 __read_cost_factors(); 630 __set_cost_factors(); 631 __write_cost_factors(); 632 633 __trace_vector_size_init(); 634 __trace_hashtable_size_init(); 635 __trace_hash_func_init(); 636 __trace_vector_to_list_init(); 637 __trace_list_to_slist_init(); 638 __trace_list_to_vector_init(); 639 __trace_map_to_unordered_map_init(); 640 641 std::atexit(__report_and_free); 642 643 __turn_on(); 644 } 645 } 646 } 647 648 /** @brief This function must be called by each instrumentation point. 649 * 650 * The common path is inlined fully. 651 */ 652 inline bool __profcxx_init()653 __profcxx_init() 654 { 655 if (__is_invalid()) 656 __profcxx_init_unconditional(); 657 658 return __is_on(); 659 } 660 661 } // namespace __gnu_profile 662 663 #endif /* _GLIBCXX_PROFILE_PROFILER_TRACE_H */ 664