1 //===- unittest/ProfileData/SampleProfTest.cpp ------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "llvm/ProfileData/SampleProf.h"
11 #include "llvm/ADT/StringMap.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/IR/LLVMContext.h"
14 #include "llvm/IR/Metadata.h"
15 #include "llvm/IR/Module.h"
16 #include "llvm/ProfileData/SampleProfReader.h"
17 #include "llvm/ProfileData/SampleProfWriter.h"
18 #include "llvm/Support/Casting.h"
19 #include "llvm/Support/ErrorOr.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include "llvm/Support/raw_ostream.h"
22 #include "gtest/gtest.h"
27 using namespace sampleprof
;
29 static ::testing::AssertionResult
NoError(std::error_code EC
) {
31 return ::testing::AssertionSuccess();
32 return ::testing::AssertionFailure() << "error " << EC
.value() << ": "
38 struct SampleProfTest
: ::testing::Test
{
40 std::unique_ptr
<SampleProfileWriter
> Writer
;
41 std::unique_ptr
<SampleProfileReader
> Reader
;
43 SampleProfTest() : Writer(), Reader() {}
45 void createWriter(SampleProfileFormat Format
, StringRef Profile
) {
47 std::unique_ptr
<raw_ostream
> OS(
48 new raw_fd_ostream(Profile
, EC
, sys::fs::F_None
));
49 auto WriterOrErr
= SampleProfileWriter::create(OS
, Format
);
50 ASSERT_TRUE(NoError(WriterOrErr
.getError()));
51 Writer
= std::move(WriterOrErr
.get());
54 void readProfile(const Module
&M
, StringRef Profile
) {
55 auto ReaderOrErr
= SampleProfileReader::create(Profile
, Context
);
56 ASSERT_TRUE(NoError(ReaderOrErr
.getError()));
57 Reader
= std::move(ReaderOrErr
.get());
58 Reader
->collectFuncsToUse(M
);
61 void testRoundTrip(SampleProfileFormat Format
) {
62 SmallVector
<char, 128> ProfilePath
;
63 ASSERT_TRUE(NoError(llvm::sys::fs::createTemporaryFile("profile", "", ProfilePath
)));
64 StringRef
Profile(ProfilePath
.data(), ProfilePath
.size());
65 createWriter(Format
, Profile
);
67 StringRef
FooName("_Z3fooi");
68 FunctionSamples FooSamples
;
69 FooSamples
.setName(FooName
);
70 FooSamples
.addTotalSamples(7711);
71 FooSamples
.addHeadSamples(610);
72 FooSamples
.addBodySamples(1, 0, 610);
73 FooSamples
.addBodySamples(2, 0, 600);
74 FooSamples
.addBodySamples(4, 0, 60000);
75 FooSamples
.addBodySamples(8, 0, 60351);
76 FooSamples
.addBodySamples(10, 0, 605);
78 StringRef
BarName("_Z3bari");
79 FunctionSamples BarSamples
;
80 BarSamples
.setName(BarName
);
81 BarSamples
.addTotalSamples(20301);
82 BarSamples
.addHeadSamples(1437);
83 BarSamples
.addBodySamples(1, 0, 1437);
84 // Test how reader/writer handles unmangled names.
85 StringRef
MconstructName("_M_construct<char *>");
86 StringRef
StringviewName("string_view<std::allocator<char> >");
87 BarSamples
.addCalledTargetSamples(1, 0, MconstructName
, 1000);
88 BarSamples
.addCalledTargetSamples(1, 0, StringviewName
, 437);
90 Module
M("my_module", Context
);
91 FunctionType
*fn_type
=
92 FunctionType::get(Type::getVoidTy(Context
), {}, false);
93 M
.getOrInsertFunction(FooName
, fn_type
);
94 M
.getOrInsertFunction(BarName
, fn_type
);
96 StringMap
<FunctionSamples
> Profiles
;
97 Profiles
[FooName
] = std::move(FooSamples
);
98 Profiles
[BarName
] = std::move(BarSamples
);
101 EC
= Writer
->write(Profiles
);
102 ASSERT_TRUE(NoError(EC
));
104 Writer
->getOutputStream().flush();
106 readProfile(M
, Profile
);
109 ASSERT_TRUE(NoError(EC
));
111 StringMap
<FunctionSamples
> &ReadProfiles
= Reader
->getProfiles();
112 ASSERT_EQ(2u, ReadProfiles
.size());
115 StringRef FooRep
= getRepInFormat(FooName
, Format
, FooGUID
);
116 FunctionSamples
&ReadFooSamples
= ReadProfiles
[FooRep
];
117 ASSERT_EQ(7711u, ReadFooSamples
.getTotalSamples());
118 ASSERT_EQ(610u, ReadFooSamples
.getHeadSamples());
121 StringRef BarRep
= getRepInFormat(BarName
, Format
, BarGUID
);
122 FunctionSamples
&ReadBarSamples
= ReadProfiles
[BarRep
];
123 ASSERT_EQ(20301u, ReadBarSamples
.getTotalSamples());
124 ASSERT_EQ(1437u, ReadBarSamples
.getHeadSamples());
125 ErrorOr
<SampleRecord::CallTargetMap
> CTMap
=
126 ReadBarSamples
.findCallTargetMapAt(1, 0);
127 ASSERT_FALSE(CTMap
.getError());
129 std::string MconstructGUID
;
130 StringRef MconstructRep
=
131 getRepInFormat(MconstructName
, Format
, MconstructGUID
);
132 std::string StringviewGUID
;
133 StringRef StringviewRep
=
134 getRepInFormat(StringviewName
, Format
, StringviewGUID
);
135 ASSERT_EQ(1000u, CTMap
.get()[MconstructRep
]);
136 ASSERT_EQ(437u, CTMap
.get()[StringviewRep
]);
138 auto VerifySummary
= [](ProfileSummary
&Summary
) mutable {
139 ASSERT_EQ(ProfileSummary::PSK_Sample
, Summary
.getKind());
140 ASSERT_EQ(123603u, Summary
.getTotalCount());
141 ASSERT_EQ(6u, Summary
.getNumCounts());
142 ASSERT_EQ(2u, Summary
.getNumFunctions());
143 ASSERT_EQ(1437u, Summary
.getMaxFunctionCount());
144 ASSERT_EQ(60351u, Summary
.getMaxCount());
146 uint32_t Cutoff
= 800000;
147 auto Predicate
= [&Cutoff
](const ProfileSummaryEntry
&PE
) {
148 return PE
.Cutoff
== Cutoff
;
150 std::vector
<ProfileSummaryEntry
> &Details
= Summary
.getDetailedSummary();
151 auto EightyPerc
= find_if(Details
, Predicate
);
153 auto NinetyPerc
= find_if(Details
, Predicate
);
155 auto NinetyFivePerc
= find_if(Details
, Predicate
);
157 auto NinetyNinePerc
= find_if(Details
, Predicate
);
158 ASSERT_EQ(60000u, EightyPerc
->MinCount
);
159 ASSERT_EQ(60000u, NinetyPerc
->MinCount
);
160 ASSERT_EQ(60000u, NinetyFivePerc
->MinCount
);
161 ASSERT_EQ(610u, NinetyNinePerc
->MinCount
);
164 ProfileSummary
&Summary
= Reader
->getSummary();
165 VerifySummary(Summary
);
167 // Test that conversion of summary to and from Metadata works.
168 Metadata
*MD
= Summary
.getMD(Context
);
170 ProfileSummary
*PS
= ProfileSummary::getFromMD(MD
);
175 // Test that summary can be attached to and read back from module.
176 M
.setProfileSummary(MD
);
177 MD
= M
.getProfileSummary();
179 PS
= ProfileSummary::getFromMD(MD
);
186 TEST_F(SampleProfTest
, roundtrip_text_profile
) {
187 testRoundTrip(SampleProfileFormat::SPF_Text
);
190 TEST_F(SampleProfTest
, roundtrip_raw_binary_profile
) {
191 testRoundTrip(SampleProfileFormat::SPF_Binary
);
194 TEST_F(SampleProfTest
, roundtrip_compact_binary_profile
) {
195 testRoundTrip(SampleProfileFormat::SPF_Compact_Binary
);
198 TEST_F(SampleProfTest
, sample_overflow_saturation
) {
199 const uint64_t Max
= std::numeric_limits
<uint64_t>::max();
200 sampleprof_error Result
;
202 StringRef
FooName("_Z3fooi");
203 FunctionSamples FooSamples
;
204 Result
= FooSamples
.addTotalSamples(1);
205 ASSERT_EQ(Result
, sampleprof_error::success
);
207 Result
= FooSamples
.addHeadSamples(1);
208 ASSERT_EQ(Result
, sampleprof_error::success
);
210 Result
= FooSamples
.addBodySamples(10, 0, 1);
211 ASSERT_EQ(Result
, sampleprof_error::success
);
213 Result
= FooSamples
.addTotalSamples(Max
);
214 ASSERT_EQ(Result
, sampleprof_error::counter_overflow
);
215 ASSERT_EQ(FooSamples
.getTotalSamples(), Max
);
217 Result
= FooSamples
.addHeadSamples(Max
);
218 ASSERT_EQ(Result
, sampleprof_error::counter_overflow
);
219 ASSERT_EQ(FooSamples
.getHeadSamples(), Max
);
221 Result
= FooSamples
.addBodySamples(10, 0, Max
);
222 ASSERT_EQ(Result
, sampleprof_error::counter_overflow
);
223 ErrorOr
<uint64_t> BodySamples
= FooSamples
.findSamplesAt(10, 0);
224 ASSERT_FALSE(BodySamples
.getError());
225 ASSERT_EQ(BodySamples
.get(), Max
);
228 } // end anonymous namespace