Commit a266236e by Martin Liska Committed by Martin Liska

Add new *_atomic counter update function

	PR gcov-profile/58306
	* Makefile.in: New functions (modules) are added.
	* libgcov-profiler.c (__gcov_interval_profiler_atomic): New
	function.
	(__gcov_pow2_profiler_atomic): New function.
	(__gcov_one_value_profiler_body): New argument is instroduced.
	(__gcov_one_value_profiler): Call with the new argument.
	(__gcov_one_value_profiler_atomic): Likewise.
	(__gcov_indirect_call_profiler_v2): Likewise.
	(__gcov_time_profiler_atomic): New function.
	(__gcov_average_profiler_atomic): Likewise.
	(__gcov_ior_profiler_atomic): Likewise.
	* libgcov.h: Declare the aforementioned functions.
	PR gcov-profile/58306
	* gcc.dg/tree-prof/val-profiler-threads-1.c: New test.
	PR gcov-profile/58306
	* tree-profile.c (gimple_init_edge_profiler): Create conditionally
	atomic variants of profile update functions.

From-SVN: r239324
parent 22063dbc
2016-08-10 Martin Liska <mliska@suse.cz> 2016-08-10 Martin Liska <mliska@suse.cz>
PR gcov-profile/58306
* tree-profile.c (gimple_init_edge_profiler): Create conditionally
atomic variants of profile update functions.
2016-08-10 Martin Liska <mliska@suse.cz>
Cherry picked (and modified) from google-4_7 branch Cherry picked (and modified) from google-4_7 branch
2012-12-26 Rong Xu <xur@google.com> 2012-12-26 Rong Xu <xur@google.com>
* common.opt (fprofile-update): Add new flag. * common.opt (fprofile-update): Add new flag.
......
2016-08-10 Martin Liska <mliska@suse.cz> 2016-08-10 Martin Liska <mliska@suse.cz>
PR gcov-profile/58306
* gcc.dg/tree-prof/val-profiler-threads-1.c: New test.
2016-08-10 Martin Liska <mliska@suse.cz>
* g++.dg/gcov/gcov-threads-1.C: New test. * g++.dg/gcov/gcov-threads-1.C: New test.
2016-08-10 Senthil Kumar Selvaraj <senthil_kumar.selvaraj@atmel.com> 2016-08-10 Senthil Kumar Selvaraj <senthil_kumar.selvaraj@atmel.com>
......
/* { dg-options "-O0 -pthread -fprofile-update=atomic" } */
#include <pthread.h>
#define NUM_THREADS 8
#define SIZE 1024
#define ITERATIONS (1000 * 1000)
char buffer[SIZE];
char buffer2[SIZE];
void *copy_memory(char *dst, char *src, unsigned size)
{
for (unsigned i = 0; i < ITERATIONS; i++)
{
dst[size % 10] = src[size % 20];
}
}
void *foo(void *d)
{
copy_memory (buffer, buffer2, SIZE);
}
int main(int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc;
long t;
for(t=0;t<NUM_THREADS;t++){
rc = pthread_create(&threads[t], NULL, foo, 0);
if (rc){
return 1;
}
}
int retval;
for(t=0;t<NUM_THREADS;t++)
pthread_join (threads[t], (void**)&retval);
return buffer[10];
}
...@@ -128,9 +128,13 @@ gimple_init_edge_profiler (void) ...@@ -128,9 +128,13 @@ gimple_init_edge_profiler (void)
tree average_profiler_fn_type; tree average_profiler_fn_type;
tree time_profiler_fn_type; tree time_profiler_fn_type;
const char *profiler_fn_name; const char *profiler_fn_name;
const char *fn_name;
if (!gcov_type_node) if (!gcov_type_node)
{ {
const char *fn_suffix
= flag_profile_update == PROFILE_UPDATE_ATOMIC ? "_atomic" : "";
gcov_type_node = get_gcov_type (); gcov_type_node = get_gcov_type ();
gcov_type_ptr = build_pointer_type (gcov_type_node); gcov_type_ptr = build_pointer_type (gcov_type_node);
...@@ -140,9 +144,10 @@ gimple_init_edge_profiler (void) ...@@ -140,9 +144,10 @@ gimple_init_edge_profiler (void)
gcov_type_ptr, gcov_type_node, gcov_type_ptr, gcov_type_node,
integer_type_node, integer_type_node,
unsigned_type_node, NULL_TREE); unsigned_type_node, NULL_TREE);
tree_interval_profiler_fn fn_name = concat ("__gcov_interval_profiler", fn_suffix, NULL);
= build_fn_decl ("__gcov_interval_profiler", tree_interval_profiler_fn = build_fn_decl (fn_name,
interval_profiler_fn_type); interval_profiler_fn_type);
free (CONST_CAST (char *, fn_name));
TREE_NOTHROW (tree_interval_profiler_fn) = 1; TREE_NOTHROW (tree_interval_profiler_fn) = 1;
DECL_ATTRIBUTES (tree_interval_profiler_fn) DECL_ATTRIBUTES (tree_interval_profiler_fn)
= tree_cons (get_identifier ("leaf"), NULL, = tree_cons (get_identifier ("leaf"), NULL,
...@@ -153,8 +158,9 @@ gimple_init_edge_profiler (void) ...@@ -153,8 +158,9 @@ gimple_init_edge_profiler (void)
= build_function_type_list (void_type_node, = build_function_type_list (void_type_node,
gcov_type_ptr, gcov_type_node, gcov_type_ptr, gcov_type_node,
NULL_TREE); NULL_TREE);
tree_pow2_profiler_fn = build_fn_decl ("__gcov_pow2_profiler", fn_name = concat ("__gcov_pow2_profiler", fn_suffix, NULL);
pow2_profiler_fn_type); tree_pow2_profiler_fn = build_fn_decl (fn_name, pow2_profiler_fn_type);
free (CONST_CAST (char *, fn_name));
TREE_NOTHROW (tree_pow2_profiler_fn) = 1; TREE_NOTHROW (tree_pow2_profiler_fn) = 1;
DECL_ATTRIBUTES (tree_pow2_profiler_fn) DECL_ATTRIBUTES (tree_pow2_profiler_fn)
= tree_cons (get_identifier ("leaf"), NULL, = tree_cons (get_identifier ("leaf"), NULL,
...@@ -165,9 +171,10 @@ gimple_init_edge_profiler (void) ...@@ -165,9 +171,10 @@ gimple_init_edge_profiler (void)
= build_function_type_list (void_type_node, = build_function_type_list (void_type_node,
gcov_type_ptr, gcov_type_node, gcov_type_ptr, gcov_type_node,
NULL_TREE); NULL_TREE);
tree_one_value_profiler_fn fn_name = concat ("__gcov_one_value_profiler", fn_suffix, NULL);
= build_fn_decl ("__gcov_one_value_profiler", tree_one_value_profiler_fn = build_fn_decl (fn_name,
one_value_profiler_fn_type); one_value_profiler_fn_type);
free (CONST_CAST (char *, fn_name));
TREE_NOTHROW (tree_one_value_profiler_fn) = 1; TREE_NOTHROW (tree_one_value_profiler_fn) = 1;
DECL_ATTRIBUTES (tree_one_value_profiler_fn) DECL_ATTRIBUTES (tree_one_value_profiler_fn)
= tree_cons (get_identifier ("leaf"), NULL, = tree_cons (get_identifier ("leaf"), NULL,
...@@ -197,9 +204,9 @@ gimple_init_edge_profiler (void) ...@@ -197,9 +204,9 @@ gimple_init_edge_profiler (void)
time_profiler_fn_type time_profiler_fn_type
= build_function_type_list (void_type_node, = build_function_type_list (void_type_node,
gcov_type_ptr, NULL_TREE); gcov_type_ptr, NULL_TREE);
tree_time_profiler_fn fn_name = concat ("__gcov_time_profiler", fn_suffix, NULL);
= build_fn_decl ("__gcov_time_profiler", tree_time_profiler_fn = build_fn_decl (fn_name, time_profiler_fn_type);
time_profiler_fn_type); free (CONST_CAST (char *, fn_name));
TREE_NOTHROW (tree_time_profiler_fn) = 1; TREE_NOTHROW (tree_time_profiler_fn) = 1;
DECL_ATTRIBUTES (tree_time_profiler_fn) DECL_ATTRIBUTES (tree_time_profiler_fn)
= tree_cons (get_identifier ("leaf"), NULL, = tree_cons (get_identifier ("leaf"), NULL,
...@@ -209,16 +216,17 @@ gimple_init_edge_profiler (void) ...@@ -209,16 +216,17 @@ gimple_init_edge_profiler (void)
average_profiler_fn_type average_profiler_fn_type
= build_function_type_list (void_type_node, = build_function_type_list (void_type_node,
gcov_type_ptr, gcov_type_node, NULL_TREE); gcov_type_ptr, gcov_type_node, NULL_TREE);
tree_average_profiler_fn fn_name = concat ("__gcov_average_profiler", fn_suffix, NULL);
= build_fn_decl ("__gcov_average_profiler", tree_average_profiler_fn = build_fn_decl (fn_name,
average_profiler_fn_type); average_profiler_fn_type);
free (CONST_CAST (char *, fn_name));
TREE_NOTHROW (tree_average_profiler_fn) = 1; TREE_NOTHROW (tree_average_profiler_fn) = 1;
DECL_ATTRIBUTES (tree_average_profiler_fn) DECL_ATTRIBUTES (tree_average_profiler_fn)
= tree_cons (get_identifier ("leaf"), NULL, = tree_cons (get_identifier ("leaf"), NULL,
DECL_ATTRIBUTES (tree_average_profiler_fn)); DECL_ATTRIBUTES (tree_average_profiler_fn));
tree_ior_profiler_fn fn_name = concat ("__gcov_ior_profiler", fn_suffix, NULL);
= build_fn_decl ("__gcov_ior_profiler", tree_ior_profiler_fn = build_fn_decl (fn_name, average_profiler_fn_type);
average_profiler_fn_type); free (CONST_CAST (char *, fn_name));
TREE_NOTHROW (tree_ior_profiler_fn) = 1; TREE_NOTHROW (tree_ior_profiler_fn) = 1;
DECL_ATTRIBUTES (tree_ior_profiler_fn) DECL_ATTRIBUTES (tree_ior_profiler_fn)
= tree_cons (get_identifier ("leaf"), NULL, = tree_cons (get_identifier ("leaf"), NULL,
......
2016-08-10 Martin Liska <mliska@suse.cz>
PR gcov-profile/58306
* Makefile.in: New functions (modules) are added.
* libgcov-profiler.c (__gcov_interval_profiler_atomic): New
function.
(__gcov_pow2_profiler_atomic): New function.
(__gcov_one_value_profiler_body): New argument is instroduced.
(__gcov_one_value_profiler): Call with the new argument.
(__gcov_one_value_profiler_atomic): Likewise.
(__gcov_indirect_call_profiler_v2): Likewise.
(__gcov_time_profiler_atomic): New function.
(__gcov_average_profiler_atomic): Likewise.
(__gcov_ior_profiler_atomic): Likewise.
* libgcov.h: Declare the aforementioned functions.
2016-08-09 Martin Liska <mliska@suse.cz> 2016-08-09 Martin Liska <mliska@suse.cz>
* libgcov-util.c: Fix typo and GNU coding style. * libgcov-util.c: Fix typo and GNU coding style.
......
...@@ -858,10 +858,18 @@ include $(iterator) ...@@ -858,10 +858,18 @@ include $(iterator)
LIBGCOV_MERGE = _gcov_merge_add _gcov_merge_single _gcov_merge_delta \ LIBGCOV_MERGE = _gcov_merge_add _gcov_merge_single _gcov_merge_delta \
_gcov_merge_ior _gcov_merge_time_profile _gcov_merge_icall_topn _gcov_merge_ior _gcov_merge_time_profile _gcov_merge_icall_topn
LIBGCOV_PROFILER = _gcov_interval_profiler _gcov_pow2_profiler \ LIBGCOV_PROFILER = _gcov_interval_profiler \
_gcov_interval_profiler_atomic \
_gcov_pow2_profiler \
_gcov_pow2_profiler_atomic \
_gcov_one_value_profiler \ _gcov_one_value_profiler \
_gcov_average_profiler _gcov_ior_profiler \ _gcov_one_value_profiler_atomic \
_gcov_indirect_call_profiler_v2 _gcov_time_profiler \ _gcov_average_profiler \
_gcov_average_profiler_atomic \
_gcov_ior_profiler \
_gcov_ior_profiler_atomic \
_gcov_indirect_call_profiler_v2 \
_gcov_time_profiler \
_gcov_indirect_call_topn_profiler _gcov_indirect_call_topn_profiler
LIBGCOV_INTERFACE = _gcov_dump _gcov_flush _gcov_fork \ LIBGCOV_INTERFACE = _gcov_dump _gcov_flush _gcov_fork \
_gcov_execl _gcov_execlp \ _gcov_execl _gcov_execlp \
......
...@@ -46,6 +46,26 @@ __gcov_interval_profiler (gcov_type *counters, gcov_type value, ...@@ -46,6 +46,26 @@ __gcov_interval_profiler (gcov_type *counters, gcov_type value,
} }
#endif #endif
#ifdef L_gcov_interval_profiler_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, MEMMODEL_RELAXED);
else if (delta >= steps)
__atomic_fetch_add (&counters[steps], 1, MEMMODEL_RELAXED);
else
__atomic_fetch_add (&counters[delta], 1, MEMMODEL_RELAXED);
}
#endif
#ifdef L_gcov_pow2_profiler #ifdef L_gcov_pow2_profiler
/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise /* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
COUNTERS[0] is incremented. */ COUNTERS[0] is incremented. */
...@@ -60,6 +80,21 @@ __gcov_pow2_profiler (gcov_type *counters, gcov_type value) ...@@ -60,6 +80,21 @@ __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
} }
#endif #endif
#ifdef L_gcov_pow2_profiler_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, MEMMODEL_RELAXED);
else
__atomic_fetch_add (&counters[1], 1, MEMMODEL_RELAXED);
}
#endif
/* Tries to determine the most common value among its inputs. Checks if the /* 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] 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, is incremented. If this is not the case and COUNTERS[1] is not zero,
...@@ -68,10 +103,12 @@ __gcov_pow2_profiler (gcov_type *counters, gcov_type value) ...@@ -68,10 +103,12 @@ __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
function is called more than 50% of the time with one value, this value function is called more than 50% of the time with one value, this value
will be in COUNTERS[0] in the end. 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 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]) if (value == counters[0])
counters[1]++; counters[1]++;
...@@ -82,14 +119,36 @@ __gcov_one_value_profiler_body (gcov_type *counters, gcov_type value) ...@@ -82,14 +119,36 @@ __gcov_one_value_profiler_body (gcov_type *counters, gcov_type value)
} }
else else
counters[1]--; counters[1]--;
counters[2]++;
if (use_atomic)
__atomic_fetch_add (&counters[2], 1, MEMMODEL_RELAXED);
else
counters[2]++;
} }
#ifdef L_gcov_one_value_profiler #ifdef L_gcov_one_value_profiler
void void
__gcov_one_value_profiler (gcov_type *counters, gcov_type value) __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
#ifdef L_gcov_one_value_profiler_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 #endif
...@@ -265,7 +324,7 @@ __gcov_indirect_call_profiler_v2 (gcov_type value, void* cur_func) ...@@ -265,7 +324,7 @@ __gcov_indirect_call_profiler_v2 (gcov_type value, void* cur_func)
if (cur_func == __gcov_indirect_call_callee if (cur_func == __gcov_indirect_call_callee
|| (__LIBGCC_VTABLE_USES_DESCRIPTORS__ && __gcov_indirect_call_callee || (__LIBGCC_VTABLE_USES_DESCRIPTORS__ && __gcov_indirect_call_callee
&& *(void **) cur_func == *(void **) __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 #endif
...@@ -282,8 +341,19 @@ __gcov_time_profiler (gcov_type* counters) ...@@ -282,8 +341,19 @@ __gcov_time_profiler (gcov_type* counters)
if (!counters[0]) if (!counters[0])
counters[0] = ++function_counter; counters[0] = ++function_counter;
} }
/* Sets corresponding COUNTERS if there is no value.
Function is thread-safe. */
void
__gcov_time_profiler_atomic (gcov_type* counters)
{
if (!counters[0])
counters[0] = __atomic_add_fetch (&function_counter, 1, MEMMODEL_RELAXED);
}
#endif #endif
#ifdef L_gcov_average_profiler #ifdef L_gcov_average_profiler
/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want /* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
to saturate up. */ to saturate up. */
...@@ -296,6 +366,18 @@ __gcov_average_profiler (gcov_type *counters, gcov_type value) ...@@ -296,6 +366,18 @@ __gcov_average_profiler (gcov_type *counters, gcov_type value)
} }
#endif #endif
#ifdef L_gcov_average_profiler_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, MEMMODEL_RELAXED);
__atomic_fetch_add (&counters[1], 1, MEMMODEL_RELAXED);
}
#endif
#ifdef L_gcov_ior_profiler #ifdef L_gcov_ior_profiler
/* Bitwise-OR VALUE into COUNTER. */ /* Bitwise-OR VALUE into COUNTER. */
...@@ -306,4 +388,15 @@ __gcov_ior_profiler (gcov_type *counters, gcov_type value) ...@@ -306,4 +388,15 @@ __gcov_ior_profiler (gcov_type *counters, gcov_type value)
} }
#endif #endif
#ifdef L_gcov_ior_profiler_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, MEMMODEL_RELAXED);
}
#endif
#endif /* inhibit_libc */ #endif /* inhibit_libc */
...@@ -268,12 +268,19 @@ extern void __gcov_merge_icall_topn (gcov_type *, unsigned) ATTRIBUTE_HIDDEN; ...@@ -268,12 +268,19 @@ extern void __gcov_merge_icall_topn (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
/* The profiler functions. */ /* The profiler functions. */
extern void __gcov_interval_profiler (gcov_type *, gcov_type, int, unsigned); extern void __gcov_interval_profiler (gcov_type *, gcov_type, int, unsigned);
extern void __gcov_interval_profiler_atomic (gcov_type *, gcov_type, int,
unsigned);
extern void __gcov_pow2_profiler (gcov_type *, gcov_type); extern void __gcov_pow2_profiler (gcov_type *, gcov_type);
extern void __gcov_pow2_profiler_atomic (gcov_type *, gcov_type);
extern void __gcov_one_value_profiler (gcov_type *, gcov_type); extern void __gcov_one_value_profiler (gcov_type *, gcov_type);
extern void __gcov_one_value_profiler_atomic (gcov_type *, gcov_type);
extern void __gcov_indirect_call_profiler_v2 (gcov_type, void *); extern void __gcov_indirect_call_profiler_v2 (gcov_type, void *);
extern void __gcov_time_profiler (gcov_type *); extern void __gcov_time_profiler (gcov_type *);
extern void __gcov_time_profiler_atomic (gcov_type *);
extern void __gcov_average_profiler (gcov_type *, gcov_type); extern void __gcov_average_profiler (gcov_type *, gcov_type);
extern void __gcov_average_profiler_atomic (gcov_type *, gcov_type);
extern void __gcov_ior_profiler (gcov_type *, gcov_type); extern void __gcov_ior_profiler (gcov_type *, gcov_type);
extern void __gcov_ior_profiler_atomic (gcov_type *, gcov_type);
extern void __gcov_indirect_call_topn_profiler (gcov_type, void *); extern void __gcov_indirect_call_topn_profiler (gcov_type, void *);
extern void gcov_sort_n_vals (gcov_type *, int); extern void gcov_sort_n_vals (gcov_type *, int);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment