Mercurial > hg > CbC > CbC_gcc
comparison libgcc/libgcov-profiler.c @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
1 /* Routines required for instrumenting a program. */ | 1 /* Routines required for instrumenting a program. */ |
2 /* Compile this one with gcc. */ | 2 /* Compile this one with gcc. */ |
3 /* Copyright (C) 1989-2018 Free Software Foundation, Inc. | 3 /* Copyright (C) 1989-2020 Free Software Foundation, Inc. |
4 | 4 |
5 This file is part of GCC. | 5 This file is part of GCC. |
6 | 6 |
7 GCC is free software; you can redistribute it and/or modify it under | 7 GCC is free software; you can redistribute it and/or modify it under |
8 the terms of the GNU General Public License as published by the Free | 8 the terms of the GNU General Public License as published by the Free |
104 __atomic_fetch_add (&counters[1], 1, __ATOMIC_RELAXED); | 104 __atomic_fetch_add (&counters[1], 1, __ATOMIC_RELAXED); |
105 } | 105 } |
106 #endif | 106 #endif |
107 | 107 |
108 | 108 |
109 /* Tries to determine the most common value among its inputs. Checks if the | 109 /* Tries to determine N most commons value among its inputs. */ |
110 value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1] | |
111 is incremented. If this is not the case and COUNTERS[1] is not zero, | |
112 COUNTERS[1] is decremented. Otherwise COUNTERS[1] is set to one and | |
113 VALUE is stored to COUNTERS[0]. This algorithm guarantees that if this | |
114 function is called more than 50% of the time with one value, this value | |
115 will be in COUNTERS[0] in the end. | |
116 | |
117 In any case, COUNTERS[2] is incremented. If USE_ATOMIC is set to 1, | |
118 COUNTERS[2] is updated with an atomic instruction. */ | |
119 | 110 |
120 static inline void | 111 static inline void |
121 __gcov_one_value_profiler_body (gcov_type *counters, gcov_type value, | 112 __gcov_topn_values_profiler_body (gcov_type *counters, gcov_type value, |
122 int use_atomic) | 113 int use_atomic) |
123 { | 114 { |
124 if (value == counters[0]) | 115 if (use_atomic) |
125 counters[1]++; | 116 __atomic_fetch_add (&counters[0], 1, __ATOMIC_RELAXED); |
126 else if (counters[1] == 0) | 117 else |
118 counters[0]++; | |
119 | |
120 ++counters; | |
121 | |
122 /* First try to find an existing value. */ | |
123 int empty_counter = -1; | |
124 | |
125 for (unsigned i = 0; i < GCOV_TOPN_VALUES; i++) | |
126 if (value == counters[2 * i]) | |
127 { | |
128 if (use_atomic) | |
129 __atomic_fetch_add (&counters[2 * i + 1], GCOV_TOPN_VALUES, | |
130 __ATOMIC_RELAXED); | |
131 else | |
132 counters[2 * i + 1] += GCOV_TOPN_VALUES; | |
133 return; | |
134 } | |
135 else if (counters[2 * i + 1] <= 0) | |
136 empty_counter = i; | |
137 | |
138 /* Find an empty slot for a new value. */ | |
139 if (empty_counter != -1) | |
127 { | 140 { |
128 counters[1] = 1; | 141 counters[2 * empty_counter] = value; |
129 counters[0] = value; | 142 counters[2 * empty_counter + 1] = GCOV_TOPN_VALUES; |
143 return; | |
130 } | 144 } |
131 else | 145 |
132 counters[1]--; | 146 /* We haven't found an empty slot, then decrement all |
133 | 147 counter values by one. */ |
134 if (use_atomic) | 148 for (unsigned i = 0; i < GCOV_TOPN_VALUES; i++) |
135 __atomic_fetch_add (&counters[2], 1, __ATOMIC_RELAXED); | 149 if (use_atomic) |
136 else | 150 __atomic_fetch_sub (&counters[2 * i + 1], 1, __ATOMIC_RELAXED); |
137 counters[2]++; | 151 else |
138 } | 152 counters[2 * i + 1]--; |
139 | 153 } |
140 #ifdef L_gcov_one_value_profiler | 154 |
141 void | 155 #ifdef L_gcov_topn_values_profiler |
142 __gcov_one_value_profiler (gcov_type *counters, gcov_type value) | 156 void |
143 { | 157 __gcov_topn_values_profiler (gcov_type *counters, gcov_type value) |
144 __gcov_one_value_profiler_body (counters, value, 0); | 158 { |
145 } | 159 __gcov_topn_values_profiler_body (counters, value, 0); |
146 #endif | 160 } |
147 | 161 #endif |
148 #if defined(L_gcov_one_value_profiler_atomic) && GCOV_SUPPORTS_ATOMIC | 162 |
163 #if defined(L_gcov_topn_values_profiler_atomic) && GCOV_SUPPORTS_ATOMIC | |
149 | 164 |
150 /* Update one value profilers (COUNTERS) for a given VALUE. | 165 /* Update one value profilers (COUNTERS) for a given VALUE. |
151 | 166 |
152 CAVEAT: Following function is not thread-safe, only total number | 167 CAVEAT: Following function is not thread-safe, only total number |
153 of executions (COUNTERS[2]) is update with an atomic instruction. | 168 of executions (COUNTERS[2]) is update with an atomic instruction. |
155 (COUNTERS[0] and COUNTERS[1]), for more information please read | 170 (COUNTERS[0] and COUNTERS[1]), for more information please read |
156 following email thread: | 171 following email thread: |
157 https://gcc.gnu.org/ml/gcc-patches/2016-08/msg00024.html. */ | 172 https://gcc.gnu.org/ml/gcc-patches/2016-08/msg00024.html. */ |
158 | 173 |
159 void | 174 void |
160 __gcov_one_value_profiler_atomic (gcov_type *counters, gcov_type value) | 175 __gcov_topn_values_profiler_atomic (gcov_type *counters, gcov_type value) |
161 { | 176 { |
162 __gcov_one_value_profiler_body (counters, value, 1); | 177 __gcov_topn_values_profiler_body (counters, value, 1); |
163 } | 178 } |
164 #endif | 179 #endif |
165 | 180 |
166 #ifdef L_gcov_indirect_call_topn_profiler | 181 #ifdef L_gcov_indirect_call_profiler_v4 |
167 /* Tries to keep track the most frequent N values in the counters where | |
168 N is specified by parameter TOPN_VAL. To track top N values, 2*N counter | |
169 entries are used. | |
170 counter[0] --- the accumative count of the number of times one entry in | |
171 in the counters gets evicted/replaced due to limited capacity. | |
172 When this value reaches a threshold, the bottom N values are | |
173 cleared. | |
174 counter[1] through counter[2*N] records the top 2*N values collected so far. | |
175 Each value is represented by two entries: count[2*i+1] is the ith value, and | |
176 count[2*i+2] is the number of times the value is seen. */ | |
177 | |
178 static void | |
179 __gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value) | |
180 { | |
181 unsigned i, found = 0, have_zero_count = 0; | |
182 gcov_type *entry; | |
183 gcov_type *lfu_entry = &counters[1]; | |
184 gcov_type *value_array = &counters[1]; | |
185 gcov_type *num_eviction = &counters[0]; | |
186 gcov_unsigned_t topn_val = GCOV_ICALL_TOPN_VAL; | |
187 | |
188 /* There are 2*topn_val values tracked, each value takes two slots in the | |
189 counter array. */ | |
190 for (i = 0; i < (topn_val << 2); i += 2) | |
191 { | |
192 entry = &value_array[i]; | |
193 if (entry[0] == value) | |
194 { | |
195 entry[1]++ ; | |
196 found = 1; | |
197 break; | |
198 } | |
199 else if (entry[1] == 0) | |
200 { | |
201 lfu_entry = entry; | |
202 have_zero_count = 1; | |
203 } | |
204 else if (entry[1] < lfu_entry[1]) | |
205 lfu_entry = entry; | |
206 } | |
207 | |
208 if (found) | |
209 return; | |
210 | |
211 /* lfu_entry is either an empty entry or an entry | |
212 with lowest count, which will be evicted. */ | |
213 lfu_entry[0] = value; | |
214 lfu_entry[1] = 1; | |
215 | |
216 #define GCOV_ICALL_COUNTER_CLEAR_THRESHOLD 3000 | |
217 | |
218 /* Too many evictions -- time to clear bottom entries to | |
219 avoid hot values bumping each other out. */ | |
220 if (!have_zero_count | |
221 && ++*num_eviction >= GCOV_ICALL_COUNTER_CLEAR_THRESHOLD) | |
222 { | |
223 unsigned i, j; | |
224 gcov_type *p, minv; | |
225 gcov_type* tmp_cnts | |
226 = (gcov_type *)alloca (topn_val * sizeof (gcov_type)); | |
227 | |
228 *num_eviction = 0; | |
229 | |
230 for (i = 0; i < topn_val; i++) | |
231 tmp_cnts[i] = 0; | |
232 | |
233 /* Find the largest topn_val values from the group of | |
234 2*topn_val values and put them into tmp_cnts. */ | |
235 | |
236 for (i = 0; i < 2 * topn_val; i += 2) | |
237 { | |
238 p = 0; | |
239 for (j = 0; j < topn_val; j++) | |
240 { | |
241 if (!p || tmp_cnts[j] < *p) | |
242 p = &tmp_cnts[j]; | |
243 } | |
244 if (value_array[i + 1] > *p) | |
245 *p = value_array[i + 1]; | |
246 } | |
247 | |
248 minv = tmp_cnts[0]; | |
249 for (j = 1; j < topn_val; j++) | |
250 { | |
251 if (tmp_cnts[j] < minv) | |
252 minv = tmp_cnts[j]; | |
253 } | |
254 /* Zero out low value entries. */ | |
255 for (i = 0; i < 2 * topn_val; i += 2) | |
256 { | |
257 if (value_array[i + 1] < minv) | |
258 { | |
259 value_array[i] = 0; | |
260 value_array[i + 1] = 0; | |
261 } | |
262 } | |
263 } | |
264 } | |
265 | |
266 /* These two variables are used to actually track caller and callee. Keep | |
267 them in TLS memory so races are not common (they are written to often). | |
268 The variables are set directly by GCC instrumented code, so declaration | |
269 here must match one in tree-profile.c. */ | |
270 | |
271 #if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS) | |
272 __thread | |
273 #endif | |
274 struct indirect_call_tuple __gcov_indirect_call_topn; | |
275 | |
276 #ifdef TARGET_VTABLE_USES_DESCRIPTORS | |
277 #define VTABLE_USES_DESCRIPTORS 1 | |
278 #else | |
279 #define VTABLE_USES_DESCRIPTORS 0 | |
280 #endif | |
281 | |
282 /* This fucntion is instrumented at function entry to track topn indirect | |
283 calls to CUR_FUNC. */ | |
284 | |
285 void | |
286 __gcov_indirect_call_topn_profiler (gcov_type value, void* cur_func) | |
287 { | |
288 void *callee_func = __gcov_indirect_call_topn.callee; | |
289 /* If the C++ virtual tables contain function descriptors then one | |
290 function may have multiple descriptors and we need to dereference | |
291 the descriptors to see if they point to the same function. */ | |
292 if (cur_func == callee_func | |
293 || (VTABLE_USES_DESCRIPTORS && callee_func | |
294 && *(void **) cur_func == *(void **) callee_func)) | |
295 __gcov_topn_value_profiler_body (__gcov_indirect_call_topn.counters, value); | |
296 } | |
297 #endif | |
298 | |
299 #ifdef L_gcov_indirect_call_profiler_v2 | |
300 | 182 |
301 /* These two variables are used to actually track caller and callee. Keep | 183 /* These two variables are used to actually track caller and callee. Keep |
302 them in TLS memory so races are not common (they are written to often). | 184 them in TLS memory so races are not common (they are written to often). |
303 The variables are set directly by GCC instrumented code, so declaration | 185 The variables are set directly by GCC instrumented code, so declaration |
304 here must match one in tree-profile.c */ | 186 here must match one in tree-profile.c */ |
315 | 197 |
316 It is assumed that the address of a function descriptor may be treated | 198 It is assumed that the address of a function descriptor may be treated |
317 as a pointer to a function. */ | 199 as a pointer to a function. */ |
318 | 200 |
319 /* Tries to determine the most common value among its inputs. */ | 201 /* Tries to determine the most common value among its inputs. */ |
320 void | 202 static inline void |
321 __gcov_indirect_call_profiler_v2 (gcov_type value, void* cur_func) | 203 __gcov_indirect_call_profiler_body (gcov_type value, void *cur_func, |
204 int use_atomic) | |
322 { | 205 { |
323 /* If the C++ virtual tables contain function descriptors then one | 206 /* If the C++ virtual tables contain function descriptors then one |
324 function may have multiple descriptors and we need to dereference | 207 function may have multiple descriptors and we need to dereference |
325 the descriptors to see if they point to the same function. */ | 208 the descriptors to see if they point to the same function. */ |
326 if (cur_func == __gcov_indirect_call.callee | 209 if (cur_func == __gcov_indirect_call.callee |
327 || (__LIBGCC_VTABLE_USES_DESCRIPTORS__ | 210 || (__LIBGCC_VTABLE_USES_DESCRIPTORS__ |
328 && *(void **) cur_func == *(void **) __gcov_indirect_call.callee)) | 211 && *(void **) cur_func == *(void **) __gcov_indirect_call.callee)) |
329 __gcov_one_value_profiler_body (__gcov_indirect_call.counters, value, 0); | 212 __gcov_topn_values_profiler_body (__gcov_indirect_call.counters, value, |
213 use_atomic); | |
330 | 214 |
331 __gcov_indirect_call.callee = NULL; | 215 __gcov_indirect_call.callee = NULL; |
332 } | 216 } |
217 | |
218 void | |
219 __gcov_indirect_call_profiler_v4 (gcov_type value, void *cur_func) | |
220 { | |
221 __gcov_indirect_call_profiler_body (value, cur_func, 0); | |
222 } | |
223 | |
224 #if GCOV_SUPPORTS_ATOMIC | |
225 void | |
226 __gcov_indirect_call_profiler_v4_atomic (gcov_type value, void *cur_func) | |
227 { | |
228 __gcov_indirect_call_profiler_body (value, cur_func, 1); | |
229 } | |
230 #endif | |
231 | |
333 #endif | 232 #endif |
334 | 233 |
335 #ifdef L_gcov_time_profiler | 234 #ifdef L_gcov_time_profiler |
336 | 235 |
337 /* Counter for first visit of each function. */ | 236 /* Counter for first visit of each function. */ |
338 gcov_type __gcov_time_profiler_counter ATTRIBUTE_HIDDEN = 1; | 237 gcov_type __gcov_time_profiler_counter ATTRIBUTE_HIDDEN; |
339 | 238 |
340 #endif | 239 #endif |
341 | 240 |
342 #ifdef L_gcov_average_profiler | 241 #ifdef L_gcov_average_profiler |
343 /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want | 242 /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want |