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