diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-05-02 14:43:35 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-05-02 14:43:35 +0000 |
commit | 34efdaf078b01a7387007c4e6bde6db86384c4b7 (patch) | |
tree | d503eaf41d085669d1481bb46ec038bc866fece6 /libgcc/libgcov-profiler.c | |
parent | f733cf303bcdc952c92b81dd62199a40a1f555ec (diff) | |
download | gcc-tarball-master.tar.gz |
gcc-7.1.0gcc-7.1.0
Diffstat (limited to 'libgcc/libgcov-profiler.c')
-rw-r--r-- | libgcc/libgcov-profiler.c | 144 |
1 files changed, 101 insertions, 43 deletions
diff --git a/libgcc/libgcov-profiler.c b/libgcc/libgcov-profiler.c index e94718834e..067d762c2a 100644 --- a/libgcc/libgcov-profiler.c +++ b/libgcc/libgcov-profiler.c @@ -1,6 +1,6 @@ /* Routines required for instrumenting a program. */ /* Compile this one with gcc. */ -/* Copyright (C) 1989-2016 Free Software Foundation, Inc. +/* Copyright (C) 1989-2017 Free Software Foundation, Inc. This file is part of GCC. @@ -26,6 +26,17 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include "libgcov.h" #if !defined(inhibit_libc) +/* Detect whether target can support atomic update of profilers. */ +#if __SIZEOF_LONG_LONG__ == 4 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 +#define GCOV_SUPPORTS_ATOMIC 1 +#else +#if __SIZEOF_LONG_LONG__ == 8 && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 +#define GCOV_SUPPORTS_ATOMIC 1 +#else +#define GCOV_SUPPORTS_ATOMIC 0 +#endif +#endif + #ifdef L_gcov_interval_profiler /* If VALUE is in interval <START, START + STEPS - 1>, then increases the corresponding counter in COUNTERS. If the VALUE is above or below @@ -46,6 +57,26 @@ __gcov_interval_profiler (gcov_type *counters, gcov_type value, } #endif +#if defined(L_gcov_interval_profiler_atomic) && GCOV_SUPPORTS_ATOMIC +/* If VALUE is in interval <START, START + STEPS - 1>, then increases the + corresponding counter in COUNTERS. If the VALUE is above or below + the interval, COUNTERS[STEPS] or COUNTERS[STEPS + 1] is increased + instead. Function is thread-safe. */ + +void +__gcov_interval_profiler_atomic (gcov_type *counters, gcov_type value, + int start, unsigned steps) +{ + gcov_type delta = value - start; + if (delta < 0) + __atomic_fetch_add (&counters[steps + 1], 1, __ATOMIC_RELAXED); + else if (delta >= steps) + __atomic_fetch_add (&counters[steps], 1, __ATOMIC_RELAXED); + else + __atomic_fetch_add (&counters[delta], 1, __ATOMIC_RELAXED); +} +#endif + #ifdef L_gcov_pow2_profiler /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise COUNTERS[0] is incremented. */ @@ -53,13 +84,28 @@ __gcov_interval_profiler (gcov_type *counters, gcov_type value, void __gcov_pow2_profiler (gcov_type *counters, gcov_type value) { - if (value & (value - 1)) + if (value == 0 || (value & (value - 1))) counters[0]++; else counters[1]++; } #endif +#if defined(L_gcov_pow2_profiler_atomic) && GCOV_SUPPORTS_ATOMIC +/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise + COUNTERS[0] is incremented. Function is thread-safe. */ + +void +__gcov_pow2_profiler_atomic (gcov_type *counters, gcov_type value) +{ + if (value == 0 || (value & (value - 1))) + __atomic_fetch_add (&counters[0], 1, __ATOMIC_RELAXED); + else + __atomic_fetch_add (&counters[1], 1, __ATOMIC_RELAXED); +} +#endif + + /* Tries to determine the most common value among its inputs. Checks if the value stored in COUNTERS[0] matches VALUE. If this is the case, COUNTERS[1] is incremented. If this is not the case and COUNTERS[1] is not zero, @@ -68,10 +114,12 @@ __gcov_pow2_profiler (gcov_type *counters, gcov_type value) function is called more than 50% of the time with one value, this value will be in COUNTERS[0] in the end. - In any case, COUNTERS[2] is incremented. */ + In any case, COUNTERS[2] is incremented. If USE_ATOMIC is set to 1, + COUNTERS[2] is updated with an atomic instruction. */ static inline void -__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value) +__gcov_one_value_profiler_body (gcov_type *counters, gcov_type value, + int use_atomic) { if (value == counters[0]) counters[1]++; @@ -82,14 +130,36 @@ __gcov_one_value_profiler_body (gcov_type *counters, gcov_type value) } else counters[1]--; - counters[2]++; + + if (use_atomic) + __atomic_fetch_add (&counters[2], 1, __ATOMIC_RELAXED); + else + counters[2]++; } #ifdef L_gcov_one_value_profiler void __gcov_one_value_profiler (gcov_type *counters, gcov_type value) { - __gcov_one_value_profiler_body (counters, value); + __gcov_one_value_profiler_body (counters, value, 0); +} +#endif + +#if defined(L_gcov_one_value_profiler_atomic) && GCOV_SUPPORTS_ATOMIC + +/* Update one value profilers (COUNTERS) for a given VALUE. + + CAVEAT: Following function is not thread-safe, only total number + of executions (COUNTERS[2]) is update with an atomic instruction. + Problem is that one cannot atomically update two counters + (COUNTERS[0] and COUNTERS[1]), for more information please read + following email thread: + https://gcc.gnu.org/ml/gcc-patches/2016-08/msg00024.html. */ + +void +__gcov_one_value_profiler_atomic (gcov_type *counters, gcov_type value) +{ + __gcov_one_value_profiler_body (counters, value, 1); } #endif @@ -231,33 +301,6 @@ __gcov_indirect_call_topn_profiler (gcov_type value, void* cur_func) } #endif -#ifdef L_gcov_indirect_call_profiler -/* This function exist only for workaround of binutils bug 14342. - Once this compatibility hack is obsolette, it can be removed. */ - -/* By default, the C++ compiler will use function addresses in the - vtable entries. Setting TARGET_VTABLE_USES_DESCRIPTORS to nonzero - tells the compiler to use function descriptors instead. The value - of this macro says how many words wide the descriptor is (normally 2). - - It is assumed that the address of a function descriptor may be treated - as a pointer to a function. */ - -/* Tries to determine the most common value among its inputs. */ -void -__gcov_indirect_call_profiler (gcov_type* counter, gcov_type value, - void* cur_func, void* callee_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 == callee_func - || (__LIBGCC_VTABLE_USES_DESCRIPTORS__ && callee_func - && *(void **) cur_func == *(void **) callee_func)) - __gcov_one_value_profiler_body (counter, value); -} -#endif - #ifdef L_gcov_indirect_call_profiler_v2 /* These two variables are used to actually track caller and callee. Keep @@ -292,23 +335,15 @@ __gcov_indirect_call_profiler_v2 (gcov_type value, void* cur_func) if (cur_func == __gcov_indirect_call_callee || (__LIBGCC_VTABLE_USES_DESCRIPTORS__ && __gcov_indirect_call_callee && *(void **) cur_func == *(void **) __gcov_indirect_call_callee)) - __gcov_one_value_profiler_body (__gcov_indirect_call_counters, value); + __gcov_one_value_profiler_body (__gcov_indirect_call_counters, value, 0); } #endif #ifdef L_gcov_time_profiler /* Counter for first visit of each function. */ -static gcov_type function_counter; +gcov_type __gcov_time_profiler_counter ATTRIBUTE_HIDDEN; -/* Sets corresponding COUNTERS if there is no value. */ - -void -__gcov_time_profiler (gcov_type* counters) -{ - if (!counters[0]) - counters[0] = ++function_counter; -} #endif #ifdef L_gcov_average_profiler @@ -323,6 +358,18 @@ __gcov_average_profiler (gcov_type *counters, gcov_type value) } #endif +#if defined(L_gcov_average_profiler_atomic) && GCOV_SUPPORTS_ATOMIC +/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want + to saturate up. Function is thread-safe. */ + +void +__gcov_average_profiler_atomic (gcov_type *counters, gcov_type value) +{ + __atomic_fetch_add (&counters[0], value, __ATOMIC_RELAXED); + __atomic_fetch_add (&counters[1], 1, __ATOMIC_RELAXED); +} +#endif + #ifdef L_gcov_ior_profiler /* Bitwise-OR VALUE into COUNTER. */ @@ -333,4 +380,15 @@ __gcov_ior_profiler (gcov_type *counters, gcov_type value) } #endif +#if defined(L_gcov_ior_profiler_atomic) && GCOV_SUPPORTS_ATOMIC +/* Bitwise-OR VALUE into COUNTER. Function is thread-safe. */ + +void +__gcov_ior_profiler_atomic (gcov_type *counters, gcov_type value) +{ + __atomic_fetch_or (&counters[0], value, __ATOMIC_RELAXED); +} +#endif + + #endif /* inhibit_libc */ |