libstdc++

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