llvm.org GIT mirror llvm / 8061fe5
Revert "[llvm-profdata] Add support for weighted merge of profile data" This reverts commit b7250858d96b8ce567681214273ac0e62713c661. Reverting in order to investigate Windows test failure. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@254687 91177308-0d34-0410-b5e6-96231b3b80d8 Nathan Slingerland 3 years ago
13 changed file(s) with 47 addition(s) and 266 deletion(s). Raw diff Collapse all Expand all
2727 SYNOPSIS
2828 ^^^^^^^^
2929
30 :program:`llvm-profdata merge` [*options*] [*filename[:weight]...*]
30 :program:`llvm-profdata merge` [*options*] [*filenames...*]
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 The profile counts in each input file can be scaled (multiplied) by specifying
40 ``:``, where `` is a decimal integer >= 1.
41 A default weight of 1 is assumed if only `` is given.
4238
4339 OPTIONS
4440 ^^^^^^^
217217 }
218218
219219 /// Merge data from another InstrProfValueSiteRecord
220 /// Optionally scale merged counts by \p Weight.
221 void mergeValueData(InstrProfValueSiteRecord &Input, uint64_t Weight = 1) {
220 void mergeValueData(InstrProfValueSiteRecord &Input) {
222221 this->sortByTargetValues();
223222 Input.sortByTargetValues();
224223 auto I = ValueData.begin();
228227 while (I != IE && I->Value < J->Value)
229228 ++I;
230229 if (I != IE && I->Value == J->Value) {
231 // TODO: Check for counter overflow and return error if it occurs.
232 uint64_t JCount = J->Count;
233 if (Weight > 1)
234 JCount = SaturatingMultiply(JCount, Weight);
235 I->Count = SaturatingAdd(I->Count, JCount);
230 I->Count = SaturatingAdd(I->Count, J->Count);
236231 ++I;
237232 continue;
238233 }
278273 ValueMapType *HashKeys);
279274
280275 /// Merge the counts in \p Other into this one.
281 /// Optionally scale merged counts by \p Weight.
282 inline instrprof_error merge(InstrProfRecord &Other, uint64_t Weight = 1);
276 inline instrprof_error merge(InstrProfRecord &Other);
283277
284278 /// Used by InstrProfWriter: update the value strings to commoned strings in
285279 /// the writer instance.
331325 }
332326
333327 // Merge Value Profile data from Src record to this record for ValueKind.
334 // Scale merged value counts by \p Weight.
335 instrprof_error mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src,
336 uint64_t Weight) {
328 instrprof_error mergeValueProfData(uint32_t ValueKind, InstrProfRecord &Src) {
337329 uint32_t ThisNumValueSites = getNumValueSites(ValueKind);
338330 uint32_t OtherNumValueSites = Src.getNumValueSites(ValueKind);
339331 if (ThisNumValueSites != OtherNumValueSites)
343335 std::vector &OtherSiteRecords =
344336 Src.getValueSitesForKind(ValueKind);
345337 for (uint32_t I = 0; I < ThisNumValueSites; I++)
346 ThisSiteRecords[I].mergeValueData(OtherSiteRecords[I], Weight);
338 ThisSiteRecords[I].mergeValueData(OtherSiteRecords[I]);
347339 return instrprof_error::success;
348340 }
349341 };
429421 VData.Value = (uint64_t)StrTab->insertString((const char *)VData.Value);
430422 }
431423
432 instrprof_error InstrProfRecord::merge(InstrProfRecord &Other,
433 uint64_t Weight) {
424 instrprof_error InstrProfRecord::merge(InstrProfRecord &Other) {
434425 // If the number of counters doesn't match we either have bad data
435426 // or a hash collision.
436427 if (Counts.size() != Other.Counts.size())
440431
441432 for (size_t I = 0, E = Other.Counts.size(); I < E; ++I) {
442433 bool ResultOverflowed;
443 uint64_t OtherCount = Other.Counts[I];
444 if (Weight > 1) {
445 OtherCount = SaturatingMultiply(OtherCount, Weight, ResultOverflowed);
446 if (ResultOverflowed)
447 Result = instrprof_error::counter_overflow;
448 }
449 Counts[I] = SaturatingAdd(Counts[I], OtherCount, ResultOverflowed);
434 Counts[I] = SaturatingAdd(Counts[I], Other.Counts[I], ResultOverflowed);
450435 if (ResultOverflowed)
451436 Result = instrprof_error::counter_overflow;
452437 }
453438
454439 for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) {
455 instrprof_error MergeValueResult = mergeValueProfData(Kind, Other, Weight);
440 instrprof_error MergeValueResult = mergeValueProfData(Kind, Other);
456441 if (MergeValueResult != instrprof_error::success)
457442 Result = MergeValueResult;
458443 }
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. Optionally scale counts by \p Weight.
42 std::error_code addRecord(InstrProfRecord &&I, uint64_t Weight = 1);
41 /// summed.
42 std::error_code addRecord(InstrProfRecord &&I);
4343 /// Write the profile to \c OS
4444 void write(raw_fd_ostream &OS);
4545 /// Write the profile in text format to \c OS
172172 SampleRecord() : NumSamples(0), CallTargets() {}
173173
174174 /// Increment the number of samples for this record by \p S.
175 /// Optionally scale sample count \p S by \p Weight.
176175 ///
177176 /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
178177 /// around unsigned integers.
179 void addSamples(uint64_t S, uint64_t Weight = 1) {
180 if (Weight > 1)
181 S = SaturatingMultiply(S, Weight);
178 void addSamples(uint64_t S) {
182179 NumSamples = SaturatingAdd(NumSamples, S);
183180 }
184181
185182 /// Add called function \p F with samples \p S.
186 /// Optionally scale sample count \p S by \p Weight.
187183 ///
188184 /// Sample counts accumulate using saturating arithmetic, to avoid wrapping
189185 /// around unsigned integers.
190 void addCalledTarget(StringRef F, uint64_t S, uint64_t Weight = 1) {
186 void addCalledTarget(StringRef F, uint64_t S) {
191187 uint64_t &TargetSamples = CallTargets[F];
192 if (Weight > 1)
193 S = SaturatingMultiply(S, Weight);
194188 TargetSamples = SaturatingAdd(TargetSamples, S);
195189 }
196190
201195 const CallTargetMap &getCallTargets() const { return CallTargets; }
202196
203197 /// Merge the samples in \p Other into this record.
204 /// Optionally scale sample counts by \p Weight.
205 void merge(const SampleRecord &Other, uint64_t Weight = 1) {
206 addSamples(Other.getSamples(), Weight);
198 void merge(const SampleRecord &Other) {
199 addSamples(Other.getSamples());
207200 for (const auto &I : Other.getCallTargets())
208 addCalledTarget(I.first(), I.second, Weight);
201 addCalledTarget(I.first(), I.second);
209202 }
210203
211204 void print(raw_ostream &OS, unsigned Indent) const;
232225 FunctionSamples() : TotalSamples(0), TotalHeadSamples(0) {}
233226 void print(raw_ostream &OS = dbgs(), unsigned Indent = 0) const;
234227 void dump() const;
235 void addTotalSamples(uint64_t Num, uint64_t Weight = 1) {
236 if (Weight > 1)
237 Num = SaturatingMultiply(Num, Weight);
238 TotalSamples += Num;
239 }
240 void addHeadSamples(uint64_t Num, uint64_t Weight = 1) {
241 if (Weight > 1)
242 Num = SaturatingMultiply(Num, Weight);
243 TotalHeadSamples += Num;
244 }
245 void addBodySamples(uint32_t LineOffset, uint32_t Discriminator, uint64_t Num,
246 uint64_t Weight = 1) {
247 BodySamples[LineLocation(LineOffset, Discriminator)].addSamples(Num,
248 Weight);
228 void addTotalSamples(uint64_t Num) { TotalSamples += Num; }
229 void addHeadSamples(uint64_t Num) { TotalHeadSamples += Num; }
230 void addBodySamples(uint32_t LineOffset, uint32_t Discriminator,
231 uint64_t Num) {
232 BodySamples[LineLocation(LineOffset, Discriminator)].addSamples(Num);
249233 }
250234 void addCalledTargetSamples(uint32_t LineOffset, uint32_t Discriminator,
251 std::string FName, uint64_t Num,
252 uint64_t Weight = 1) {
253 BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget(
254 FName, Num, Weight);
235 std::string FName, uint64_t Num) {
236 BodySamples[LineLocation(LineOffset, Discriminator)].addCalledTarget(FName,
237 Num);
255238 }
256239
257240 /// Return the number of samples collected at the given location.
300283 }
301284
302285 /// Merge the samples in \p Other into this one.
303 /// Optionally scale samples by \p Weight.
304 void merge(const FunctionSamples &Other, uint64_t Weight = 1) {
305 addTotalSamples(Other.getTotalSamples(), Weight);
306 addHeadSamples(Other.getHeadSamples(), Weight);
286 void merge(const FunctionSamples &Other) {
287 addTotalSamples(Other.getTotalSamples());
288 addHeadSamples(Other.getHeadSamples());
307289 for (const auto &I : Other.getBodySamples()) {
308290 const LineLocation &Loc = I.first;
309291 const SampleRecord &Rec = I.second;
310 BodySamples[Loc].merge(Rec, Weight);
292 BodySamples[Loc].merge(Rec);
311293 }
312294 for (const auto &I : Other.getCallsiteSamples()) {
313295 const CallsiteLocation &Loc = I.first;
314296 const FunctionSamples &Rec = I.second;
315 functionSamplesAt(Loc).merge(Rec, Weight);
297 functionSamplesAt(Loc).merge(Rec);
316298 }
317299 }
318300
9797 I.updateStrings(&StringTable);
9898 }
9999
100 std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I,
101 uint64_t Weight) {
100 std::error_code InstrProfWriter::addRecord(InstrProfRecord &&I) {
102101 updateStringTableReferences(I);
103102 auto &ProfileDataMap = FunctionData[I.Name];
104103
113112 // We've never seen a function with this name and hash, add it.
114113 Dest = std::move(I);
115114 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 }
125115 } else {
126116 // We're updating a function we've seen before.
127 Result = Dest.merge(I, Weight);
117 Result = Dest.merge(I);
128118 }
129119
130120 // We keep track of the max function count as we go for simplicity.
test/tools/llvm-profdata/Inputs/weight-instr-bar.profdata less more
Binary diff not shown
test/tools/llvm-profdata/Inputs/weight-instr-foo.profdata less more
Binary diff not shown
+0
-8
test/tools/llvm-profdata/Inputs/weight-sample-bar.proftext less more
None 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
-8
test/tools/llvm-profdata/Inputs/weight-sample-foo.proftext less more
None 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
+0
-55
test/tools/llvm-profdata/weight-instr.test less more
None 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 %p/Inputs/weight-instr-bar.profdata:1 %p/Inputs/weight-instr-foo.profdata:1 -o %t
4 RUN: llvm-profdata show --instr -all-functions %t | FileCheck %s --check-prefix=WEIGHT1
5 WEIGHT1: Counters:
6 WEIGHT1: usage:
7 WEIGHT1: Hash: 0x0000000000000000
8 WEIGHT1: Counters: 1
9 WEIGHT1: Function count: 0
10 WEIGHT1: foo:
11 WEIGHT1: Hash: 0x000000000000028a
12 WEIGHT1: Counters: 3
13 WEIGHT1: Function count: 866988873
14 WEIGHT1: bar:
15 WEIGHT1: Hash: 0x000000000000028a
16 WEIGHT1: Counters: 3
17 WEIGHT1: Function count: 866988873
18 WEIGHT1: main:
19 WEIGHT1: Hash: 0x7d31c47ea98f8248
20 WEIGHT1: Counters: 60
21 WEIGHT1: Function count: 2
22 WEIGHT1: Functions shown: 4
23 WEIGHT1: Total functions: 4
24 WEIGHT1: Maximum function count: 866988873
25 WEIGHT1: Maximum internal block count: 267914296
26
27 2- Merge the foo and bar profiles with weight 3x and 5x respectively and verify the combined output
28 RUN: llvm-profdata merge --instr %p/Inputs/weight-instr-bar.profdata:3 %p/Inputs/weight-instr-foo.profdata:5 -o %t
29 RUN: llvm-profdata show --instr -all-functions %t | FileCheck %s --check-prefix=WEIGHT2
30 WEIGHT2: Counters:
31 WEIGHT2: usage:
32 WEIGHT2: Hash: 0x0000000000000000
33 WEIGHT2: Counters: 1
34 WEIGHT2: Function count: 0
35 WEIGHT2: foo:
36 WEIGHT2: Hash: 0x000000000000028a
37 WEIGHT2: Counters: 3
38 WEIGHT2: Function count: 4334944365
39 WEIGHT2: bar:
40 WEIGHT2: Hash: 0x000000000000028a
41 WEIGHT2: Counters: 3
42 WEIGHT2: Function count: 2600966619
43 WEIGHT2: main:
44 WEIGHT2: Hash: 0x7d31c47ea98f8248
45 WEIGHT2: Counters: 60
46 WEIGHT2: Function count: 8
47 WEIGHT2: Functions shown: 4
48 WEIGHT2: Total functions: 4
49 WEIGHT2: Maximum function count: 4334944365
50 WEIGHT2: Maximum internal block count: 1339571480
51
52 3- Bad merge: foo and bar profiles with invalid weights
53 RUN: not llvm-profdata merge --instr %p/Inputs/weight-instr-bar.profdata:3 %p/Inputs/weight-instr-foo.profdata:-5 -o %t.out 2>&1 | FileCheck %s --check-prefix=ERROR3
54 ERROR3: error: Input weight must be a positive integer.
+0
-43
test/tools/llvm-profdata/weight-sample.test less more
None 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 %p/Inputs/weight-sample-bar.proftext:1 %p/Inputs/weight-sample-foo.proftext:1 -o - | FileCheck %s --check-prefix=WEIGHT1
4 WEIGHT1: foo:1763288:35327
5 WEIGHT1: 7: 35327
6 WEIGHT1: 8: 35327
7 WEIGHT1: 9: 6930
8 WEIGHT1: 10: 29341
9 WEIGHT1: 11: 11906
10 WEIGHT1: 13: 18185 foo:19531
11 WEIGHT1: 15: 36458
12 WEIGHT1: bar:1772037:35370
13 WEIGHT1: 17: 35370
14 WEIGHT1: 18: 35370
15 WEIGHT1: 19: 7005
16 WEIGHT1: 20: 29407
17 WEIGHT1: 21: 12170
18 WEIGHT1: 23: 18150 bar:19829
19 WEIGHT1: 25: 36666
20
21 2- Merge the foo and bar profiles with weight 3x and 5x respectively and verify the combined output
22 RUN: llvm-profdata merge --sample --text %p/Inputs/weight-sample-bar.proftext:3 %p/Inputs/weight-sample-foo.proftext:5 -o - | FileCheck %s --check-prefix=WEIGHT2
23 WEIGHT2: foo:8816440:176635
24 WEIGHT2: 7: 176635
25 WEIGHT2: 8: 176635
26 WEIGHT2: 9: 34650
27 WEIGHT2: 10: 146705
28 WEIGHT2: 11: 59530
29 WEIGHT2: 13: 90925 foo:97655
30 WEIGHT2: 15: 182290
31 WEIGHT2: bar:5316111:106110
32 WEIGHT2: 17: 106110
33 WEIGHT2: 18: 106110
34 WEIGHT2: 19: 21015
35 WEIGHT2: 20: 88221
36 WEIGHT2: 21: 36510
37 WEIGHT2: 23: 54450 bar:59487
38 WEIGHT2: 25: 109998
39
40 3- Bad merge: foo and bar profiles with invalid weights
41 RUN: not llvm-profdata merge --sample --text %p/Inputs/weight-sample-bar.proftext:3 %p/Inputs/weight-sample-foo.proftext:-5 -o %t.out 2>&1 | FileCheck %s --check-prefix=ERROR3
42 ERROR3: error: Input weight must be a positive integer.
1111 //===----------------------------------------------------------------------===//
1212
1313 #include "llvm/ADT/SmallSet.h"
14 #include "llvm/ADT/SmallVector.h"
1514 #include "llvm/ADT/StringRef.h"
1615 #include "llvm/IR/LLVMContext.h"
1716 #include "llvm/ProfileData/InstrProfReader.h"
2726 #include "llvm/Support/PrettyStackTrace.h"
2827 #include "llvm/Support/Signals.h"
2928 #include "llvm/Support/raw_ostream.h"
30 #include
3129
3230 using namespace llvm;
3331
9492 }
9593 }
9694
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,
95 static void mergeInstrProfile(const cl::list &Inputs,
10896 StringRef OutputFilename,
10997 ProfileFormat OutputFormat) {
11098 if (OutputFilename.compare("-") == 0)
120108
121109 InstrProfWriter Writer;
122110 SmallSet WriterErrorCodes;
123 for (const auto &Input : Inputs) {
124 auto ReaderOrErr = InstrProfReader::create(Input.Filename);
111 for (const auto &Filename : Inputs) {
112 auto ReaderOrErr = InstrProfReader::create(Filename);
125113 if (std::error_code ec = ReaderOrErr.getError())
126 exitWithErrorCode(ec, Input.Filename);
114 exitWithErrorCode(ec, Filename);
127115
128116 auto Reader = std::move(ReaderOrErr.get());
129117 for (auto &I : *Reader) {
130 if (std::error_code EC = Writer.addRecord(std::move(I), Input.Weight)) {
118 if (std::error_code EC = Writer.addRecord(std::move(I))) {
131119 // Only show hint the first time an error occurs.
132120 bool firstTime = WriterErrorCodes.insert(EC).second;
133 handleMergeWriterError(EC, Input.Filename, I.Name, firstTime);
121 handleMergeWriterError(EC, Filename, I.Name, firstTime);
134122 }
135123 }
136124 if (Reader->hasError())
137 exitWithErrorCode(Reader->getError(), Input.Filename);
125 exitWithErrorCode(Reader->getError(), Filename);
138126 }
139127 if (OutputFormat == PF_Text)
140128 Writer.writeText(Output);
146134 sampleprof::SPF_None, sampleprof::SPF_Text, sampleprof::SPF_Binary,
147135 sampleprof::SPF_GCC};
148136
149 static void mergeSampleProfile(const WeightedFileVector &Inputs,
137 static void mergeSampleProfile(const cl::list &Inputs,
150138 StringRef OutputFilename,
151139 ProfileFormat OutputFormat) {
152140 using namespace sampleprof;
158146 auto Writer = std::move(WriterOrErr.get());
159147 StringMap ProfileMap;
160148 SmallVector, 5> Readers;
161 for (const auto &Input : Inputs) {
149 for (const auto &Filename : Inputs) {
162150 auto ReaderOrErr =
163 SampleProfileReader::create(Input.Filename, getGlobalContext());
151 SampleProfileReader::create(Filename, getGlobalContext());
164152 if (std::error_code EC = ReaderOrErr.getError())
165 exitWithErrorCode(EC, Input.Filename);
153 exitWithErrorCode(EC, Filename);
166154
167155 // We need to keep the readers around until after all the files are
168156 // read so that we do not lose the function names stored in each
171159 Readers.push_back(std::move(ReaderOrErr.get()));
172160 const auto Reader = Readers.back().get();
173161 if (std::error_code EC = Reader->read())
174 exitWithErrorCode(EC, Input.Filename);
162 exitWithErrorCode(EC, Filename);
175163
176164 StringMap &Profiles = Reader->getProfiles();
177165 for (StringMap::iterator I = Profiles.begin(),
179167 I != E; ++I) {
180168 StringRef FName = I->first();
181169 FunctionSamples &Samples = I->second;
182 ProfileMap[FName].merge(Samples, Input.Weight);
170 ProfileMap[FName].merge(Samples);
183171 }
184172 }
185173 Writer->write(ProfileMap);
186 }
187
188 static void parseInputFiles(const cl::list &Inputs,
189 WeightedFileVector &WeightedInputs) {
190 WeightedInputs.reserve(Inputs.size());
191
192 for (StringRef Input : Inputs) {
193 StringRef FileName;
194 StringRef WeightStr;
195 std::tie(FileName, WeightStr) = Input.rsplit(':');
196 if (WeightStr.empty() || sys::fs::exists(Input)) {
197 // No weight specified or valid path containing delimiter.
198 WeightedInputs.push_back(WeightedFile(Input, 1));
199 } else {
200 // Input weight specified.
201 uint64_t Weight;
202 if (WeightStr.getAsInteger(10, Weight) || Weight < 1) {
203 // Invalid input weight.
204 exitWithError("Input weight must be a positive integer.");
205 }
206 WeightedInputs.push_back(WeightedFile(FileName, Weight));
207 }
208 }
209174 }
210175
211176 static int merge_main(int argc, const char *argv[]) {
212177 cl::list Inputs(cl::Positional, cl::Required, cl::OneOrMore,
213 cl::desc("[:weight]...>"));
178 cl::desc("s...>"));
214179
215180 cl::opt OutputFilename("output", cl::value_desc("output"),
216181 cl::init("-"), cl::Required,
232197
233198 cl::ParseCommandLineOptions(argc, argv, "LLVM profile data merger\n");
234199
235 WeightedFileVector WeightedInputs;
236 parseInputFiles(Inputs, WeightedInputs);
237
238200 if (ProfileKind == instr)
239 mergeInstrProfile(WeightedInputs, OutputFilename, OutputFormat);
201 mergeInstrProfile(Inputs, OutputFilename, OutputFormat);
240202 else
241 mergeSampleProfile(WeightedInputs, OutputFilename, OutputFormat);
203 mergeSampleProfile(Inputs, OutputFilename, OutputFormat);
242204
243205 return 0;
244206 }
489489 ASSERT_EQ(1ULL << 63, Reader->getMaximumFunctionCount());
490490 }
491491
492 TEST_F(InstrProfTest, get_weighted_function_counts) {
493 InstrProfRecord Record1("foo", 0x1234, {1, 2});
494 InstrProfRecord Record2("foo", 0x1235, {3, 4});
495 Writer.addRecord(std::move(Record1), 3);
496 Writer.addRecord(std::move(Record2), 5);
497 auto Profile = Writer.writeBuffer();
498 readProfile(std::move(Profile));
499
500 std::vector Counts;
501 ASSERT_TRUE(NoError(Reader->getFunctionCounts("foo", 0x1234, Counts)));
502 ASSERT_EQ(2U, Counts.size());
503 ASSERT_EQ(3U, Counts[0]);
504 ASSERT_EQ(6U, Counts[1]);
505
506 ASSERT_TRUE(NoError(Reader->getFunctionCounts("foo", 0x1235, Counts)));
507 ASSERT_EQ(2U, Counts.size());
508 ASSERT_EQ(15U, Counts[0]);
509 ASSERT_EQ(20U, Counts[1]);
510 }
511
512492 } // end anonymous namespace