Skip to content

Commit c597dc3

Browse files
[nfc][InstrProfTest]Factor out common code for value profile test (#72611)
Three existing test cases {get_icall_data_read_write, get_icall_data_read_write_with_weight,get_icall_data_read_write_big_endian} have common test data and testing logic. Extract common code into `testICallDataReadWrite`. - Add helper function `addValueProfData` and `testValueDataArray`. This two helper functions are used by `testICallDataReadWrite`, and possibly other test cases.
1 parent 523c0d3 commit c597dc3

File tree

1 file changed

+129
-145
lines changed

1 file changed

+129
-145
lines changed

llvm/unittests/ProfileData/InstrProfTest.cpp

+129-145
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,130 @@ struct InstrProfTest : ::testing::Test {
6464
}
6565
};
6666

67+
static const char callee1[] = "callee1";
68+
static const char callee2[] = "callee2";
69+
static const char callee3[] = "callee3";
70+
static const char callee4[] = "callee4";
71+
static const char callee5[] = "callee5";
72+
static const char callee6[] = "callee6";
73+
74+
static const auto Err = [](Error E) {
75+
consumeError(std::move(E));
76+
FAIL();
77+
};
78+
79+
typedef std::vector<MutableArrayRef<InstrProfValueData>> VDArray;
80+
81+
// This helper function adds the value profile data to Record. The type of
82+
// value profiles is specified by 'ValueKind'. 'ValueDataArray' is a non-const
83+
// reference and the vector element is a mutable array reference. This is mainly
84+
// because method `InstrProfRecord::addValueData` takes a pointer and might
85+
// modify the pointed-to content.
86+
static void addValueProfData(InstrProfRecord &Record, uint32_t ValueKind,
87+
VDArray &ValueDataArray) {
88+
Record.reserveSites(ValueKind, ValueDataArray.size());
89+
for (long unsigned int i = 0; i < ValueDataArray.size(); i++) {
90+
// The state of vector::data() is not specified when the vector is empty,
91+
// and MutableArrayRef takes vector::data() when initialized with a vector.
92+
Record.addValueData(ValueKind, i,
93+
ValueDataArray[i].empty() ? nullptr
94+
: ValueDataArray[i].data(),
95+
ValueDataArray[i].size(), nullptr);
96+
}
97+
}
98+
6799
struct SparseInstrProfTest : public InstrProfTest {
68100
void SetUp() override { Writer.setOutputSparse(true); }
69101
};
70102

71103
struct MaybeSparseInstrProfTest : public InstrProfTest,
72104
public ::testing::WithParamInterface<bool> {
73105
void SetUp() override { Writer.setOutputSparse(GetParam()); }
106+
107+
public:
108+
// Tests that value profiles in Record has the same content as (possibly
109+
// weighted and sorted) InputVDs for each value kind. ValueProfSorted is true
110+
// iff the value profiles of Record are already sorted by count.
111+
// InputVDs is a non-const reference since it might need a in-place sort.
112+
void testValueDataArray(
113+
std::vector<std::pair<uint32_t /* ValueKind */, VDArray &>> &InputVDs,
114+
InstrProfRecord &Record, bool ValueProfSorted = false,
115+
uint64_t ProfWeight = 1) {
116+
for (auto &[ValueKind, InputVD] : InputVDs) {
117+
ASSERT_EQ(InputVD.size(), Record.getNumValueSites(ValueKind));
118+
for (unsigned i = 0; i < InputVD.size(); i++) {
119+
ASSERT_EQ(InputVD[i].size(),
120+
Record.getNumValueDataForSite(ValueKind, i));
121+
122+
uint64_t WantTotalC = 0, GetTotalC = 0;
123+
std::unique_ptr<InstrProfValueData[]> OutputVD =
124+
Record.getValueForSite(ValueKind, i, &GetTotalC);
125+
126+
// If value profile elements of the same instrumented site are sorted by
127+
// count in Record, sort the input value data array the same way for
128+
// comparison purpose.
129+
if (ValueProfSorted) {
130+
llvm::stable_sort(InputVD[i], [](const InstrProfValueData &lhs,
131+
const InstrProfValueData &rhs) {
132+
return lhs.Count > rhs.Count;
133+
});
134+
}
135+
136+
// The previous ASSERT_EQ already tests the number of value data is
137+
// InputVD[i].size(), so there won't be out-of-bound access.
138+
for (unsigned j = 0; j < InputVD[i].size(); j++) {
139+
EXPECT_EQ(InputVD[i][j].Count * ProfWeight, OutputVD[j].Count);
140+
EXPECT_EQ(InputVD[i][j].Value, OutputVD[j].Value);
141+
WantTotalC += InputVD[i][j].Count;
142+
}
143+
EXPECT_EQ(WantTotalC * ProfWeight, GetTotalC);
144+
}
145+
}
146+
}
147+
148+
// A helper function to test the writes and reads of indirect call value
149+
// profiles. The profile writer will scale counters by `ProfWeight` when
150+
// adding a record. `Endianness` specifies the endianness used by profile
151+
// writer and reader when handling value profile records.
152+
void testICallDataReadWrite(
153+
uint64_t ProfWeight = 1,
154+
llvm::endianness Endianness = llvm::endianness::little) {
155+
NamedInstrProfRecord Record1("caller", 0x1234, {1, 2});
156+
157+
// 4 function value sites.
158+
std::vector<InstrProfValueData> FuncVD0 = {
159+
{uint64_t(callee1), 1}, {uint64_t(callee2), 2}, {uint64_t(callee3), 3}};
160+
std::vector<InstrProfValueData> FuncVD2 = {{uint64_t(callee1), 1},
161+
{uint64_t(callee2), 2}};
162+
std::vector<InstrProfValueData> FuncVD3 = {{uint64_t(callee1), 1}};
163+
VDArray FuncVD = {FuncVD0, {}, FuncVD2, FuncVD3};
164+
addValueProfData(Record1, IPVK_IndirectCallTarget, FuncVD);
165+
166+
if (ProfWeight == 1U) {
167+
Writer.addRecord(std::move(Record1), Err);
168+
} else {
169+
Writer.addRecord(std::move(Record1), ProfWeight, Err);
170+
}
171+
Writer.addRecord({"callee1", 0x1235, {3, 4}}, Err);
172+
Writer.addRecord({"callee2", 0x1235, {3, 4}}, Err);
173+
Writer.addRecord({"callee3", 0x1235, {3, 4}}, Err);
174+
175+
// Set writer endianness.
176+
Writer.setValueProfDataEndianness(Endianness);
177+
178+
auto Profile = Writer.writeBuffer();
179+
readProfile(std::move(Profile));
180+
181+
// Set reader endianness.
182+
Reader->setValueProfDataEndianness(Endianness);
183+
184+
Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
185+
EXPECT_THAT_ERROR(R.takeError(), Succeeded());
186+
187+
std::vector<std::pair<uint32_t, VDArray &>> InputVDs = {
188+
std::pair<uint32_t, VDArray &>{IPVK_IndirectCallTarget, FuncVD}};
189+
testValueDataArray(InputVDs, R.get(), true, ProfWeight);
190+
}
74191
};
75192

76193
TEST_P(MaybeSparseInstrProfTest, write_and_read_empty_profile) {
@@ -79,11 +196,6 @@ TEST_P(MaybeSparseInstrProfTest, write_and_read_empty_profile) {
79196
ASSERT_TRUE(Reader->begin() == Reader->end());
80197
}
81198

82-
static const auto Err = [](Error E) {
83-
consumeError(std::move(E));
84-
FAIL();
85-
};
86-
87199
TEST_P(MaybeSparseInstrProfTest, write_and_read_one_function) {
88200
Writer.addRecord({"foo", 0x1234, {1, 2, 3, 4}}, Err);
89201
auto Profile = Writer.writeBuffer();
@@ -633,55 +745,8 @@ TEST_F(InstrProfTest, test_irpgo_read_deprecated_names) {
633745
Succeeded());
634746
}
635747

636-
static const char callee1[] = "callee1";
637-
static const char callee2[] = "callee2";
638-
static const char callee3[] = "callee3";
639-
static const char callee4[] = "callee4";
640-
static const char callee5[] = "callee5";
641-
static const char callee6[] = "callee6";
642-
643-
TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write) {
644-
NamedInstrProfRecord Record1("caller", 0x1234, {1, 2});
645-
646-
// 4 value sites.
647-
Record1.reserveSites(IPVK_IndirectCallTarget, 4);
648-
InstrProfValueData VD0[] = {
649-
{(uint64_t)callee1, 1}, {(uint64_t)callee2, 2}, {(uint64_t)callee3, 3}};
650-
Record1.addValueData(IPVK_IndirectCallTarget, 0, VD0, 3, nullptr);
651-
// No value profile data at the second site.
652-
Record1.addValueData(IPVK_IndirectCallTarget, 1, nullptr, 0, nullptr);
653-
InstrProfValueData VD2[] = {{(uint64_t)callee1, 1}, {(uint64_t)callee2, 2}};
654-
Record1.addValueData(IPVK_IndirectCallTarget, 2, VD2, 2, nullptr);
655-
InstrProfValueData VD3[] = {{(uint64_t)callee1, 1}};
656-
Record1.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, nullptr);
657-
658-
Writer.addRecord(std::move(Record1), Err);
659-
Writer.addRecord({"callee1", 0x1235, {3, 4}}, Err);
660-
Writer.addRecord({"callee2", 0x1235, {3, 4}}, Err);
661-
Writer.addRecord({"callee3", 0x1235, {3, 4}}, Err);
662-
auto Profile = Writer.writeBuffer();
663-
readProfile(std::move(Profile));
664-
665-
Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
666-
EXPECT_THAT_ERROR(R.takeError(), Succeeded());
667-
ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget));
668-
ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0));
669-
ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1));
670-
ASSERT_EQ(2U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 2));
671-
ASSERT_EQ(1U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 3));
672-
673-
uint64_t TotalC;
674-
std::unique_ptr<InstrProfValueData[]> VD =
675-
R->getValueForSite(IPVK_IndirectCallTarget, 0, &TotalC);
676-
677-
ASSERT_EQ(3U, VD[0].Count);
678-
ASSERT_EQ(2U, VD[1].Count);
679-
ASSERT_EQ(1U, VD[2].Count);
680-
ASSERT_EQ(6U, TotalC);
681-
682-
ASSERT_EQ(StringRef((const char *)VD[0].Value, 7), StringRef("callee3"));
683-
ASSERT_EQ(StringRef((const char *)VD[1].Value, 7), StringRef("callee2"));
684-
ASSERT_EQ(StringRef((const char *)VD[2].Value, 7), StringRef("callee1"));
748+
TEST_P(MaybeSparseInstrProfTest, icall_data_read_write) {
749+
testICallDataReadWrite();
685750
}
686751

687752
TEST_P(MaybeSparseInstrProfTest, annotate_vp_data) {
@@ -780,94 +845,15 @@ TEST_P(MaybeSparseInstrProfTest, annotate_vp_data) {
780845
ASSERT_EQ(1U, ValueData[3].Count);
781846
}
782847

783-
TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_with_weight) {
784-
NamedInstrProfRecord Record1("caller", 0x1234, {1, 2});
785-
786-
// 4 value sites.
787-
Record1.reserveSites(IPVK_IndirectCallTarget, 4);
788-
InstrProfValueData VD0[] = {
789-
{(uint64_t)callee1, 1}, {(uint64_t)callee2, 2}, {(uint64_t)callee3, 3}};
790-
Record1.addValueData(IPVK_IndirectCallTarget, 0, VD0, 3, nullptr);
791-
// No value profile data at the second site.
792-
Record1.addValueData(IPVK_IndirectCallTarget, 1, nullptr, 0, nullptr);
793-
InstrProfValueData VD2[] = {{(uint64_t)callee1, 1}, {(uint64_t)callee2, 2}};
794-
Record1.addValueData(IPVK_IndirectCallTarget, 2, VD2, 2, nullptr);
795-
InstrProfValueData VD3[] = {{(uint64_t)callee1, 1}};
796-
Record1.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, nullptr);
797-
798-
Writer.addRecord(std::move(Record1), 10, Err);
799-
Writer.addRecord({"callee1", 0x1235, {3, 4}}, Err);
800-
Writer.addRecord({"callee2", 0x1235, {3, 4}}, Err);
801-
Writer.addRecord({"callee3", 0x1235, {3, 4}}, Err);
802-
auto Profile = Writer.writeBuffer();
803-
readProfile(std::move(Profile));
804-
805-
Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
806-
EXPECT_THAT_ERROR(R.takeError(), Succeeded());
807-
ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget));
808-
ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0));
809-
ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1));
810-
ASSERT_EQ(2U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 2));
811-
ASSERT_EQ(1U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 3));
812-
813-
uint64_t TotalC;
814-
std::unique_ptr<InstrProfValueData[]> VD =
815-
R->getValueForSite(IPVK_IndirectCallTarget, 0, &TotalC);
816-
ASSERT_EQ(30U, VD[0].Count);
817-
ASSERT_EQ(20U, VD[1].Count);
818-
ASSERT_EQ(10U, VD[2].Count);
819-
ASSERT_EQ(60U, TotalC);
820-
821-
ASSERT_EQ(StringRef((const char *)VD[0].Value, 7), StringRef("callee3"));
822-
ASSERT_EQ(StringRef((const char *)VD[1].Value, 7), StringRef("callee2"));
823-
ASSERT_EQ(StringRef((const char *)VD[2].Value, 7), StringRef("callee1"));
848+
TEST_P(MaybeSparseInstrProfTest, icall_data_read_write_with_weight) {
849+
testICallDataReadWrite(10 /* ProfWeight */);
824850
}
825851

826-
TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_big_endian) {
827-
NamedInstrProfRecord Record1("caller", 0x1234, {1, 2});
828-
829-
// 4 value sites.
830-
Record1.reserveSites(IPVK_IndirectCallTarget, 4);
831-
InstrProfValueData VD0[] = {
832-
{(uint64_t)callee1, 1}, {(uint64_t)callee2, 2}, {(uint64_t)callee3, 3}};
833-
Record1.addValueData(IPVK_IndirectCallTarget, 0, VD0, 3, nullptr);
834-
// No value profile data at the second site.
835-
Record1.addValueData(IPVK_IndirectCallTarget, 1, nullptr, 0, nullptr);
836-
InstrProfValueData VD2[] = {{(uint64_t)callee1, 1}, {(uint64_t)callee2, 2}};
837-
Record1.addValueData(IPVK_IndirectCallTarget, 2, VD2, 2, nullptr);
838-
InstrProfValueData VD3[] = {{(uint64_t)callee1, 1}};
839-
Record1.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, nullptr);
840-
841-
Writer.addRecord(std::move(Record1), Err);
842-
Writer.addRecord({"callee1", 0x1235, {3, 4}}, Err);
843-
Writer.addRecord({"callee2", 0x1235, {3, 4}}, Err);
844-
Writer.addRecord({"callee3", 0x1235, {3, 4}}, Err);
845-
846-
// Set big endian output.
847-
Writer.setValueProfDataEndianness(llvm::endianness::big);
848-
849-
auto Profile = Writer.writeBuffer();
850-
readProfile(std::move(Profile));
851-
852-
// Set big endian input.
853-
Reader->setValueProfDataEndianness(llvm::endianness::big);
854-
855-
Expected<InstrProfRecord> R = Reader->getInstrProfRecord("caller", 0x1234);
856-
EXPECT_THAT_ERROR(R.takeError(), Succeeded());
857-
ASSERT_EQ(4U, R->getNumValueSites(IPVK_IndirectCallTarget));
858-
ASSERT_EQ(3U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 0));
859-
ASSERT_EQ(0U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 1));
860-
ASSERT_EQ(2U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 2));
861-
ASSERT_EQ(1U, R->getNumValueDataForSite(IPVK_IndirectCallTarget, 3));
862-
863-
std::unique_ptr<InstrProfValueData[]> VD =
864-
R->getValueForSite(IPVK_IndirectCallTarget, 0);
865-
ASSERT_EQ(StringRef((const char *)VD[0].Value, 7), StringRef("callee3"));
866-
ASSERT_EQ(StringRef((const char *)VD[1].Value, 7), StringRef("callee2"));
867-
ASSERT_EQ(StringRef((const char *)VD[2].Value, 7), StringRef("callee1"));
868-
869-
// Restore little endian default:
852+
TEST_P(MaybeSparseInstrProfTest, icall_data_read_write_big_endian) {
853+
testICallDataReadWrite(1 /* ProfWeight */, llvm::endianness::big);
854+
// Restore little endianness after this test case.
870855
Writer.setValueProfDataEndianness(llvm::endianness::little);
856+
Reader->setValueProfDataEndianness(llvm::endianness::little);
871857
}
872858

873859
TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) {
@@ -893,9 +879,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) {
893879
InstrProfValueData VD3[] = {{uint64_t(callee1), 1}};
894880
Record11.addValueData(IPVK_IndirectCallTarget, 3, VD3, 1, nullptr);
895881

896-
InstrProfValueData VD4[] = {{uint64_t(callee1), 1},
897-
{uint64_t(callee2), 2},
898-
{uint64_t(callee3), 3}};
882+
InstrProfValueData VD4[] = {
883+
{uint64_t(callee1), 1}, {uint64_t(callee2), 2}, {uint64_t(callee3), 3}};
899884
Record11.addValueData(IPVK_IndirectCallTarget, 4, VD4, 3, nullptr);
900885

901886
// A different record for the same caller.
@@ -912,9 +897,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) {
912897

913898
Record12.addValueData(IPVK_IndirectCallTarget, 3, nullptr, 0, nullptr);
914899

915-
InstrProfValueData VD42[] = {{uint64_t(callee1), 1},
916-
{uint64_t(callee2), 2},
917-
{uint64_t(callee3), 3}};
900+
InstrProfValueData VD42[] = {
901+
{uint64_t(callee1), 1}, {uint64_t(callee2), 2}, {uint64_t(callee3), 3}};
918902
Record12.addValueData(IPVK_IndirectCallTarget, 4, VD42, 3, nullptr);
919903

920904
Writer.addRecord(std::move(Record11), Err);

0 commit comments

Comments
 (0)