@@ -64,13 +64,130 @@ struct InstrProfTest : ::testing::Test {
64
64
}
65
65
};
66
66
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
+
67
99
struct SparseInstrProfTest : public InstrProfTest {
68
100
void SetUp () override { Writer.setOutputSparse (true ); }
69
101
};
70
102
71
103
struct MaybeSparseInstrProfTest : public InstrProfTest ,
72
104
public ::testing::WithParamInterface<bool > {
73
105
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
+ }
74
191
};
75
192
76
193
TEST_P (MaybeSparseInstrProfTest, write_and_read_empty_profile) {
@@ -79,11 +196,6 @@ TEST_P(MaybeSparseInstrProfTest, write_and_read_empty_profile) {
79
196
ASSERT_TRUE (Reader->begin () == Reader->end ());
80
197
}
81
198
82
- static const auto Err = [](Error E) {
83
- consumeError (std::move (E));
84
- FAIL ();
85
- };
86
-
87
199
TEST_P (MaybeSparseInstrProfTest, write_and_read_one_function) {
88
200
Writer.addRecord ({" foo" , 0x1234 , {1 , 2 , 3 , 4 }}, Err);
89
201
auto Profile = Writer.writeBuffer ();
@@ -633,55 +745,8 @@ TEST_F(InstrProfTest, test_irpgo_read_deprecated_names) {
633
745
Succeeded ());
634
746
}
635
747
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 ();
685
750
}
686
751
687
752
TEST_P (MaybeSparseInstrProfTest, annotate_vp_data) {
@@ -780,94 +845,15 @@ TEST_P(MaybeSparseInstrProfTest, annotate_vp_data) {
780
845
ASSERT_EQ (1U , ValueData[3 ].Count );
781
846
}
782
847
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 */ );
824
850
}
825
851
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.
870
855
Writer.setValueProfDataEndianness (llvm::endianness::little);
856
+ Reader->setValueProfDataEndianness (llvm::endianness::little);
871
857
}
872
858
873
859
TEST_P (MaybeSparseInstrProfTest, get_icall_data_merge1) {
@@ -893,9 +879,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) {
893
879
InstrProfValueData VD3[] = {{uint64_t (callee1), 1 }};
894
880
Record11.addValueData (IPVK_IndirectCallTarget, 3 , VD3, 1 , nullptr );
895
881
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 }};
899
884
Record11.addValueData (IPVK_IndirectCallTarget, 4 , VD4, 3 , nullptr );
900
885
901
886
// A different record for the same caller.
@@ -912,9 +897,8 @@ TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) {
912
897
913
898
Record12.addValueData (IPVK_IndirectCallTarget, 3 , nullptr , 0 , nullptr );
914
899
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 }};
918
902
Record12.addValueData (IPVK_IndirectCallTarget, 4 , VD42, 3 , nullptr );
919
903
920
904
Writer.addRecord (std::move (Record11), Err);
0 commit comments