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