libstdc++
profiler_trace.h
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 //
00003 // Copyright (C) 2009, 2010 Free Software Foundation, Inc.
00004 //
00005 // This file is part of the GNU ISO C++ Library.  This library is free
00006 // software; you can redistribute it and/or modify it under the
00007 // terms of the GNU General Public License as published by the
00008 // Free Software Foundation; either version 3, or (at your option)
00009 // any later version.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 // GNU General Public License for more details.
00015 
00016 // Under Section 7 of GPL version 3, you are granted additional
00017 // permissions described in the GCC Runtime Library Exception, version
00018 // 3.1, as published by the Free Software Foundation.
00019 
00020 // You should have received a copy of the GNU General Public License along
00021 // with this library; see the file COPYING3.  If not see
00022 // <http://www.gnu.org/licenses/>.
00023 
00024 /** @file profile/impl/profiler_trace.h
00025  *  @brief Data structures to represent profiling traces.
00026  */
00027 
00028 // Written by Lixia Liu and Silvius Rus.
00029 
00030 #ifndef _GLIBCXX_PROFILE_PROFILER_TRACE_H
00031 #define _GLIBCXX_PROFILE_PROFILER_TRACE_H 1
00032 
00033 #include <cstdio>  // fopen, fclose, fprintf, FILE
00034 #include <cerrno>
00035 #include <cstdlib> // atof, atoi, strtol, getenv, atexit, abort
00036 
00037 #ifdef __GXX_EXPERIMENTAL_CXX0X__
00038 #define _GLIBCXX_IMPL_UNORDERED_MAP std::_GLIBCXX_STD_C::unordered_map
00039 #include <unordered_map>
00040 #else
00041 #include <tr1/unordered_map>
00042 #define _GLIBCXX_IMPL_UNORDERED_MAP std::tr1::unordered_map
00043 #endif
00044 
00045 #include <ext/concurrence.h>
00046 #include <fstream>
00047 #include <string>
00048 #include <utility>
00049 #include <vector>
00050 
00051 #include "profile/impl/profiler_algos.h"
00052 #include "profile/impl/profiler_state.h"
00053 #include "profile/impl/profiler_node.h"
00054 
00055 namespace __gnu_profile
00056 {
00057   /** @brief Internal environment.  Values can be set one of two ways:
00058       1. In config file "var = value".  The default config file path is 
00059          libstdcxx-profile.conf.
00060       2. By setting process environment variables.  For instance, in a Bash
00061          shell you can set the unit cost of iterating through a map like this:
00062          export __map_iterate_cost_factor=5.0.
00063      If a value is set both in the input file and through an environment
00064      variable, the environment value takes precedence.  */
00065   typedef _GLIBCXX_IMPL_UNORDERED_MAP<std::string, std::string> __env_t;
00066 
00067   _GLIBCXX_PROFILE_DEFINE_UNINIT_DATA(__env_t, __env);
00068 
00069   /** @brief Master lock.  */
00070   _GLIBCXX_PROFILE_DEFINE_UNINIT_DATA(__gnu_cxx::__mutex, __global_lock);
00071 
00072   /** @brief Representation of a warning.  */
00073   struct __warning_data
00074   {
00075     float __magnitude;
00076     __stack_t __context;
00077     const char* __warning_id;
00078     std::string __warning_message;
00079 
00080     __warning_data()
00081     : __magnitude(0.0), __context(0), __warning_id(0) { }
00082 
00083     __warning_data(float __m, __stack_t __c, const char* __id, 
00084            const std::string& __msg)
00085     : __magnitude(__m), __context(__c), __warning_id(__id), 
00086       __warning_message(__msg) { }
00087 
00088     bool
00089     operator<(const __warning_data& __other) const
00090     { return __magnitude < __other.__magnitude; }
00091   };
00092 
00093   typedef std::_GLIBCXX_STD_C::vector<__warning_data> __warning_vector_t;
00094 
00095   // Defined in profiler_<diagnostic name>.h.
00096   class __trace_hash_func;
00097   class __trace_hashtable_size;
00098   class __trace_map2umap;
00099   class __trace_vector_size;
00100   class __trace_vector_to_list;
00101   class __trace_list_to_slist; 
00102   class __trace_list_to_vector; 
00103   void __trace_vector_size_init();
00104   void __trace_hashtable_size_init();
00105   void __trace_hash_func_init();
00106   void __trace_vector_to_list_init();
00107   void __trace_list_to_slist_init();  
00108   void __trace_list_to_vector_init();  
00109   void __trace_map_to_unordered_map_init();
00110   void __trace_vector_size_report(FILE*, __warning_vector_t&);
00111   void __trace_hashtable_size_report(FILE*, __warning_vector_t&);
00112   void __trace_hash_func_report(FILE*, __warning_vector_t&);
00113   void __trace_vector_to_list_report(FILE*, __warning_vector_t&);
00114   void __trace_list_to_slist_report(FILE*, __warning_vector_t&); 
00115   void __trace_list_to_vector_report(FILE*, __warning_vector_t&);
00116   void __trace_map_to_unordered_map_report(FILE*, __warning_vector_t&);
00117 
00118   struct __cost_factor
00119   {
00120     const char* __env_var;
00121     float __value;
00122   };
00123 
00124   typedef std::_GLIBCXX_STD_C::vector<__cost_factor*> __cost_factor_vector;
00125 
00126   _GLIBCXX_PROFILE_DEFINE_DATA(__trace_hash_func*, _S_hash_func, 0);
00127   _GLIBCXX_PROFILE_DEFINE_DATA(__trace_hashtable_size*, _S_hashtable_size, 0);
00128   _GLIBCXX_PROFILE_DEFINE_DATA(__trace_map2umap*, _S_map2umap, 0);
00129   _GLIBCXX_PROFILE_DEFINE_DATA(__trace_vector_size*, _S_vector_size, 0);
00130   _GLIBCXX_PROFILE_DEFINE_DATA(__trace_vector_to_list*, _S_vector_to_list, 0);
00131   _GLIBCXX_PROFILE_DEFINE_DATA(__trace_list_to_slist*, _S_list_to_slist, 0); 
00132   _GLIBCXX_PROFILE_DEFINE_DATA(__trace_list_to_vector*, _S_list_to_vector, 0);
00133 
00134   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __vector_shift_cost_factor, 
00135                    {"__vector_shift_cost_factor", 1.0});
00136   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __vector_iterate_cost_factor,
00137                    {"__vector_iterate_cost_factor", 1.0});
00138   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __vector_resize_cost_factor,
00139                    {"__vector_resize_cost_factor", 1.0}); 
00140   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __list_shift_cost_factor,
00141                    {"__list_shift_cost_factor", 0.0});
00142   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __list_iterate_cost_factor,
00143                    {"__list_iterate_cost_factor", 10.0}); 
00144   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __list_resize_cost_factor,
00145                    {"__list_resize_cost_factor", 0.0}); 
00146   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_insert_cost_factor,
00147                    {"__map_insert_cost_factor", 1.5});
00148   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_erase_cost_factor,
00149                    {"__map_erase_cost_factor", 1.5});
00150   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_find_cost_factor,
00151                    {"__map_find_cost_factor", 1});
00152   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_iterate_cost_factor,
00153                    {"__map_iterate_cost_factor", 2.3});
00154   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_insert_cost_factor,
00155                    {"__umap_insert_cost_factor", 12.0});
00156   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_erase_cost_factor,
00157                    {"__umap_erase_cost_factor", 12.0});
00158   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_find_cost_factor,
00159                    {"__umap_find_cost_factor", 10.0});
00160   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_iterate_cost_factor,
00161                    {"__umap_iterate_cost_factor", 1.7});
00162   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor_vector*, __cost_factors, 0);
00163 
00164   _GLIBCXX_PROFILE_DEFINE_DATA(const char*, _S_trace_file_name,
00165                    _GLIBCXX_PROFILE_TRACE_PATH_ROOT);
00166   _GLIBCXX_PROFILE_DEFINE_DATA(std::size_t, _S_max_warn_count,
00167                    _GLIBCXX_PROFILE_MAX_WARN_COUNT);
00168   _GLIBCXX_PROFILE_DEFINE_DATA(std::size_t, _S_max_stack_depth,
00169                    _GLIBCXX_PROFILE_MAX_STACK_DEPTH);
00170   _GLIBCXX_PROFILE_DEFINE_DATA(std::size_t, _S_max_mem,
00171                    _GLIBCXX_PROFILE_MEM_PER_DIAGNOSTIC);
00172 
00173   inline std::size_t
00174   __stack_max_depth()
00175   { return _GLIBCXX_PROFILE_DATA(_S_max_stack_depth); }
00176 
00177   inline std::size_t
00178   __max_mem()
00179   { return _GLIBCXX_PROFILE_DATA(_S_max_mem); }
00180 
00181   /** @brief Base class for all trace producers.  */
00182   template<typename __object_info, typename __stack_info>
00183     class __trace_base
00184     {
00185     public:
00186       // Do not pick the initial size too large, as we don't know which
00187       // diagnostics are more active.
00188       __trace_base()
00189       : __object_table(10000), __stack_table(10000),
00190     __stack_table_byte_size(0), __id(0) { }
00191 
00192       virtual ~__trace_base() { }
00193 
00194       void __add_object(__object_t object, __object_info __info);
00195       __object_info* __get_object_info(__object_t __object);
00196       void __retire_object(__object_t __object);
00197       void __write(FILE* __f);
00198       void __collect_warnings(__warning_vector_t& __warnings);
00199 
00200     private:
00201       __gnu_cxx::__mutex __object_table_lock;
00202       __gnu_cxx::__mutex __stack_table_lock;
00203       typedef _GLIBCXX_IMPL_UNORDERED_MAP<__object_t, 
00204                       __object_info> __object_table_t;
00205       typedef _GLIBCXX_IMPL_UNORDERED_MAP<__stack_t, __stack_info,
00206                       __stack_hash, 
00207                       __stack_hash> __stack_table_t;
00208       __object_table_t __object_table;
00209       __stack_table_t __stack_table;
00210       std::size_t __stack_table_byte_size;
00211 
00212     protected:
00213       const char* __id;
00214     };
00215 
00216   template<typename __object_info, typename __stack_info>
00217     void
00218     __trace_base<__object_info, __stack_info>::
00219     __collect_warnings(__warning_vector_t& __warnings)
00220     {
00221       for (typename __stack_table_t::iterator __it
00222          = __stack_table.begin(); __it != __stack_table.end(); ++__it)
00223     __warnings.push_back(__warning_data((*__it).second.__magnitude(),
00224                         (*__it).first, __id,
00225                         (*__it).second.__advice()));
00226     }
00227 
00228   template<typename __object_info, typename __stack_info>
00229     void
00230     __trace_base<__object_info, __stack_info>::
00231     __add_object(__object_t __object, __object_info __info)
00232     {
00233       if (__max_mem() == 0 
00234       || __object_table.size() * sizeof(__object_info) <= __max_mem())
00235     {
00236       this->__object_table_lock.lock();
00237       __object_table.insert(typename __object_table_t::
00238                 value_type(__object, __info));
00239       this->__object_table_lock.unlock();
00240     }
00241     }
00242 
00243   template<typename __object_info, typename __stack_info>
00244     __object_info*
00245     __trace_base<__object_info, __stack_info>::
00246     __get_object_info(__object_t __object)
00247     {
00248       // XXX: Revisit this to see if we can decrease mutex spans.
00249       // Without this mutex, the object table could be rehashed during an
00250       // insertion on another thread, which could result in a segfault.
00251       this->__object_table_lock.lock();
00252       typename __object_table_t::iterator __object_it
00253     =  __object_table.find(__object);
00254 
00255       if (__object_it == __object_table.end())
00256     {
00257       this->__object_table_lock.unlock();
00258       return 0;
00259     }
00260       else
00261     {
00262       this->__object_table_lock.unlock();
00263       return &__object_it->second;
00264     }
00265     }
00266 
00267   template<typename __object_info, typename __stack_info>
00268     void
00269     __trace_base<__object_info, __stack_info>::
00270     __retire_object(__object_t __object)
00271     {
00272       this->__object_table_lock.lock();
00273       this->__stack_table_lock.lock();
00274       typename __object_table_t::iterator __object_it
00275     = __object_table.find(__object);
00276   
00277       if (__object_it != __object_table.end())
00278     {
00279       const __object_info& __info = __object_it->second;
00280       const __stack_t& __stack = __info.__stack();
00281       typename __stack_table_t::iterator __stack_it
00282         = __stack_table.find(__stack);
00283     
00284       if (__stack_it == __stack_table.end())
00285         {
00286           // First occurence of this call context.
00287           if (__max_mem() == 0 || __stack_table_byte_size < __max_mem()) 
00288         {
00289           __stack_table_byte_size 
00290             += (sizeof(__instruction_address_t) * __size(__stack)
00291             + sizeof(__stack) + sizeof(__stack_info));
00292           __stack_table.insert(make_pair(__stack,
00293                          __stack_info(__info)));
00294         }
00295         }
00296       else
00297         {
00298           // Merge object info into info summary for this call context.
00299           __stack_it->second.__merge(__info);
00300           delete __stack;
00301         }
00302       __object_table.erase(__object);
00303     }
00304 
00305       this->__object_table_lock.unlock();
00306       this->__stack_table_lock.unlock();
00307     }
00308 
00309   template<typename __object_info, typename __stack_info>
00310     void
00311     __trace_base<__object_info, __stack_info>::
00312     __write(FILE* __f)
00313     {
00314       for (typename __stack_table_t::iterator __it
00315          = __stack_table.begin(); __it != __stack_table.end(); ++__it)
00316     if (__it->second.__is_valid())
00317       {
00318         std::fprintf(__f, __id);
00319         std::fprintf(__f, "|");
00320         __gnu_profile::__write(__f, __it->first);
00321         std::fprintf(__f, "|");
00322         __it->second.__write(__f);
00323       }
00324     }
00325 
00326   inline std::size_t
00327   __env_to_size_t(const char* __env_var, std::size_t __default_value)
00328   {
00329     char* __env_value = std::getenv(__env_var);
00330     if (__env_value)
00331       {
00332     errno = 0;
00333     long __converted_value = std::strtol(__env_value, 0, 10);
00334     if (errno || __converted_value < 0)
00335       {
00336         std::fprintf(stderr,
00337              "Bad value for environment variable '%s'.\n",
00338              __env_var);
00339         std::abort();
00340       }
00341     else
00342       return static_cast<std::size_t>(__converted_value);
00343       }
00344     else
00345       return __default_value;
00346   }
00347 
00348   inline void
00349   __set_max_stack_trace_depth()
00350   {
00351     _GLIBCXX_PROFILE_DATA(_S_max_stack_depth)
00352       = __env_to_size_t(_GLIBCXX_PROFILE_MAX_STACK_DEPTH_ENV_VAR,
00353             _GLIBCXX_PROFILE_DATA(_S_max_stack_depth));
00354   }
00355 
00356   inline void
00357   __set_max_mem()
00358   {
00359     _GLIBCXX_PROFILE_DATA(_S_max_mem) 
00360       = __env_to_size_t(_GLIBCXX_PROFILE_MEM_PER_DIAGNOSTIC_ENV_VAR,
00361             _GLIBCXX_PROFILE_DATA(_S_max_mem));
00362   }
00363 
00364   inline int
00365   __log_magnitude(float __f)
00366   {
00367     const float __log_base = 10.0;
00368     int __result = 0;
00369     int __sign = 1;
00370 
00371     if (__f < 0) 
00372       {
00373     __f = -__f;
00374     __sign = -1;
00375       }
00376 
00377     while (__f > __log_base) 
00378       {
00379     ++__result;
00380     __f /= 10.0;
00381       }
00382     return __sign * __result;
00383   }
00384 
00385   inline FILE* 
00386   __open_output_file(const char* __extension)
00387   {
00388     // The path is made of _S_trace_file_name + "." + extension.
00389     std::size_t __root_len 
00390       = __builtin_strlen(_GLIBCXX_PROFILE_DATA(_S_trace_file_name));
00391     std::size_t __ext_len = __builtin_strlen(__extension);
00392     char* __file_name = new char[__root_len + 1 + __ext_len + 1];
00393     __builtin_memcpy(__file_name,
00394              _GLIBCXX_PROFILE_DATA(_S_trace_file_name),
00395              __root_len);
00396     *(__file_name + __root_len) = '.';
00397     __builtin_memcpy(__file_name + __root_len + 1,
00398              __extension, __ext_len + 1);
00399 
00400     FILE* __out_file = std::fopen(__file_name, "w");
00401     if (!__out_file)
00402       {
00403     std::fprintf(stderr, "Could not open trace file '%s'.\n",
00404              __file_name);
00405     std::abort();
00406       }
00407 
00408     delete[] __file_name;
00409     return __out_file;
00410   }
00411 
00412   struct __warn
00413   {
00414     FILE* __file;
00415 
00416     __warn(FILE* __f)
00417     { __file = __f; }
00418 
00419     void
00420     operator()(const __warning_data& __info)
00421     {
00422       std::fprintf(__file,  __info.__warning_id);
00423       std::fprintf(__file, ": improvement = %d",
00424            __log_magnitude(__info.__magnitude));
00425       std::fprintf(__file, ": call stack = ");
00426       __gnu_profile::__write(__file, __info.__context);
00427       std::fprintf(__file, ": advice = %s\n",
00428            __info.__warning_message.c_str());
00429     }
00430   };
00431 
00432   /** @brief Final report method, registered with @b atexit.
00433    *
00434    * This can also be called directly by user code, including signal handlers.
00435    * It is protected against deadlocks by the reentrance guard in profiler.h.
00436    * However, when called from a signal handler that triggers while within
00437    * __gnu_profile (under the guarded zone), no output will be produced.
00438    */
00439   inline void
00440   __report(void)
00441   {
00442     _GLIBCXX_PROFILE_DATA(__global_lock).lock();
00443 
00444     __warning_vector_t __warnings, __top_warnings;
00445 
00446     FILE* __raw_file = __open_output_file("raw");
00447     __trace_vector_size_report(__raw_file, __warnings);
00448     __trace_hashtable_size_report(__raw_file, __warnings);
00449     __trace_hash_func_report(__raw_file, __warnings);
00450     __trace_vector_to_list_report(__raw_file, __warnings);
00451     __trace_list_to_slist_report(__raw_file, __warnings);
00452     __trace_list_to_vector_report(__raw_file, __warnings);
00453     __trace_map_to_unordered_map_report(__raw_file, __warnings);
00454     std::fclose(__raw_file);
00455 
00456     // Sort data by magnitude, keeping just top N.
00457     std::size_t __cutoff = std::min(_GLIBCXX_PROFILE_DATA(_S_max_warn_count),
00458                     __warnings.size());
00459     __top_n(__warnings, __top_warnings, __cutoff);
00460 
00461     FILE* __warn_file = __open_output_file("txt");
00462     __for_each(__top_warnings.begin(), __top_warnings.end(),
00463            __warn(__warn_file));
00464     std::fclose(__warn_file);
00465 
00466     _GLIBCXX_PROFILE_DATA(__global_lock).unlock();
00467   }
00468 
00469   inline void
00470   __set_trace_path()
00471   {
00472     char* __env_trace_file_name = std::getenv(_GLIBCXX_PROFILE_TRACE_ENV_VAR);
00473 
00474     if (__env_trace_file_name)
00475       _GLIBCXX_PROFILE_DATA(_S_trace_file_name) = __env_trace_file_name;
00476 
00477     // Make sure early that we can create the trace file.
00478     std::fclose(__open_output_file("txt"));
00479   }
00480 
00481   inline void
00482   __set_max_warn_count()
00483   {
00484     char* __env_max_warn_count_str
00485       = std::getenv(_GLIBCXX_PROFILE_MAX_WARN_COUNT_ENV_VAR);
00486 
00487     if (__env_max_warn_count_str)
00488       _GLIBCXX_PROFILE_DATA(_S_max_warn_count)
00489     = static_cast<std::size_t>(std::atoi(__env_max_warn_count_str));
00490   }
00491 
00492   inline void
00493   __read_cost_factors()
00494   {
00495     std::string __conf_file_name(_GLIBCXX_PROFILE_DATA(_S_trace_file_name));
00496     __conf_file_name += ".conf";
00497 
00498     std::ifstream __conf_file(__conf_file_name.c_str());
00499 
00500     if (__conf_file.is_open())
00501       {
00502     std::string __line;
00503 
00504     while (std::getline(__conf_file, __line))
00505       {
00506         std::string::size_type __i = __line.find_first_not_of(" \t\n\v");
00507 
00508         if (__line.length() <= 0 || __line[__i] == '#')
00509           // Skip empty lines or comments.
00510           continue;
00511       }
00512 
00513     // Trim.
00514     __line.erase(__remove(__line.begin(), __line.end(), ' '),
00515              __line.end());
00516     std::string::size_type __pos = __line.find("=");
00517     std::string __factor_name = __line.substr(0, __pos);
00518     std::string::size_type __end = __line.find_first_of(";\n");
00519     std::string __factor_value = __line.substr(__pos + 1, __end - __pos);
00520 
00521     _GLIBCXX_PROFILE_DATA(__env)[__factor_name] = __factor_value;
00522       }
00523   }
00524 
00525   struct __cost_factor_writer
00526   {
00527     FILE* __file;
00528 
00529     __cost_factor_writer(FILE* __f)
00530     : __file(__f) { }
00531 
00532     void
00533     operator() (const __cost_factor* __factor)
00534     { std::fprintf(__file, "%s = %f\n", __factor->__env_var,
00535            __factor->__value); }
00536   };
00537 
00538   inline void
00539   __write_cost_factors()
00540   {
00541     FILE* __file = __open_output_file("conf.out");
00542     __for_each(_GLIBCXX_PROFILE_DATA(__cost_factors)->begin(),
00543            _GLIBCXX_PROFILE_DATA(__cost_factors)->end(),
00544            __cost_factor_writer(__file));
00545     std::fclose(__file);
00546   }
00547 
00548   struct __cost_factor_setter
00549   {
00550     void
00551     operator()(__cost_factor* __factor)
00552     {
00553       // Look it up in the process environment first.
00554       const char* __env_value = std::getenv(__factor->__env_var);
00555 
00556       if (!__env_value)
00557         {
00558           // Look it up in the config file.
00559           __env_t::iterator __it 
00560         = _GLIBCXX_PROFILE_DATA(__env).find(__factor->__env_var);
00561           if (__it != _GLIBCXX_PROFILE_DATA(__env).end())
00562             __env_value = (*__it).second.c_str();
00563         }
00564 
00565       if (__env_value)
00566         __factor->__value = std::atof(__env_value);
00567     }
00568   };
00569 
00570   inline void
00571   __set_cost_factors()
00572   {
00573     _GLIBCXX_PROFILE_DATA(__cost_factors) = new __cost_factor_vector;
00574     _GLIBCXX_PROFILE_DATA(__cost_factors)->
00575       push_back(&_GLIBCXX_PROFILE_DATA(__vector_shift_cost_factor));
00576     _GLIBCXX_PROFILE_DATA(__cost_factors)->
00577       push_back(&_GLIBCXX_PROFILE_DATA(__vector_iterate_cost_factor));
00578     _GLIBCXX_PROFILE_DATA(__cost_factors)->
00579       push_back(&_GLIBCXX_PROFILE_DATA(__vector_resize_cost_factor));
00580     _GLIBCXX_PROFILE_DATA(__cost_factors)->
00581       push_back(&_GLIBCXX_PROFILE_DATA(__list_shift_cost_factor));
00582     _GLIBCXX_PROFILE_DATA(__cost_factors)->
00583       push_back(&_GLIBCXX_PROFILE_DATA(__list_iterate_cost_factor));
00584     _GLIBCXX_PROFILE_DATA(__cost_factors)->
00585       push_back(&_GLIBCXX_PROFILE_DATA(__list_resize_cost_factor));
00586     _GLIBCXX_PROFILE_DATA(__cost_factors)->
00587       push_back(&_GLIBCXX_PROFILE_DATA(__map_insert_cost_factor));
00588     _GLIBCXX_PROFILE_DATA(__cost_factors)->
00589       push_back(&_GLIBCXX_PROFILE_DATA(__map_erase_cost_factor));
00590     _GLIBCXX_PROFILE_DATA(__cost_factors)->
00591       push_back(&_GLIBCXX_PROFILE_DATA(__map_find_cost_factor));
00592     _GLIBCXX_PROFILE_DATA(__cost_factors)->
00593       push_back(&_GLIBCXX_PROFILE_DATA(__map_iterate_cost_factor));
00594     _GLIBCXX_PROFILE_DATA(__cost_factors)->
00595       push_back(&_GLIBCXX_PROFILE_DATA(__umap_insert_cost_factor));
00596     _GLIBCXX_PROFILE_DATA(__cost_factors)->
00597       push_back(&_GLIBCXX_PROFILE_DATA(__umap_erase_cost_factor));
00598     _GLIBCXX_PROFILE_DATA(__cost_factors)->
00599       push_back(&_GLIBCXX_PROFILE_DATA(__umap_find_cost_factor));
00600     _GLIBCXX_PROFILE_DATA(__cost_factors)->
00601       push_back(&_GLIBCXX_PROFILE_DATA(__umap_iterate_cost_factor));
00602     __for_each(_GLIBCXX_PROFILE_DATA(__cost_factors)->begin(),
00603            _GLIBCXX_PROFILE_DATA(__cost_factors)->end(),
00604            __cost_factor_setter());
00605   }
00606 
00607   inline void
00608   __profcxx_init_unconditional()
00609   {
00610     _GLIBCXX_PROFILE_DATA(__global_lock).lock();
00611 
00612     if (__is_invalid())
00613       {
00614     __set_max_warn_count();
00615 
00616     if (_GLIBCXX_PROFILE_DATA(_S_max_warn_count) == 0)
00617       __turn_off();
00618     else
00619       {
00620         __set_max_stack_trace_depth();
00621         __set_max_mem();
00622         __set_trace_path();
00623         __read_cost_factors(); 
00624         __set_cost_factors();
00625         __write_cost_factors();
00626 
00627         __trace_vector_size_init();
00628         __trace_hashtable_size_init();
00629         __trace_hash_func_init();
00630         __trace_vector_to_list_init();
00631         __trace_list_to_slist_init(); 
00632         __trace_list_to_vector_init();
00633         __trace_map_to_unordered_map_init();
00634 
00635         std::atexit(__report);
00636 
00637         __turn_on();
00638       }
00639       }
00640 
00641     _GLIBCXX_PROFILE_DATA(__global_lock).unlock();
00642   }
00643 
00644   /** @brief This function must be called by each instrumentation point.
00645    *
00646    * The common path is inlined fully.
00647    */
00648   inline bool
00649   __profcxx_init()
00650   {
00651     if (__is_invalid())
00652       __profcxx_init_unconditional();
00653 
00654     return __is_on();
00655   }
00656 
00657 } // namespace __gnu_profile
00658 
00659 #endif /* _GLIBCXX_PROFILE_PROFILER_TRACE_H */