1 // -*- C++ -*-
2 //
3 // Copyright (C) 2009, 2010 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 #ifdef __GXX_EXPERIMENTAL_CXX0X__
38 #define _GLIBCXX_IMPL_UNORDERED_MAP std::_GLIBCXX_STD_C::unordered_map
39 #include <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_lock);
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 
118   struct __cost_factor
119   {
120     const char* __env_var;
121     float __value;
122   };
123 
124   typedef std::_GLIBCXX_STD_C::vector<__cost_factor*> __cost_factor_vector;
125 
126   _GLIBCXX_PROFILE_DEFINE_DATA(__trace_hash_func*, _S_hash_func, 0);
127   _GLIBCXX_PROFILE_DEFINE_DATA(__trace_hashtable_size*, _S_hashtable_size, 0);
128   _GLIBCXX_PROFILE_DEFINE_DATA(__trace_map2umap*, _S_map2umap, 0);
129   _GLIBCXX_PROFILE_DEFINE_DATA(__trace_vector_size*, _S_vector_size, 0);
130   _GLIBCXX_PROFILE_DEFINE_DATA(__trace_vector_to_list*, _S_vector_to_list, 0);
131   _GLIBCXX_PROFILE_DEFINE_DATA(__trace_list_to_slist*, _S_list_to_slist, 0);
132   _GLIBCXX_PROFILE_DEFINE_DATA(__trace_list_to_vector*, _S_list_to_vector, 0);
133 
134   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __vector_shift_cost_factor,
135 			       {"__vector_shift_cost_factor", 1.0});
136   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __vector_iterate_cost_factor,
137 			       {"__vector_iterate_cost_factor", 1.0});
138   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __vector_resize_cost_factor,
139 			       {"__vector_resize_cost_factor", 1.0});
140   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __list_shift_cost_factor,
141 			       {"__list_shift_cost_factor", 0.0});
142   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __list_iterate_cost_factor,
143 			       {"__list_iterate_cost_factor", 10.0});
144   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __list_resize_cost_factor,
145 			       {"__list_resize_cost_factor", 0.0});
146   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_insert_cost_factor,
147 			       {"__map_insert_cost_factor", 1.5});
148   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_erase_cost_factor,
149 			       {"__map_erase_cost_factor", 1.5});
150   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_find_cost_factor,
151 			       {"__map_find_cost_factor", 1});
152   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __map_iterate_cost_factor,
153 			       {"__map_iterate_cost_factor", 2.3});
154   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_insert_cost_factor,
155 			       {"__umap_insert_cost_factor", 12.0});
156   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_erase_cost_factor,
157 			       {"__umap_erase_cost_factor", 12.0});
158   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_find_cost_factor,
159 			       {"__umap_find_cost_factor", 10.0});
160   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor, __umap_iterate_cost_factor,
161 			       {"__umap_iterate_cost_factor", 1.7});
162   _GLIBCXX_PROFILE_DEFINE_DATA(__cost_factor_vector*, __cost_factors, 0);
163 
164   _GLIBCXX_PROFILE_DEFINE_DATA(const char*, _S_trace_file_name,
165 			       _GLIBCXX_PROFILE_TRACE_PATH_ROOT);
166   _GLIBCXX_PROFILE_DEFINE_DATA(std::size_t, _S_max_warn_count,
167 			       _GLIBCXX_PROFILE_MAX_WARN_COUNT);
168   _GLIBCXX_PROFILE_DEFINE_DATA(std::size_t, _S_max_stack_depth,
169 			       _GLIBCXX_PROFILE_MAX_STACK_DEPTH);
170   _GLIBCXX_PROFILE_DEFINE_DATA(std::size_t, _S_max_mem,
171 			       _GLIBCXX_PROFILE_MEM_PER_DIAGNOSTIC);
172 
173   inline std::size_t
174   __stack_max_depth()
175   { return _GLIBCXX_PROFILE_DATA(_S_max_stack_depth); }
176 
177   inline std::size_t
178   __max_mem()
179   { return _GLIBCXX_PROFILE_DATA(_S_max_mem); }
180 
181   /** @brief Base class for all trace producers.  */
182   template<typename __object_info, typename __stack_info>
183     class __trace_base
184     {
185     public:
186       // Do not pick the initial size too large, as we don't know which
187       // diagnostics are more active.
188       __trace_base()
189       : __object_table(10000), __stack_table(10000),
190 	__stack_table_byte_size(0), __id(0) { }
191 
192       virtual ~__trace_base() { }
193 
194       void __add_object(__object_t object, __object_info __info);
195       __object_info* __get_object_info(__object_t __object);
196       void __retire_object(__object_t __object);
197       void __write(FILE* __f);
198       void __collect_warnings(__warning_vector_t& __warnings);
199 
200     private:
201       __gnu_cxx::__mutex __object_table_lock;
202       __gnu_cxx::__mutex __stack_table_lock;
203       typedef _GLIBCXX_IMPL_UNORDERED_MAP<__object_t,
204 					  __object_info> __object_table_t;
205       typedef _GLIBCXX_IMPL_UNORDERED_MAP<__stack_t, __stack_info,
206 					  __stack_hash,
207 					  __stack_hash> __stack_table_t;
208       __object_table_t __object_table;
209       __stack_table_t __stack_table;
210       std::size_t __stack_table_byte_size;
211 
212     protected:
213       const char* __id;
214     };
215 
216   template<typename __object_info, typename __stack_info>
217     void
218     __trace_base<__object_info, __stack_info>::
219     __collect_warnings(__warning_vector_t& __warnings)
220     {
221       for (typename __stack_table_t::iterator __it
222 	     = __stack_table.begin(); __it != __stack_table.end(); ++__it)
223 	__warnings.push_back(__warning_data((*__it).second.__magnitude(),
224 					    (*__it).first, __id,
225 					    (*__it).second.__advice()));
226     }
227 
228   template<typename __object_info, typename __stack_info>
229     void
230     __trace_base<__object_info, __stack_info>::
231     __add_object(__object_t __object, __object_info __info)
232     {
233       if (__max_mem() == 0
234 	  || __object_table.size() * sizeof(__object_info) <= __max_mem())
235 	{
236 	  this->__object_table_lock.lock();
237 	  __object_table.insert(typename __object_table_t::
238 				value_type(__object, __info));
239 	  this->__object_table_lock.unlock();
240 	}
241     }
242 
243   template<typename __object_info, typename __stack_info>
244     __object_info*
245     __trace_base<__object_info, __stack_info>::
246     __get_object_info(__object_t __object)
247     {
248       // XXX: Revisit this to see if we can decrease mutex spans.
249       // Without this mutex, the object table could be rehashed during an
250       // insertion on another thread, which could result in a segfault.
251       this->__object_table_lock.lock();
252       typename __object_table_t::iterator __object_it
253 	=  __object_table.find(__object);
254 
255       if (__object_it == __object_table.end())
256 	{
257 	  this->__object_table_lock.unlock();
258 	  return 0;
259 	}
260       else
261 	{
262 	  this->__object_table_lock.unlock();
263 	  return &__object_it->second;
264 	}
265     }
266 
267   template<typename __object_info, typename __stack_info>
268     void
269     __trace_base<__object_info, __stack_info>::
270     __retire_object(__object_t __object)
271     {
272       this->__object_table_lock.lock();
273       this->__stack_table_lock.lock();
274       typename __object_table_t::iterator __object_it
275 	= __object_table.find(__object);
276 
277       if (__object_it != __object_table.end())
278 	{
279 	  const __object_info& __info = __object_it->second;
280 	  const __stack_t& __stack = __info.__stack();
281 	  typename __stack_table_t::iterator __stack_it
282 	    = __stack_table.find(__stack);
283 
284 	  if (__stack_it == __stack_table.end())
285 	    {
286 	      // First occurence of this call context.
287 	      if (__max_mem() == 0 || __stack_table_byte_size < __max_mem())
288 		{
289 		  __stack_table_byte_size
290 		    += (sizeof(__instruction_address_t) * __size(__stack)
291 			+ sizeof(__stack) + sizeof(__stack_info));
292 		  __stack_table.insert(make_pair(__stack,
293 						 __stack_info(__info)));
294 		}
295 	    }
296 	  else
297 	    {
298 	      // Merge object info into info summary for this call context.
299 	      __stack_it->second.__merge(__info);
300 	      delete __stack;
301 	    }
302 	  __object_table.erase(__object);
303 	}
304 
305       this->__object_table_lock.unlock();
306       this->__stack_table_lock.unlock();
307     }
308 
309   template<typename __object_info, typename __stack_info>
310     void
311     __trace_base<__object_info, __stack_info>::
312     __write(FILE* __f)
313     {
314       for (typename __stack_table_t::iterator __it
315 	     = __stack_table.begin(); __it != __stack_table.end(); ++__it)
316 	if (__it->second.__is_valid())
317 	  {
318 	    std::fprintf(__f, __id);
319 	    std::fprintf(__f, "|");
320 	    __gnu_profile::__write(__f, __it->first);
321 	    std::fprintf(__f, "|");
322 	    __it->second.__write(__f);
323 	  }
324     }
325 
326   inline std::size_t
327   __env_to_size_t(const char* __env_var, std::size_t __default_value)
328   {
329     char* __env_value = std::getenv(__env_var);
330     if (__env_value)
331       {
332 	errno = 0;
333 	long __converted_value = std::strtol(__env_value, 0, 10);
334 	if (errno || __converted_value < 0)
335 	  {
336 	    std::fprintf(stderr,
337 			 "Bad value for environment variable '%s'.\n",
338 			 __env_var);
339 	    std::abort();
340 	  }
341 	else
342 	  return static_cast<std::size_t>(__converted_value);
343       }
344     else
345       return __default_value;
346   }
347 
348   inline void
349   __set_max_stack_trace_depth()
350   {
351     _GLIBCXX_PROFILE_DATA(_S_max_stack_depth)
352       = __env_to_size_t(_GLIBCXX_PROFILE_MAX_STACK_DEPTH_ENV_VAR,
353 			_GLIBCXX_PROFILE_DATA(_S_max_stack_depth));
354   }
355 
356   inline void
357   __set_max_mem()
358   {
359     _GLIBCXX_PROFILE_DATA(_S_max_mem)
360       = __env_to_size_t(_GLIBCXX_PROFILE_MEM_PER_DIAGNOSTIC_ENV_VAR,
361 			_GLIBCXX_PROFILE_DATA(_S_max_mem));
362   }
363 
364   inline int
365   __log_magnitude(float __f)
366   {
367     const float __log_base = 10.0;
368     int __result = 0;
369     int __sign = 1;
370 
371     if (__f < 0)
372       {
373 	__f = -__f;
374 	__sign = -1;
375       }
376 
377     while (__f > __log_base)
378       {
379 	++__result;
380 	__f /= 10.0;
381       }
382     return __sign * __result;
383   }
384 
385   inline FILE*
386   __open_output_file(const char* __extension)
387   {
388     // The path is made of _S_trace_file_name + "." + extension.
389     std::size_t __root_len
390       = __builtin_strlen(_GLIBCXX_PROFILE_DATA(_S_trace_file_name));
391     std::size_t __ext_len = __builtin_strlen(__extension);
392     char* __file_name = new char[__root_len + 1 + __ext_len + 1];
393     __builtin_memcpy(__file_name,
394 		     _GLIBCXX_PROFILE_DATA(_S_trace_file_name),
395 		     __root_len);
396     *(__file_name + __root_len) = '.';
397     __builtin_memcpy(__file_name + __root_len + 1,
398 		     __extension, __ext_len + 1);
399 
400     FILE* __out_file = std::fopen(__file_name, "w");
401     if (!__out_file)
402       {
403 	std::fprintf(stderr, "Could not open trace file '%s'.\n",
404 		     __file_name);
405 	std::abort();
406       }
407 
408     delete[] __file_name;
409     return __out_file;
410   }
411 
412   struct __warn
413   {
414     FILE* __file;
415 
416     __warn(FILE* __f)
417     { __file = __f; }
418 
419     void
420     operator()(const __warning_data& __info)
421     {
422       std::fprintf(__file,  __info.__warning_id);
423       std::fprintf(__file, ": improvement = %d",
424 		   __log_magnitude(__info.__magnitude));
425       std::fprintf(__file, ": call stack = ");
426       __gnu_profile::__write(__file, __info.__context);
427       std::fprintf(__file, ": advice = %s\n",
428 		   __info.__warning_message.c_str());
429     }
430   };
431 
432   /** @brief Final report method, registered with @b atexit.
433    *
434    * This can also be called directly by user code, including signal handlers.
435    * It is protected against deadlocks by the reentrance guard in profiler.h.
436    * However, when called from a signal handler that triggers while within
437    * __gnu_profile (under the guarded zone), no output will be produced.
438    */
439   inline void
440   __report(void)
441   {
442     _GLIBCXX_PROFILE_DATA(__global_lock).lock();
443 
444     __warning_vector_t __warnings, __top_warnings;
445 
446     FILE* __raw_file = __open_output_file("raw");
447     __trace_vector_size_report(__raw_file, __warnings);
448     __trace_hashtable_size_report(__raw_file, __warnings);
449     __trace_hash_func_report(__raw_file, __warnings);
450     __trace_vector_to_list_report(__raw_file, __warnings);
451     __trace_list_to_slist_report(__raw_file, __warnings);
452     __trace_list_to_vector_report(__raw_file, __warnings);
453     __trace_map_to_unordered_map_report(__raw_file, __warnings);
454     std::fclose(__raw_file);
455 
456     // Sort data by magnitude, keeping just top N.
457     std::size_t __cutoff = std::min(_GLIBCXX_PROFILE_DATA(_S_max_warn_count),
458 				    __warnings.size());
459     __top_n(__warnings, __top_warnings, __cutoff);
460 
461     FILE* __warn_file = __open_output_file("txt");
462     __for_each(__top_warnings.begin(), __top_warnings.end(),
463 	       __warn(__warn_file));
464     std::fclose(__warn_file);
465 
466     _GLIBCXX_PROFILE_DATA(__global_lock).unlock();
467   }
468 
469   inline void
470   __set_trace_path()
471   {
472     char* __env_trace_file_name = std::getenv(_GLIBCXX_PROFILE_TRACE_ENV_VAR);
473 
474     if (__env_trace_file_name)
475       _GLIBCXX_PROFILE_DATA(_S_trace_file_name) = __env_trace_file_name;
476 
477     // Make sure early that we can create the trace file.
478     std::fclose(__open_output_file("txt"));
479   }
480 
481   inline void
482   __set_max_warn_count()
483   {
484     char* __env_max_warn_count_str
485       = std::getenv(_GLIBCXX_PROFILE_MAX_WARN_COUNT_ENV_VAR);
486 
487     if (__env_max_warn_count_str)
488       _GLIBCXX_PROFILE_DATA(_S_max_warn_count)
489 	= static_cast<std::size_t>(std::atoi(__env_max_warn_count_str));
490   }
491 
492   inline void
493   __read_cost_factors()
494   {
495     std::string __conf_file_name(_GLIBCXX_PROFILE_DATA(_S_trace_file_name));
496     __conf_file_name += ".conf";
497 
498     std::ifstream __conf_file(__conf_file_name.c_str());
499 
500     if (__conf_file.is_open())
501       {
502 	std::string __line;
503 
504 	while (std::getline(__conf_file, __line))
505 	  {
506 	    std::string::size_type __i = __line.find_first_not_of(" \t\n\v");
507 
508 	    if (__line.length() <= 0 || __line[__i] == '#')
509 	      // Skip empty lines or comments.
510 	      continue;
511 	  }
512 
513 	// Trim.
514 	__line.erase(__remove(__line.begin(), __line.end(), ' '),
515 		     __line.end());
516 	std::string::size_type __pos = __line.find("=");
517 	std::string __factor_name = __line.substr(0, __pos);
518 	std::string::size_type __end = __line.find_first_of(";\n");
519 	std::string __factor_value = __line.substr(__pos + 1, __end - __pos);
520 
521 	_GLIBCXX_PROFILE_DATA(__env)[__factor_name] = __factor_value;
522       }
523   }
524 
525   struct __cost_factor_writer
526   {
527     FILE* __file;
528 
529     __cost_factor_writer(FILE* __f)
530     : __file(__f) { }
531 
532     void
533     operator() (const __cost_factor* __factor)
534     { std::fprintf(__file, "%s = %f\n", __factor->__env_var,
535 		   __factor->__value); }
536   };
537 
538   inline void
539   __write_cost_factors()
540   {
541     FILE* __file = __open_output_file("conf.out");
542     __for_each(_GLIBCXX_PROFILE_DATA(__cost_factors)->begin(),
543 	       _GLIBCXX_PROFILE_DATA(__cost_factors)->end(),
544 	       __cost_factor_writer(__file));
545     std::fclose(__file);
546   }
547 
548   struct __cost_factor_setter
549   {
550     void
551     operator()(__cost_factor* __factor)
552     {
553       // Look it up in the process environment first.
554       const char* __env_value = std::getenv(__factor->__env_var);
555 
556       if (!__env_value)
557         {
558           // Look it up in the config file.
559           __env_t::iterator __it
560 	    = _GLIBCXX_PROFILE_DATA(__env).find(__factor->__env_var);
561           if (__it != _GLIBCXX_PROFILE_DATA(__env).end())
562             __env_value = (*__it).second.c_str();
563         }
564 
565       if (__env_value)
566         __factor->__value = std::atof(__env_value);
567     }
568   };
569 
570   inline void
571   __set_cost_factors()
572   {
573     _GLIBCXX_PROFILE_DATA(__cost_factors) = new __cost_factor_vector;
574     _GLIBCXX_PROFILE_DATA(__cost_factors)->
575       push_back(&_GLIBCXX_PROFILE_DATA(__vector_shift_cost_factor));
576     _GLIBCXX_PROFILE_DATA(__cost_factors)->
577       push_back(&_GLIBCXX_PROFILE_DATA(__vector_iterate_cost_factor));
578     _GLIBCXX_PROFILE_DATA(__cost_factors)->
579       push_back(&_GLIBCXX_PROFILE_DATA(__vector_resize_cost_factor));
580     _GLIBCXX_PROFILE_DATA(__cost_factors)->
581       push_back(&_GLIBCXX_PROFILE_DATA(__list_shift_cost_factor));
582     _GLIBCXX_PROFILE_DATA(__cost_factors)->
583       push_back(&_GLIBCXX_PROFILE_DATA(__list_iterate_cost_factor));
584     _GLIBCXX_PROFILE_DATA(__cost_factors)->
585       push_back(&_GLIBCXX_PROFILE_DATA(__list_resize_cost_factor));
586     _GLIBCXX_PROFILE_DATA(__cost_factors)->
587       push_back(&_GLIBCXX_PROFILE_DATA(__map_insert_cost_factor));
588     _GLIBCXX_PROFILE_DATA(__cost_factors)->
589       push_back(&_GLIBCXX_PROFILE_DATA(__map_erase_cost_factor));
590     _GLIBCXX_PROFILE_DATA(__cost_factors)->
591       push_back(&_GLIBCXX_PROFILE_DATA(__map_find_cost_factor));
592     _GLIBCXX_PROFILE_DATA(__cost_factors)->
593       push_back(&_GLIBCXX_PROFILE_DATA(__map_iterate_cost_factor));
594     _GLIBCXX_PROFILE_DATA(__cost_factors)->
595       push_back(&_GLIBCXX_PROFILE_DATA(__umap_insert_cost_factor));
596     _GLIBCXX_PROFILE_DATA(__cost_factors)->
597       push_back(&_GLIBCXX_PROFILE_DATA(__umap_erase_cost_factor));
598     _GLIBCXX_PROFILE_DATA(__cost_factors)->
599       push_back(&_GLIBCXX_PROFILE_DATA(__umap_find_cost_factor));
600     _GLIBCXX_PROFILE_DATA(__cost_factors)->
601       push_back(&_GLIBCXX_PROFILE_DATA(__umap_iterate_cost_factor));
602     __for_each(_GLIBCXX_PROFILE_DATA(__cost_factors)->begin(),
603 	       _GLIBCXX_PROFILE_DATA(__cost_factors)->end(),
604 	       __cost_factor_setter());
605   }
606 
607   inline void
608   __profcxx_init_unconditional()
609   {
610     _GLIBCXX_PROFILE_DATA(__global_lock).lock();
611 
612     if (__is_invalid())
613       {
614 	__set_max_warn_count();
615 
616 	if (_GLIBCXX_PROFILE_DATA(_S_max_warn_count) == 0)
617 	  __turn_off();
618 	else
619 	  {
620 	    __set_max_stack_trace_depth();
621 	    __set_max_mem();
622 	    __set_trace_path();
623 	    __read_cost_factors();
624 	    __set_cost_factors();
625 	    __write_cost_factors();
626 
627 	    __trace_vector_size_init();
628 	    __trace_hashtable_size_init();
629 	    __trace_hash_func_init();
630 	    __trace_vector_to_list_init();
631 	    __trace_list_to_slist_init();
632 	    __trace_list_to_vector_init();
633 	    __trace_map_to_unordered_map_init();
634 
635 	    std::atexit(__report);
636 
637 	    __turn_on();
638 	  }
639       }
640 
641     _GLIBCXX_PROFILE_DATA(__global_lock).unlock();
642   }
643 
644   /** @brief This function must be called by each instrumentation point.
645    *
646    * The common path is inlined fully.
647    */
648   inline bool
649   __profcxx_init()
650   {
651     if (__is_invalid())
652       __profcxx_init_unconditional();
653 
654     return __is_on();
655   }
656 
657 } // namespace __gnu_profile
658 
659 #endif /* _GLIBCXX_PROFILE_PROFILER_TRACE_H */
660