From c912e4c787ae01a34fa48576e099fcb5950dd828 Mon Sep 17 00:00:00 2001 From: Justin Bogner Date: Thu, 26 Jun 2014 01:45:07 +0000 Subject: 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 --- include/clang/Basic/DiagnosticGroups.td | 1 + include/clang/Basic/DiagnosticSemaKinds.td | 4 ++++ lib/CodeGen/CodeGenModule.cpp | 18 +++++++++++++++--- lib/CodeGen/CodeGenModule.h | 30 +++++++++++++++++++++++++++--- lib/CodeGen/CodeGenPGO.cpp | 12 +++++++----- lib/CodeGen/CodeGenPGO.h | 3 ++- test/Profile/Inputs/c-unprofiled.proftext | 10 ++++++++++ test/Profile/Inputs/profiled_header.h | 3 +++ test/Profile/c-unprofiled.c | 26 ++++++++++++++++++++++++++ 9 files changed, 95 insertions(+), 12 deletions(-) create mode 100644 test/Profile/Inputs/c-unprofiled.proftext create mode 100644 test/Profile/Inputs/profiled_header.h create mode 100644 test/Profile/c-unprofiled.c 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; +def warn_profile_data_unprofiled : Warning< + "no profile data available for file \"%0\"">, + InGroup; + } // 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 = ""; + 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 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 -- cgit v1.2.3