"sample-profile-max-propagate-iterations", cl::init(100),
cl::desc("Maximum number of iterations to go through when propagating "
"sample block/edge weights through the CFG."));
-static cl::opt<unsigned> SampleProfileCoverage(
- "sample-profile-check-coverage", cl::init(0), cl::value_desc("N"),
+static cl::opt<unsigned> SampleProfileRecordCoverage(
+ "sample-profile-check-record-coverage", cl::init(0), cl::value_desc("N"),
+ cl::desc("Emit a warning if less than N% of records in the input profile "
+ "are matched to the IR."));
+static cl::opt<unsigned> SampleProfileSampleCoverage(
+ "sample-profile-check-sample-coverage", cl::init(0), cl::value_desc("N"),
cl::desc("Emit a warning if less than N% of samples in the input profile "
"are matched to the IR."));
class SampleCoverageTracker {
public:
- SampleCoverageTracker() : SampleCoverage() {}
+ SampleCoverageTracker() : SampleCoverage(), TotalUsedSamples(0) {}
- bool markSamplesUsed(const FunctionSamples *Samples, uint32_t LineOffset,
- uint32_t Discriminator);
+ bool markSamplesUsed(const FunctionSamples *FS, uint32_t LineOffset,
+ uint32_t Discriminator, uint64_t Samples);
unsigned computeCoverage(unsigned Used, unsigned Total) const;
- unsigned countUsedSamples(const FunctionSamples *Samples) const;
- unsigned countBodySamples(const FunctionSamples *Samples) const;
- void clear() { SampleCoverage.clear(); }
+ unsigned countUsedRecords(const FunctionSamples *FS) const;
+ unsigned countBodyRecords(const FunctionSamples *FS) const;
+ uint64_t getTotalUsedSamples() const { return TotalUsedSamples; }
+ uint64_t countBodySamples(const FunctionSamples *FS) const;
+ void clear() {
+ SampleCoverage.clear();
+ TotalUsedSamples = 0;
+ }
private:
typedef DenseMap<LineLocation, unsigned> BodySampleCoverageMap;
/// another map that counts how many times the sample record at the
/// given location has been used.
FunctionSamplesCoverageMap SampleCoverage;
+
+ /// Number of samples used from the profile.
+ ///
+ /// When a sampling record is used for the first time, the samples from
+ /// that record are added to this accumulator. Coverage is later computed
+ /// based on the total number of samples available in this function and
+ /// its callsites.
+ ///
+ /// Note that this accumulator tracks samples used from a single function
+ /// and all the inlined callsites. Strictly, we should have a map of counters
+ /// keyed by FunctionSamples pointers, but these stats are cleared after
+ /// every function, so we just need to keep a single counter.
+ uint64_t TotalUsedSamples;
};
SampleCoverageTracker CoverageTracker;
/// (LineOffset, Discriminator).
///
/// \returns true if this is the first time we mark the given record.
-bool SampleCoverageTracker::markSamplesUsed(const FunctionSamples *Samples,
+bool SampleCoverageTracker::markSamplesUsed(const FunctionSamples *FS,
uint32_t LineOffset,
- uint32_t Discriminator) {
+ uint32_t Discriminator,
+ uint64_t Samples) {
LineLocation Loc(LineOffset, Discriminator);
- unsigned &Count = SampleCoverage[Samples][Loc];
- return ++Count == 1;
+ unsigned &Count = SampleCoverage[FS][Loc];
+ bool FirstTime = (++Count == 1);
+ if (FirstTime)
+ TotalUsedSamples += Samples;
+ return FirstTime;
}
/// Return the number of sample records that were applied from this profile.
unsigned
-SampleCoverageTracker::countUsedSamples(const FunctionSamples *Samples) const {
- auto I = SampleCoverage.find(Samples);
+SampleCoverageTracker::countUsedRecords(const FunctionSamples *FS) const {
+ auto I = SampleCoverage.find(FS);
- // The size of the coverage map for Samples represents the number of records
+ // The size of the coverage map for FS represents the number of records
// that were marked used at least once.
unsigned Count = (I != SampleCoverage.end()) ? I->second.size() : 0;
// If there are inlined callsites in this function, count the samples found
// in the respective bodies. However, do not bother counting callees with 0
// total samples, these are callees that were never invoked at runtime.
- for (const auto &I : Samples->getCallsiteSamples()) {
+ for (const auto &I : FS->getCallsiteSamples()) {
const FunctionSamples *CalleeSamples = &I.second;
if (CalleeSamples->getTotalSamples() > 0)
- Count += countUsedSamples(CalleeSamples);
+ Count += countUsedRecords(CalleeSamples);
}
return Count;
/// with 0 samples indicate inlined function calls that were never actually
/// invoked at runtime. Ignore these callsites for coverage purposes.
unsigned
-SampleCoverageTracker::countBodySamples(const FunctionSamples *Samples) const {
- unsigned Count = Samples->getBodySamples().size();
+SampleCoverageTracker::countBodyRecords(const FunctionSamples *FS) const {
+ unsigned Count = FS->getBodySamples().size();
// Count all the callsites with non-zero samples.
- for (const auto &I : Samples->getCallsiteSamples()) {
+ for (const auto &I : FS->getCallsiteSamples()) {
const FunctionSamples *CalleeSamples = &I.second;
if (CalleeSamples->getTotalSamples() > 0)
- Count += countBodySamples(CalleeSamples);
+ Count += countBodyRecords(CalleeSamples);
}
return Count;
}
+/// Return the number of samples collected in the body of this profile.
+///
+/// The count includes all the samples in inlined callees. However, callsites
+/// with 0 samples indicate inlined function calls that were never actually
+/// invoked at runtime. Ignore these callsites for coverage purposes.
+uint64_t
+SampleCoverageTracker::countBodySamples(const FunctionSamples *FS) const {
+ uint64_t Total = 0;
+ for (const auto &I : FS->getBodySamples())
+ Total += I.second.getSamples();
+
+ // Count all the callsites with non-zero samples.
+ for (const auto &I : FS->getCallsiteSamples()) {
+ const FunctionSamples *CalleeSamples = &I.second;
+ if (CalleeSamples->getTotalSamples() > 0)
+ Total += countBodySamples(CalleeSamples);
+ }
+
+ return Total;
+}
+
/// Return the fraction of sample records used in this profile.
///
/// The returned value is an unsigned integer in the range 0-100 indicating
ErrorOr<uint64_t> R = FS->findSamplesAt(LineOffset, Discriminator);
if (R) {
bool FirstMark =
- CoverageTracker.markSamplesUsed(FS, LineOffset, Discriminator);
+ CoverageTracker.markSamplesUsed(FS, LineOffset, Discriminator, R.get());
if (FirstMark) {
const Function *F = Inst.getParent()->getParent();
LLVMContext &Ctx = F->getContext();
}
// If coverage checking was requested, compute it now.
- if (SampleProfileCoverage) {
- unsigned Used = CoverageTracker.countUsedSamples(Samples);
- unsigned Total = CoverageTracker.countBodySamples(Samples);
+ if (SampleProfileRecordCoverage) {
+ unsigned Used = CoverageTracker.countUsedRecords(Samples);
+ unsigned Total = CoverageTracker.countBodyRecords(Samples);
unsigned Coverage = CoverageTracker.computeCoverage(Used, Total);
- if (Coverage < SampleProfileCoverage) {
+ if (Coverage < SampleProfileRecordCoverage) {
F.getContext().diagnose(DiagnosticInfoSampleProfile(
getDISubprogram(&F)->getFilename(), getFunctionLoc(F),
Twine(Used) + " of " + Twine(Total) + " available profile records (" +
}
}
+ if (SampleProfileSampleCoverage) {
+ uint64_t Used = CoverageTracker.getTotalUsedSamples();
+ uint64_t Total = CoverageTracker.countBodySamples(Samples);
+ unsigned Coverage = CoverageTracker.computeCoverage(Used, Total);
+ if (Coverage < SampleProfileSampleCoverage) {
+ F.getContext().diagnose(DiagnosticInfoSampleProfile(
+ getDISubprogram(&F)->getFilename(), getFunctionLoc(F),
+ Twine(Used) + " of " + Twine(Total) + " available profile samples (" +
+ Twine(Coverage) + "%) were applied",
+ DS_Warning));
+ }
+ }
return Changed;
}