| //===- unittests/Support/DataAccessProfTest.cpp |
| //----------------------------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "llvm/ProfileData/DataAccessProf.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include "llvm/Testing/Support/SupportHelpers.h" |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| |
| namespace llvm { |
| namespace memprof { |
| namespace { |
| |
| using ::llvm::StringRef; |
| using llvm::ValueIs; |
| using ::testing::ElementsAre; |
| using ::testing::Field; |
| using ::testing::HasSubstr; |
| using ::testing::IsEmpty; |
| |
| static std::string ErrorToString(Error E) { |
| std::string ErrMsg; |
| llvm::raw_string_ostream OS(ErrMsg); |
| llvm::logAllUnhandledErrors(std::move(E), OS); |
| return ErrMsg; |
| } |
| |
| // Test the various scenarios when DataAccessProfData should return error on |
| // invalid input. |
| TEST(MemProf, DataAccessProfileError) { |
| // Returns error if the input symbol name is empty. |
| DataAccessProfData Data; |
| EXPECT_THAT(ErrorToString(Data.setDataAccessProfile("", 100)), |
| HasSubstr("Empty symbol name")); |
| |
| // Returns error when the same symbol gets added twice. |
| ASSERT_FALSE(Data.setDataAccessProfile("foo", 100)); |
| EXPECT_THAT(ErrorToString(Data.setDataAccessProfile("foo", 100)), |
| HasSubstr("Duplicate symbol or string literal added")); |
| |
| // Returns error when the same string content hash gets added twice. |
| ASSERT_FALSE(Data.setDataAccessProfile((uint64_t)135246, 1000)); |
| EXPECT_THAT(ErrorToString(Data.setDataAccessProfile((uint64_t)135246, 1000)), |
| HasSubstr("Duplicate symbol or string literal added")); |
| } |
| |
| // Test the following operations on DataAccessProfData: |
| // - Profile record look up. |
| // - Serialization and de-serialization. |
| TEST(MemProf, DataAccessProfile) { |
| using internal::DataAccessProfRecordRef; |
| using internal::SourceLocationRef; |
| DataAccessProfData Data; |
| |
| // In the bool conversion, Error is true if it's in a failure state and false |
| // if it's in an accept state. Use ASSERT_FALSE or EXPECT_FALSE for no error. |
| ASSERT_FALSE(Data.setDataAccessProfile("foo.llvm.123", 100)); |
| ASSERT_FALSE(Data.addKnownSymbolWithoutSamples((uint64_t)789)); |
| ASSERT_FALSE(Data.addKnownSymbolWithoutSamples("sym2")); |
| ASSERT_FALSE(Data.setDataAccessProfile("bar.__uniq.321", 123, |
| { |
| SourceLocation{"file2", 3}, |
| })); |
| ASSERT_FALSE(Data.addKnownSymbolWithoutSamples("sym1")); |
| ASSERT_FALSE(Data.addKnownSymbolWithoutSamples((uint64_t)678)); |
| ASSERT_FALSE(Data.setDataAccessProfile( |
| (uint64_t)135246, 1000, |
| {SourceLocation{"file1", 1}, SourceLocation{"file2", 2}})); |
| |
| { |
| // Test that symbol names and file names are stored in the input order. |
| EXPECT_THAT( |
| llvm::to_vector(llvm::make_first_range(Data.getStrToIndexMapRef())), |
| ElementsAre("foo", "sym2", "bar.__uniq.321", "file2", "sym1", "file1")); |
| EXPECT_THAT(Data.getKnownColdSymbols(), ElementsAre("sym2", "sym1")); |
| EXPECT_THAT(Data.getKnownColdHashes(), ElementsAre(789, 678)); |
| |
| // Look up profiles. |
| EXPECT_TRUE(Data.isKnownColdSymbol((uint64_t)789)); |
| EXPECT_TRUE(Data.isKnownColdSymbol((uint64_t)678)); |
| EXPECT_TRUE(Data.isKnownColdSymbol("sym2")); |
| EXPECT_TRUE(Data.isKnownColdSymbol("sym1")); |
| |
| EXPECT_EQ(Data.getProfileRecord("non-existence"), std::nullopt); |
| EXPECT_EQ(Data.getProfileRecord((uint64_t)789987), std::nullopt); |
| |
| EXPECT_THAT( |
| Data.getProfileRecord("foo.llvm.123"), |
| ValueIs( |
| AllOf(Field(&DataAccessProfRecord::SymHandle, |
| testing::VariantWith<std::string>(testing::Eq("foo"))), |
| Field(&DataAccessProfRecord::Locations, IsEmpty())))); |
| EXPECT_THAT( |
| Data.getProfileRecord("bar.__uniq.321"), |
| ValueIs(AllOf( |
| Field(&DataAccessProfRecord::SymHandle, |
| testing::VariantWith<std::string>( |
| testing::Eq("bar.__uniq.321"))), |
| Field(&DataAccessProfRecord::Locations, |
| ElementsAre(AllOf(Field(&SourceLocation::FileName, "file2"), |
| Field(&SourceLocation::Line, 3))))))); |
| EXPECT_THAT( |
| Data.getProfileRecord((uint64_t)135246), |
| ValueIs(AllOf( |
| Field(&DataAccessProfRecord::SymHandle, |
| testing::VariantWith<uint64_t>(testing::Eq(135246))), |
| Field(&DataAccessProfRecord::Locations, |
| ElementsAre(AllOf(Field(&SourceLocation::FileName, "file1"), |
| Field(&SourceLocation::Line, 1)), |
| AllOf(Field(&SourceLocation::FileName, "file2"), |
| Field(&SourceLocation::Line, 2))))))); |
| } |
| |
| // Tests serialization and de-serialization. |
| DataAccessProfData deserializedData; |
| { |
| std::string serializedData; |
| llvm::raw_string_ostream OS(serializedData); |
| llvm::ProfOStream POS(OS); |
| |
| EXPECT_FALSE(Data.serialize(POS)); |
| |
| const unsigned char *p = |
| reinterpret_cast<const unsigned char *>(serializedData.data()); |
| ASSERT_THAT(llvm::to_vector(llvm::make_first_range( |
| deserializedData.getStrToIndexMapRef())), |
| IsEmpty()); |
| EXPECT_FALSE(deserializedData.deserialize(p)); |
| |
| EXPECT_THAT( |
| llvm::to_vector( |
| llvm::make_first_range(deserializedData.getStrToIndexMapRef())), |
| ElementsAre("foo", "sym2", "bar.__uniq.321", "file2", "sym1", "file1")); |
| EXPECT_THAT(deserializedData.getKnownColdSymbols(), |
| ElementsAre("sym2", "sym1")); |
| EXPECT_THAT(deserializedData.getKnownColdHashes(), ElementsAre(789, 678)); |
| |
| // Look up profiles after deserialization. |
| EXPECT_TRUE(deserializedData.isKnownColdSymbol((uint64_t)789)); |
| EXPECT_TRUE(deserializedData.isKnownColdSymbol((uint64_t)678)); |
| EXPECT_TRUE(deserializedData.isKnownColdSymbol("sym2")); |
| EXPECT_TRUE(deserializedData.isKnownColdSymbol("sym1")); |
| |
| auto Records = |
| llvm::to_vector(llvm::make_second_range(deserializedData.getRecords())); |
| |
| EXPECT_THAT( |
| Records, |
| ElementsAre( |
| AllOf(Field(&DataAccessProfRecordRef::SymbolID, 0), |
| Field(&DataAccessProfRecordRef::AccessCount, 100), |
| Field(&DataAccessProfRecordRef::IsStringLiteral, false), |
| Field(&DataAccessProfRecordRef::Locations, IsEmpty())), |
| AllOf(Field(&DataAccessProfRecordRef::SymbolID, 2), |
| Field(&DataAccessProfRecordRef::AccessCount, 123), |
| Field(&DataAccessProfRecordRef::IsStringLiteral, false), |
| Field(&DataAccessProfRecordRef::Locations, |
| ElementsAre( |
| AllOf(Field(&SourceLocationRef::FileName, "file2"), |
| Field(&SourceLocationRef::Line, 3))))), |
| AllOf(Field(&DataAccessProfRecordRef::SymbolID, 135246), |
| Field(&DataAccessProfRecordRef::AccessCount, 1000), |
| Field(&DataAccessProfRecordRef::IsStringLiteral, true), |
| Field(&DataAccessProfRecordRef::Locations, |
| ElementsAre( |
| AllOf(Field(&SourceLocationRef::FileName, "file1"), |
| Field(&SourceLocationRef::Line, 1)), |
| AllOf(Field(&SourceLocationRef::FileName, "file2"), |
| Field(&SourceLocationRef::Line, 2))))))); |
| } |
| } |
| } // namespace |
| } // namespace memprof |
| } // namespace llvm |