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