Index: llvm/trunk/include/llvm/ProfileData/SampleProfReader.h =================================================================== --- llvm/trunk/include/llvm/ProfileData/SampleProfReader.h +++ llvm/trunk/include/llvm/ProfileData/SampleProfReader.h @@ -222,6 +222,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/SymbolRemappingReader.h" #include #include #include @@ -289,11 +290,16 @@ // The function name may have been updated by adding suffix. In sample // profile, the function names are all stripped, so we need to strip // the function name suffix before matching with profile. - StringRef Fname = F.getName().split('.').first; + return getSamplesFor(F.getName().split('.').first); + } + + /// Return the samples collected for function \p F. + virtual FunctionSamples *getSamplesFor(StringRef Fname) { std::string FGUID; Fname = getRepInFormat(Fname, getFormat(), FGUID); - if (Profiles.count(Fname)) - return &Profiles[Fname]; + auto It = Profiles.find(Fname); + if (It != Profiles.end()) + return &It->second; return nullptr; } @@ -337,6 +343,12 @@ /// Profile summary information. std::unique_ptr Summary; + /// Take ownership of the summary of this reader. + static std::unique_ptr + takeSummary(SampleProfileReader &Reader) { + return std::move(Reader.Summary); + } + /// Compute summary for this profile. void computeSummary(); @@ -525,6 +537,40 @@ static const uint32_t GCOVTagAFDOFunction = 0xac000000; }; +/// A profile data reader proxy that remaps the profile data from another +/// sample profile data reader, by applying a provided set of equivalences +/// between components of the symbol names in the profile. +class SampleProfileReaderItaniumRemapper : public SampleProfileReader { +public: + SampleProfileReaderItaniumRemapper( + std::unique_ptr B, LLVMContext &C, + std::unique_ptr Underlying) + : SampleProfileReader(std::move(B), C, Underlying->getFormat()) { + Profiles = std::move(Underlying->getProfiles()); + Summary = takeSummary(*Underlying); + } + + /// Create a remapped sample profile from the given remapping file and + /// underlying samples. + static ErrorOr> + create(const Twine &Filename, LLVMContext &C, + std::unique_ptr Underlying); + + /// Read and validate the file header. + std::error_code readHeader() override { return sampleprof_error::success; } + + /// Read remapping file and apply it to the sample profile. + std::error_code read() override; + + /// Return the samples collected for function \p F. + FunctionSamples *getSamplesFor(StringRef FunctionName) override; + using SampleProfileReader::getSamplesFor; + +private: + SymbolRemappingReader Remappings; + DenseMap SampleMap; +}; + } // end namespace sampleprof } // end namespace llvm Index: llvm/trunk/lib/ProfileData/SampleProfReader.cpp =================================================================== --- llvm/trunk/lib/ProfileData/SampleProfReader.cpp +++ llvm/trunk/lib/ProfileData/SampleProfReader.cpp @@ -912,6 +912,40 @@ return Magic == "adcg*704"; } +std::error_code SampleProfileReaderItaniumRemapper::read() { + // If the underlying data is in compact format, we can't remap it because + // we don't know what the original function names were. + if (getFormat() == SPF_Compact_Binary) { + Ctx.diagnose(DiagnosticInfoSampleProfile( + Buffer->getBufferIdentifier(), + "Profile data remapping cannot be applied to profile data " + "in compact format (original mangled names are not available).", + DS_Warning)); + return sampleprof_error::success; + } + + if (Error E = Remappings.read(*Buffer)) { + handleAllErrors( + std::move(E), [&](const SymbolRemappingParseError &ParseError) { + reportError(ParseError.getLineNum(), ParseError.getMessage()); + }); + return sampleprof_error::malformed; + } + + for (auto &Sample : getProfiles()) + if (auto Key = Remappings.insert(Sample.first())) + SampleMap.insert({Key, &Sample.second}); + + return sampleprof_error::success; +} + +FunctionSamples * +SampleProfileReaderItaniumRemapper::getSamplesFor(StringRef Fname) { + if (auto Key = Remappings.lookup(Fname)) + return SampleMap.lookup(Key); + return SampleProfileReader::getSamplesFor(Fname); +} + /// Prepare a memory buffer for the contents of \p Filename. /// /// \returns an error code indicating the status of the buffer. @@ -944,6 +978,27 @@ return create(BufferOrError.get(), C); } +/// Create a sample profile remapper from the given input, to remap the +/// function names in the given profile data. +/// +/// \param Filename The file to open. +/// +/// \param C The LLVM context to use to emit diagnostics. +/// +/// \param Underlying The underlying profile data reader to remap. +/// +/// \returns an error code indicating the status of the created reader. +ErrorOr> +SampleProfileReaderItaniumRemapper::create( + const Twine &Filename, LLVMContext &C, + std::unique_ptr Underlying) { + auto BufferOrError = setupMemoryBuffer(Filename); + if (std::error_code EC = BufferOrError.getError()) + return EC; + return llvm::make_unique( + std::move(BufferOrError.get()), C, std::move(Underlying)); +} + /// Create a sample profile reader based on the format of the input data. /// /// \param B The memory buffer to create the reader from (assumes ownership). Index: llvm/trunk/unittests/ProfileData/SampleProfTest.cpp =================================================================== --- llvm/trunk/unittests/ProfileData/SampleProfTest.cpp +++ llvm/trunk/unittests/ProfileData/SampleProfTest.cpp @@ -58,7 +58,7 @@ Reader->collectFuncsToUse(M); } - void testRoundTrip(SampleProfileFormat Format) { + void testRoundTrip(SampleProfileFormat Format, bool Remap) { SmallVector ProfilePath; ASSERT_TRUE(NoError(llvm::sys::fs::createTemporaryFile("profile", "", ProfilePath))); StringRef Profile(ProfilePath.data(), ProfilePath.size()); @@ -108,22 +108,35 @@ EC = Reader->read(); ASSERT_TRUE(NoError(EC)); - StringMap &ReadProfiles = Reader->getProfiles(); - ASSERT_EQ(2u, ReadProfiles.size()); - - std::string FooGUID; - StringRef FooRep = getRepInFormat(FooName, Format, FooGUID); - FunctionSamples &ReadFooSamples = ReadProfiles[FooRep]; - ASSERT_EQ(7711u, ReadFooSamples.getTotalSamples()); - ASSERT_EQ(610u, ReadFooSamples.getHeadSamples()); - - std::string BarGUID; - StringRef BarRep = getRepInFormat(BarName, Format, BarGUID); - FunctionSamples &ReadBarSamples = ReadProfiles[BarRep]; - ASSERT_EQ(20301u, ReadBarSamples.getTotalSamples()); - ASSERT_EQ(1437u, ReadBarSamples.getHeadSamples()); + if (Remap) { + auto MemBuffer = llvm::MemoryBuffer::getMemBuffer(R"( + # Types 'int' and 'long' are equivalent + type i l + # Function names 'foo' and 'faux' are equivalent + name 3foo 4faux + )"); + Reader.reset(new SampleProfileReaderItaniumRemapper( + std::move(MemBuffer), Context, std::move(Reader))); + FooName = "_Z4fauxi"; + BarName = "_Z3barl"; + + EC = Reader->read(); + ASSERT_TRUE(NoError(EC)); + } + + ASSERT_EQ(2u, Reader->getProfiles().size()); + + FunctionSamples *ReadFooSamples = Reader->getSamplesFor(FooName); + ASSERT_TRUE(ReadFooSamples != nullptr); + ASSERT_EQ(7711u, ReadFooSamples->getTotalSamples()); + ASSERT_EQ(610u, ReadFooSamples->getHeadSamples()); + + FunctionSamples *ReadBarSamples = Reader->getSamplesFor(BarName); + ASSERT_TRUE(ReadBarSamples != nullptr); + ASSERT_EQ(20301u, ReadBarSamples->getTotalSamples()); + ASSERT_EQ(1437u, ReadBarSamples->getHeadSamples()); ErrorOr CTMap = - ReadBarSamples.findCallTargetMapAt(1, 0); + ReadBarSamples->findCallTargetMapAt(1, 0); ASSERT_FALSE(CTMap.getError()); std::string MconstructGUID; @@ -184,15 +197,23 @@ }; TEST_F(SampleProfTest, roundtrip_text_profile) { - testRoundTrip(SampleProfileFormat::SPF_Text); + testRoundTrip(SampleProfileFormat::SPF_Text, false); } TEST_F(SampleProfTest, roundtrip_raw_binary_profile) { - testRoundTrip(SampleProfileFormat::SPF_Binary); + testRoundTrip(SampleProfileFormat::SPF_Binary, false); } TEST_F(SampleProfTest, roundtrip_compact_binary_profile) { - testRoundTrip(SampleProfileFormat::SPF_Compact_Binary); + testRoundTrip(SampleProfileFormat::SPF_Compact_Binary, false); +} + +TEST_F(SampleProfTest, remap_text_profile) { + testRoundTrip(SampleProfileFormat::SPF_Text, true); +} + +TEST_F(SampleProfTest, remap_raw_binary_profile) { + testRoundTrip(SampleProfileFormat::SPF_Binary, true); } TEST_F(SampleProfTest, sample_overflow_saturation) {