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