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.

llvm-svn: 211760
This commit is contained in:
Justin Bogner 2014-06-26 01:45:07 +00:00
parent 2710d01ce2
commit 40b8ba1496
9 changed files with 95 additions and 12 deletions

View File

@ -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">;

View File

@ -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.

View File

@ -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();

View File

@ -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

View File

@ -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();
}
}

View File

@ -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();

View File

@ -0,0 +1,10 @@
function_in_header
10
2
1
0
main
0
1
1

View File

@ -0,0 +1,3 @@
void function_in_header(int i) {
if (i) {}
}

View File

@ -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