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