forked from OSchip/llvm-project
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:
parent
2710d01ce2
commit
40b8ba1496
|
@ -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">;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
function_in_header
|
||||
10
|
||||
2
|
||||
1
|
||||
0
|
||||
|
||||
main
|
||||
0
|
||||
1
|
||||
1
|
|
@ -0,0 +1,3 @@
|
|||
void function_in_header(int i) {
|
||||
if (i) {}
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue