gcov: Improve -fprofile-update=atomic
commit20a3c74c347429c109bc7002285b735be83f6a0b
authorSebastian Huber <sebastian.huber@embedded-brains.de>
Tue, 14 Nov 2023 20:36:51 +0000 (14 21:36 +0100)
committerSebastian Huber <sebastian.huber@embedded-brains.de>
Sat, 18 Nov 2023 11:45:15 +0000 (18 12:45 +0100)
tree73ccca0643ffc4957012fb20838ded2a9516eb7c
parenta350a74d6113e3a84943266eb691275951c109d9
gcov: Improve -fprofile-update=atomic

The code coverage support uses counters to determine which edges in the control
flow graph were executed.  If a counter overflows, then the code coverage
information is invalid.  Therefore the counter type should be a 64-bit integer.
In multi-threaded applications, it is important that the counter increments are
atomic.  This is not the case by default.  The user can enable atomic counter
increments through the -fprofile-update=atomic and
-fprofile-update=prefer-atomic options.

If the target supports 64-bit atomic operations, then everything is fine.  If
not and -fprofile-update=prefer-atomic was chosen by the user, then non-atomic
counter increments will be used.  However, if the target does not support the
required atomic operations and -fprofile-atomic=update was chosen by the user,
then a warning was issued and as a forced fallback to non-atomic operations was
done.  This is probably not what a user wants.  There is still hardware on the
market which does not have atomic operations and is used for multi-threaded
applications.  A user which selects -fprofile-update=atomic wants consistent
code coverage data and not random data.

This patch removes the fallback to non-atomic operations for
-fprofile-update=atomic the target platform supports libatomic.  To
mitigate potential performance issues an optimization for systems which
only support 32-bit atomic operations is provided.  Here, the edge
counter increments are done like this:

  low = __atomic_add_fetch_4 (&counter.low, 1, MEMMODEL_RELAXED);
  high_inc = low == 0 ? 1 : 0;
  __atomic_add_fetch_4 (&counter.high, high_inc, MEMMODEL_RELAXED);

In gimple_gen_time_profiler() this split operation cannot be used, since the
updated counter value is also required.  Here, a library call is emitted.  This
is not a performance issue since the update is only done if counters[0] == 0.

gcc/c-family/ChangeLog:

* c-cppbuiltin.cc (c_cpp_builtins):  Define
__LIBGCC_HAVE_LIBATOMIC for libgcov.

gcc/ChangeLog:

* doc/invoke.texi (-fprofile-update): Clarify default method.  Document
the atomic method behaviour.
* tree-profile.cc (enum counter_update_method): New.
(counter_update): Likewise.
(gen_counter_update): Use counter_update_method.  Split the
atomic counter update in two 32-bit atomic operations if
necessary.
(tree_profiling): Select counter_update_method.

libgcc/ChangeLog:

* libgcov.h (GCOV_SUPPORTS_ATOMIC): Always define it.
Set it also to 1, if __LIBGCC_HAVE_LIBATOMIC is defined.
gcc/c-family/c-cppbuiltin.cc
gcc/doc/invoke.texi
gcc/tree-profile.cc
libgcc/libgcov.h