1// -*- C++ -*-
2//
3// Copyright (C) 2009-2013 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#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
55namespace __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