Home | History | Annotate | Line # | Download | only in impl
      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 
     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   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
    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       : __objects_byte_size(0), __stack_table(10000),
    197 	__stack_table_byte_size(0), __id(0) { }
    198 
    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>::
    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>::
    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>::
    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>::
    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
    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
    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
    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
    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
    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*
    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 
    424     __warn(FILE* __f)
    425     { __file = __f; }
    426 
    427     void
    428     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
    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
    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
    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
    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
    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 
    550     __cost_factor_writer(FILE* __f)
    551     : __file(__f) { }
    552 
    553     void
    554     operator() (const __cost_factor* __factor)
    555     { std::fprintf(__file, "%s = %f\n", __factor->__env_var,
    556 		   __factor->__value); }
    557   };
    558 
    559   inline void
    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
    572     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
    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
    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
    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