Skip to content

Commit

Permalink
[Remarks][2/2] Expand remarks hotness threshold option support in mor…
Browse files Browse the repository at this point in the history
…e tools

This is the #2 of 2 changes that make remarks hotness threshold option
available in more tools. The changes also allow the threshold to sync with
hotness threshold from profile summary with special value 'auto'.

This change expands remarks hotness threshold option
-fdiagnostics-hotness-threshold in clang and *-remarks-hotness-threshold in
other tools to utilize hotness threshold from profile summary.

Remarks hotness filtering relies on several driver options. Table below lists
how different options are correlated and affect final remarks outputs:

| profile | hotness | threshold | remarks printed |
|---------|---------|-----------|-----------------|
| No      | No      | No        | All             |
| No      | No      | Yes       | None            |
| No      | Yes     | No        | All             |
| No      | Yes     | Yes       | None            |
| Yes     | No      | No        | All             |
| Yes     | No      | Yes       | None            |
| Yes     | Yes     | No        | All             |
| Yes     | Yes     | Yes       | >=threshold     |

In the presence of profile summary, it is often more desirable to directly use
the hotness threshold from profile summary. The new argument value 'auto'
indicates threshold will be synced with hotness threshold from profile summary
during compilation. The "auto" threshold relies on the availability of profile
summary. In case of missing such information, no remarks will be generated.

Differential Revision: https://reviews.llvm.org/D85808
  • Loading branch information
apolloww committed Dec 1, 2020
1 parent 3acda91 commit 93dc1b5
Show file tree
Hide file tree
Showing 18 changed files with 313 additions and 23 deletions.
4 changes: 0 additions & 4 deletions clang/include/clang/Basic/CodeGenOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -366,10 +366,6 @@ VALUE_CODEGENOPT(EmitCheckPathComponentsToStrip, 32, 0)
/// Whether to report the hotness of the code region for optimization remarks.
CODEGENOPT(DiagnosticsWithHotness, 1, 0)

/// The minimum hotness value a diagnostic needs in order to be included in
/// optimization diagnostics.
VALUE_CODEGENOPT(DiagnosticsHotnessThreshold, 32, 0)

/// Whether copy relocations support is available when building as PIE.
CODEGENOPT(PIECopyRelocations, 1, 0)

Expand Down
15 changes: 15 additions & 0 deletions clang/include/clang/Basic/CodeGenOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,21 @@ class CodeGenOptions : public CodeGenOptionsBase {
const char *Argv0 = nullptr;
ArrayRef<const char *> CommandLineArgs;

/// The minimum hotness value a diagnostic needs in order to be included in
/// optimization diagnostics.
///
/// The threshold is an Optional value, which maps to one of the 3 states:
/// 1. 0 => threshold disabled. All remarks will be printed.
/// 2. positive int => manual threshold by user. Remarks with hotness exceed
/// threshold will be printed.
/// 3. None => 'auto' threshold by user. The actual value is not
/// available at command line, but will be synced with
/// hotness threshold from profile summary during
/// compilation.
///
/// If threshold option is not specified, it is disabled by default.
Optional<uint64_t> DiagnosticsHotnessThreshold = 0;

public:
// Define accessors/mutators for code generation options of enumeration type.
#define CODEGENOPT(Name, Bits, Default)
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,8 @@ def err_drv_command_failure : Error<
"unable to execute command: %0">;
def err_drv_invalid_darwin_version : Error<
"invalid Darwin version number: %0">;
def err_drv_invalid_diagnotics_hotness_threshold : Error<
"invalid argument in '%0', only integer or 'auto' is supported">;
def err_drv_missing_argument : Error<
"argument to '%0' is missing (expected %1 value%s1)">;
def err_drv_invalid_Xarch_argument_with_args : Error<
Expand Down
5 changes: 3 additions & 2 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -984,8 +984,9 @@ def fdiagnostics_print_source_range_info : Flag<["-"], "fdiagnostics-print-sourc
def fdiagnostics_show_hotness : Flag<["-"], "fdiagnostics-show-hotness">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Enable profile hotness information in diagnostic line">;
def fdiagnostics_hotness_threshold_EQ : Joined<["-"], "fdiagnostics-hotness-threshold=">,
Group<f_Group>, Flags<[CC1Option]>, MetaVarName<"<number>">,
HelpText<"Prevent optimization remarks from being output if they do not have at least this profile count">;
Group<f_Group>, Flags<[CC1Option]>, MetaVarName<"<value>">,
HelpText<"Prevent optimization remarks from being output if they do not have at least this profile count. "
"Use 'auto' to apply the threshold from profile summary">;
def fdiagnostics_show_option : Flag<["-"], "fdiagnostics-show-option">, Group<f_Group>,
HelpText<"Print option name with mappable diagnostics">;
def fdiagnostics_show_note_include_stack : Flag<["-"], "fdiagnostics-show-note-include-stack">,
Expand Down
25 changes: 20 additions & 5 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "clang/Basic/CommentOptions.h"
#include "clang/Basic/DebugInfoOptions.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticDriver.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/FileSystemOptions.h"
#include "clang/Basic/LLVM.h"
Expand Down Expand Up @@ -66,6 +67,7 @@
#include "llvm/Option/OptTable.h"
#include "llvm/Option/Option.h"
#include "llvm/ProfileData/InstrProfReader.h"
#include "llvm/Remarks/HotnessThresholdParser.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Error.h"
Expand Down Expand Up @@ -1501,11 +1503,24 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
<< "-fdiagnostics-show-hotness";

Opts.DiagnosticsHotnessThreshold = getLastArgUInt64Value(
Args, options::OPT_fdiagnostics_hotness_threshold_EQ, 0);
if (Opts.DiagnosticsHotnessThreshold > 0 && !UsingProfile)
Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
<< "-fdiagnostics-hotness-threshold=";
// Parse remarks hotness threshold. Valid value is either integer or 'auto'.
if (auto *arg =
Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) {
auto ResultOrErr =
llvm::remarks::parseHotnessThresholdOption(arg->getValue());

if (!ResultOrErr) {
Diags.Report(diag::err_drv_invalid_diagnotics_hotness_threshold)
<< "-fdiagnostics-hotness-threshold=";
} else {
Opts.DiagnosticsHotnessThreshold = *ResultOrErr;
if ((!Opts.DiagnosticsHotnessThreshold.hasValue() ||
Opts.DiagnosticsHotnessThreshold.getValue() > 0) &&
!UsingProfile)
Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo)
<< "-fdiagnostics-hotness-threshold=";
}
}

// If the user requested to use a sample profile for PGO, then the
// backend will need to track source location information so the profile
Expand Down
3 changes: 3 additions & 0 deletions clang/test/Driver/opt-record.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
// RUN: %clang -target x86_64-linux -### -o FOO -fuse-ld=gold -flto -fdiagnostics-hotness-threshold=100 -fsave-optimization-record -foptimization-record-passes=inline %s 2>&1 | FileCheck %s -check-prefix=CHECK-PASS
// RUN: %clang -target x86_64-linux -### -o FOO -fuse-ld=lld -flto=thin -fdiagnostics-hotness-threshold=100 -fsave-optimization-record=some-format -foptimization-record-file=FOO.txt %s 2>&1 | FileCheck %s -check-prefix=CHECK-PASS-CUSTOM
// RUN: %clang -target x86_64-linux -### -o FOO -fuse-ld=lld -flto=thin -fdiagnostics-hotness-threshold=100 -Rpass=inline -Rpass-missed=inline -Rpass-analysis=inline %s 2>&1 | FileCheck %s -check-prefix=CHECK-PASS-RPASS
// RUN: %clang -target x86_64-linux -### -o FOO -fuse-ld=lld -flto=thin -fdiagnostics-hotness-threshold=auto -Rpass=inline -Rpass-missed=inline -Rpass-analysis=inline %s 2>&1 | FileCheck %s -check-prefix=CHECK-PASS-AUTO

// CHECK-NOPASS-NOT: "--plugin-opt=opt-remarks-filename="
// CHECK-NOPASS-NOT: "--plugin-opt=opt-remarks-passes=inline"
Expand All @@ -75,3 +76,5 @@
// CHECK-PASS-RPASS-SAME: "--plugin-opt=-pass-remarks-missed=inline"
// CHECK-PASS-RPASS-SAME: "--plugin-opt=-pass-remarks-analysis=inline"
// CHECK-PASS-RPASS-SAME: "--plugin-opt=opt-remarks-hotness-threshold=100"

// CHECK-PASS-AUTO: "--plugin-opt=opt-remarks-hotness-threshold=auto"
8 changes: 8 additions & 0 deletions clang/test/Frontend/Inputs/remarks-hotness.prof
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
_Z7callee1v:600:600
1: 600
_Z7callee2v:1:1
1: 1
_Z7caller1v:400:400
1: 400
_Z7caller2v:1:1
1: 1
34 changes: 34 additions & 0 deletions clang/test/Frontend/remarks-hotness.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Without hotness threshold, print both hot and cold remarks.
// RUN: %clang_cc1 -triple x86_64-linux %s -emit-llvm-only -O3 \
// RUN: -fprofile-sample-use=%S/Inputs/remarks-hotness.prof \
// RUN: -Rpass=inline -Rpass-analysis=inline -Rpass-missed=inline \
// RUN: -fexperimental-new-pass-manager -fdiagnostics-show-hotness 2>&1 \
// RUN: | FileCheck -check-prefix=REMARKS %s

// With auto hotness threshold, only print hot remarks.
// RUN: %clang_cc1 -triple x86_64-linux %s -emit-llvm-only -O3 \
// RUN: -fprofile-sample-use=%S/Inputs/remarks-hotness.prof \
// RUN: -Rpass=inline -Rpass-analysis=inline -Rpass-missed=inline \
// RUN: -fexperimental-new-pass-manager -fdiagnostics-show-hotness \
// RUN: -fdiagnostics-hotness-threshold=auto 2>&1 \
// RUN: | FileCheck -check-prefix=HOT_CALL %s

int callee1() {
return 1;
}

__attribute__((noinline)) int callee2() {
return 2;
}

// REMARKS: _Z7callee1v inlined into _Z7caller1v
// HOT_CALL: _Z7callee1v inlined into _Z7caller1v
int caller1() {
return callee1();
}

// REMARKS: _Z7callee2v not inlined into _Z7caller2v
// HOT_CALL-NOT: _Z7callee2v not inlined into _Z7caller2v
int caller2() {
return callee2();
}
5 changes: 3 additions & 2 deletions llvm/include/llvm/Analysis/ProfileSummaryInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class Function;
// units. This would require making this depend on BFI.
class ProfileSummaryInfo {
private:
Module &M;
const Module &M;
std::unique_ptr<ProfileSummary> Summary;
void computeThresholds();
// Count thresholds to answer isHotCount and isColdCount queries.
Expand All @@ -58,7 +58,8 @@ class ProfileSummaryInfo {
mutable DenseMap<int, uint64_t> ThresholdCache;

public:
ProfileSummaryInfo(Module &M) : M(M) { refresh(); }
ProfileSummaryInfo(const Module &M) : M(M) { refresh(); }

ProfileSummaryInfo(ProfileSummaryInfo &&Arg) = default;

/// If no summary is present, attempt to refresh.
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/LLVMContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,9 @@ class LLVMContext {
/// included in optimization diagnostics.
void setDiagnosticsHotnessThreshold(Optional<uint64_t> Threshold);

/// Return if hotness threshold is requested from PSI.
bool isDiagnosticsHotnessThresholdSetFromPSI() const;

/// The "main remark streamer" used by all the specialized remark streamers.
/// This streamer keeps generic remark metadata in memory throughout the life
/// of the LLVMContext. This metadata may be emitted in a section in object
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/IR/Module.h
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,7 @@ class Module {

/// Returns profile summary metadata. When IsCS is true, use the context
/// sensitive profile summary.
Metadata *getProfileSummary(bool IsCS);
Metadata *getProfileSummary(bool IsCS) const;
/// @}

/// Returns whether semantic interposition is to be respected.
Expand Down
28 changes: 24 additions & 4 deletions llvm/lib/Analysis/OptimizationRemarkEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/Analysis/LazyBlockFrequencyInfo.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/LLVMContext.h"
Expand Down Expand Up @@ -96,9 +97,17 @@ OptimizationRemarkEmitterWrapperPass::OptimizationRemarkEmitterWrapperPass()
bool OptimizationRemarkEmitterWrapperPass::runOnFunction(Function &Fn) {
BlockFrequencyInfo *BFI;

if (Fn.getContext().getDiagnosticsHotnessRequested())
auto &Context = Fn.getContext();
if (Context.getDiagnosticsHotnessRequested()) {
BFI = &getAnalysis<LazyBlockFrequencyInfoPass>().getBFI();
else
// Get hotness threshold from PSI. This should only happen once.
if (Context.isDiagnosticsHotnessThresholdSetFromPSI()) {
if (ProfileSummaryInfo *PSI =
&getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI())
Context.setDiagnosticsHotnessThreshold(
PSI->getOrCompHotCountThreshold());
}
} else
BFI = nullptr;

ORE = std::make_unique<OptimizationRemarkEmitter>(&Fn, BFI);
Expand All @@ -108,6 +117,7 @@ bool OptimizationRemarkEmitterWrapperPass::runOnFunction(Function &Fn) {
void OptimizationRemarkEmitterWrapperPass::getAnalysisUsage(
AnalysisUsage &AU) const {
LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU);
AU.addRequired<ProfileSummaryInfoWrapperPass>();
AU.setPreservesAll();
}

Expand All @@ -117,10 +127,19 @@ OptimizationRemarkEmitter
OptimizationRemarkEmitterAnalysis::run(Function &F,
FunctionAnalysisManager &AM) {
BlockFrequencyInfo *BFI;
auto &Context = F.getContext();

if (F.getContext().getDiagnosticsHotnessRequested())
if (Context.getDiagnosticsHotnessRequested()) {
BFI = &AM.getResult<BlockFrequencyAnalysis>(F);
else
// Get hotness threshold from PSI. This should only happen once.
if (Context.isDiagnosticsHotnessThresholdSetFromPSI()) {
auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
if (ProfileSummaryInfo *PSI =
MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent()))
Context.setDiagnosticsHotnessThreshold(
PSI->getOrCompHotCountThreshold());
}
} else
BFI = nullptr;

return OptimizationRemarkEmitter(&F, BFI);
Expand All @@ -133,5 +152,6 @@ static const char ore_name[] = "Optimization Remark Emitter";
INITIALIZE_PASS_BEGIN(OptimizationRemarkEmitterWrapperPass, ORE_NAME, ore_name,
false, true)
INITIALIZE_PASS_DEPENDENCY(LazyBFIPass)
INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
INITIALIZE_PASS_END(OptimizationRemarkEmitterWrapperPass, ORE_NAME, ore_name,
false, true)
5 changes: 5 additions & 0 deletions llvm/lib/IR/LLVMContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,15 @@ bool LLVMContext::getDiagnosticsHotnessRequested() const {
void LLVMContext::setDiagnosticsHotnessThreshold(Optional<uint64_t> Threshold) {
pImpl->DiagnosticsHotnessThreshold = Threshold;
}

uint64_t LLVMContext::getDiagnosticsHotnessThreshold() const {
return pImpl->DiagnosticsHotnessThreshold.getValueOr(UINT64_MAX);
}

bool LLVMContext::isDiagnosticsHotnessThresholdSetFromPSI() const {
return !pImpl->DiagnosticsHotnessThreshold.hasValue();
}

remarks::RemarkStreamer *LLVMContext::getMainRemarkStreamer() {
return pImpl->MainRemarkStreamer.get();
}
Expand Down
6 changes: 2 additions & 4 deletions llvm/lib/IR/LLVMRemarkStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ Expected<std::unique_ptr<ToolOutputFile>> llvm::setupLLVMOptimizationRemarks(
if (RemarksWithHotness)
Context.setDiagnosticsHotnessRequested(true);

if (RemarksHotnessThreshold)
Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold);
Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold);

if (RemarksFilename.empty())
return nullptr;
Expand Down Expand Up @@ -144,8 +143,7 @@ Error llvm::setupLLVMOptimizationRemarks(
if (RemarksWithHotness)
Context.setDiagnosticsHotnessRequested(true);

if (RemarksHotnessThreshold)
Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold);
Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold);

Expected<remarks::Format> Format = remarks::parseFormat(RemarksFormat);
if (Error E = Format.takeError())
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/IR/Module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ void Module::setProfileSummary(Metadata *M, ProfileSummary::Kind Kind) {
setModuleFlag(ModFlagBehavior::Error, "ProfileSummary", M);
}

Metadata *Module::getProfileSummary(bool IsCS) {
Metadata *Module::getProfileSummary(bool IsCS) const {
return (IsCS ? getModuleFlag("CSProfileSummary")
: getModuleFlag("ProfileSummary"));
}
Expand Down
85 changes: 85 additions & 0 deletions llvm/test/Other/optimization-remarks-auto.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
;; This test verifies 'auto' hotness threshold when profile summary is available.
;;
;; new PM
; RUN: rm -f %t.yaml %t.hot.yaml
; RUN: opt < %s --disable-output --enable-new-pm \
; RUN: --passes='inline' \
; RUN: --pass-remarks-output=%t.yaml --pass-remarks-filter='inline' \
; RUN: --pass-remarks-with-hotness
; RUN: FileCheck %s -check-prefix=YAML-PASS < %t.yaml
; RUN: FileCheck %s -check-prefix=YAML-MISS < %t.yaml

;; test 'auto' threshold
; RUN: opt < %s --disable-output --enable-new-pm \
; RUN: --passes='module(print-profile-summary,cgscc(inline))' \
; RUN: --pass-remarks-output=%t.hot.yaml --pass-remarks-filter='inline' \
; RUN: --pass-remarks-with-hotness --pass-remarks-hotness-threshold=auto 2>&1 | FileCheck %s
; RUN: FileCheck %s -check-prefix=YAML-PASS < %t.hot.yaml
; RUN: not FileCheck %s -check-prefix=YAML-MISS < %t.hot.yaml

; RUN: opt < %s --disable-output --enable-new-pm \
; RUN: --passes='module(print-profile-summary,cgscc(inline))' \
; RUN: --pass-remarks=inline --pass-remarks-missed=inline --pass-remarks-analysis=inline \
; RUN: --pass-remarks-with-hotness --pass-remarks-hotness-threshold=auto 2>&1 | FileCheck %s -check-prefix=CHECK-RPASS

; YAML-PASS: --- !Passed
; YAML-PASS-NEXT: Pass: inline
; YAML-PASS-NEXT: Name: Inlined
; YAML-PASS-NEXT: Function: caller1
; YAML-PASS-NEXT: Hotness: 400

; YAML-MISS: --- !Missed
; YAML-MISS-NEXT: Pass: inline
; YAML-MISS-NEXT: Name: NeverInline
; YAML-MISS-NEXT: Function: caller2
; YAML-MISS-NEXT: Hotness: 1

; CHECK-RPASS: callee1 inlined into caller1 with (cost=-30, threshold=4500) (hotness: 400)
; CHECK-RPASS-NOT: callee2 not inlined into caller2 because it should never be inlined (cost=never): noinline function attribute (hotness: 1)

define void @callee1() !prof !20 {
; CHECK: callee1 :hot
entry:
ret void
}

; Function Attrs: noinline
define void @callee2() noinline !prof !21 {
; CHECK: callee2 :cold
entry:
ret void
}

define void @caller1() !prof !20 {
; CHECK: caller1 :hot
entry:
call void @callee1()
ret void
}

define void @caller2() !prof !21 {
; CHECK: caller2 :cold
entry:
call void @callee2()
ret void
}

!llvm.module.flags = !{!1}
!20 = !{!"function_entry_count", i64 400}
!21 = !{!"function_entry_count", i64 1}

!1 = !{i32 1, !"ProfileSummary", !2}
!2 = !{!3, !4, !5, !6, !7, !8, !9, !10}
!3 = !{!"ProfileFormat", !"InstrProf"}
!4 = !{!"TotalCount", i64 10000}
!5 = !{!"MaxCount", i64 10}
!6 = !{!"MaxInternalCount", i64 1}
!7 = !{!"MaxFunctionCount", i64 1000}
!8 = !{!"NumCounts", i64 3}
!9 = !{!"NumFunctions", i64 3}
!10 = !{!"DetailedSummary", !11}
!11 = !{!12, !13, !14}
!12 = !{i32 10000, i64 100, i32 1}
!13 = !{i32 999000, i64 100, i32 1}
!14 = !{i32 999999, i64 1, i32 2}

Loading

0 comments on commit 93dc1b5

Please sign in to comment.