@@ -64,130 +64,13 @@ 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-
9967struct SparseInstrProfTest : public InstrProfTest {
10068 void SetUp () override { Writer.setOutputSparse (true ); }
10169};
10270
10371struct MaybeSparseInstrProfTest : public InstrProfTest ,
10472 public ::testing::WithParamInterface<bool > {
10573 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- }
19174};
19275
19376TEST_P (MaybeSparseInstrProfTest, write_and_read_empty_profile) {
@@ -196,6 +79,11 @@ TEST_P(MaybeSparseInstrProfTest, write_and_read_empty_profile) {
19679 ASSERT_TRUE (Reader->begin () == Reader->end ());
19780}
19881
82+ static const auto Err = [](Error E) {
83+ consumeError (std::move (E));
84+ FAIL ();
85+ };
86+
19987TEST_P (MaybeSparseInstrProfTest, write_and_read_one_function) {
20088 Writer.addRecord ({" foo" , 0x1234 , {1 , 2 , 3 , 4 }}, Err);
20189 auto Profile = Writer.writeBuffer ();
@@ -745,8 +633,55 @@ TEST_F(InstrProfTest, test_irpgo_read_deprecated_names) {
745633 Succeeded ());
746634}
747635
748- TEST_P (MaybeSparseInstrProfTest, icall_data_read_write) {
749- testICallDataReadWrite ();
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" ));
750685}
751686
752687TEST_P (MaybeSparseInstrProfTest, annotate_vp_data) {
@@ -845,15 +780,94 @@ TEST_P(MaybeSparseInstrProfTest, annotate_vp_data) {
845780 ASSERT_EQ (1U , ValueData[3 ].Count );
846781}
847782
848- TEST_P (MaybeSparseInstrProfTest, icall_data_read_write_with_weight) {
849- testICallDataReadWrite (10 /* ProfWeight */ );
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" ));
850824}
851825
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.
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:
855870 Writer.setValueProfDataEndianness (llvm::endianness::little);
856- Reader->setValueProfDataEndianness (llvm::endianness::little);
857871}
858872
859873TEST_P (MaybeSparseInstrProfTest, get_icall_data_merge1) {
@@ -879,8 +893,9 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) {
879893 InstrProfValueData VD3[] = {{uint64_t (callee1), 1 }};
880894 Record11.addValueData (IPVK_IndirectCallTarget, 3 , VD3, 1 , nullptr );
881895
882- InstrProfValueData VD4[] = {
883- {uint64_t (callee1), 1 }, {uint64_t (callee2), 2 }, {uint64_t (callee3), 3 }};
896+ InstrProfValueData VD4[] = {{uint64_t (callee1), 1 },
897+ {uint64_t (callee2), 2 },
898+ {uint64_t (callee3), 3 }};
884899 Record11.addValueData (IPVK_IndirectCallTarget, 4 , VD4, 3 , nullptr );
885900
886901 // A different record for the same caller.
@@ -897,8 +912,9 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) {
897912
898913 Record12.addValueData (IPVK_IndirectCallTarget, 3 , nullptr , 0 , nullptr );
899914
900- InstrProfValueData VD42[] = {
901- {uint64_t (callee1), 1 }, {uint64_t (callee2), 2 }, {uint64_t (callee3), 3 }};
915+ InstrProfValueData VD42[] = {{uint64_t (callee1), 1 },
916+ {uint64_t (callee2), 2 },
917+ {uint64_t (callee3), 3 }};
902918 Record12.addValueData (IPVK_IndirectCallTarget, 4 , VD42, 3 , nullptr );
903919
904920 Writer.addRecord (std::move (Record11), Err);
0 commit comments