llvm.org GIT mirror llvm / 824c3ec
[llvm-profdata] Add support for weighted merge of profile data (2nd try) Summary: This change adds support for specifying a weight when merging profile data with the llvm-profdata tool. Weights are specified by using the --weighted-input=<weight>,<filename> option. Input files not specified with this option (normal positional list after options) are given a default weight of 1. Adding support for arbitrary weighting of input profile data allows for relative importance to be placed on the input data from multiple training runs. Both sampled and instrumented profiles are supported. Reviewers: davidxl, dnovillo, bogner, silvas Subscribers: silvas, davidxl, llvm-commits Differential Revision: http://reviews.llvm.org/D15306 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@255659 91177308-0d34-0410-b5e6-96231b3b80d8 Nathan Slingerland 3 years ago
14 changed file(s) with 369 addition(s) and 55 deletion(s). Raw diff Collapse all Expand all
2727 SYNOPSIS
2828 ^^^^^^^^
2929
30 :program:`llvm-profdata merge` [*options*] [*filenames...*]
30 :program:`llvm-profdata merge` [*options*] [*filename...*]
3131
3232 DESCRIPTION
3333 ^^^^^^^^^^^
3535 :program:`llvm-profdata merge` takes several profile data files
3636 generated by PGO instrumentation and merges them together into a single
3737 indexed profile data file.
38
39 By default profile data is merged without modification. This means that the
40 relative importance of each input file is proportional to the number of samples
41 or counts it contains. In general, the input from a longer training run will be
42 interpreted as relatively more important than a shorter run. Depending on the
43 nature of the training runs it may be useful to adjust the weight given to each
44 input file by using the ``-weighted-input`` option.
45
3846
3947 OPTIONS
4048 ^^^^^^^
4755
4856 Specify the output file name. *Output* cannot be ``-`` as the resulting
4957 indexed profile data can't be written to standard output.
58
59 .. option:: -weighted-input=weight,filename
60
61 Specify an input file name along with a weight. The profile counts of the input
62 file will be scaled (multiplied) by the supplied ``weight``, where where ``weight``
63 is a decimal integer >= 1. Input files specified without using this option are
64 assigned a default weight of 1. Examples are shown below.
5065
5166 .. option:: -instr (default)
5267
7388 .. option:: -gcc
7489
7590 Emit the profile using GCC's gcov format (Not yet supported).
91
92 EXAMPLES
93 ^^^^^^^^
94 Basic Usage
95 +++++++++++
96 Merge three profiles:
97
98 ::
99
100 llvm-profdata merge foo.profdata bar.profdata baz.profdata -output merged.profdata
101
102 Weighted Input
103 ++++++++++++++
104 The input file `foo.profdata` is especially important, multiply its counts by 10:
105
106 ::
107
108 llvm-profdata merge -weighted-input=10,foo.profdata bar.profdata baz.profdata -output merged.profdata
109
110 Exactly equivalent to the previous invocation (explicit form; useful for programmatic invocation):
111
112 ::
113
114 llvm-profdata merge -weighted-input=10,foo.profdata -weighted-input=1,bar.profdata -weighted-input=1,baz.profdata -output merged.profdata
76115
77116 .. program:: llvm-profdata show
78117
218218 }
219219
220220 /// Merge data from another InstrProfValueSiteRecord
221 void mergeValueData(InstrProfValueSiteRecord &Input) {
221 /// Optionally scale merged counts by \p Weight.
222 void mergeValueData(InstrProfValueSiteRecord &Input, uint64_t Weight = 1) {
222223 this->sortByTargetValues();
223224 Input.sortByTargetValues();
224225 auto I = ValueData.begin();
228229 while (I != IE && I->Value < J->Value)
229230 ++I;
230231 if (I != IE && I->Value == J->Value) {
231 I->Count = SaturatingAdd(I->Count, J->Count);
232 // FIXME: Improve handling of counter overflow.
233 uint64_t JCount = J->Count;
234 bool Overflowed;
235 if (Weight > 1) {
236 JCount = SaturatingMultiply(JCount, Weight, &Overflowed);
237 assert(!Overflowed && "Value data counter overflowed!");
238 }
239 I->Count = SaturatingAdd(I->Count, JCount, &Overflowed);
240 assert(!Overflowed && "Value data counter overflowed!");
232241 ++I;
233242 continue;
234243 }
274283 ValueMapType *HashKeys);
275284
276285 /// Merge the counts in \p Other into this one.
277 inline instrprof_error merge(InstrProfRecord &Other);
286 /// Optionally scale merged counts by \p Weight.
287 inline instrprof_error merge(InstrProfRecord &Other, uint64_t Weight = 1);
278288
279289 /// Used by InstrProfWriter: update the value strings to commoned strings in
280290 /// the writer instance.
326336 }
327337
328338 // Merge Value Profile data from Src record to this record for ValueKind.
329 instrprof_error mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src) {
339 // Scale merged value counts by \p Weight.
340 instrprof_error mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src,
341 uint64_t Weight) {
330342 uint32_t ThisNumValueSites = getNumValueSites(ValueKind);
331343 uint32_t OtherNumValueSites = Src.getNumValueSites(ValueKind);
332344 if (ThisNumValueSites != OtherNumValueSites)
336348 std::vector &OtherSiteRecords =
337349 Src.getValueSitesForKind(ValueKind);
338350 for (uint32_t I = 0; I < ThisNumValueSites; I++)
339 ThisSiteRecords[I].mergeValueData(OtherSiteRecords[I]);
351 ThisSiteRecords[I].mergeValueData(OtherSiteRecords[I], Weight);
340352 return instrprof_error::success;
341353 }
342354 };
422434 VData.Value = (uint64_t)StrTab->insertString((const char *)VData.Value);
423435 }
424436
425 instrprof_error InstrProfRecord::merge(InstrProfRecord &Other) {
437 instrprof_error InstrProfRecord::merge(InstrProfRecord &Other,
438 uint64_t Weight) {
426439 // If the number of counters doesn't match we either have bad data
427440 // or a hash collision.
428441 if (Counts.size() != Other.Counts.size())
431444 instrprof_error Result = instrprof_error::success;
432445
433446 for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) {
434 bool ResultOverflowed;
435 Counts[I] = SaturatingAdd(Counts[I], Other.Counts[I], &ResultOverflowed);
436 if (ResultOverflowed)
447 bool Overflowed;
448 uint64_t OtherCount = Other.Counts[I];
449 if (Weight > 1) {
450 OtherCount = SaturatingMultiply(OtherCount, Weight, &Overflowed);
451 if (Overflowed)
452 Result = instrprof_error::counter_overflow;
453 }
454 Counts[I] = SaturatingAdd(Counts[I], OtherCount, &Overflowed);
455 if (Overflowed)
437456 Result = instrprof_error::counter_overflow;
438457 }
439458
440459 for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
441 instrprof_error MergeValueResult = mergeValueProfData(Kind, Other);
460 instrprof_error MergeValueResult = mergeValueProfData(Kind, Other, Weight);
442461 if (MergeValueResult != instrprof_error::success)
443462 Result = MergeValueResult;
444463 }
3838 void updateStringTableReferences(InstrProfRecord &I);
3939 /// Add function counts for the given function. If there are already counts
4040 /// for this function and the hash and number of counts match, each counter is
41 /// summed.
42 std::error_code addRecord(InstrProfRecord &&I);
41 /// summed. Optionally scale counts by \p Weight.
42 std::error_code addRecord(InstrProfRecord &&I, uint64_t Weight = 1);
4343 /// Write the profile to \c OS
4444 void write(raw_fd_ostream &OS);
4545 /// Write the profile in text format to \c OS
122122 SampleRecord() : NumSamples(0), CallTargets() {}
123123
124124 /// Increment the number of samples for this record by \p S.
125 /// Optionally scale sample count \p S by \p Weight.
125126 ///
126127 /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
127128 /// around unsigned integers.
128 void addSamples(uint64_t S) { NumSamples = SaturatingAdd(NumSamples, S); }
129 void addSamples(uint64_t S, uint64_t Weight = 1) {
130 // FIXME: Improve handling of counter overflow.
131 bool Overflowed;
132 if (Weight > 1) {
133 S = SaturatingMultiply(S, Weight, &Overflowed);
134 assert(!Overflowed && "Sample counter overflowed!");
135 }
136 NumSamples = SaturatingAdd(NumSamples, S, &Overflowed);
137 assert(!Overflowed && "Sample counter overflowed!");
138 }
129139
130140 /// Add called function \p F with samples \p S.
141 /// Optionally scale sample count \p S by \p Weight.
131142 ///
132143 /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
133144 /// around unsigned integers.
134 void addCalledTarget(StringRef F, uint64_t S) {
145 void addCalledTarget(StringRef F, uint64_t S, uint64_t Weight = 1) {
146 // FIXME: Improve handling of counter overflow.
135147 uint64_t &TargetSamples = CallTargets[F];
136 TargetSamples = SaturatingAdd(TargetSamples, S);
148 bool Overflowed;
149 if (Weight > 1) {
150 S = SaturatingMultiply(S, Weight, &Overflowed);
151 assert(!Overflowed && "Called target counter overflowed!");
152 }
153 TargetSamples = SaturatingAdd(TargetSamples, S, &Overflowed);
154 assert(!Overflowed && "Called target counter overflowed!");
137155 }
138156
139157 /// Return true if this sample record contains function calls.
143161 const CallTargetMap &getCallTargets() const { return CallTargets; }
144162
145163 /// Merge the samples in \p Other into this record.
146 void merge(const SampleRecord &Other) {
147 addSamples(Other.getSamples());
164 /// Optionally scale sample counts by \p Weight.
165 void merge(const SampleRecord &Other, uint64_t Weight = 1) {
166 addSamples(Other.getSamples(), Weight);
148167 for (const auto &I : Other.getCallTargets())
149 addCalledTarget(I.first(), I.second);
168 addCalledTarget(I.first(), I.second, Weight);
150169 }
151170
152171 void print(raw_ostream &OS, unsigned Indent) const;
173192 FunctionSamples() : TotalSamples(0), TotalHeadSamples(0) {}
174193 void print(raw_ostream &OS = dbgs(), unsigned Indent = 0) const;
175194 void dump() const;
176 void addTotalSamples(uint64_t Num) { TotalSamples += Num; }
177 void addHeadSamples(uint64_t Num) { TotalHeadSamples += Num; }
178 void addBodySamples(uint32_t LineOffset, uint32_t Discriminator,
179 uint64_t Num) {
180 BodySamples[LineLocation(LineOffset, Discriminator)].addSamples(Num);
195 void addTotalSamples(uint64_t Num, uint64_t Weight = 1) {
196 // FIXME: Improve handling of counter overflow.
197 bool Overflowed;
198 if (Weight > 1) {
199 Num = SaturatingMultiply(Num, Weight, &Overflowed);
200 assert(!Overflowed && "Total samples counter overflowed!");
201 }
202 TotalSamples = SaturatingAdd(TotalSamples, Num, &Overflowed);
203 assert(!Overflowed && "Total samples counter overflowed!");
204 }
205 void addHeadSamples(uint64_t Num, uint64_t Weight = 1) {
206 // FIXME: Improve handling of counter overflow.
207 bool Overflowed;
208 if (Weight > 1) {
209 Num = SaturatingMultiply(Num, Weight, &Overflowed);
210 assert(!Overflowed && "Total head samples counter overflowed!");
211 }
212 TotalHeadSamples = SaturatingAdd(TotalHeadSamples, Num, &Overflowed);
213 assert(!Overflowed && "Total head samples counter overflowed!");
214 }
215 void addBodySamples(uint32_t LineOffset, uint32_t Discriminator, uint64_t Num,
216 uint64_t Weight = 1) {
217 BodySamples[LineLocation(LineOffset, Discriminator)].addSamples(Num,
218 Weight);
181219 }
182220 void addCalledTargetSamples(uint32_t LineOffset, uint32_t Discriminator,
183 std::string FName, uint64_t Num) {
184 BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget(FName,
185 Num);
221 std::string FName, uint64_t Num,
222 uint64_t Weight = 1) {
223 BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget(
224 FName, Num, Weight);
186225 }
187226
188227 /// Return the number of samples collected at the given location.
231270 }
232271
233272 /// Merge the samples in \p Other into this one.
234 void merge(const FunctionSamples &Other) {
235 addTotalSamples(Other.getTotalSamples());
236 addHeadSamples(Other.getHeadSamples());
273 /// Optionally scale samples by \p Weight.
274 void merge(const FunctionSamples &Other, uint64_t Weight = 1) {
275 addTotalSamples(Other.getTotalSamples(), Weight);
276 addHeadSamples(Other.getHeadSamples(), Weight);
237277 for (const auto &I : Other.getBodySamples()) {
238278 const LineLocation &Loc = I.first;
239279 const SampleRecord &Rec = I.second;
240 BodySamples[Loc].merge(Rec);
280 BodySamples[Loc].merge(Rec, Weight);
241281 }
242282 for (const auto &I : Other.getCallsiteSamples()) {
243283 const CallsiteLocation &Loc = I.first;
244284 const FunctionSamples &Rec = I.second;
245 functionSamplesAt(Loc).merge(Rec);
285 functionSamplesAt(Loc).merge(Rec, Weight);
246286 }
247287 }
248288
9797 I.updateStrings(&StringTable);
9898 }
9999
100 std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I) {
100 std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I,
101 uint64_t Weight) {
101102 updateStringTableReferences(I);
102103 auto &ProfileDataMap = FunctionData[I.Name];
103104
112113 // We've never seen a function with this name and hash, add it.
113114 Dest = std::move(I);
114115 Result = instrprof_error::success;
116 if (Weight > 1) {
117 for (auto &Count : Dest.Counts) {
118 bool Overflowed;
119 Count = SaturatingMultiply(Count, Weight, &Overflowed);
120 if (Overflowed && Result == instrprof_error::success) {
121 Result = instrprof_error::counter_overflow;
122 }
123 }
124 }
115125 } else {
116126 // We're updating a function we've seen before.
117 Result = Dest.merge(I);
127 Result = Dest.merge(I, Weight);
118128 }
119129
120130 // We keep track of the max function count as we go for simplicity.
0 bar:1772037:35370
1 17: 35370
2 18: 35370
3 19: 7005
4 20: 29407
5 21: 12170
6 23: 18150 bar:19829
7 25: 36666
0 foo:1763288:35327
1 7: 35327
2 8: 35327
3 9: 6930
4 10: 29341
5 11: 11906
6 13: 18185 foo:19531
7 15: 36458
11
22 1- Detect invalid count
33 RUN: not llvm-profdata show %p/Inputs/invalid-count-later.proftext 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER
4 RUN: not llvm-profdata merge %p/Inputs/invalid-count-later.proftext %p/Inputs/invalid-count-later.profdata -o %t.out 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER
4 RUN: not llvm-profdata merge %p/Inputs/invalid-count-later.proftext %p/Inputs/invalid-count-later.proftext -o %t.out 2>&1 | FileCheck %s --check-prefix=INVALID-COUNT-LATER
55 INVALID-COUNT-LATER: error: {{.*}}invalid-count-later.proftext: Malformed instrumentation profile data
66
77 2- Detect bad hash
0 Tests for weighted merge of instrumented profiles.
1
2 1- Merge the foo and bar profiles with unity weight and verify the combined output
3 RUN: llvm-profdata merge -instr -weighted-input=1,%p/Inputs/weight-instr-bar.profdata -weighted-input=1,%p/Inputs/weight-instr-foo.profdata -o %t
4 RUN: llvm-profdata show -instr -all-functions %t | FileCheck %s -check-prefix=1X_1X_WEIGHT
5 RUN: llvm-profdata merge -instr -weighted-input=1,%p/Inputs/weight-instr-bar.profdata %p/Inputs/weight-instr-foo.profdata -o %t
6 RUN: llvm-profdata show -instr -all-functions %t | FileCheck %s -check-prefix=1X_1X_WEIGHT
7 1X_1X_WEIGHT: Counters:
8 1X_1X_WEIGHT-NEXT: usage:
9 1X_1X_WEIGHT-NEXT: Hash: 0x0000000000000000
10 1X_1X_WEIGHT-NEXT: Counters: 1
11 1X_1X_WEIGHT-NEXT: Function count: 0
12 1X_1X_WEIGHT-NEXT: foo:
13 1X_1X_WEIGHT-NEXT: Hash: 0x000000000000028a
14 1X_1X_WEIGHT-NEXT: Counters: 3
15 1X_1X_WEIGHT-NEXT: Function count: 866988873
16 1X_1X_WEIGHT-NEXT: bar:
17 1X_1X_WEIGHT-NEXT: Hash: 0x000000000000028a
18 1X_1X_WEIGHT-NEXT: Counters: 3
19 1X_1X_WEIGHT-NEXT: Function count: 866988873
20 1X_1X_WEIGHT-NEXT: main:
21 1X_1X_WEIGHT-NEXT: Hash: 0x7d31c47ea98f8248
22 1X_1X_WEIGHT-NEXT: Counters: 60
23 1X_1X_WEIGHT-NEXT: Function count: 2
24 1X_1X_WEIGHT-NEXT: Functions shown: 4
25 1X_1X_WEIGHT-NEXT: Total functions: 4
26 1X_1X_WEIGHT-NEXT: Maximum function count: 866988873
27 1X_1X_WEIGHT-NEXT: Maximum internal block count: 267914296
28
29 2- Merge the foo and bar profiles with weight 3x and 5x respectively and verify the combined output
30 RUN: llvm-profdata merge -instr -weighted-input=3,%p/Inputs/weight-instr-bar.profdata -weighted-input=5,%p/Inputs/weight-instr-foo.profdata -o %t
31 RUN: llvm-profdata show -instr -all-functions %t | FileCheck %s -check-prefix=3X_5X_WEIGHT
32 3X_5X_WEIGHT: Counters:
33 3X_5X_WEIGHT-NEXT: usage:
34 3X_5X_WEIGHT-NEXT: Hash: 0x0000000000000000
35 3X_5X_WEIGHT-NEXT: Counters: 1
36 3X_5X_WEIGHT-NEXT: Function count: 0
37 3X_5X_WEIGHT-NEXT: foo:
38 3X_5X_WEIGHT-NEXT: Hash: 0x000000000000028a
39 3X_5X_WEIGHT-NEXT: Counters: 3
40 3X_5X_WEIGHT-NEXT: Function count: 4334944365
41 3X_5X_WEIGHT-NEXT: bar:
42 3X_5X_WEIGHT-NEXT: Hash: 0x000000000000028a
43 3X_5X_WEIGHT-NEXT: Counters: 3
44 3X_5X_WEIGHT-NEXT: Function count: 2600966619
45 3X_5X_WEIGHT-NEXT: main:
46 3X_5X_WEIGHT-NEXT: Hash: 0x7d31c47ea98f8248
47 3X_5X_WEIGHT-NEXT: Counters: 60
48 3X_5X_WEIGHT-NEXT: Function count: 8
49 3X_5X_WEIGHT-NEXT: Functions shown: 4
50 3X_5X_WEIGHT-NEXT: Total functions: 4
51 3X_5X_WEIGHT-NEXT: Maximum function count: 4334944365
52 3X_5X_WEIGHT-NEXT: Maximum internal block count: 1339571480
53
54 3- Bad merge: invalid weight
55 RUN: not llvm-profdata merge -instr -weighted-input=3,%p/Inputs/weight-instr-bar.profdata -weighted-input=0,%p/Inputs/weight-instr-foo.profdata -o %t.out 2>&1 | FileCheck %s -check-prefix=INVALID_WEIGHT
56 RUN: not llvm-profdata merge -instr -weighted-input=3,%p/Inputs/weight-instr-bar.profdata -weighted-input=0.75,%p/Inputs/weight-instr-foo.profdata -o %t.out 2>&1 | FileCheck %s -check-prefix=INVALID_WEIGHT
57 RUN: not llvm-profdata merge -instr -weighted-input=3,%p/Inputs/weight-instr-bar.profdata -weighted-input=-5,%p/Inputs/weight-instr-foo.profdata -o %t.out 2>&1 | FileCheck %s -check-prefix=INVALID_WEIGHT
58 RUN: not llvm-profdata merge -instr -weighted-input=3,%p/Inputs/weight-instr-bar.profdata -weighted-input=,%p/Inputs/weight-instr-foo.profdata -o %t.out 2>&1 | FileCheck %s -check-prefix=INVALID_WEIGHT
59 RUN: not llvm-profdata merge -instr -weighted-input=3,%p/Inputs/weight-instr-bar.profdata -weighted-input=%p/Inputs/weight-instr-foo.profdata -o %t.out 2>&1 | FileCheck %s -check-prefix=INVALID_WEIGHT
60 INVALID_WEIGHT: error: Input weight must be a positive integer.
61
62 4- Bad merge: input path does not exist
63 RUN: not llvm-profdata merge -instr -weighted-input=3,%p/Inputs/does-not-exist.profdata -weighted-input=2,%p/Inputs/does-not-exist-either.profdata -o %t.out 2>&1 | FileCheck %s -check-prefix=INVALID_INPUT
64 INVALID_INPUT: {{.*}}: {{.*}}does-not-exist.profdata: {{[Nn]}}o such file or directory
65
66 5- No inputs
67 RUN: not llvm-profdata merge -instr -o %t.out 2>&1 | FileCheck %s -check-prefix=NO_INPUT
68 NO_INPUT: {{.*}}: No input files specified. See llvm-profdata{{(\.EXE|\.exe)?}} merge -help
0 Tests for weighted merge of sample profiles.
1
2 1- Merge the foo and bar profiles with unity weight and verify the combined output
3 RUN: llvm-profdata merge -sample -text -weighted-input=1,%p/Inputs/weight-sample-bar.proftext -weighted-input=1,%p/Inputs/weight-sample-foo.proftext -o - | FileCheck %s -check-prefix=1X_1X_WEIGHT
4 RUN: llvm-profdata merge -sample -text -weighted-input=1,%p/Inputs/weight-sample-bar.proftext %p/Inputs/weight-sample-foo.proftext -o - | FileCheck %s -check-prefix=1X_1X_WEIGHT
5 1X_1X_WEIGHT: foo:1763288:35327
6 1X_1X_WEIGHT-NEXT: 7: 35327
7 1X_1X_WEIGHT-NEXT: 8: 35327
8 1X_1X_WEIGHT-NEXT: 9: 6930
9 1X_1X_WEIGHT-NEXT: 10: 29341
10 1X_1X_WEIGHT-NEXT: 11: 11906
11 1X_1X_WEIGHT-NEXT: 13: 18185 foo:19531
12 1X_1X_WEIGHT-NEXT: 15: 36458
13 1X_1X_WEIGHT-NEXT: bar:1772037:35370
14 1X_1X_WEIGHT-NEXT: 17: 35370
15 1X_1X_WEIGHT-NEXT: 18: 35370
16 1X_1X_WEIGHT-NEXT: 19: 7005
17 1X_1X_WEIGHT-NEXT: 20: 29407
18 1X_1X_WEIGHT-NEXT: 21: 12170
19 1X_1X_WEIGHT-NEXT: 23: 18150 bar:19829
20 1X_1X_WEIGHT-NEXT: 25: 36666
21
22 2- Merge the foo and bar profiles with weight 3x and 5x respectively and verify the combined output
23 RUN: llvm-profdata merge -sample -text -weighted-input=3,%p/Inputs/weight-sample-bar.proftext -weighted-input=5,%p/Inputs/weight-sample-foo.proftext -o - | FileCheck %s -check-prefix=3X_5X_WEIGHT
24 3X_5X_WEIGHT: foo:8816440:176635
25 3X_5X_WEIGHT-NEXT: 7: 176635
26 3X_5X_WEIGHT-NEXT: 8: 176635
27 3X_5X_WEIGHT-NEXT: 9: 34650
28 3X_5X_WEIGHT-NEXT: 10: 146705
29 3X_5X_WEIGHT-NEXT: 11: 59530
30 3X_5X_WEIGHT-NEXT: 13: 90925 foo:97655
31 3X_5X_WEIGHT-NEXT: 15: 182290
32 3X_5X_WEIGHT-NEXT: bar:5316111:106110
33 3X_5X_WEIGHT-NEXT: 17: 106110
34 3X_5X_WEIGHT-NEXT: 18: 106110
35 3X_5X_WEIGHT-NEXT: 19: 21015
36 3X_5X_WEIGHT-NEXT: 20: 88221
37 3X_5X_WEIGHT-NEXT: 21: 36510
38 3X_5X_WEIGHT-NEXT: 23: 54450 bar:59487
39 3X_5X_WEIGHT-NEXT: 25: 109998
40
41 3- Bad merge: invalid weight
42 RUN: not llvm-profdata merge -sample -weighted-input=3,%p/Inputs/weight-sample-bar.proftext -weighted-input=0,%p/Inputs/weight-sample-foo.proftext -o %t.out 2>&1 | FileCheck %s -check-prefix=INVALID_WEIGHT
43 RUN: not llvm-profdata merge -sample -weighted-input=3,%p/Inputs/weight-sample-bar.proftext -weighted-input=0.75,%p/Inputs/weight-sample-foo.proftext -o %t.out 2>&1 | FileCheck %s -check-prefix=INVALID_WEIGHT
44 RUN: not llvm-profdata merge -sample -weighted-input=3,%p/Inputs/weight-sample-bar.proftext -weighted-input=-5,%p/Inputs/weight-sample-foo.proftext -o %t.out 2>&1 | FileCheck %s -check-prefix=INVALID_WEIGHT
45 RUN: not llvm-profdata merge -sample -weighted-input=3,%p/Inputs/weight-sample-bar.proftext -weighted-input=,%p/Inputs/weight-sample-foo.proftext -o %t.out 2>&1 | FileCheck %s -check-prefix=INVALID_WEIGHT
46 RUN: not llvm-profdata merge -sample -weighted-input=3,%p/Inputs/weight-sample-bar.proftext -weighted-input=%p/Inputs/weight-sample-foo.proftext -o %t.out 2>&1 | FileCheck %s -check-prefix=INVALID_WEIGHT
47 INVALID_WEIGHT: error: Input weight must be a positive integer.
48
49 4- Bad merge: input path does not exist
50 RUN: not llvm-profdata merge -sample -weighted-input=3,%p/Inputs/does-not-exist.proftext -weighted-input=2,%p/Inputs/does-not-exist-either.proftext -o %t.out 2>&1 | FileCheck %s -check-prefix=INVALID_INPUT
51 INVALID_INPUT: {{.*}}: {{.*}}does-not-exist.proftext: {{[Nn]}}o such file or directory
52
53 5- No inputs
54 RUN: not llvm-profdata merge -sample -o %t.out 2>&1 | FileCheck %s -check-prefix=NO_INPUT
55 NO_INPUT: {{.*}}: No input files specified. See llvm-profdata{{(\.EXE|\.exe)?}} merge -help
1111 //===----------------------------------------------------------------------===//
1212
1313 #include "llvm/ADT/SmallSet.h"
14 #include "llvm/ADT/SmallVector.h"
1415 #include "llvm/ADT/StringRef.h"
1516 #include "llvm/IR/LLVMContext.h"
1617 #include "llvm/ProfileData/InstrProfReader.h"
1819 #include "llvm/ProfileData/SampleProfReader.h"
1920 #include "llvm/ProfileData/SampleProfWriter.h"
2021 #include "llvm/Support/CommandLine.h"
22 #include "llvm/Support/Errc.h"
2123 #include "llvm/Support/FileSystem.h"
2224 #include "llvm/Support/Format.h"
2325 #include "llvm/Support/ManagedStatic.h"
2628 #include "llvm/Support/PrettyStackTrace.h"
2729 #include "llvm/Support/Signals.h"
2830 #include "llvm/Support/raw_ostream.h"
31 #include
32 #include
2933
3034 using namespace llvm;
3135
9094 }
9195 }
9296
93 static void mergeInstrProfile(const cl::list &Inputs,
97 struct WeightedFile {
98 StringRef Filename;
99 uint64_t Weight;
100
101 WeightedFile() {}
102
103 WeightedFile(StringRef F, uint64_t W) : Filename{F}, Weight{W} {}
104 };
105 typedef SmallVector WeightedFileVector;
106
107 static void mergeInstrProfile(const WeightedFileVector &Inputs,
94108 StringRef OutputFilename,
95109 ProfileFormat OutputFormat) {
96110 if (OutputFilename.compare("-") == 0)
106120
107121 InstrProfWriter Writer;
108122 SmallSet WriterErrorCodes;
109 for (const auto &Filename : Inputs) {
110 auto ReaderOrErr = InstrProfReader::create(Filename);
123 for (const auto &Input : Inputs) {
124 auto ReaderOrErr = InstrProfReader::create(Input.Filename);
111125 if (std::error_code ec = ReaderOrErr.getError())
112 exitWithErrorCode(ec, Filename);
126 exitWithErrorCode(ec, Input.Filename);
113127
114128 auto Reader = std::move(ReaderOrErr.get());
115129 for (auto &I : *Reader) {
116 if (std::error_code EC = Writer.addRecord(std::move(I))) {
130 if (std::error_code EC = Writer.addRecord(std::move(I), Input.Weight)) {
117131 // Only show hint the first time an error occurs.
118132 bool firstTime = WriterErrorCodes.insert(EC).second;
119 handleMergeWriterError(EC, Filename, I.Name, firstTime);
133 handleMergeWriterError(EC, Input.Filename, I.Name, firstTime);
120134 }
121135 }
122136 if (Reader->hasError())
123 exitWithErrorCode(Reader->getError(), Filename);
137 exitWithErrorCode(Reader->getError(), Input.Filename);
124138 }
125139 if (OutputFormat == PF_Text)
126140 Writer.writeText(Output);
132146 sampleprof::SPF_None, sampleprof::SPF_Text, sampleprof::SPF_Binary,
133147 sampleprof::SPF_GCC};
134148
135 static void mergeSampleProfile(const cl::list &Inputs,
149 static void mergeSampleProfile(const WeightedFileVector &Inputs,
136150 StringRef OutputFilename,
137151 ProfileFormat OutputFormat) {
138152 using namespace sampleprof;
144158 auto Writer = std::move(WriterOrErr.get());
145159 StringMap ProfileMap;
146160 SmallVector, 5> Readers;
147 for (const auto &Filename : Inputs) {
161 for (const auto &Input : Inputs) {
148162 auto ReaderOrErr =
149 SampleProfileReader::create(Filename, getGlobalContext());
163 SampleProfileReader::create(Input.Filename, getGlobalContext());
150164 if (std::error_code EC = ReaderOrErr.getError())
151 exitWithErrorCode(EC, Filename);
165 exitWithErrorCode(EC, Input.Filename);
152166
153167 // We need to keep the readers around until after all the files are
154168 // read so that we do not lose the function names stored in each
157171 Readers.push_back(std::move(ReaderOrErr.get()));
158172 const auto Reader = Readers.back().get();
159173 if (std::error_code EC = Reader->read())
160 exitWithErrorCode(EC, Filename);
174 exitWithErrorCode(EC, Input.Filename);
161175
162176 StringMap &Profiles = Reader->getProfiles();
163177 for (StringMap::iterator I = Profiles.begin(),
165179 I != E; ++I) {
166180 StringRef FName = I->first();
167181 FunctionSamples &Samples = I->second;
168 ProfileMap[FName].merge(Samples);
182 ProfileMap[FName].merge(Samples, Input.Weight);
169183 }
170184 }
171185 Writer->write(ProfileMap);
172186 }
173187
188 static WeightedFile parseWeightedFile(const StringRef &WeightedFilename) {
189 StringRef WeightStr, FileName;
190 std::tie(WeightStr, FileName) = WeightedFilename.split(',');
191
192 uint64_t Weight;
193 if (WeightStr.getAsInteger(10, Weight) || Weight < 1)
194 exitWithError("Input weight must be a positive integer.");
195
196 if (!sys::fs::exists(FileName))
197 exitWithErrorCode(make_error_code(errc::no_such_file_or_directory),
198 FileName);
199
200 return WeightedFile(FileName, Weight);
201 }
202
174203 static int merge_main(int argc, const char *argv[]) {
175 cl::list Inputs(cl::Positional, cl::Required, cl::OneOrMore,
176 cl::desc(""));
177
204 cl::list InputFilenames(cl::Positional,
205 cl::desc(""));
206 cl::list WeightedInputFilenames("weighted-input",
207 cl::desc(","));
178208 cl::opt OutputFilename("output", cl::value_desc("output"),
179209 cl::init("-"), cl::Required,
180210 cl::desc("Output file"));
195225
196226 cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
197227
228 if (InputFilenames.empty() && WeightedInputFilenames.empty())
229 exitWithError("No input files specified. See " +
230 sys::path::filename(argv[0]) + " -help");
231
232 WeightedFileVector WeightedInputs;
233 for (StringRef Filename : InputFilenames)
234 WeightedInputs.push_back(WeightedFile(Filename, 1));
235 for (StringRef WeightedFilename : WeightedInputFilenames)
236 WeightedInputs.push_back(parseWeightedFile(WeightedFilename));
237
198238 if (ProfileKind == instr)
199 mergeInstrProfile(Inputs, OutputFilename, OutputFormat);
239 mergeInstrProfile(WeightedInputs, OutputFilename, OutputFormat);
200240 else
201 mergeSampleProfile(Inputs, OutputFilename, OutputFormat);
241 mergeSampleProfile(WeightedInputs, OutputFilename, OutputFormat);
202242
203243 return 0;
204244 }
361361 Record1.addValueData(IPVK_IndirectCallTarget, 0, VD1, 1, nullptr);
362362
363363 Record2.reserveSites(IPVK_IndirectCallTarget, 1);
364 InstrProfValueData VD2[] = {{(uint64_t) "callee1", Max}};
364 // FIXME: Improve handling of counter overflow. ValueData asserts on overflow.
365 // InstrProfValueData VD2[] = {{(uint64_t) "callee1", Max}};
366 InstrProfValueData VD2[] = {{(uint64_t) "callee1", 1}};
365367 Record2.addValueData(IPVK_IndirectCallTarget, 0, VD2, 1, nullptr);
366368
367369 Writer.addRecord(std::move(Record1));
381383 std::unique_ptr VD =
382384 R.get().getValueForSite(IPVK_IndirectCallTarget, 0);
383385 ASSERT_EQ(StringRef("callee1"), StringRef((const char *)VD[0].Value, 7));
384 ASSERT_EQ(Max, VD[0].Count);
386
387 // FIXME: Improve handling of counter overflow. ValueData asserts on overflow.
388 // ASSERT_EQ(Max, VD[0].Count);
389 ASSERT_EQ(2U, VD[0].Count);
385390 }
386391
387392 // Synthesize runtime value profile data.
489494 ASSERT_EQ(1ULL << 63, Reader->getMaximumFunctionCount());
490495 }
491496
497 TEST_F(InstrProfTest, get_weighted_function_counts) {
498 InstrProfRecord Record1("foo", 0x1234, {1, 2});
499 InstrProfRecord Record2("foo", 0x1235, {3, 4});
500 Writer.addRecord(std::move(Record1), 3);
501 Writer.addRecord(std::move(Record2), 5);
502 auto Profile = Writer.writeBuffer();
503 readProfile(std::move(Profile));
504
505 std::vector Counts;
506 ASSERT_TRUE(NoError(Reader->getFunctionCounts("foo", 0x1234, Counts)));
507 ASSERT_EQ(2U, Counts.size());
508 ASSERT_EQ(3U, Counts[0]);
509 ASSERT_EQ(6U, Counts[1]);
510
511 ASSERT_TRUE(NoError(Reader->getFunctionCounts("foo", 0x1235, Counts)));
512 ASSERT_EQ(2U, Counts.size());
513 ASSERT_EQ(15U, Counts[0]);
514 ASSERT_EQ(20U, Counts[1]);
515 }
516
492517 } // end anonymous namespace