@@ -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+
6799struct SparseInstrProfTest : public InstrProfTest {
68100 void SetUp () override { Writer.setOutputSparse (true ); }
69101};
70102
71103struct 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
76193TEST_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-
87199TEST_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
687752TEST_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
873859TEST_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