Add -fdiagnostics-show-hotness
authorAdam Nemet <anemet@apple.com>
Mon, 12 Sep 2016 23:48:16 +0000 (23:48 +0000)
committerAdam Nemet <anemet@apple.com>
Mon, 12 Sep 2016 23:48:16 +0000 (23:48 +0000)
Summary:
I've recently added the ability for optimization remarks to include the
hotness of the corresponding code region.  This uses PGO and allows
filtering of the optimization remarks by relevance.  The idea was first
discussed here:
http://thread.gmane.org/gmane.comp.compilers.llvm.devel/98334

The general goal is to produce a YAML file with the remarks.  Then, an
external tool could dynamically filter these by hotness and perhaps by
other things.

That said it makes sense to also expose this at the more basic level
where we just include the hotness info with each optimization remark.
For example, in D22694, the clang flag was pretty useful to measure the
overhead of the additional analyses required to include hotness.
(Without the flag we don't even run the analyses.)

For the record, Hal has already expressed support for the idea of this
patch on IRC.

Differential Revision: https://reviews.llvm.org/D23284

llvm-svn: 281276

clang/docs/UsersManual.rst
clang/include/clang/Basic/DiagnosticDriverKinds.td
clang/include/clang/Driver/Options.td
clang/include/clang/Frontend/CodeGenOptions.def
clang/lib/CodeGen/CodeGenAction.cpp
clang/lib/Driver/Tools.cpp
clang/lib/Frontend/CompilerInvocation.cpp
clang/test/Frontend/Inputs/optimization-remark-with-hotness.proftext [new file with mode: 0644]
clang/test/Frontend/optimization-remark-with-hotness.c [new file with mode: 0644]

index e9cc2d3..1f1dd4f 100644 (file)
@@ -317,6 +317,28 @@ output format of the diagnostics that it generates.
    by category, so it should be a high level category. We want dozens
    of these, not hundreds or thousands of them.
 
+.. _opt_fdiagnostics-show-hotness:
+
+**-f[no-]diagnostics-show-hotness**
+   Enable profile hotness information in diagnostic line.
+
+   This option, which defaults to off, controls whether Clang prints the
+   profile hotness associated with a diagnostics in the presence of
+   profile-guided optimization information.  This is currently supported with
+   optimization remarks (see :ref:`Options to Emit Optimization Reports
+   <rpass>`).  The hotness information allows users to focus on the hot
+   optimization remarks that are likely to be more relevant for run-time
+   performance.
+
+   For example, in this output, the block containing the callsite of `foo` was
+   executed 3000 times according to the profile data:
+
+   ::
+
+         s.c:7:10: remark: foo inlined into bar (hotness: 3000) [-Rpass-analysis=inline]
+           sum += foo(x, x - 2);
+                  ^
+
 .. _opt_fdiagnostics-fixit-info:
 
 **-f[no-]diagnostics-fixit-info**
@@ -535,6 +557,8 @@ control the crash diagnostics.
 The -fno-crash-diagnostics flag can be helpful for speeding the process
 of generating a delta reduced test case.
 
+.. _rpass:
+
 Options to Emit Optimization Reports
 ------------------------------------
 
@@ -578,6 +602,10 @@ outside of the major transformations (e.g., inlining, vectorization,
 loop optimizations) and not every optimization pass supports this
 feature.
 
+Note that when using profile-guided optimization information, profile hotness
+information can be included in the remarks (see
+:ref:`-fdiagnostics-show-hotness <opt_fdiagnostics-show-hotness>`).
+
 Current limitations
 ^^^^^^^^^^^^^^^^^^^
 
index 33d2af0..064919f 100644 (file)
@@ -189,6 +189,9 @@ def warn_drv_unused_argument : Warning<
 def warn_drv_empty_joined_argument : Warning<
   "joined argument expects additional value: '%0'">,
   InGroup<UnusedCommandLineArgument>;
+def warn_drv_fdiagnostics_show_hotness_requires_pgo : Warning<
+  "argument '-fdiagnostics-show-hotness' requires profile-guided optimization information">,
+  InGroup<UnusedCommandLineArgument>;
 def warn_drv_clang_unsupported : Warning<
   "the clang compiler does not support '%0'">;
 def warn_drv_deprecated_arg : Warning<
index 32d3fb4..fb6b1b6 100644 (file)
@@ -583,6 +583,8 @@ def fdiagnostics_parseable_fixits : Flag<["-"], "fdiagnostics-parseable-fixits">
 def fdiagnostics_print_source_range_info : Flag<["-"], "fdiagnostics-print-source-range-info">,
     Group<f_clang_Group>,  Flags<[CC1Option]>,
     HelpText<"Print source range spans in numeric form">;
+def fdiagnostics_show_hotness : Flag<["-"], "fdiagnostics-show-hotness">, Group<f_Group>,
+    Flags<[CC1Option]>, HelpText<"Enable profile hotness information in diagnostic line">;
 def fdiagnostics_show_option : Flag<["-"], "fdiagnostics-show-option">, Group<f_Group>,
     Flags<[CC1Option]>, HelpText<"Print option name with mappable diagnostics">;
 def fdiagnostics_show_note_include_stack : Flag<["-"], "fdiagnostics-show-note-include-stack">,
@@ -939,6 +941,7 @@ def fno_cxx_modules : Flag <["-"], "fno-cxx-modules">, Group<f_Group>,
   Flags<[DriverOption]>;
 def fno_diagnostics_fixit_info : Flag<["-"], "fno-diagnostics-fixit-info">, Group<f_Group>,
   Flags<[CC1Option]>, HelpText<"Do not include fixit information in diagnostics">;
+def fno_diagnostics_show_hotness : Flag<["-"], "fno-diagnostics-show-hotness">, Group<f_Group>;
 def fno_diagnostics_show_option : Flag<["-"], "fno-diagnostics-show-option">, Group<f_Group>;
 def fno_diagnostics_show_note_include_stack : Flag<["-"], "fno-diagnostics-show-note-include-stack">,
     Flags<[CC1Option]>, Group<f_Group>;
index 677baa9..5ebbc2c 100644 (file)
@@ -247,6 +247,9 @@ ENUM_CODEGENOPT(DefaultTLSModel, TLSModel, 2, GeneralDynamicTLSModel)
 /// filename)
 VALUE_CODEGENOPT(EmitCheckPathComponentsToStrip, 32, 0)
 
+/// Whether to report the hotness of the code region for optimization remarks.
+CODEGENOPT(DiagnosticsWithHotness, 1, 0)
+
 #undef CODEGENOPT
 #undef ENUM_CODEGENOPT
 #undef VALUE_CODEGENOPT
index dd80390..6a3b9c6 100644 (file)
@@ -179,6 +179,7 @@ namespace clang {
           Ctx.getDiagnosticHandler();
       void *OldDiagnosticContext = Ctx.getDiagnosticContext();
       Ctx.setDiagnosticHandler(DiagnosticHandler, this);
+      Ctx.setDiagnosticHotnessRequested(CodeGenOpts.DiagnosticsWithHotness);
 
       // Link LinkModule into this module if present, preserving its validity.
       for (auto &I : LinkModules) {
@@ -511,9 +512,16 @@ void BackendConsumer::EmitOptimizationMessage(
   FullSourceLoc Loc = getBestLocationFromDebugLoc(D, BadDebugInfo, Filename,
       Line, Column);
 
+  std::string Msg;
+  raw_string_ostream MsgStream(Msg);
+  MsgStream << D.getMsg().str();
+
+  if (D.getHotness())
+    MsgStream << " (hotness: " << *D.getHotness() << ")";
+
   Diags.Report(Loc, DiagID)
       << AddFlagValue(D.getPassName() ? D.getPassName() : "")
-      << D.getMsg().str();
+      << MsgStream.str();
 
   if (BadDebugInfo)
     // If we were not able to translate the file:line:col information
index 8a77fab..f3f40f2 100644 (file)
@@ -4902,6 +4902,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
   claimNoWarnArgs(Args);
 
   Args.AddAllArgs(CmdArgs, options::OPT_R_Group);
+
   Args.AddAllArgs(CmdArgs, options::OPT_W_Group);
   if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false))
     CmdArgs.push_back("-pedantic");
@@ -5904,6 +5905,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
     CmdArgs.push_back(A->getValue());
   }
 
+  if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness,
+                   options::OPT_fno_diagnostics_show_hotness, false))
+    CmdArgs.push_back("-fdiagnostics-show-hotness");
+
   if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) {
     CmdArgs.push_back("-fdiagnostics-format");
     CmdArgs.push_back(A->getValue());
index 619ea9c..1536738 100644 (file)
@@ -839,6 +839,12 @@ static bool ParseCodeGenArgs(CodeGenOptions &Opts, ArgList &Args, InputKind IK,
     NeedLocTracking = true;
   }
 
+  Opts.DiagnosticsWithHotness =
+      Args.hasArg(options::OPT_fdiagnostics_show_hotness);
+  if (Opts.DiagnosticsWithHotness &&
+      Opts.getProfileUse() == CodeGenOptions::ProfileNone)
+    Diags.Report(diag::warn_drv_fdiagnostics_show_hotness_requires_pgo);
+
   // If the user requested to use a sample profile for PGO, then the
   // backend will need to track source location information so the profile
   // can be incorporated into the IR.
diff --git a/clang/test/Frontend/Inputs/optimization-remark-with-hotness.proftext b/clang/test/Frontend/Inputs/optimization-remark-with-hotness.proftext
new file mode 100644 (file)
index 0000000..af111d6
--- /dev/null
@@ -0,0 +1,25 @@
+foo
+# Func Hash:
+0
+# Num Counters:
+1
+# Counter Values:
+30
+
+bar
+# Func Hash:
+0
+# Num Counters:
+1
+# Counter Values:
+30
+
+main
+# Func Hash:
+4
+# Num Counters:
+2
+# Counter Values:
+1
+30
+
diff --git a/clang/test/Frontend/optimization-remark-with-hotness.c b/clang/test/Frontend/optimization-remark-with-hotness.c
new file mode 100644 (file)
index 0000000..ab9f6a5
--- /dev/null
@@ -0,0 +1,45 @@
+// RUN: llvm-profdata merge \
+// RUN:     %S/Inputs/optimization-remark-with-hotness.proftext   \
+// RUN:     -o %t.profdata
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \
+// RUN:     optimization-remark-with-hotness.c %s -emit-llvm-only \
+// RUN:     -fprofile-instrument-use-path=%t.profdata -Rpass=inline \
+// RUN:     -Rpass-analysis=inline -fdiagnostics-show-hotness -verify
+// The clang version of the previous test.
+// RUN: %clang -target x86_64-apple-macosx10.9 %s -o /dev/null \
+// RUN:     -fprofile-instr-use=%t.profdata -Rpass=inline \
+// RUN:     -Rpass-analysis=inline -fdiagnostics-show-hotness -Xclang -verify
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \
+// RUN:     optimization-remark-with-hotness.c %s -emit-llvm-only \
+// RUN:     -fprofile-instrument-use-path=%t.profdata -Rpass=inline \
+// RUN:     -Rpass-analysis=inline 2>&1 | FileCheck -check-prefix=HOTNESS_OFF %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \
+// RUN:     optimization-remark-with-hotness.c %s -emit-llvm-only \
+// RUN:     -fprofile-instrument-use-path=%t.profdata -Rpass=inline \
+// RUN:     -Rpass-analysis=inline -Rno-pass-with-hotness  2>&1 | FileCheck \
+// RUN:     -check-prefix=HOTNESS_OFF %s
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name \
+// RUN:     optimization-remark-with-hotness.c %s -emit-llvm-only \
+// RUN:     -Rpass=inline -Rpass-analysis=inline -fdiagnostics-show-hotness  2>&1 \
+// RUN:     | FileCheck -check-prefix=NO_PGO %s
+
+int foo(int x, int y) __attribute__((always_inline));
+int foo(int x, int y) { return x + y; }
+
+int sum = 0;
+
+void bar(int x) {
+  // HOTNESS_OFF: foo inlined into bar
+  // HOTNESS_OFF-NOT: hotness:
+  // NO_PGO: '-fdiagnostics-show-hotness' requires profile-guided optimization information
+  // expected-remark@+2 {{foo should always be inlined (cost=always) (hotness: 30)}}
+  // expected-remark@+1 {{foo inlined into bar (hotness: 30)}}
+  sum += foo(x, x - 2);
+}
+
+int main(int argc, const char *argv[]) {
+  for (int i = 0; i < 30; i++)
+    // expected-remark@+1 {{bar should never be inlined}}
+    bar(argc);
+  return sum;
+}