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