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