1 // -*- C++ -*- 2 // 3 // Copyright (C) 2009-2013 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 #define _GLIBCXX_IMPL_UNORDERED_MAP std::_GLIBCXX_STD_C::unordered_map 39 #include <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_lock); 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 80 __warning_data() 81 : __magnitude(0.0), __context(0), __warning_id(0) { } 82 83 __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 118 struct __cost_factor 119 { 120 const char* __env_var; 121 float __value; 122 }; 123 124 typedef std::_GLIBCXX_STD_C::vector<__cost_factor*> __cost_factor_vector; 125 126 _GLIBCXX_PROFILE_DEFINE_DATA(__trace_hash_func*, _S_hash_func, 0); 127 _GLIBCXX_PROFILE_DEFINE_DATA(__trace_hashtable_size*, _S_hashtable_size, 0); 128 _GLIBCXX_PROFILE_DEFINE_DATA(__trace_map2umap*, _S_map2umap, 0); 129 _GLIBCXX_PROFILE_DEFINE_DATA(__trace_vector_size*, _S_vector_size, 0); 130 _GLIBCXX_PROFILE_DEFINE_DATA(__trace_vector_to_list*, _S_vector_to_list, 0); 131 _GLIBCXX_PROFILE_DEFINE_DATA(__trace_list_to_slist*, _S_list_to_slist, 0); 132 _GLIBCXX_PROFILE_DEFINE_DATA(__trace_list_to_vector*, _S_list_to_vector, 0); 133 134 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __vector_shift_cost_factor, 135 {"__vector_shift_cost_factor", 1.0}); 136 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __vector_iterate_cost_factor, 137 {"__vector_iterate_cost_factor", 1.0}); 138 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __vector_resize_cost_factor, 139 {"__vector_resize_cost_factor", 1.0}); 140 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __list_shift_cost_factor, 141 {"__list_shift_cost_factor", 0.0}); 142 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __list_iterate_cost_factor, 143 {"__list_iterate_cost_factor", 10.0}); 144 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __list_resize_cost_factor, 145 {"__list_resize_cost_factor", 0.0}); 146 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_insert_cost_factor, 147 {"__map_insert_cost_factor", 1.5}); 148 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_erase_cost_factor, 149 {"__map_erase_cost_factor", 1.5}); 150 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_find_cost_factor, 151 {"__map_find_cost_factor", 1}); 152 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_iterate_cost_factor, 153 {"__map_iterate_cost_factor", 2.3}); 154 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_insert_cost_factor, 155 {"__umap_insert_cost_factor", 12.0}); 156 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_erase_cost_factor, 157 {"__umap_erase_cost_factor", 12.0}); 158 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_find_cost_factor, 159 {"__umap_find_cost_factor", 10.0}); 160 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_iterate_cost_factor, 161 {"__umap_iterate_cost_factor", 1.7}); 162 _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor_vector*, __cost_factors, 0); 163 164 _GLIBCXX_PROFILE_DEFINE_DATA(const char*, _S_trace_file_name, 165 _GLIBCXX_PROFILE_TRACE_PATH_ROOT); 166 _GLIBCXX_PROFILE_DEFINE_DATA(std::size_t, _S_max_warn_count, 167 _GLIBCXX_PROFILE_MAX_WARN_COUNT); 168 _GLIBCXX_PROFILE_DEFINE_DATA(std::size_t, _S_max_stack_depth, 169 _GLIBCXX_PROFILE_MAX_STACK_DEPTH); 170 _GLIBCXX_PROFILE_DEFINE_DATA(std::size_t, _S_max_mem, 171 _GLIBCXX_PROFILE_MEM_PER_DIAGNOSTIC); 172 173 inline std::size_t 174 __stack_max_depth() 175 { return _GLIBCXX_PROFILE_DATA(_S_max_stack_depth); } 176 177 inline std::size_t 178 __max_mem() 179 { return _GLIBCXX_PROFILE_DATA(_S_max_mem); } 180 181 /** @brief Base class for all trace producers. */ 182 template<typename __object_info, typename __stack_info> 183 class __trace_base 184 { 185 public: 186 // Do not pick the initial size too large, as we don't know which 187 // diagnostics are more active. 188 __trace_base() 189 : __object_table(10000), __stack_table(10000), 190 __stack_table_byte_size(0), __id(0) { } 191 192 virtual ~__trace_base() { } 193 194 void __add_object(__object_t object, __object_info __info); 195 __object_info* __get_object_info(__object_t __object); 196 void __retire_object(__object_t __object); 197 void __write(FILE* __f); 198 void __collect_warnings(__warning_vector_t& __warnings); 199 200 private: 201 __gnu_cxx::__mutex __object_table_lock; 202 __gnu_cxx::__mutex __stack_table_lock; 203 typedef _GLIBCXX_IMPL_UNORDERED_MAP<__object_t, 204 __object_info> __object_table_t; 205 typedef _GLIBCXX_IMPL_UNORDERED_MAP<__stack_t, __stack_info, 206 __stack_hash, 207 __stack_hash> __stack_table_t; 208 __object_table_t __object_table; 209 __stack_table_t __stack_table; 210 std::size_t __stack_table_byte_size; 211 212 protected: 213 const char* __id; 214 }; 215 216 template<typename __object_info, typename __stack_info> 217 void 218 __trace_base<__object_info, __stack_info>:: 219 __collect_warnings(__warning_vector_t& __warnings) 220 { 221 for (typename __stack_table_t::iterator __it 222 = __stack_table.begin(); __it != __stack_table.end(); ++__it) 223 __warnings.push_back(__warning_data((*__it).second.__magnitude(), 224 (*__it).first, __id, 225 (*__it).second.__advice())); 226 } 227 228 template<typename __object_info, typename __stack_info> 229 void 230 __trace_base<__object_info, __stack_info>:: 231 __add_object(__object_t __object, __object_info __info) 232 { 233 if (__max_mem() == 0 234 || __object_table.size() * sizeof(__object_info) <= __max_mem()) 235 { 236 this->__object_table_lock.lock(); 237 __object_table.insert(typename __object_table_t:: 238 value_type(__object, __info)); 239 this->__object_table_lock.unlock(); 240 } 241 } 242 243 template<typename __object_info, typename __stack_info> 244 __object_info* 245 __trace_base<__object_info, __stack_info>:: 246 __get_object_info(__object_t __object) 247 { 248 // XXX: Revisit this to see if we can decrease mutex spans. 249 // Without this mutex, the object table could be rehashed during an 250 // insertion on another thread, which could result in a segfault. 251 this->__object_table_lock.lock(); 252 typename __object_table_t::iterator __object_it 253 = __object_table.find(__object); 254 255 if (__object_it == __object_table.end()) 256 { 257 this->__object_table_lock.unlock(); 258 return 0; 259 } 260 else 261 { 262 this->__object_table_lock.unlock(); 263 return &__object_it->second; 264 } 265 } 266 267 template<typename __object_info, typename __stack_info> 268 void 269 __trace_base<__object_info, __stack_info>:: 270 __retire_object(__object_t __object) 271 { 272 this->__object_table_lock.lock(); 273 this->__stack_table_lock.lock(); 274 typename __object_table_t::iterator __object_it 275 = __object_table.find(__object); 276 277 if (__object_it != __object_table.end()) 278 { 279 const __object_info& __info = __object_it->second; 280 const __stack_t& __stack = __info.__stack(); 281 typename __stack_table_t::iterator __stack_it 282 = __stack_table.find(__stack); 283 284 if (__stack_it == __stack_table.end()) 285 { 286 // First occurence of this call context. 287 if (__max_mem() == 0 || __stack_table_byte_size < __max_mem()) 288 { 289 __stack_table_byte_size 290 += (sizeof(__instruction_address_t) * __size(__stack) 291 + sizeof(__stack) + sizeof(__stack_info)); 292 __stack_table.insert(make_pair(__stack, 293 __stack_info(__info))); 294 } 295 } 296 else 297 { 298 // Merge object info into info summary for this call context. 299 __stack_it->second.__merge(__info); 300 delete __stack; 301 } 302 __object_table.erase(__object); 303 } 304 305 this->__object_table_lock.unlock(); 306 this->__stack_table_lock.unlock(); 307 } 308 309 template<typename __object_info, typename __stack_info> 310 void 311 __trace_base<__object_info, __stack_info>:: 312 __write(FILE* __f) 313 { 314 for (typename __stack_table_t::iterator __it 315 = __stack_table.begin(); __it != __stack_table.end(); ++__it) 316 if (__it->second.__is_valid()) 317 { 318 std::fprintf(__f, __id); 319 std::fprintf(__f, "|"); 320 __gnu_profile::__write(__f, __it->first); 321 std::fprintf(__f, "|"); 322 __it->second.__write(__f); 323 } 324 } 325 326 inline std::size_t 327 __env_to_size_t(const char* __env_var, std::size_t __default_value) 328 { 329 char* __env_value = std::getenv(__env_var); 330 if (__env_value) 331 { 332 errno = 0; 333 long __converted_value = std::strtol(__env_value, 0, 10); 334 if (errno || __converted_value < 0) 335 { 336 std::fprintf(stderr, 337 "Bad value for environment variable '%s'.\n", 338 __env_var); 339 std::abort(); 340 } 341 else 342 return static_cast<std::size_t>(__converted_value); 343 } 344 else 345 return __default_value; 346 } 347 348 inline void 349 __set_max_stack_trace_depth() 350 { 351 _GLIBCXX_PROFILE_DATA(_S_max_stack_depth) 352 = __env_to_size_t(_GLIBCXX_PROFILE_MAX_STACK_DEPTH_ENV_VAR, 353 _GLIBCXX_PROFILE_DATA(_S_max_stack_depth)); 354 } 355 356 inline void 357 __set_max_mem() 358 { 359 _GLIBCXX_PROFILE_DATA(_S_max_mem) 360 = __env_to_size_t(_GLIBCXX_PROFILE_MEM_PER_DIAGNOSTIC_ENV_VAR, 361 _GLIBCXX_PROFILE_DATA(_S_max_mem)); 362 } 363 364 inline int 365 __log_magnitude(float __f) 366 { 367 const float __log_base = 10.0; 368 int __result = 0; 369 int __sign = 1; 370 371 if (__f < 0) 372 { 373 __f = -__f; 374 __sign = -1; 375 } 376 377 while (__f > __log_base) 378 { 379 ++__result; 380 __f /= 10.0; 381 } 382 return __sign * __result; 383 } 384 385 inline FILE* 386 __open_output_file(const char* __extension) 387 { 388 // The path is made of _S_trace_file_name + "." + extension. 389 std::size_t __root_len 390 = __builtin_strlen(_GLIBCXX_PROFILE_DATA(_S_trace_file_name)); 391 std::size_t __ext_len = __builtin_strlen(__extension); 392 char* __file_name = new char[__root_len + 1 + __ext_len + 1]; 393 __builtin_memcpy(__file_name, 394 _GLIBCXX_PROFILE_DATA(_S_trace_file_name), 395 __root_len); 396 *(__file_name + __root_len) = '.'; 397 __builtin_memcpy(__file_name + __root_len + 1, 398 __extension, __ext_len + 1); 399 400 FILE* __out_file = std::fopen(__file_name, "w"); 401 if (!__out_file) 402 { 403 std::fprintf(stderr, "Could not open trace file '%s'.\n", 404 __file_name); 405 std::abort(); 406 } 407 408 delete[] __file_name; 409 return __out_file; 410 } 411 412 struct __warn 413 { 414 FILE* __file; 415 416 __warn(FILE* __f) 417 { __file = __f; } 418 419 void 420 operator()(const __warning_data& __info) 421 { 422 std::fprintf(__file, __info.__warning_id); 423 std::fprintf(__file, ": improvement = %d", 424 __log_magnitude(__info.__magnitude)); 425 std::fprintf(__file, ": call stack = "); 426 __gnu_profile::__write(__file, __info.__context); 427 std::fprintf(__file, ": advice = %s\n", 428 __info.__warning_message.c_str()); 429 } 430 }; 431 432 /** @brief Final report method, registered with @b atexit. 433 * 434 * This can also be called directly by user code, including signal handlers. 435 * It is protected against deadlocks by the reentrance guard in profiler.h. 436 * However, when called from a signal handler that triggers while within 437 * __gnu_profile (under the guarded zone), no output will be produced. 438 */ 439 inline void 440 __report(void) 441 { 442 _GLIBCXX_PROFILE_DATA(__global_lock).lock(); 443 444 __warning_vector_t __warnings, __top_warnings; 445 446 FILE* __raw_file = __open_output_file("raw"); 447 __trace_vector_size_report(__raw_file, __warnings); 448 __trace_hashtable_size_report(__raw_file, __warnings); 449 __trace_hash_func_report(__raw_file, __warnings); 450 __trace_vector_to_list_report(__raw_file, __warnings); 451 __trace_list_to_slist_report(__raw_file, __warnings); 452 __trace_list_to_vector_report(__raw_file, __warnings); 453 __trace_map_to_unordered_map_report(__raw_file, __warnings); 454 std::fclose(__raw_file); 455 456 // Sort data by magnitude, keeping just top N. 457 std::size_t __cutoff = std::min(_GLIBCXX_PROFILE_DATA(_S_max_warn_count), 458 __warnings.size()); 459 __top_n(__warnings, __top_warnings, __cutoff); 460 461 FILE* __warn_file = __open_output_file("txt"); 462 __for_each(__top_warnings.begin(), __top_warnings.end(), 463 __warn(__warn_file)); 464 std::fclose(__warn_file); 465 466 _GLIBCXX_PROFILE_DATA(__global_lock).unlock(); 467 } 468 469 inline void 470 __set_trace_path() 471 { 472 char* __env_trace_file_name = std::getenv(_GLIBCXX_PROFILE_TRACE_ENV_VAR); 473 474 if (__env_trace_file_name) 475 _GLIBCXX_PROFILE_DATA(_S_trace_file_name) = __env_trace_file_name; 476 477 // Make sure early that we can create the trace file. 478 std::fclose(__open_output_file("txt")); 479 } 480 481 inline void 482 __set_max_warn_count() 483 { 484 char* __env_max_warn_count_str 485 = std::getenv(_GLIBCXX_PROFILE_MAX_WARN_COUNT_ENV_VAR); 486 487 if (__env_max_warn_count_str) 488 _GLIBCXX_PROFILE_DATA(_S_max_warn_count) 489 = static_cast<std::size_t>(std::atoi(__env_max_warn_count_str)); 490 } 491 492 inline void 493 __read_cost_factors() 494 { 495 std::string __conf_file_name(_GLIBCXX_PROFILE_DATA(_S_trace_file_name)); 496 __conf_file_name += ".conf"; 497 498 std::ifstream __conf_file(__conf_file_name.c_str()); 499 500 if (__conf_file.is_open()) 501 { 502 std::string __line; 503 504 while (std::getline(__conf_file, __line)) 505 { 506 std::string::size_type __i = __line.find_first_not_of(" \t\n\v"); 507 508 if (__line.length() <= 0 || __line[__i] == '#') 509 // Skip empty lines or comments. 510 continue; 511 } 512 513 // Trim. 514 __line.erase(__remove(__line.begin(), __line.end(), ' '), 515 __line.end()); 516 std::string::size_type __pos = __line.find("="); 517 std::string __factor_name = __line.substr(0, __pos); 518 std::string::size_type __end = __line.find_first_of(";\n"); 519 std::string __factor_value = __line.substr(__pos + 1, __end - __pos); 520 521 _GLIBCXX_PROFILE_DATA(__env)[__factor_name] = __factor_value; 522 } 523 } 524 525 struct __cost_factor_writer 526 { 527 FILE* __file; 528 529 __cost_factor_writer(FILE* __f) 530 : __file(__f) { } 531 532 void 533 operator() (const __cost_factor* __factor) 534 { std::fprintf(__file, "%s = %f\n", __factor->__env_var, 535 __factor->__value); } 536 }; 537 538 inline void 539 __write_cost_factors() 540 { 541 FILE* __file = __open_output_file("conf.out"); 542 __for_each(_GLIBCXX_PROFILE_DATA(__cost_factors)->begin(), 543 _GLIBCXX_PROFILE_DATA(__cost_factors)->end(), 544 __cost_factor_writer(__file)); 545 std::fclose(__file); 546 } 547 548 struct __cost_factor_setter 549 { 550 void 551 operator()(__cost_factor* __factor) 552 { 553 // Look it up in the process environment first. 554 const char* __env_value = std::getenv(__factor->__env_var); 555 556 if (!__env_value) 557 { 558 // Look it up in the config file. 559 __env_t::iterator __it 560 = _GLIBCXX_PROFILE_DATA(__env).find(__factor->__env_var); 561 if (__it != _GLIBCXX_PROFILE_DATA(__env).end()) 562 __env_value = (*__it).second.c_str(); 563 } 564 565 if (__env_value) 566 __factor->__value = std::atof(__env_value); 567 } 568 }; 569 570 inline void 571 __set_cost_factors() 572 { 573 _GLIBCXX_PROFILE_DATA(__cost_factors) = new __cost_factor_vector; 574 _GLIBCXX_PROFILE_DATA(__cost_factors)-> 575 push_back(&_GLIBCXX_PROFILE_DATA(__vector_shift_cost_factor)); 576 _GLIBCXX_PROFILE_DATA(__cost_factors)-> 577 push_back(&_GLIBCXX_PROFILE_DATA(__vector_iterate_cost_factor)); 578 _GLIBCXX_PROFILE_DATA(__cost_factors)-> 579 push_back(&_GLIBCXX_PROFILE_DATA(__vector_resize_cost_factor)); 580 _GLIBCXX_PROFILE_DATA(__cost_factors)-> 581 push_back(&_GLIBCXX_PROFILE_DATA(__list_shift_cost_factor)); 582 _GLIBCXX_PROFILE_DATA(__cost_factors)-> 583 push_back(&_GLIBCXX_PROFILE_DATA(__list_iterate_cost_factor)); 584 _GLIBCXX_PROFILE_DATA(__cost_factors)-> 585 push_back(&_GLIBCXX_PROFILE_DATA(__list_resize_cost_factor)); 586 _GLIBCXX_PROFILE_DATA(__cost_factors)-> 587 push_back(&_GLIBCXX_PROFILE_DATA(__map_insert_cost_factor)); 588 _GLIBCXX_PROFILE_DATA(__cost_factors)-> 589 push_back(&_GLIBCXX_PROFILE_DATA(__map_erase_cost_factor)); 590 _GLIBCXX_PROFILE_DATA(__cost_factors)-> 591 push_back(&_GLIBCXX_PROFILE_DATA(__map_find_cost_factor)); 592 _GLIBCXX_PROFILE_DATA(__cost_factors)-> 593 push_back(&_GLIBCXX_PROFILE_DATA(__map_iterate_cost_factor)); 594 _GLIBCXX_PROFILE_DATA(__cost_factors)-> 595 push_back(&_GLIBCXX_PROFILE_DATA(__umap_insert_cost_factor)); 596 _GLIBCXX_PROFILE_DATA(__cost_factors)-> 597 push_back(&_GLIBCXX_PROFILE_DATA(__umap_erase_cost_factor)); 598 _GLIBCXX_PROFILE_DATA(__cost_factors)-> 599 push_back(&_GLIBCXX_PROFILE_DATA(__umap_find_cost_factor)); 600 _GLIBCXX_PROFILE_DATA(__cost_factors)-> 601 push_back(&_GLIBCXX_PROFILE_DATA(__umap_iterate_cost_factor)); 602 __for_each(_GLIBCXX_PROFILE_DATA(__cost_factors)->begin(), 603 _GLIBCXX_PROFILE_DATA(__cost_factors)->end(), 604 __cost_factor_setter()); 605 } 606 607 inline void 608 __profcxx_init_unconditional() 609 { 610 _GLIBCXX_PROFILE_DATA(__global_lock).lock(); 611 612 if (__is_invalid()) 613 { 614 __set_max_warn_count(); 615 616 if (_GLIBCXX_PROFILE_DATA(_S_max_warn_count) == 0) 617 __turn_off(); 618 else 619 { 620 __set_max_stack_trace_depth(); 621 __set_max_mem(); 622 __set_trace_path(); 623 __read_cost_factors(); 624 __set_cost_factors(); 625 __write_cost_factors(); 626 627 __trace_vector_size_init(); 628 __trace_hashtable_size_init(); 629 __trace_hash_func_init(); 630 __trace_vector_to_list_init(); 631 __trace_list_to_slist_init(); 632 __trace_list_to_vector_init(); 633 __trace_map_to_unordered_map_init(); 634 635 std::atexit(__report); 636 637 __turn_on(); 638 } 639 } 640 641 _GLIBCXX_PROFILE_DATA(__global_lock).unlock(); 642 } 643 644 /** @brief This function must be called by each instrumentation point. 645 * 646 * The common path is inlined fully. 647 */ 648 inline bool 649 __profcxx_init() 650 { 651 if (__is_invalid()) 652 __profcxx_init_unconditional(); 653 654 return __is_on(); 655 } 656 657 } // namespace __gnu_profile 658 659 #endif /* _GLIBCXX_PROFILE_PROFILER_TRACE_H */ 660