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