Skip to content

Commit 3681be8

Browse files
committed
Add -fprofile-update={atomic,prefer-atomic,single}
GCC 7 introduced -fprofile-update={atomic,prefer-atomic} (prefer-atomic is for best efforts (some targets do not support atomics)) to increment counters atomically, which is exactly what we have done with -fprofile-instr-generate (D50867) and -fprofile-arcs (b5ef137). This patch adds the option to clang to surface the internal options at driver level. GCC 7 also turned on -fprofile-update=prefer-atomic when -pthread is specified, but it has performance regression (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89307). So we don't follow suit. Differential Revision: https://reviews.llvm.org/D87737
1 parent 5409e48 commit 3681be8

File tree

9 files changed

+50
-10
lines changed

9 files changed

+50
-10
lines changed

clang/docs/UsersManual.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2172,6 +2172,17 @@ programs using the same instrumentation method as ``-fprofile-generate``.
21722172
profile file, it reads from that file. If ``pathname`` is a directory name,
21732173
it reads from ``pathname/default.profdata``.
21742174

2175+
.. option:: -fprofile-update[=<method>]
2176+
2177+
Unless ``-fsanitize=thread`` is specified, the default is ``single``, which
2178+
uses non-atomic increments. The counters can be inaccurate under thread
2179+
contention. ``atomic`` uses atomic increments which is accurate but has
2180+
overhead. ``prefer-atomic`` will be transformed to ``atomic`` when supported
2181+
by the target, or ``single`` otherwise.
2182+
2183+
This option currently works with ``-fprofile-arcs`` and ``-fprofile-instr-generate``,
2184+
but not with ``-fprofile-generate``.
2185+
21752186
Disabling Instrumentation
21762187
^^^^^^^^^^^^^^^^^^^^^^^^^
21772188

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ CODEGENOPT(ObjCConvertMessagesToRuntimeCalls , 1, 1)
185185
VALUE_CODEGENOPT(OptimizationLevel, 2, 0) ///< The -O[0-3] option specified.
186186
VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified.
187187

188+
CODEGENOPT(AtomicProfileUpdate , 1, 0) ///< Set -fprofile-update=atomic
188189
/// Choose profile instrumenation kind or no instrumentation.
189190
ENUM_CODEGENOPT(ProfileInstr, ProfileInstrKind, 2, ProfileNone)
190191
/// Choose profile kind for PGO use compilation.

clang/include/clang/Driver/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,9 @@ def fprofile_filter_files_EQ : Joined<["-"], "fprofile-filter-files=">,
853853
def fprofile_exclude_files_EQ : Joined<["-"], "fprofile-exclude-files=">,
854854
Group<f_Group>, Flags<[CC1Option, CoreOption]>,
855855
HelpText<"Instrument only functions from files where names don't match all the regexes separated by a semi-colon">;
856+
def fprofile_update_EQ : Joined<["-"], "fprofile-update=">,
857+
Group<f_Group>, Flags<[CC1Option, CoreOption]>, Values<"atomic,prefer-atomic,single">,
858+
MetaVarName<"<method>">, HelpText<"Set update method of profile counters (atomic,prefer-atomic,single)">;
856859
def forder_file_instrumentation : Flag<["-"], "forder-file-instrumentation">,
857860
Group<f_Group>, Flags<[CC1Option, CoreOption]>,
858861
HelpText<"Generate instrumented code to collect order file into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;

clang/lib/CodeGen/BackendUtil.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ static Optional<GCOVOptions> getGCOVOptions(const CodeGenOptions &CodeGenOpts,
570570
Options.NoRedZone = CodeGenOpts.DisableRedZone;
571571
Options.Filter = CodeGenOpts.ProfileFilterFiles;
572572
Options.Exclude = CodeGenOpts.ProfileExcludeFiles;
573-
Options.Atomic = LangOpts.Sanitize.has(SanitizerKind::Thread);
573+
Options.Atomic = CodeGenOpts.AtomicProfileUpdate;
574574
return Options;
575575
}
576576

@@ -582,10 +582,7 @@ getInstrProfOptions(const CodeGenOptions &CodeGenOpts,
582582
InstrProfOptions Options;
583583
Options.NoRedZone = CodeGenOpts.DisableRedZone;
584584
Options.InstrProfileOutput = CodeGenOpts.InstrProfileOutput;
585-
586-
// TODO: Surface the option to emit atomic profile counter increments at
587-
// the driver level.
588-
Options.Atomic = LangOpts.Sanitize.has(SanitizerKind::Thread);
585+
Options.Atomic = CodeGenOpts.AtomicProfileUpdate;
589586
return Options;
590587
}
591588

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,17 @@ static void addPGOAndCoverageFlags(const ToolChain &TC, Compilation &C,
868868
CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-filter-files=" + v)));
869869
}
870870

871+
if (const auto *A = Args.getLastArg(options::OPT_fprofile_update_EQ)) {
872+
StringRef Val = A->getValue();
873+
if (Val == "atomic" || Val == "prefer-atomic")
874+
CmdArgs.push_back("-fprofile-update=atomic");
875+
else if (Val != "single")
876+
D.Diag(diag::err_drv_unsupported_option_argument)
877+
<< A->getOption().getName() << Val;
878+
} else if (TC.getSanitizerArgs().needsTsanRt()) {
879+
CmdArgs.push_back("-fprofile-update=atomic");
880+
}
881+
871882
// Leave -fprofile-dir= an unused argument unless .gcda emission is
872883
// enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider
873884
// the flag used. There is no -fno-profile-dir, so the user has no

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,7 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
884884
Opts.DebugRangesBaseAddress = Args.hasArg(OPT_fdebug_ranges_base_address);
885885

886886
setPGOInstrumentor(Opts, Args, Diags);
887+
Opts.AtomicProfileUpdate = Args.hasArg(OPT_fprofile_update_EQ);
887888
Opts.InstrProfileOutput =
888889
std::string(Args.getLastArgValue(OPT_fprofile_instrument_path_EQ));
889890
Opts.ProfileInstrumentUsePath =
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
/// -fsanitize=thread requires the (potentially concurrent) counter updates to be atomic.
2-
// RUN: %clang_cc1 %s -triple x86_64 -emit-llvm -fsanitize=thread -femit-coverage-notes -femit-coverage-data \
1+
/// -fprofile-update=atomic (implied by -fsanitize=thread) requires the
2+
/// (potentially concurrent) counter updates to be atomic.
3+
// RUN: %clang_cc1 %s -triple x86_64 -emit-llvm -fprofile-update=atomic -femit-coverage-notes -femit-coverage-data \
34
// RUN: -coverage-notes-file /dev/null -coverage-data-file /dev/null -o - | FileCheck %s
45

56
// CHECK-LABEL: void @foo()
67
/// Two counters are incremented by __tsan_atomic64_fetch_add.
7-
// CHECK: call i64 @__tsan_atomic64_fetch_add
8-
// CHECK-NEXT: call i32 @__tsan_atomic32_fetch_sub
8+
// CHECK: atomicrmw add i64* {{.*}} @__llvm_gcov_ctr
9+
// CHECK-NEXT: atomicrmw sub i32*
910

1011
_Atomic(int) cnt;
1112
void foo() { cnt--; }

clang/test/CodeGen/tsan-instrprof-atomic.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 %s -emit-llvm -fprofile-instrument=clang -fsanitize=thread -o - | FileCheck %s
1+
// RUN: %clang_cc1 %s -emit-llvm -fprofile-instrument=clang -fprofile-update=atomic -o - | FileCheck %s
22

33
// CHECK: define {{.*}}@foo
44
// CHECK-NOT: load {{.*}}foo

clang/test/Driver/fprofile-update.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// For -fprofile-instr-generate and -fprofile-arcs, increment counters atomically
2+
/// if -fprofile-update={atomic,prefer-atomic} or -fsanitize=thread is specified.
3+
// RUN: %clang -### %s -c -target x86_64-linux -fsanitize=thread %s 2>&1 | FileCheck %s
4+
// RUN: %clang -### %s -c -fprofile-update=atomic 2>&1 | FileCheck %s
5+
// RUN: %clang -### %s -c -fprofile-update=prefer-atomic 2>&1 | FileCheck %s
6+
7+
// CHECK: "-fprofile-update=atomic"
8+
9+
// RUN: %clang -### %s -c -fprofile-update=atomic -fprofile-update=single 2>&1 | FileCheck %s --check-prefix=SINGLE
10+
11+
// SINGLE-NOT: "-fprofile-update=atomic"
12+
13+
// RUN: not %clang %s -c -fprofile-update=unknown 2>&1 | FileCheck %s --check-prefix=ERROR
14+
15+
// ERROR: error: unsupported argument 'unknown' to option 'fprofile-update='

0 commit comments

Comments
 (0)