Cherry-pick fprofile-generate-atomic from google/gcc-4_9
authorMartin Liska <mliska@suse.cz>
Wed, 10 Aug 2016 13:11:42 +0000 (15:11 +0200)
committerMartin Liska <marxin@gcc.gnu.org>
Wed, 10 Aug 2016 13:11:42 +0000 (13:11 +0000)
Cherry picked (and modified) from google-4_7 branch
2012-12-26  Rong Xu  <xur@google.com>
* 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.
* g++.dg/gcov/gcov-threads-1.C: New test.

From-SVN: r239323

gcc/ChangeLog
gcc/common.opt
gcc/coretypes.h
gcc/doc/invoke.texi
gcc/gcov-io.h
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/gcov/gcov-threads-1.C [new file with mode: 0644]
gcc/tree-profile.c

index cc23c1559b69e909c73a0ce01223c059829caac9..cdf8b7740bd498c2352acbcddc683b5bd29603c3 100644 (file)
@@ -1,3 +1,16 @@
+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.
+       * 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.
+
 2016-08-10  David Malcolm  <dmalcolm@redhat.com>
 
        * toplev.c (finalize): Set aux_info_file, asm_out_file, and
index 8a292ed78c8c6f1b0c18d84b388ceb8d181a0c1a..44adae89a23ec0f91c5fa638b19efe4300c40688 100644 (file)
@@ -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.
index b3a91a6d5c5c2c1e62a4f65497461150cdf1bc7c..fe1e984311cdad337d62b249924011a94ab80771 100644 (file)
@@ -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
index 22001f9a6a5ceb93c24df19380f435de99c8a057..1cfaae73a989cb7c161a8132349c92049e5ce74f 100644 (file)
@@ -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.
index bbf013aa21ad7455aefc4869ab5b79c75265b778..afd00acb866ee6efea6568d2e586da3f5de2dcf8 100644 (file)
@@ -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 */
 
index c9a4eedfb2643df54261e46eb0af3c312d3a69b9..20bd72a0dbc0c13e0df56f5ba413abd440f1677d 100644 (file)
@@ -1,3 +1,7 @@
+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>
 
        PR target/71873
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 (file)
index 0000000..a4a6f0a
--- /dev/null
@@ -0,0 +1,46 @@
+/* { dg-options "-fprofile-arcs -ftest-coverage -pthread -fprofile-update=atomic" } */
+/* { dg-do run { target native } } */
+
+#include <stdint.h>
+#include <pthread.h>
+#include <assert.h>
+
+#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 } } */
index 39fe15fae9bba12d5d9bbe251ef4f5a8fe20adbd..740f7ab7d5a56d06c195dfe93cba81ae0ebb3955 100644 (file)
@@ -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