Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

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