summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormarxin <marxin@138bc75d-0d04-0410-961f-82ee72b054a4>2016-08-10 13:14:56 +0000
committermarxin <marxin@138bc75d-0d04-0410-961f-82ee72b054a4>2016-08-10 13:14:56 +0000
commit2d2b41077a0e1851e8100737f3d2c5dd90bbefb3 (patch)
tree4e0657ae5a14e0c48b2bae73db433a086900d985
parent7132b7551ee4b4305f440e633bcd3fda396927b5 (diff)
downloadgcc-2d2b41077a0e1851e8100737f3d2c5dd90bbefb3.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@239324 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/tree-prof/val-profiler-threads-1.c41
-rw-r--r--gcc/tree-profile.c42
-rw-r--r--libgcc/ChangeLog16
-rw-r--r--libgcc/Makefile.in14
-rw-r--r--libgcc/libgcov-profiler.c103
-rw-r--r--libgcc/libgcov.h7
8 files changed, 209 insertions, 25 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index cdf8b7740bd..7dbe48608f0 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,11 @@
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
2012-12-26 Rong Xu <xur@google.com>
* common.opt (fprofile-update): Add new flag.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 20bd72a0dbc..c9f58fec411 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,10 @@
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.
2016-08-10 Senthil Kumar Selvaraj <senthil_kumar.selvaraj@atmel.com>
diff --git a/gcc/testsuite/gcc.dg/tree-prof/val-profiler-threads-1.c b/gcc/testsuite/gcc.dg/tree-prof/val-profiler-threads-1.c
new file mode 100644
index 00000000000..e9b04a0e67d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-prof/val-profiler-threads-1.c
@@ -0,0 +1,41 @@
+/* { 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];
+}
diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c
index 740f7ab7d5a..fdf0201f2e4 100644
--- a/gcc/tree-profile.c
+++ b/gcc/tree-profile.c
@@ -128,9 +128,13 @@ gimple_init_edge_profiler (void)
tree average_profiler_fn_type;
tree time_profiler_fn_type;
const char *profiler_fn_name;
+ const char *fn_name;
if (!gcov_type_node)
{
+ const char *fn_suffix
+ = flag_profile_update == PROFILE_UPDATE_ATOMIC ? "_atomic" : "";
+
gcov_type_node = get_gcov_type ();
gcov_type_ptr = build_pointer_type (gcov_type_node);
@@ -140,9 +144,10 @@ gimple_init_edge_profiler (void)
gcov_type_ptr, gcov_type_node,
integer_type_node,
unsigned_type_node, NULL_TREE);
- tree_interval_profiler_fn
- = build_fn_decl ("__gcov_interval_profiler",
- interval_profiler_fn_type);
+ fn_name = concat ("__gcov_interval_profiler", fn_suffix, NULL);
+ tree_interval_profiler_fn = build_fn_decl (fn_name,
+ interval_profiler_fn_type);
+ free (CONST_CAST (char *, fn_name));
TREE_NOTHROW (tree_interval_profiler_fn) = 1;
DECL_ATTRIBUTES (tree_interval_profiler_fn)
= tree_cons (get_identifier ("leaf"), NULL,
@@ -153,8 +158,9 @@ gimple_init_edge_profiler (void)
= build_function_type_list (void_type_node,
gcov_type_ptr, gcov_type_node,
NULL_TREE);
- tree_pow2_profiler_fn = build_fn_decl ("__gcov_pow2_profiler",
- pow2_profiler_fn_type);
+ fn_name = concat ("__gcov_pow2_profiler", fn_suffix, NULL);
+ 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;
DECL_ATTRIBUTES (tree_pow2_profiler_fn)
= tree_cons (get_identifier ("leaf"), NULL,
@@ -165,9 +171,10 @@ gimple_init_edge_profiler (void)
= build_function_type_list (void_type_node,
gcov_type_ptr, gcov_type_node,
NULL_TREE);
- tree_one_value_profiler_fn
- = build_fn_decl ("__gcov_one_value_profiler",
- one_value_profiler_fn_type);
+ fn_name = concat ("__gcov_one_value_profiler", fn_suffix, NULL);
+ tree_one_value_profiler_fn = build_fn_decl (fn_name,
+ one_value_profiler_fn_type);
+ free (CONST_CAST (char *, fn_name));
TREE_NOTHROW (tree_one_value_profiler_fn) = 1;
DECL_ATTRIBUTES (tree_one_value_profiler_fn)
= tree_cons (get_identifier ("leaf"), NULL,
@@ -197,9 +204,9 @@ gimple_init_edge_profiler (void)
time_profiler_fn_type
= build_function_type_list (void_type_node,
gcov_type_ptr, NULL_TREE);
- tree_time_profiler_fn
- = build_fn_decl ("__gcov_time_profiler",
- time_profiler_fn_type);
+ fn_name = concat ("__gcov_time_profiler", fn_suffix, NULL);
+ tree_time_profiler_fn = build_fn_decl (fn_name, time_profiler_fn_type);
+ free (CONST_CAST (char *, fn_name));
TREE_NOTHROW (tree_time_profiler_fn) = 1;
DECL_ATTRIBUTES (tree_time_profiler_fn)
= tree_cons (get_identifier ("leaf"), NULL,
@@ -209,16 +216,17 @@ gimple_init_edge_profiler (void)
average_profiler_fn_type
= build_function_type_list (void_type_node,
gcov_type_ptr, gcov_type_node, NULL_TREE);
- tree_average_profiler_fn
- = build_fn_decl ("__gcov_average_profiler",
- average_profiler_fn_type);
+ fn_name = concat ("__gcov_average_profiler", fn_suffix, NULL);
+ tree_average_profiler_fn = build_fn_decl (fn_name,
+ average_profiler_fn_type);
+ free (CONST_CAST (char *, fn_name));
TREE_NOTHROW (tree_average_profiler_fn) = 1;
DECL_ATTRIBUTES (tree_average_profiler_fn)
= tree_cons (get_identifier ("leaf"), NULL,
DECL_ATTRIBUTES (tree_average_profiler_fn));
- tree_ior_profiler_fn
- = build_fn_decl ("__gcov_ior_profiler",
- average_profiler_fn_type);
+ fn_name = concat ("__gcov_ior_profiler", fn_suffix, NULL);
+ tree_ior_profiler_fn = build_fn_decl (fn_name, average_profiler_fn_type);
+ free (CONST_CAST (char *, fn_name));
TREE_NOTHROW (tree_ior_profiler_fn) = 1;
DECL_ATTRIBUTES (tree_ior_profiler_fn)
= tree_cons (get_identifier ("leaf"), NULL,
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index 866d14a17a3..49186faa70f 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -1,3 +1,19 @@
+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>
* libgcov-util.c: Fix typo and GNU coding style.
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
index efaf7f7bf1a..ba37c657baf 100644
--- a/libgcc/Makefile.in
+++ b/libgcc/Makefile.in
@@ -858,10 +858,18 @@ include $(iterator)
LIBGCOV_MERGE = _gcov_merge_add _gcov_merge_single _gcov_merge_delta \
_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_average_profiler _gcov_ior_profiler \
- _gcov_indirect_call_profiler_v2 _gcov_time_profiler \
+ _gcov_one_value_profiler_atomic \
+ _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
LIBGCOV_INTERFACE = _gcov_dump _gcov_flush _gcov_fork \
_gcov_execl _gcov_execlp \
diff --git a/libgcc/libgcov-profiler.c b/libgcc/libgcov-profiler.c
index a99d93bb412..70a821dc625 100644
--- a/libgcc/libgcov-profiler.c
+++ b/libgcc/libgcov-profiler.c
@@ -46,6 +46,26 @@ __gcov_interval_profiler (gcov_type *counters, gcov_type value,
}
#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
/* If VALUE is a power of two, COUNTERS[1] is incremented. Otherwise
COUNTERS[0] is incremented. */
@@ -60,6 +80,21 @@ __gcov_pow2_profiler (gcov_type *counters, gcov_type value)
}
#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
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 +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
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 +119,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, MEMMODEL_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
+
+#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
@@ -265,7 +324,7 @@ __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
@@ -282,8 +341,19 @@ __gcov_time_profiler (gcov_type* counters)
if (!counters[0])
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
+
#ifdef L_gcov_average_profiler
/* Increase corresponding COUNTER by VALUE. FIXME: Perhaps we want
to saturate up. */
@@ -296,6 +366,18 @@ __gcov_average_profiler (gcov_type *counters, gcov_type value)
}
#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
/* Bitwise-OR VALUE into COUNTER. */
@@ -306,4 +388,15 @@ __gcov_ior_profiler (gcov_type *counters, gcov_type value)
}
#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 */
diff --git a/libgcc/libgcov.h b/libgcc/libgcov.h
index 80f13e26777..25147de2be7 100644
--- a/libgcc/libgcov.h
+++ b/libgcc/libgcov.h
@@ -268,12 +268,19 @@ extern void __gcov_merge_icall_topn (gcov_type *, unsigned) ATTRIBUTE_HIDDEN;
/* The profiler functions. */
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_atomic (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_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_atomic (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_sort_n_vals (gcov_type *, int);