From 0b3ac8636ef34b02e301f22c86dde0602f9969ef Mon Sep 17 00:00:00 2001 From: marxin Date: Thu, 28 Jul 2016 14:32:47 +0200 Subject: [PATCH 1/4] Cherry-pick fprofile-generate-atomic from google/gcc-4_9 branch gcc/ChangeLog: 2016-08-05 Martin Liska Cherry picked (and modified) from google-4_7 branch 2012-12-26 Rong Xu * common.opt (fprofile-update): Add new flag. * coretypes.h: Define enum profile_update. * doc/invoke.texi: Document -fprofile-update. * gcov-io.h: Declare GCOV_TYPE_ATOMIC_FETCH_ADD and GCOV_TYPE_ATOMIC_FETCH_ADD_FN. * tree-profile.c (gimple_init_edge_profiler): Generate also atomic profiler update. (gimple_gen_edge_profiler): Likewise. gcc/testsuite/ChangeLog: 2016-08-05 Martin Liska * g++.dg/gcov/gcov-threads-1.C: New test. --- gcc/common.opt | 13 ++++++++ gcc/coretypes.h | 6 ++++ gcc/doc/invoke.texi | 12 +++++++ gcc/gcov-io.h | 8 +++++ gcc/testsuite/g++.dg/gcov/gcov-threads-1.C | 46 ++++++++++++++++++++++++++ gcc/tree-profile.c | 53 ++++++++++++++++++++---------- 6 files changed, 120 insertions(+), 18 deletions(-) create mode 100644 gcc/testsuite/g++.dg/gcov/gcov-threads-1.C diff --git a/gcc/common.opt b/gcc/common.opt index 8a292ed..44adae8 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -1916,6 +1916,19 @@ fprofile-correction Common Report Var(flag_profile_correction) Enable correction of flow inconsistent profile data input. +fprofile-update= +Common Joined RejectNegative Enum(profile_update) Var(flag_profile_update) Init(PROFILE_UPDATE_SINGLE) +-fprofile-update=[single|atomic] Set the profile update method. + +Enum +Name(profile_update) Type(enum profile_update) UnknownError(unknown profile update method %qs) + +EnumValue +Enum(profile_update) String(single) Value(PROFILE_UPDATE_SINGLE) + +EnumValue +Enum(profile_update) String(atomic) Value(PROFILE_UPDATE_ATOMIC) + fprofile-generate Common Enable common options for generating profile info for profile feedback directed optimizations. diff --git a/gcc/coretypes.h b/gcc/coretypes.h index b3a91a6..fe1e984 100644 --- a/gcc/coretypes.h +++ b/gcc/coretypes.h @@ -174,6 +174,12 @@ enum offload_abi { OFFLOAD_ABI_ILP32 }; +/* Types of profile update methods. */ +enum profile_update { + PROFILE_UPDATE_SINGLE, + PROFILE_UPDATE_ATOMIC +}; + /* Types of unwind/exception handling info that can be generated. */ enum unwind_info_type diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 22001f9..1cfaae7 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -9933,6 +9933,18 @@ the profile feedback data files. See @option{-fprofile-dir}. To optimize the program based on the collected profile information, use @option{-fprofile-use}. @xref{Optimize Options}, for more information. +@item -fprofile-update=@var{method} +@opindex fprofile-update + +Alter the update method for an application instrumented for profile +feedback based optimization. The @var{method} argument should be one of +@samp{single} or @samp{atomic}. The first one is useful for single-threaded +applications, while the second one prevents profile corruption by emitting +thread-safe code. + +@strong{Warning:} When an application does not properly join all threads +(or creates an detached thread), a profile file can be still corrupted. + @item -fsanitize=address @opindex fsanitize=address Enable AddressSanitizer, a fast memory error detector. diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h index bbf013a..afd00ac 100644 --- a/gcc/gcov-io.h +++ b/gcc/gcov-io.h @@ -164,6 +164,14 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #ifndef GCC_GCOV_IO_H #define GCC_GCOV_IO_H +#if LONG_LONG_TYPE_SIZE > 32 +#define GCOV_TYPE_ATOMIC_FETCH_ADD_FN __atomic_fetch_add_8 +#define GCOV_TYPE_ATOMIC_FETCH_ADD BUILT_IN_ATOMIC_FETCH_ADD_8 +#else +#define GCOV_TYPE_ATOMIC_FETCH_ADD_FN __atomic_fetch_add_4 +#define GCOV_TYPE_ATOMIC_FETCH_ADD BUILT_IN_ATOMIC_FETCH_ADD_4 +#endif + #ifndef IN_LIBGCOV /* About the host */ diff --git a/gcc/testsuite/g++.dg/gcov/gcov-threads-1.C b/gcc/testsuite/g++.dg/gcov/gcov-threads-1.C new file mode 100644 index 0000000..a4a6f0a --- /dev/null +++ b/gcc/testsuite/g++.dg/gcov/gcov-threads-1.C @@ -0,0 +1,46 @@ +/* { dg-options "-fprofile-arcs -ftest-coverage -pthread -fprofile-update=atomic" } */ +/* { dg-do run { target native } } */ + +#include +#include +#include + +#define NR 5 + +pthread_mutex_t cndMs[NR]; +static void *ContentionNoDeadlock_thread(void *start) +{ + for (uint32_t k = 0; k < 100000; ++k) /* count(500005) */ + { + int starti = *(int*)start; /* count(500000) */ + for (uint32_t i = starti; i < NR; ++i) + pthread_mutex_lock (&cndMs[i]); + for (int32_t i = NR - 1; i >= starti; --i) + pthread_mutex_unlock (&cndMs[i]); + } +} +int main(int argc, char **argv) { + for (unsigned i = 0; i < NR; i++) + cndMs[i] = PTHREAD_MUTEX_INITIALIZER; + + pthread_t t[NR]; + int ids[NR]; + + for (int i = 0; i < NR; i++) + { + ids[i] = i; + int r = pthread_create (&t[i], NULL, ContentionNoDeadlock_thread, &ids[i]); + assert (r == 0); /* count(5) */ + } + + int ret; + for (int i = 0; i < NR; i++) + { + int r = pthread_join (t[i], (void**)&ret); + assert (r == 0); /* count(5) */ + } + + return 0; /* count(1) */ +} + +/* { dg-final { run-gcov gcov-threads-1.C } } */ diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c index 39fe15f..740f7ab 100644 --- a/gcc/tree-profile.c +++ b/gcc/tree-profile.c @@ -127,6 +127,7 @@ gimple_init_edge_profiler (void) tree ic_profiler_fn_type; tree average_profiler_fn_type; tree time_profiler_fn_type; + const char *profiler_fn_name; if (!gcov_type_node) { @@ -180,11 +181,12 @@ gimple_init_edge_profiler (void) gcov_type_node, ptr_void, NULL_TREE); + profiler_fn_name = "__gcov_indirect_call_profiler_v2"; + if (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE)) + profiler_fn_name = "__gcov_indirect_call_topn_profiler"; + tree_indirect_call_profiler_fn - = build_fn_decl ( (PARAM_VALUE (PARAM_INDIR_CALL_TOPN_PROFILE) ? - "__gcov_indirect_call_topn_profiler": - "__gcov_indirect_call_profiler_v2"), - ic_profiler_fn_type); + = build_fn_decl (profiler_fn_name, ic_profiler_fn_type); TREE_NOTHROW (tree_indirect_call_profiler_fn) = 1; DECL_ATTRIBUTES (tree_indirect_call_profiler_fn) @@ -241,22 +243,37 @@ gimple_init_edge_profiler (void) void gimple_gen_edge_profiler (int edgeno, edge e) { - tree ref, one, gcov_type_tmp_var; - gassign *stmt1, *stmt2, *stmt3; + tree one; - ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); one = build_int_cst (gcov_type_node, 1); - gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node, - NULL, "PROF_edge_counter"); - stmt1 = gimple_build_assign (gcov_type_tmp_var, ref); - gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node, - NULL, "PROF_edge_counter"); - stmt2 = gimple_build_assign (gcov_type_tmp_var, PLUS_EXPR, - gimple_assign_lhs (stmt1), one); - stmt3 = gimple_build_assign (unshare_expr (ref), gimple_assign_lhs (stmt2)); - gsi_insert_on_edge (e, stmt1); - gsi_insert_on_edge (e, stmt2); - gsi_insert_on_edge (e, stmt3); + + if (flag_profile_update == PROFILE_UPDATE_ATOMIC) + { + /* __atomic_fetch_add (&counter, 1, MEMMODEL_RELAXED); */ + tree addr = tree_coverage_counter_addr (GCOV_COUNTER_ARCS, edgeno); + gcall *stmt + = gimple_build_call (builtin_decl_explicit (GCOV_TYPE_ATOMIC_FETCH_ADD), + 3, addr, one, + build_int_cst (integer_type_node, + MEMMODEL_RELAXED)); + gsi_insert_on_edge (e, stmt); + } + else + { + tree ref = tree_coverage_counter_ref (GCOV_COUNTER_ARCS, edgeno); + tree gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node, + NULL, "PROF_edge_counter"); + gassign *stmt1 = gimple_build_assign (gcov_type_tmp_var, ref); + gcov_type_tmp_var = make_temp_ssa_name (gcov_type_node, + NULL, "PROF_edge_counter"); + gassign *stmt2 = gimple_build_assign (gcov_type_tmp_var, PLUS_EXPR, + gimple_assign_lhs (stmt1), one); + gassign *stmt3 = gimple_build_assign (unshare_expr (ref), + gimple_assign_lhs (stmt2)); + gsi_insert_on_edge (e, stmt1); + gsi_insert_on_edge (e, stmt2); + gsi_insert_on_edge (e, stmt3); + } } /* Emits code to get VALUE to instrument at GSI, and returns the -- 2.9.2