diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/ProfileData/SampleProfReader.cpp | 112 | ||||
-rw-r--r-- | llvm/lib/ProfileData/SampleProfWriter.cpp | 23 |
2 files changed, 88 insertions, 47 deletions
diff --git a/llvm/lib/ProfileData/SampleProfReader.cpp b/llvm/lib/ProfileData/SampleProfReader.cpp index 94f87996bea..6d7d182e46c 100644 --- a/llvm/lib/ProfileData/SampleProfReader.cpp +++ b/llvm/lib/ProfileData/SampleProfReader.cpp @@ -132,13 +132,14 @@ using namespace llvm; /// \brief Print the samples collected for a function on stream \p OS. /// /// \param OS Stream to emit the output to. -void FunctionSamples::print(raw_ostream &OS) { +void FunctionSamples::print(raw_ostream &OS, unsigned Indent) const { OS << TotalSamples << ", " << TotalHeadSamples << ", " << BodySamples.size() << " sampled lines\n"; for (const auto &SI : BodySamples) { LineLocation Loc = SI.first; const SampleRecord &Sample = SI.second; - OS << "\tline offset: " << Loc.LineOffset + OS.indent(Indent); + OS << "line offset: " << Loc.LineOffset << ", discriminator: " << Loc.Discriminator << ", number of samples: " << Sample.getSamples(); if (Sample.hasCalls()) { @@ -148,7 +149,15 @@ void FunctionSamples::print(raw_ostream &OS) { } OS << "\n"; } - OS << "\n"; + for (const auto &CS : CallsiteSamples) { + CallsiteLocation Loc = CS.first; + const FunctionSamples &CalleeSamples = CS.second; + OS.indent(Indent); + OS << "line offset: " << Loc.LineOffset + << ", discriminator: " << Loc.Discriminator + << ", inlined callee: " << Loc.CalleeName << ": "; + CalleeSamples.print(OS, Indent + 2); + } } /// \brief Dump the function profile for \p FName. @@ -266,7 +275,7 @@ static bool ParseLine(const StringRef &Input, bool &IsCallsite, unsigned &Depth, std::error_code SampleProfileReaderText::read() { line_iterator LineIt(*Buffer, /*SkipBlanks=*/true, '#'); - SmallVector<FunctionSamples *, 10> InlineStack; + InlineCallStack InlineStack; for (; !LineIt.is_at_eof(); ++LineIt) { if ((*LineIt)[(*LineIt).find_first_not_of(' ')] == '#') @@ -559,31 +568,18 @@ std::error_code SampleProfileReaderGCC::readFunctionProfiles() { if (!GcovBuffer.readInt(NumFunctions)) return sampleprof_error::truncated; - SourceStack Stack; + InlineCallStack Stack; for (uint32_t I = 0; I < NumFunctions; ++I) - if (std::error_code EC = readOneFunctionProfile(Stack, true)) + if (std::error_code EC = readOneFunctionProfile(Stack, true, 0)) return EC; return sampleprof_error::success; } -std::error_code SampleProfileReaderGCC::addSourceCount(StringRef Name, - const SourceStack &Src, - uint64_t Count) { - if (Src.size() == 0 || Src[0].Malformed()) - return sampleprof_error::malformed; - FunctionSamples &FProfile = Profiles[Name]; - FProfile.addTotalSamples(Count); - // FIXME(dnovillo) - Properly update inline stack for FnName. - FProfile.addBodySamples(Src[0].Line, Src[0].Discriminator, Count); - return sampleprof_error::success; -} - -std::error_code -SampleProfileReaderGCC::readOneFunctionProfile(const SourceStack &Stack, - bool Update) { +std::error_code SampleProfileReaderGCC::readOneFunctionProfile( + const InlineCallStack &InlineStack, bool Update, uint32_t Offset) { uint64_t HeadCount = 0; - if (Stack.size() == 0) + if (InlineStack.size() == 0) if (!GcovBuffer.readInt64(HeadCount)) return sampleprof_error::truncated; @@ -597,15 +593,31 @@ SampleProfileReaderGCC::readOneFunctionProfile(const SourceStack &Stack, if (!GcovBuffer.readInt(NumPosCounts)) return sampleprof_error::truncated; - uint32_t NumCallSites; - if (!GcovBuffer.readInt(NumCallSites)) + uint32_t NumCallsites; + if (!GcovBuffer.readInt(NumCallsites)) return sampleprof_error::truncated; - if (Stack.size() == 0) { - FunctionSamples &FProfile = Profiles[Name]; - FProfile.addHeadSamples(HeadCount); - if (FProfile.getTotalSamples() > 0) + FunctionSamples *FProfile = nullptr; + if (InlineStack.size() == 0) { + // If this is a top function that we have already processed, do not + // update its profile again. This happens in the presence of + // function aliases. Since these aliases share the same function + // body, there will be identical replicated profiles for the + // original function. In this case, we simply not bother updating + // the profile of the original function. + FProfile = &Profiles[Name]; + FProfile->addHeadSamples(HeadCount); + if (FProfile->getTotalSamples() > 0) Update = false; + } else { + // Otherwise, we are reading an inlined instance. The top of the + // inline stack contains the profile of the caller. Insert this + // callee in the caller's CallsiteMap. + FunctionSamples *CallerProfile = InlineStack.front(); + uint32_t LineOffset = Offset >> 16; + uint32_t Discriminator = Offset & 0xffff; + FProfile = &CallerProfile->functionSamplesAt( + CallsiteLocation(LineOffset, Discriminator, Name)); } for (uint32_t I = 0; I < NumPosCounts; ++I) { @@ -621,13 +633,28 @@ SampleProfileReaderGCC::readOneFunctionProfile(const SourceStack &Stack, if (!GcovBuffer.readInt64(Count)) return sampleprof_error::truncated; - SourceInfo Info(Name, "", "", 0, Offset >> 16, Offset & 0xffff); - SourceStack NewStack; - NewStack.push_back(Info); - NewStack.insert(NewStack.end(), Stack.begin(), Stack.end()); - if (Update) - addSourceCount(NewStack[NewStack.size() - 1].FuncName, NewStack, Count); + // The line location is encoded in the offset as: + // high 16 bits: line offset to the start of the function. + // low 16 bits: discriminator. + uint32_t LineOffset = Offset >> 16; + uint32_t Discriminator = Offset & 0xffff; + + InlineCallStack NewStack; + NewStack.push_back(FProfile); + NewStack.insert(NewStack.end(), InlineStack.begin(), InlineStack.end()); + if (Update) { + // Walk up the inline stack, adding the samples on this line to + // the total sample count of the callers in the chain. + for (auto CallerProfile : NewStack) + CallerProfile->addTotalSamples(Count); + + // Update the body samples for the current profile. + FProfile->addBodySamples(LineOffset, Discriminator, Count); + } + // Process the list of functions called at an indirect call site. + // These are all the targets that a function pointer (or virtual + // function) resolved at runtime. for (uint32_t J = 0; J < NumTargets; J++) { uint32_t HistVal; if (!GcovBuffer.readInt(HistVal)) @@ -647,24 +674,25 @@ SampleProfileReaderGCC::readOneFunctionProfile(const SourceStack &Stack, if (Update) { FunctionSamples &TargetProfile = Profiles[TargetName]; - TargetProfile.addBodySamples(NewStack[0].Line, - NewStack[0].Discriminator, TargetCount); + TargetProfile.addCalledTargetSamples(LineOffset, Discriminator, + TargetName, TargetCount); } } } - for (uint32_t I = 0; I < NumCallSites; I++) { + // Process all the inlined callers into the current function. These + // are all the callsites that were inlined into this function. + for (uint32_t I = 0; I < NumCallsites; I++) { // The offset is encoded as: // high 16 bits: line offset to the start of the function. // low 16 bits: discriminator. uint32_t Offset; if (!GcovBuffer.readInt(Offset)) return sampleprof_error::truncated; - SourceInfo Info(Name, "", "", 0, Offset >> 16, Offset & 0xffff); - SourceStack NewStack; - NewStack.push_back(Info); - NewStack.insert(NewStack.end(), Stack.begin(), Stack.end()); - if (std::error_code EC = readOneFunctionProfile(NewStack, Update)) + InlineCallStack NewStack; + NewStack.push_back(FProfile); + NewStack.insert(NewStack.end(), InlineStack.begin(), InlineStack.end()); + if (std::error_code EC = readOneFunctionProfile(NewStack, Update, Offset)) return EC; } diff --git a/llvm/lib/ProfileData/SampleProfWriter.cpp b/llvm/lib/ProfileData/SampleProfWriter.cpp index c95267ad976..e6a4d7d1321 100644 --- a/llvm/lib/ProfileData/SampleProfWriter.cpp +++ b/llvm/lib/ProfileData/SampleProfWriter.cpp @@ -31,15 +31,15 @@ using namespace llvm; /// \brief Write samples to a text file. bool SampleProfileWriterText::write(StringRef FName, const FunctionSamples &S) { - if (S.empty()) - return true; - - OS << FName << ":" << S.getTotalSamples() << ":" << S.getHeadSamples() - << "\n"; + OS << FName << ":" << S.getTotalSamples(); + if (Indent == 0) + OS << ":" << S.getHeadSamples(); + OS << "\n"; for (const auto &I : S.getBodySamples()) { LineLocation Loc = I.first; const SampleRecord &Sample = I.second; + OS.indent(Indent + 1); if (Loc.Discriminator == 0) OS << Loc.LineOffset << ": "; else @@ -52,6 +52,19 @@ bool SampleProfileWriterText::write(StringRef FName, const FunctionSamples &S) { OS << "\n"; } + Indent += 1; + for (const auto &I : S.getCallsiteSamples()) { + CallsiteLocation Loc = I.first; + const FunctionSamples &CalleeSamples = I.second; + OS.indent(Indent); + if (Loc.Discriminator == 0) + OS << Loc.LineOffset << ": "; + else + OS << Loc.LineOffset << "." << Loc.Discriminator << ": "; + write(Loc.CalleeName, CalleeSamples); + } + Indent -= 1; + return true; } |