From 38a8aecfb882072900434499696b5c32a2274515 Mon Sep 17 00:00:00 2001 From: Rong Xu Date: Mon, 21 Jul 2014 16:47:22 -0700 Subject: [4.9] Switch gcc-4.9 to use google/gcc-4_9 branch. This source drop uses svn version r212828 of google/gcc-4.9 branch. We also cherry-picked r213062, r213063 and r213064 to fix windows build issues. All gcc-4.9 patches before July 3rd are ported to google/gcc-4.9. The following prior commits has not been merged to google branch yet. (They are included in this commit). e7af147f979e657fe2df00808e5b4319b0e088c6, baf87df3cb2683649ba7e9872362a7e721117c23, and c231900e5dcc14d8296bd9f62b45997a49d4d5e7. Change-Id: I4bea3ea470387ff751c2be4cb0d4a12059b9299b --- gcc-4.9/libgcc/libgcov-profiler.c | 219 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 219 insertions(+) (limited to 'gcc-4.9/libgcc/libgcov-profiler.c') diff --git a/gcc-4.9/libgcc/libgcov-profiler.c b/gcc-4.9/libgcc/libgcov-profiler.c index 3290bf62c..3057b6157 100644 --- a/gcc-4.9/libgcc/libgcov-profiler.c +++ b/gcc-4.9/libgcc/libgcov-profiler.c @@ -85,12 +85,37 @@ __gcov_one_value_profiler_body (gcov_type *counters, gcov_type value) counters[2]++; } +/* Atomic update version of __gcov_one_value_profile_body(). */ +static inline void +__gcov_one_value_profiler_body_atomic (gcov_type *counters, gcov_type value) +{ + if (value == counters[0]) + GCOV_TYPE_ATOMIC_FETCH_ADD_FN (&counters[1], 1, MEMMODEL_RELAXED); + else if (counters[1] == 0) + { + counters[1] = 1; + counters[0] = value; + } + else + GCOV_TYPE_ATOMIC_FETCH_ADD_FN (&counters[1], -1, MEMMODEL_RELAXED); + GCOV_TYPE_ATOMIC_FETCH_ADD_FN (&counters[2], 1, MEMMODEL_RELAXED); +} + + #ifdef L_gcov_one_value_profiler void __gcov_one_value_profiler (gcov_type *counters, gcov_type value) { __gcov_one_value_profiler_body (counters, value); } + +void +__gcov_one_value_profiler_atomic (gcov_type *counters, gcov_type value) +{ + __gcov_one_value_profiler_body_atomic (counters, value); +} + + #endif #ifdef L_gcov_indirect_call_profiler @@ -128,6 +153,19 @@ __gcov_indirect_call_profiler (gcov_type* counter, gcov_type value, __gcov_one_value_profiler_body (counter, value); } + +/* Atomic update version of __gcov_indirect_call_profiler(). */ +void +__gcov_indirect_call_profiler_atomic (gcov_type* counter, gcov_type value, + void* cur_func, void* callee_func) +{ + if (cur_func == callee_func + || (VTABLE_USES_DESCRIPTORS && callee_func + && *(void **) cur_func == *(void **) callee_func)) + __gcov_one_value_profiler_body_atomic (counter, value); +} + + #endif #ifdef L_gcov_indirect_call_profiler_v2 @@ -174,8 +212,189 @@ __gcov_indirect_call_profiler_v2 (gcov_type value, void* cur_func) && *(void **) cur_func == *(void **) __gcov_indirect_call_callee)) __gcov_one_value_profiler_body (__gcov_indirect_call_counters, value); } + +void +__gcov_indirect_call_profiler_atomic_v2 (gcov_type value, void* cur_func) +{ + /* If the C++ virtual tables contain function descriptors then one + function may have multiple descriptors and we need to dereference + the descriptors to see if they point to the same function. */ + if (cur_func == __gcov_indirect_call_callee + || (VTABLE_USES_DESCRIPTORS && __gcov_indirect_call_callee + && *(void **) cur_func == *(void **) __gcov_indirect_call_callee)) + __gcov_one_value_profiler_body_atomic (__gcov_indirect_call_counters, value); +} + #endif +#ifdef L_gcov_indirect_call_topn_profiler +/* Tries to keep track the most frequent N values in the counters where + N is specified by parameter TOPN_VAL. To track top N values, 2*N counter + entries are used. + counter[0] --- the accumative count of the number of times one entry in + in the counters gets evicted/replaced due to limited capacity. + When this value reaches a threshold, the bottom N values are + cleared. + counter[1] through counter[2*N] records the top 2*N values collected so far. + Each value is represented by two entries: count[2*i+1] is the ith value, and + count[2*i+2] is the number of times the value is seen. */ + +static void +__gcov_topn_value_profiler_body (gcov_type *counters, gcov_type value, + gcov_unsigned_t topn_val) +{ + unsigned i, found = 0, have_zero_count = 0; + + gcov_type *entry; + gcov_type *lfu_entry = &counters[1]; + gcov_type *value_array = &counters[1]; + gcov_type *num_eviction = &counters[0]; + + /* There are 2*topn_val values tracked, each value takes two slots in the + counter array */ + for ( i = 0; i < (topn_val << 2); i += 2) + { + entry = &value_array[i]; + if ( entry[0] == value) + { + entry[1]++ ; + found = 1; + break; + } + else if (entry[1] == 0) + { + lfu_entry = entry; + have_zero_count = 1; + } + else if (entry[1] < lfu_entry[1]) + lfu_entry = entry; + } + + if (found) + return; + + /* lfu_entry is either an empty entry or an entry + with lowest count, which will be evicted. */ + lfu_entry[0] = value; + lfu_entry[1] = 1; + +#define GCOV_ICALL_COUNTER_CLEAR_THRESHOLD 3000 + + /* Too many evictions -- time to clear bottom entries to + avoid hot values bumping each other out. */ + if ( !have_zero_count + && ++*num_eviction >= GCOV_ICALL_COUNTER_CLEAR_THRESHOLD) + { + unsigned i, j; + gcov_type *p, minv; + gcov_type* tmp_cnts + = (gcov_type *)alloca (topn_val * sizeof(gcov_type)); + + *num_eviction = 0; + + for ( i = 0; i < topn_val; i++ ) + tmp_cnts[i] = 0; + + /* Find the largest topn_val values from the group of + 2*topn_val values and put them into tmp_cnts. */ + + for ( i = 0; i < 2 * topn_val; i += 2 ) + { + p = 0; + for ( j = 0; j < topn_val; j++ ) + { + if ( !p || tmp_cnts[j] < *p ) + p = &tmp_cnts[j]; + } + if ( value_array[i + 1] > *p ) + *p = value_array[i + 1]; + } + + minv = tmp_cnts[0]; + for ( j = 1; j < topn_val; j++ ) + { + if (tmp_cnts[j] < minv) + minv = tmp_cnts[j]; + } + /* Zero out low value entries */ + for ( i = 0; i < 2 * topn_val; i += 2 ) + { + if (value_array[i + 1] < minv) + { + value_array[i] = 0; + value_array[i + 1] = 0; + } + } + } +} + +#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS) +__thread +#endif +gcov_type *__gcov_indirect_call_topn_counters ATTRIBUTE_HIDDEN; + +#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS) +__thread +#endif +void *__gcov_indirect_call_topn_callee ATTRIBUTE_HIDDEN; + +#ifdef TARGET_VTABLE_USES_DESCRIPTORS +#define VTABLE_USES_DESCRIPTORS 1 +#else +#define VTABLE_USES_DESCRIPTORS 0 +#endif +void +__gcov_indirect_call_topn_profiler (void *cur_func, + void *cur_module_gcov_info, + gcov_unsigned_t cur_func_id) +{ + void *callee_func = __gcov_indirect_call_topn_callee; + gcov_type *counter = __gcov_indirect_call_topn_counters; + /* If the C++ virtual tables contain function descriptors then one + function may have multiple descriptors and we need to dereference + the descriptors to see if they point to the same function. */ + if (cur_func == callee_func + || (VTABLE_USES_DESCRIPTORS && callee_func + && *(void **) cur_func == *(void **) callee_func)) + { + gcov_type global_id + = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident; + global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id); + __gcov_topn_value_profiler_body (counter, global_id, GCOV_ICALL_TOPN_VAL); + __gcov_indirect_call_topn_callee = 0; + } +} + +#endif + +#ifdef L_gcov_direct_call_profiler +#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS) +__thread +#endif +gcov_type *__gcov_direct_call_counters ATTRIBUTE_HIDDEN; +#if defined(HAVE_CC_TLS) && !defined (USE_EMUTLS) +__thread +#endif +void *__gcov_direct_call_callee ATTRIBUTE_HIDDEN; +/* Direct call profiler. */ +void +__gcov_direct_call_profiler (void *cur_func, + void *cur_module_gcov_info, + gcov_unsigned_t cur_func_id) +{ + if (cur_func == __gcov_direct_call_callee) + { + gcov_type global_id + = ((struct gcov_info *) cur_module_gcov_info)->mod_info->ident; + global_id = GEN_FUNC_GLOBAL_ID (global_id, cur_func_id); + __gcov_direct_call_counters[0] = global_id; + __gcov_direct_call_counters[1]++; + __gcov_direct_call_callee = 0; + } +} +#endif + + #ifdef L_gcov_time_profiler /* Counter for first visit of each function. */ -- cgit v1.2.3