llvm.org GIT mirror llvm / 0c94d7d
[Profiling] Add a -sparse mode to llvm-profdata merge Add an option to llvm-profdata merge for writing out sparse indexed profiles. These profiles omit InstrProfRecords for functions which are never executed. Differential Revision: http://reviews.llvm.org/D16727 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@259258 91177308-0d34-0410-b5e6-96231b3b80d8 Vedant Kumar 3 years ago
7 changed file(s) with 126 addition(s) and 45 deletion(s). Raw diff Collapse all Expand all
8989
9090 Emit the profile using GCC's gcov format (Not yet supported).
9191
92 .. option:: -sparse[=true|false]
93
94 Do not emit function records with 0 execution count. Can only be used in
95 conjunction with -instr. Defaults to false, since it can inhibit compiler
96 optimization during PGO.
97
9298 EXAMPLES
9399 ^^^^^^^^
94100 Basic Usage
3131 typedef SmallDenseMap ProfilingData;
3232
3333 private:
34 bool Sparse;
3435 StringMap FunctionData;
3536 uint64_t MaxFunctionCount;
3637 // Use raw pointer here for the incomplete type object.
3738 InstrProfRecordWriterTrait *InfoObj;
3839
3940 public:
40 InstrProfWriter();
41 InstrProfWriter(bool Sparse = false);
4142 ~InstrProfWriter();
4243
4344 /// Add function counts for the given function. If there are already counts
5657
5758 // Internal interface for testing purpose only.
5859 void setValueProfDataEndianness(support::endianness Endianness);
60 void setOutputSparse(bool Sparse);
5961
6062 private:
63 bool shouldEncodeData(const ProfilingData &PD);
6164 void writeImpl(ProfOStream &OS);
6265 };
6366
138138 };
139139 }
140140
141 InstrProfWriter::InstrProfWriter()
142 : FunctionData(), MaxFunctionCount(0),
141 InstrProfWriter::InstrProfWriter(bool Sparse)
142 : Sparse(Sparse), FunctionData(), MaxFunctionCount(0),
143143 InfoObj(new InstrProfRecordWriterTrait()) {}
144144
145145 InstrProfWriter::~InstrProfWriter() { delete InfoObj; }
148148 void InstrProfWriter::setValueProfDataEndianness(
149149 support::endianness Endianness) {
150150 InfoObj->ValueProfDataEndianness = Endianness;
151 }
152 void InstrProfWriter::setOutputSparse(bool Sparse) {
153 this->Sparse = Sparse;
151154 }
152155
153156 std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I,
183186 return Result;
184187 }
185188
189 bool InstrProfWriter::shouldEncodeData(const ProfilingData &PD) {
190 if (!Sparse)
191 return true;
192 for (const auto &Func : PD) {
193 const InstrProfRecord &IPR = Func.second;
194 if (std::any_of(IPR.Counts.begin(), IPR.Counts.end(),
195 [](uint64_t Count) { return Count > 0; }))
196 return true;
197 }
198 return false;
199 }
200
186201 void InstrProfWriter::writeImpl(ProfOStream &OS) {
187202 OnDiskChainedHashTableGenerator Generator;
188203 // Populate the hash table generator.
189204 for (const auto &I : FunctionData)
190 Generator.insert(I.getKey(), &I.getValue());
205 if (shouldEncodeData(I.getValue()))
206 Generator.insert(I.getKey(), &I.getValue());
191207 // Write the header.
192208 IndexedInstrProf::Header Header;
193209 Header.Magic = IndexedInstrProf::Magic;
278294 void InstrProfWriter::writeText(raw_fd_ostream &OS) {
279295 InstrProfSymtab Symtab;
280296 for (const auto &I : FunctionData)
281 Symtab.addFuncName(I.getKey());
297 if (shouldEncodeData(I.getValue()))
298 Symtab.addFuncName(I.getKey());
282299 Symtab.finalizeSymtab();
283300
284301 for (const auto &I : FunctionData)
285 for (const auto &Func : I.getValue())
286 writeRecordInText(Func.second, Symtab, OS);
287 }
302 if (shouldEncodeData(I.getValue()))
303 for (const auto &Func : I.getValue())
304 writeRecordInText(Func.second, Symtab, OS);
305 }
0 # RUN: llvm-profdata merge -sparse=true %s -o %t.profdata
1
1
2 # RUN: llvm-profdata merge %s -o %t.profdata
2 # RUN: llvm-profdata merge -sparse=false %s -o %t.profdata.dense
33
44 # RUN: llvm-profdata show %t.profdata --function function_count_only --counts | FileCheck %s -check-prefix=FUNC_COUNT_ONLY
55 function_count_only
1111 # FUNC_COUNT_ONLY-NEXT: Function count: 97531
1212 # FUNC_COUNT_ONLY-NEXT: Block counts: []
1313
14 # RUN: llvm-profdata show %t.profdata --function "name with spaces" --counts | FileCheck %s -check-prefix=SPACES
14 # RUN: llvm-profdata show %t.profdata.dense --function "name with spaces" --counts | FileCheck %s -check-prefix=SPACES
15 # RUN: llvm-profdata show %t.profdata --function "name with spaces" --counts | FileCheck %s --check-prefix=SPARSE_SPACES
1516 name with spaces
1617 1024
1718 2
2122 # SPACES-NEXT: Counters: 2
2223 # SPACES-NEXT: Function count: 0
2324 # SPACES-NEXT: Block counts: [0]
25 # SPARSE_SPACES-NOT: Function count: 0
2426
2527 # RUN: llvm-profdata show %t.profdata --function large_numbers --counts | FileCheck %s -check-prefix=LARGENUM
2628 large_numbers
3739 # LARGENUM-NEXT: Function count: 2305843009213693952
3840 # LARGENUM-NEXT: Block counts: [1152921504606846976, 576460752303423488, 288230376151711744, 144115188075855872, 72057594037927936]
3941
40 # RUN: llvm-profdata show %t.profdata --function hex_hash | FileCheck %s -check-prefix=HEX-HASH
42 # RUN: llvm-profdata show %t.profdata.dense --function hex_hash | FileCheck %s -check-prefix=HEX-HASH
4143 hex_hash
4244 0x1234
4345 1
5052 # NOSUCHFUNC: Functions shown: 0
5153
5254 # RUN: llvm-profdata show %t.profdata --function _ | FileCheck %s -check-prefix=SOMEFUNCS
55 # RUN: llvm-profdata show %t.profdata.dense --function _ | FileCheck %s -check-prefix=SOMEFUNCS_DENSE
5356 # SOMEFUNCS: Counters:
5457 # SOMEFUNCS: function_count_only:
5558 # SOMEFUNCS: large_numbers:
56 # SOMEFUNCS: Functions shown: 3
59 # SOMEFUNCS: Functions shown: 2
60 # SOMEFUNCS_DENSE: Functions shown: 3
5761
58 # RUN: llvm-profdata show %t.profdata | FileCheck %s -check-prefix=SUMMARY
62 # RUN: llvm-profdata show %t.profdata.dense | FileCheck %s -check-prefix=SUMMARY
5963 # SUMMARY-NOT: Counters:
6064 # SUMMARY-NOT: Functions shown:
6165 # SUMMARY: Total functions: 4
6266 # SUMMARY: Maximum function count: 2305843009213693952
6367 # SUMMARY: Maximum internal block count: 1152921504606846976
6468
65 # RUN: llvm-profdata show --detailed-summary %t.profdata | FileCheck %s -check-prefix=DETAILED-SUMMARY
69 # RUN: llvm-profdata show --detailed-summary %t.profdata.dense | FileCheck %s -check-prefix=DETAILED-SUMMARY
6670 # DETAILED-SUMMARY: Detailed summary:
6771 # DETAILED-SUMMARY: Total number of blocks: 10
6872 # DETAILED-SUMMARY: Total count: 4539628424389557499
106106
107107 static void mergeInstrProfile(const WeightedFileVector &Inputs,
108108 StringRef OutputFilename,
109 ProfileFormat OutputFormat) {
109 ProfileFormat OutputFormat, bool OutputSparse) {
110110 if (OutputFilename.compare("-") == 0)
111111 exitWithError("Cannot write indexed profdata format to stdout.");
112112
118118 if (EC)
119119 exitWithErrorCode(EC, OutputFilename);
120120
121 InstrProfWriter Writer;
121 InstrProfWriter Writer(OutputSparse);
122122 SmallSet WriterErrorCodes;
123123 for (const auto &Input : Inputs) {
124124 auto ReaderOrErr = InstrProfReader::create(Input.Filename);
227227 "GCC encoding (only meaningful for -sample)"),
228228 clEnumValEnd));
229229
230 cl::opt OutputSparse("sparse", cl::init(false),
231 cl::desc("Generate a sparse profile (only meaningful for -instr)"));
232
230233 cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
231234
232235 if (InputFilenames.empty() && WeightedInputFilenames.empty())
240243 WeightedInputs.push_back(parseWeightedFile(WeightedFilename));
241244
242245 if (ProfileKind == instr)
243 mergeInstrProfile(WeightedInputs, OutputFilename, OutputFormat);
246 mergeInstrProfile(WeightedInputs, OutputFilename, OutputFormat,
247 OutputSparse);
244248 else
245249 mergeSampleProfile(WeightedInputs, OutputFilename, OutputFormat);
246250
9191
9292 void SetUp() override {
9393 NextFile = 0;
94 ProfileWriter.setOutputSparse(false);
9495 }
9596
9697 unsigned getFile(StringRef Name) {
153154 }
154155 };
155156
156 TEST_F(CoverageMappingTest, basic_write_read) {
157 struct MaybeSparseCoverageMappingTest
158 : public CoverageMappingTest,
159 public ::testing::WithParamInterface {
160 void SetUp() {
161 CoverageMappingTest::SetUp();
162 ProfileWriter.setOutputSparse(GetParam());
163 }
164 };
165
166 TEST_P(MaybeSparseCoverageMappingTest, basic_write_read) {
157167 addCMR(Counter::getCounter(0), "foo", 1, 1, 1, 1);
158168 addCMR(Counter::getCounter(1), "foo", 2, 1, 2, 2);
159169 addCMR(Counter::getZero(), "foo", 3, 1, 3, 4);
173183 }
174184 }
175185
176 TEST_F(CoverageMappingTest, expansion_gets_first_counter) {
186 TEST_P(MaybeSparseCoverageMappingTest, expansion_gets_first_counter) {
177187 addCMR(Counter::getCounter(1), "foo", 10, 1, 10, 2);
178188 // This starts earlier in "foo", so the expansion should get its counter.
179189 addCMR(Counter::getCounter(2), "foo", 1, 1, 20, 1);
186196 ASSERT_EQ(3U, OutputCMRs[2].LineStart);
187197 }
188198
189 TEST_F(CoverageMappingTest, basic_coverage_iteration) {
199 TEST_P(MaybeSparseCoverageMappingTest, basic_coverage_iteration) {
190200 InstrProfRecord Record("func", 0x1234, {30, 20, 10, 0});
191201 ProfileWriter.addRecord(std::move(Record));
192202 readProfCounts();
209219 ASSERT_EQ(CoverageSegment(11, 11, false), Segments[6]);
210220 }
211221
212 TEST_F(CoverageMappingTest, uncovered_function) {
222 TEST_P(MaybeSparseCoverageMappingTest, uncovered_function) {
213223 readProfCounts();
214224
215225 addCMR(Counter::getZero(), "file1", 1, 2, 3, 4);
222232 ASSERT_EQ(CoverageSegment(3, 4, false), Segments[1]);
223233 }
224234
225 TEST_F(CoverageMappingTest, uncovered_function_with_mapping) {
235 TEST_P(MaybeSparseCoverageMappingTest, uncovered_function_with_mapping) {
226236 readProfCounts();
227237
228238 addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
237247 ASSERT_EQ(CoverageSegment(9, 9, false), Segments[2]);
238248 }
239249
240 TEST_F(CoverageMappingTest, combine_regions) {
250 TEST_P(MaybeSparseCoverageMappingTest, combine_regions) {
241251 InstrProfRecord Record("func", 0x1234, {10, 20, 30});
242252 ProfileWriter.addRecord(std::move(Record));
243253 readProfCounts();
256266 ASSERT_EQ(CoverageSegment(9, 9, false), Segments[3]);
257267 }
258268
259 TEST_F(CoverageMappingTest, dont_combine_expansions) {
260 InstrProfRecord Record("func", 0x1234, {10, 20});
261 ProfileWriter.addRecord(std::move(Record));
269 TEST_P(MaybeSparseCoverageMappingTest, dont_combine_expansions) {
270 InstrProfRecord Record1("func", 0x1234, {10, 20});
271 InstrProfRecord Record2("func", 0x1234, {0, 0});
272 ProfileWriter.addRecord(std::move(Record1));
273 ProfileWriter.addRecord(std::move(Record2));
262274 readProfCounts();
263275
264276 addCMR(Counter::getCounter(0), "file1", 1, 1, 9, 9);
276288 ASSERT_EQ(CoverageSegment(9, 9, false), Segments[3]);
277289 }
278290
279 TEST_F(CoverageMappingTest, strip_filename_prefix) {
280 InstrProfRecord Record("file1:func", 0x1234, {10});
291 TEST_P(MaybeSparseCoverageMappingTest, strip_filename_prefix) {
292 InstrProfRecord Record("file1:func", 0x1234, {0});
281293 ProfileWriter.addRecord(std::move(Record));
282294 readProfCounts();
283295
291303 ASSERT_EQ("func", Names[0]);
292304 }
293305
306 INSTANTIATE_TEST_CASE_P(MaybeSparse, MaybeSparseCoverageMappingTest,
307 ::testing::Bool());
308
294309 } // end anonymous namespace
3838 InstrProfWriter Writer;
3939 std::unique_ptr Reader;
4040
41 void SetUp() { Writer.setOutputSparse(false); }
42
4143 void readProfile(std::unique_ptr Profile) {
4244 auto ReaderOrErr = IndexedInstrProfReader::create(std::move(Profile));
4345 ASSERT_TRUE(NoError(ReaderOrErr.getError()));
4547 }
4648 };
4749
48 TEST_F(InstrProfTest, write_and_read_empty_profile) {
50 struct SparseInstrProfTest : public InstrProfTest {
51 void SetUp() { Writer.setOutputSparse(true); }
52 };
53
54 struct MaybeSparseInstrProfTest : public InstrProfTest,
55 public ::testing::WithParamInterface {
56 void SetUp() {
57 Writer.setOutputSparse(GetParam());
58 }
59 };
60
61 TEST_P(MaybeSparseInstrProfTest, write_and_read_empty_profile) {
4962 auto Profile = Writer.writeBuffer();
5063 readProfile(std::move(Profile));
5164 ASSERT_TRUE(Reader->begin() == Reader->end());
5265 }
5366
54 TEST_F(InstrProfTest, write_and_read_one_function) {
67 TEST_P(MaybeSparseInstrProfTest, write_and_read_one_function) {
5568 InstrProfRecord Record("foo", 0x1234, {1, 2, 3, 4});
5669 Writer.addRecord(std::move(Record));
5770 auto Profile = Writer.writeBuffer();
6982 ASSERT_TRUE(++I == E);
7083 }
7184
72 TEST_F(InstrProfTest, get_instr_prof_record) {
85 TEST_P(MaybeSparseInstrProfTest, get_instr_prof_record) {
7386 InstrProfRecord Record1("foo", 0x1234, {1, 2});
7487 InstrProfRecord Record2("foo", 0x1235, {3, 4});
7588 Writer.addRecord(std::move(Record1));
96109 ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, R.getError()));
97110 }
98111
99 TEST_F(InstrProfTest, get_function_counts) {
112 TEST_P(MaybeSparseInstrProfTest, get_function_counts) {
100113 InstrProfRecord Record1("foo", 0x1234, {1, 2});
101114 InstrProfRecord Record2("foo", 0x1235, {3, 4});
102115 Writer.addRecord(std::move(Record1));
123136 ASSERT_TRUE(ErrorEquals(instrprof_error::unknown_function, EC));
124137 }
125138
126 TEST_F(InstrProfTest, get_icall_data_read_write) {
139 TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write) {
127140 InstrProfRecord Record1("caller", 0x1234, {1, 2});
128141 InstrProfRecord Record2("callee1", 0x1235, {3, 4});
129142 InstrProfRecord Record3("callee2", 0x1235, {3, 4});
170183 ASSERT_EQ(StringRef((const char *)VD[2].Value, 7), StringRef("callee1"));
171184 }
172185
173 TEST_F(InstrProfTest, get_icall_data_read_write_with_weight) {
186 TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_with_weight) {
174187 InstrProfRecord Record1("caller", 0x1234, {1, 2});
175188 InstrProfRecord Record2("callee1", 0x1235, {3, 4});
176189 InstrProfRecord Record3("callee2", 0x1235, {3, 4});
216229 ASSERT_EQ(StringRef((const char *)VD[2].Value, 7), StringRef("callee1"));
217230 }
218231
219 TEST_F(InstrProfTest, get_icall_data_read_write_big_endian) {
232 TEST_P(MaybeSparseInstrProfTest, get_icall_data_read_write_big_endian) {
220233 InstrProfRecord Record1("caller", 0x1234, {1, 2});
221234 InstrProfRecord Record2("callee1", 0x1235, {3, 4});
222235 InstrProfRecord Record3("callee2", 0x1235, {3, 4});
268281 Writer.setValueProfDataEndianness(support::little);
269282 }
270283
271 TEST_F(InstrProfTest, get_icall_data_merge1) {
284 TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1) {
272285 static const char caller[] = "caller";
273286 static const char callee1[] = "callee1";
274287 static const char callee2[] = "callee2";
383396 ASSERT_EQ(2U, VD_4[2].Count);
384397 }
385398
386 TEST_F(InstrProfTest, get_icall_data_merge1_saturation) {
399 TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge1_saturation) {
387400 static const char bar[] = "bar";
388401
389402 const uint64_t Max = std::numeric_limits::max();
437450 // This test tests that when there are too many values
438451 // for a given site, the merged results are properly
439452 // truncated.
440 TEST_F(InstrProfTest, get_icall_data_merge_site_trunc) {
453 TEST_P(MaybeSparseInstrProfTest, get_icall_data_merge_site_trunc) {
441454 static const char caller[] = "caller";
442455
443456 InstrProfRecord Record11(caller, 0x1234, {1, 2});
507520 nullptr};
508521
509522 static uint16_t NumValueSites[IPVK_Last + 1] = {5};
510 TEST_F(InstrProfTest, runtime_value_prof_data_read_write) {
523 TEST_P(MaybeSparseInstrProfTest, runtime_value_prof_data_read_write) {
511524 ValueProfRuntimeRecord RTRecord;
512525 initializeValueProfRuntimeRecord(&RTRecord, &NumValueSites[0],
513526 &ValueProfNodes[0]);
577590 free(VPData);
578591 }
579592
580 TEST_F(InstrProfTest, get_max_function_count) {
593 TEST_P(MaybeSparseInstrProfTest, get_max_function_count) {
581594 InstrProfRecord Record1("foo", 0x1234, {1ULL << 31, 2});
582595 InstrProfRecord Record2("bar", 0, {1ULL << 63});
583596 InstrProfRecord Record3("baz", 0x5678, {0, 0, 0, 0});
590603 ASSERT_EQ(1ULL << 63, Reader->getMaximumFunctionCount());
591604 }
592605
593 TEST_F(InstrProfTest, get_weighted_function_counts) {
606 TEST_P(MaybeSparseInstrProfTest, get_weighted_function_counts) {
594607 InstrProfRecord Record1("foo", 0x1234, {1, 2});
595608 InstrProfRecord Record2("foo", 0x1235, {3, 4});
596609 Writer.addRecord(std::move(Record1), 3);
610623 ASSERT_EQ(20U, Counts[1]);
611624 }
612625
613 TEST_F(InstrProfTest, instr_prof_symtab_test) {
626 TEST_P(MaybeSparseInstrProfTest, instr_prof_symtab_test) {
614627 std::vector FuncNames;
615628 FuncNames.push_back("func1");
616629 FuncNames.push_back("func2");
661674 ASSERT_EQ(StringRef("bar3"), R);
662675 }
663676
664 TEST_F(InstrProfTest, instr_prof_symtab_module_test) {
677 TEST_P(MaybeSparseInstrProfTest, instr_prof_symtab_module_test) {
665678 LLVMContext Ctx;
666679 std::unique_ptr M = llvm::make_unique("MyModule.cpp", Ctx);
667680 FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx),
696709 }
697710 }
698711
699 TEST_F(InstrProfTest, instr_prof_symtab_compression_test) {
712 TEST_P(MaybeSparseInstrProfTest, instr_prof_symtab_compression_test) {
700713 std::vector FuncNames1;
701714 std::vector FuncNames2;
702715 for (int I = 0; I < 10 * 1024; I++) {
767780 }
768781 }
769782
783 TEST_F(SparseInstrProfTest, preserve_no_records) {
784 InstrProfRecord Record1("foo", 0x1234, {0});
785 InstrProfRecord Record2("bar", 0x4321, {0, 0});
786 InstrProfRecord Record3("bar", 0x4321, {0, 0, 0});
787
788 Writer.addRecord(std::move(Record1));
789 Writer.addRecord(std::move(Record2));
790 Writer.addRecord(std::move(Record3));
791 auto Profile = Writer.writeBuffer();
792 readProfile(std::move(Profile));
793
794 auto I = Reader->begin(), E = Reader->end();
795 ASSERT_TRUE(I == E);
796 }
797
798 INSTANTIATE_TEST_CASE_P(MaybeSparse, MaybeSparseInstrProfTest,
799 ::testing::Bool());
800
770801 } // end anonymous namespace