summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Bogner <mail@justinbogner.com>2014-06-26 01:45:07 +0000
committerJustin Bogner <mail@justinbogner.com>2014-06-26 01:45:07 +0000
commitc912e4c787ae01a34fa48576e099fcb5950dd828 (patch)
tree9b080c3726d35252f76dc40cc9fa021f69f28a40
parent5b3552f7879b2eec0cd69d282b6f2b04b73b20e1 (diff)
downloadclang-c912e4c787ae01a34fa48576e099fcb5950dd828.tar.gz
clang-c912e4c787ae01a34fa48576e099fcb5950dd828.tar.bz2
clang-c912e4c787ae01a34fa48576e099fcb5950dd828.tar.xz
CodeGen: Improve warnings about uninstrumented files when profiling
Improve the warning when building with -fprofile-instr-use and a file appears not to have been profiled at all. This keys on whether a function is defined in the main file or not to avoid false negatives when one includes a header with functions that have been profiled. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@211760 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticGroups.td1
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td4
-rw-r--r--lib/CodeGen/CodeGenModule.cpp18
-rw-r--r--lib/CodeGen/CodeGenModule.h30
-rw-r--r--lib/CodeGen/CodeGenPGO.cpp12
-rw-r--r--lib/CodeGen/CodeGenPGO.h3
-rw-r--r--test/Profile/Inputs/c-unprofiled.proftext10
-rw-r--r--test/Profile/Inputs/profiled_header.h3
-rw-r--r--test/Profile/c-unprofiled.c26
9 files changed, 95 insertions, 12 deletions
diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td
index db924a5890..3d10fcfef0 100644
--- a/include/clang/Basic/DiagnosticGroups.td
+++ b/include/clang/Basic/DiagnosticGroups.td
@@ -707,3 +707,4 @@ def BackendOptimizationRemarkAnalysis : DiagGroup<"pass-analysis">;
// Instrumentation based profiling warnings.
def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">;
+def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index c691921fa1..9be3d8543a 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -7178,6 +7178,10 @@ def warn_profile_data_out_of_date : Warning<
"profile data may be out of date: of %0 function%s0, %1 %plural{1:has|:have}1"
" no data and %2 %plural{1:has|:have}2 mismatched data that will be ignored">,
InGroup<ProfileInstrOutOfDate>;
+def warn_profile_data_unprofiled : Warning<
+ "no profile data available for file \"%0\"">,
+ InGroup<ProfileInstrUnprofiled>;
+
} // end of instrumentation issue category
} // end of sema component.
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index f1b899f49f..d172b45c68 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -314,6 +314,19 @@ void CodeGenModule::clear() {
DeferredDeclsToEmit.clear();
}
+void InstrProfStats::reportDiagnostics(DiagnosticsEngine &Diags,
+ StringRef MainFile) {
+ if (!hasDiagnostics())
+ return;
+ if (VisitedInMainFile > 0 && VisitedInMainFile == MissingInMainFile) {
+ if (MainFile.empty())
+ MainFile = "<stdin>";
+ Diags.Report(diag::warn_profile_data_unprofiled) << MainFile;
+ } else
+ Diags.Report(diag::warn_profile_data_out_of_date) << Visited << Missing
+ << Mismatched;
+}
+
void CodeGenModule::Release() {
EmitDeferred();
applyReplacements();
@@ -327,9 +340,8 @@ void CodeGenModule::Release() {
if (getCodeGenOpts().ProfileInstrGenerate)
if (llvm::Function *PGOInit = CodeGenPGO::emitInitialization(*this))
AddGlobalCtor(PGOInit, 0);
- if (PGOReader && PGOStats.isOutOfDate())
- getDiags().Report(diag::warn_profile_data_out_of_date)
- << PGOStats.Visited << PGOStats.Missing << PGOStats.Mismatched;
+ if (PGOReader && PGOStats.hasDiagnostics())
+ PGOStats.reportDiagnostics(getDiags(), getCodeGenOpts().MainFileName);
EmitCtorList(GlobalCtors, "llvm.global_ctors");
EmitCtorList(GlobalDtors, "llvm.global_dtors");
EmitGlobalAnnotations();
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 6cb4fc17c5..d96b34eee6 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -218,12 +218,36 @@ struct ARCEntrypoints {
};
/// This class records statistics on instrumentation based profiling.
-struct InstrProfStats {
- InstrProfStats() : Visited(0), Missing(0), Mismatched(0) {}
- bool isOutOfDate() { return Missing || Mismatched; }
+class InstrProfStats {
+ uint32_t VisitedInMainFile;
+ uint32_t MissingInMainFile;
uint32_t Visited;
uint32_t Missing;
uint32_t Mismatched;
+
+public:
+ InstrProfStats()
+ : VisitedInMainFile(0), MissingInMainFile(0), Visited(0), Missing(0),
+ Mismatched(0) {}
+ /// Record that we've visited a function and whether or not that function was
+ /// in the main source file.
+ void addVisited(bool MainFile) {
+ if (MainFile)
+ ++VisitedInMainFile;
+ ++Visited;
+ }
+ /// Record that a function we've visited has no profile data.
+ void addMissing(bool MainFile) {
+ if (MainFile)
+ ++MissingInMainFile;
+ ++Missing;
+ }
+ /// Record that a function we've visited has mismatched profile data.
+ void addMismatched(bool MainFile) { ++Mismatched; }
+ /// Whether or not the stats we've gathered indicate any potential problems.
+ bool hasDiagnostics() { return Missing || Mismatched; }
+ /// Report potential problems we've found to \c Diags.
+ void reportDiagnostics(DiagnosticsEngine &Diags, StringRef MainFile);
};
/// This class organizes the cross-function state that is used while generating
diff --git a/lib/CodeGen/CodeGenPGO.cpp b/lib/CodeGen/CodeGenPGO.cpp
index 22534b828e..b233e3c7d7 100644
--- a/lib/CodeGen/CodeGenPGO.cpp
+++ b/lib/CodeGen/CodeGenPGO.cpp
@@ -837,7 +837,8 @@ void CodeGenPGO::assignRegionCounters(const Decl *D, llvm::Function *Fn) {
emitCounterVariables();
}
if (PGOReader) {
- loadRegionCounts(PGOReader);
+ SourceManager &SM = CGM.getContext().getSourceManager();
+ loadRegionCounts(PGOReader, SM.isInMainFile(D->getLocation()));
computeRegionCounts(D);
applyFunctionAttributes(PGOReader, Fn);
}
@@ -912,16 +913,17 @@ void CodeGenPGO::emitCounterIncrement(CGBuilderTy &Builder, unsigned Counter) {
Builder.CreateStore(Count, Addr);
}
-void CodeGenPGO::loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader) {
- CGM.getPGOStats().Visited++;
+void CodeGenPGO::loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader,
+ bool IsInMainFile) {
+ CGM.getPGOStats().addVisited(IsInMainFile);
RegionCounts.reset(new std::vector<uint64_t>);
uint64_t Hash;
if (PGOReader->getFunctionCounts(getFuncName(), Hash, *RegionCounts)) {
- CGM.getPGOStats().Missing++;
+ CGM.getPGOStats().addMissing(IsInMainFile);
RegionCounts.reset();
} else if (Hash != FunctionHash ||
RegionCounts->size() != NumRegionCounters) {
- CGM.getPGOStats().Mismatched++;
+ CGM.getPGOStats().addMismatched(IsInMainFile);
RegionCounts.reset();
}
}
diff --git a/lib/CodeGen/CodeGenPGO.h b/lib/CodeGen/CodeGenPGO.h
index c434808588..2f4aa660be 100644
--- a/lib/CodeGen/CodeGenPGO.h
+++ b/lib/CodeGen/CodeGenPGO.h
@@ -118,7 +118,8 @@ private:
void computeRegionCounts(const Decl *D);
void applyFunctionAttributes(llvm::IndexedInstrProfReader *PGOReader,
llvm::Function *Fn);
- void loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader);
+ void loadRegionCounts(llvm::IndexedInstrProfReader *PGOReader,
+ bool IsInMainFile);
void emitCounterVariables();
llvm::GlobalVariable *buildDataVar();
diff --git a/test/Profile/Inputs/c-unprofiled.proftext b/test/Profile/Inputs/c-unprofiled.proftext
new file mode 100644
index 0000000000..d2ef7ae301
--- /dev/null
+++ b/test/Profile/Inputs/c-unprofiled.proftext
@@ -0,0 +1,10 @@
+function_in_header
+10
+2
+1
+0
+
+main
+0
+1
+1
diff --git a/test/Profile/Inputs/profiled_header.h b/test/Profile/Inputs/profiled_header.h
new file mode 100644
index 0000000000..fa649d4b59
--- /dev/null
+++ b/test/Profile/Inputs/profiled_header.h
@@ -0,0 +1,3 @@
+void function_in_header(int i) {
+ if (i) {}
+}
diff --git a/test/Profile/c-unprofiled.c b/test/Profile/c-unprofiled.c
new file mode 100644
index 0000000000..275cd2d145
--- /dev/null
+++ b/test/Profile/c-unprofiled.c
@@ -0,0 +1,26 @@
+// Test that unprofiled files are recognized. Here, we have two functions in the
+// profile, main() and function_in_header, but we use the profile on a file that
+// has the profile-less some_unprofiled_function so that the only profiled code
+// in #included in a header.
+
+// FIXME: It would be nice to use -verify here instead of FileCheck, but -verify
+// doesn't play well with warnings that have no line number.
+
+// RUN: llvm-profdata merge %S/Inputs/c-unprofiled.proftext -o %t.profdata
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.9 -main-file-name c-unprofiled.c -I %S/Inputs/ %s -o /dev/null -emit-llvm -fprofile-instr-use=%t.profdata -Wprofile-instr-unprofiled 2>&1 | FileCheck %s
+
+// CHECK: warning: no profile data available for file "c-unprofiled.c"
+
+#include "profiled_header.h"
+
+#ifdef GENERATE_OUTDATED_DATA
+int main(int argc, const char *argv[]) {
+ function_in_header(0);
+ return 0;
+}
+#else
+void some_unprofiled_function(int i) {
+ if (i)
+ function_in_header(i);
+}
+#endif