Home | History | Annotate | Download | only in impl
      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