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