libstdc++
profiler_trace.h
Go to the documentation of this file.
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 
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. */
74  {
75  float __magnitude;
76  __stack_t __context;
77  const char* __warning_id;
78  std::string __warning_message;
79 
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;
98  class __trace_map2umap;
99  class __trace_vector_size;
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>
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
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
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 */