15354a8aaSEugene Zelenko //===- unittest/ProfileData/SampleProfTest.cpp ------------------*- C++ -*-===//
251abea74SNathan Slingerland //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
651abea74SNathan Slingerland //
751abea74SNathan Slingerland //===----------------------------------------------------------------------===//
851abea74SNathan Slingerland
99a67b073SChandler Carruth #include "llvm/ProfileData/SampleProf.h"
105354a8aaSEugene Zelenko #include "llvm/ADT/StringMap.h"
115354a8aaSEugene Zelenko #include "llvm/ADT/StringRef.h"
126745ffe4SRong Xu #include "llvm/IR/DebugInfoMetadata.h"
135354a8aaSEugene Zelenko #include "llvm/IR/LLVMContext.h"
147c4f25d2SEaswaran Raman #include "llvm/IR/Metadata.h"
155354a8aaSEugene Zelenko #include "llvm/IR/Module.h"
1651abea74SNathan Slingerland #include "llvm/ProfileData/SampleProfReader.h"
1751abea74SNathan Slingerland #include "llvm/ProfileData/SampleProfWriter.h"
185354a8aaSEugene Zelenko #include "llvm/Support/Casting.h"
195354a8aaSEugene Zelenko #include "llvm/Support/ErrorOr.h"
20af450eabSReid Kleckner #include "llvm/Support/FileSystem.h"
215354a8aaSEugene Zelenko #include "llvm/Support/MemoryBuffer.h"
225354a8aaSEugene Zelenko #include "llvm/Support/raw_ostream.h"
23fad75598SSergej Jaskiewicz #include "llvm/Testing/Support/SupportHelpers.h"
2451abea74SNathan Slingerland #include "gtest/gtest.h"
255354a8aaSEugene Zelenko #include <string>
265354a8aaSEugene Zelenko #include <vector>
2751abea74SNathan Slingerland
2851abea74SNathan Slingerland using namespace llvm;
2951abea74SNathan Slingerland using namespace sampleprof;
3051abea74SNathan Slingerland
31fad75598SSergej Jaskiewicz using llvm::unittest::TempFile;
32fad75598SSergej Jaskiewicz
NoError(std::error_code EC)3351abea74SNathan Slingerland static ::testing::AssertionResult NoError(std::error_code EC) {
3451abea74SNathan Slingerland if (!EC)
3551abea74SNathan Slingerland return ::testing::AssertionSuccess();
3651abea74SNathan Slingerland return ::testing::AssertionFailure() << "error " << EC.value() << ": "
3751abea74SNathan Slingerland << EC.message();
3851abea74SNathan Slingerland }
3951abea74SNathan Slingerland
4051abea74SNathan Slingerland namespace {
4151abea74SNathan Slingerland
4251abea74SNathan Slingerland struct SampleProfTest : ::testing::Test {
4303b42e41SMehdi Amini LLVMContext Context;
4451abea74SNathan Slingerland std::unique_ptr<SampleProfileWriter> Writer;
4551abea74SNathan Slingerland std::unique_ptr<SampleProfileReader> Reader;
4667f57c67SWei Mi
SampleProfTest__anon99df410f0111::SampleProfTest4767f57c67SWei Mi SampleProfTest() : Writer(), Reader() {}
4867f57c67SWei Mi
createWriter__anon99df410f0111::SampleProfTest49a195de86SAlexander Kornienko void createWriter(SampleProfileFormat Format, StringRef Profile) {
506a14325dSWei Mi std::error_code EC;
5167f57c67SWei Mi std::unique_ptr<raw_ostream> OS(
52d9b948b6SFangrui Song new raw_fd_ostream(Profile, EC, sys::fs::OF_None));
5351abea74SNathan Slingerland auto WriterOrErr = SampleProfileWriter::create(OS, Format);
5451abea74SNathan Slingerland ASSERT_TRUE(NoError(WriterOrErr.getError()));
5551abea74SNathan Slingerland Writer = std::move(WriterOrErr.get());
5651abea74SNathan Slingerland }
5751abea74SNathan Slingerland
readProfile__anon99df410f0111::SampleProfTest588c8ec1f6SWei Mi void readProfile(const Module &M, StringRef Profile,
598c8ec1f6SWei Mi StringRef RemapFile = "") {
60adcd0268SBenjamin Kramer auto ReaderOrErr = SampleProfileReader::create(
618d581857SRong Xu std::string(Profile), Context, FSDiscriminatorPass::Base,
628d581857SRong Xu std::string(RemapFile));
6351abea74SNathan Slingerland ASSERT_TRUE(NoError(ReaderOrErr.getError()));
6451abea74SNathan Slingerland Reader = std::move(ReaderOrErr.get());
65ee35784aSWei Mi Reader->setModule(&M);
6651abea74SNathan Slingerland }
6751abea74SNathan Slingerland
createRemapFile__anon99df410f0111::SampleProfTest68fad75598SSergej Jaskiewicz TempFile createRemapFile() {
69fad75598SSergej Jaskiewicz return TempFile("remapfile", "", R"(
708c8ec1f6SWei Mi # Types 'int' and 'long' are equivalent
718c8ec1f6SWei Mi type i l
728c8ec1f6SWei Mi # Function names 'foo' and 'faux' are equivalent
738c8ec1f6SWei Mi name 3foo 4faux
74fad75598SSergej Jaskiewicz )",
75fad75598SSergej Jaskiewicz /*Unique*/ true);
768c8ec1f6SWei Mi }
778c8ec1f6SWei Mi
7810b57ca6SWei Mi // Verify profile summary is consistent in the roundtrip to and from
7910b57ca6SWei Mi // Metadata. \p AddPartialField is to choose whether the Metadata
8010b57ca6SWei Mi // contains the IsPartialProfile field which is optional.
verifyProfileSummary__anon99df410f0111::SampleProfTest8110b57ca6SWei Mi void verifyProfileSummary(ProfileSummary &Summary, Module &M,
82b5c59d77SHiroshi Yamauchi const bool AddPartialField,
83b5c59d77SHiroshi Yamauchi const bool AddPartialProfileRatioField) {
8410b57ca6SWei Mi LLVMContext &Context = M.getContext();
8510b57ca6SWei Mi const bool IsPartialProfile = Summary.isPartialProfile();
86b5c59d77SHiroshi Yamauchi const double PartialProfileRatio = Summary.getPartialProfileRatio();
87b5c59d77SHiroshi Yamauchi auto VerifySummary = [IsPartialProfile, PartialProfileRatio](
88b5c59d77SHiroshi Yamauchi ProfileSummary &Summary) mutable {
8910b57ca6SWei Mi ASSERT_EQ(ProfileSummary::PSK_Sample, Summary.getKind());
90c67ccf5fSWei Mi ASSERT_EQ(138211u, Summary.getTotalCount());
91c67ccf5fSWei Mi ASSERT_EQ(10u, Summary.getNumCounts());
9210b57ca6SWei Mi ASSERT_EQ(4u, Summary.getNumFunctions());
9310b57ca6SWei Mi ASSERT_EQ(1437u, Summary.getMaxFunctionCount());
9410b57ca6SWei Mi ASSERT_EQ(60351u, Summary.getMaxCount());
9510b57ca6SWei Mi ASSERT_EQ(IsPartialProfile, Summary.isPartialProfile());
96b5c59d77SHiroshi Yamauchi ASSERT_EQ(PartialProfileRatio, Summary.getPartialProfileRatio());
9710b57ca6SWei Mi
9810b57ca6SWei Mi uint32_t Cutoff = 800000;
9910b57ca6SWei Mi auto Predicate = [&Cutoff](const ProfileSummaryEntry &PE) {
10010b57ca6SWei Mi return PE.Cutoff == Cutoff;
10110b57ca6SWei Mi };
102*d6790a0aSMircea Trofin const std::vector<ProfileSummaryEntry> &Details =
103*d6790a0aSMircea Trofin Summary.getDetailedSummary();
10410b57ca6SWei Mi auto EightyPerc = find_if(Details, Predicate);
10510b57ca6SWei Mi Cutoff = 900000;
10610b57ca6SWei Mi auto NinetyPerc = find_if(Details, Predicate);
10710b57ca6SWei Mi Cutoff = 950000;
10810b57ca6SWei Mi auto NinetyFivePerc = find_if(Details, Predicate);
10910b57ca6SWei Mi Cutoff = 990000;
11010b57ca6SWei Mi auto NinetyNinePerc = find_if(Details, Predicate);
11110b57ca6SWei Mi ASSERT_EQ(60000u, EightyPerc->MinCount);
11210b57ca6SWei Mi ASSERT_EQ(12557u, NinetyPerc->MinCount);
11310b57ca6SWei Mi ASSERT_EQ(12557u, NinetyFivePerc->MinCount);
114c67ccf5fSWei Mi ASSERT_EQ(600u, NinetyNinePerc->MinCount);
11510b57ca6SWei Mi };
11610b57ca6SWei Mi VerifySummary(Summary);
11710b57ca6SWei Mi
11810b57ca6SWei Mi // Test that conversion of summary to and from Metadata works.
119b5c59d77SHiroshi Yamauchi Metadata *MD =
120b5c59d77SHiroshi Yamauchi Summary.getMD(Context, AddPartialField, AddPartialProfileRatioField);
12110b57ca6SWei Mi ASSERT_TRUE(MD);
12210b57ca6SWei Mi ProfileSummary *PS = ProfileSummary::getFromMD(MD);
12310b57ca6SWei Mi ASSERT_TRUE(PS);
12410b57ca6SWei Mi VerifySummary(*PS);
12510b57ca6SWei Mi delete PS;
12610b57ca6SWei Mi
12710b57ca6SWei Mi // Test that summary can be attached to and read back from module.
12810b57ca6SWei Mi M.eraseNamedMetadata(M.getOrInsertModuleFlagsMetadata());
12910b57ca6SWei Mi M.setProfileSummary(MD, ProfileSummary::PSK_Sample);
13010b57ca6SWei Mi MD = M.getProfileSummary(/* IsCS */ false);
13110b57ca6SWei Mi ASSERT_TRUE(MD);
13210b57ca6SWei Mi PS = ProfileSummary::getFromMD(MD);
13310b57ca6SWei Mi ASSERT_TRUE(PS);
13410b57ca6SWei Mi VerifySummary(*PS);
13510b57ca6SWei Mi delete PS;
13610b57ca6SWei Mi }
13710b57ca6SWei Mi
testRoundTrip__anon99df410f0111::SampleProfTest138ebad6788SWei Mi void testRoundTrip(SampleProfileFormat Format, bool Remap, bool UseMD5) {
139fad75598SSergej Jaskiewicz TempFile ProfileFile("profile", "", "", /*Unique*/ true);
140fad75598SSergej Jaskiewicz createWriter(Format, ProfileFile.path());
141ebad6788SWei Mi if (Format == SampleProfileFormat::SPF_Ext_Binary && UseMD5)
142ebad6788SWei Mi static_cast<SampleProfileWriterExtBinary *>(Writer.get())->setUseMD5();
14351abea74SNathan Slingerland
14451abea74SNathan Slingerland StringRef FooName("_Z3fooi");
14551abea74SNathan Slingerland FunctionSamples FooSamples;
14657d1dda5SDehao Chen FooSamples.setName(FooName);
14751abea74SNathan Slingerland FooSamples.addTotalSamples(7711);
14851abea74SNathan Slingerland FooSamples.addHeadSamples(610);
14951abea74SNathan Slingerland FooSamples.addBodySamples(1, 0, 610);
15040ee23dbSEaswaran Raman FooSamples.addBodySamples(2, 0, 600);
15140ee23dbSEaswaran Raman FooSamples.addBodySamples(4, 0, 60000);
15240ee23dbSEaswaran Raman FooSamples.addBodySamples(8, 0, 60351);
15340ee23dbSEaswaran Raman FooSamples.addBodySamples(10, 0, 605);
15451abea74SNathan Slingerland
155c67ccf5fSWei Mi // Add inline instance with name "_Z3gooi".
156c67ccf5fSWei Mi StringRef GooName("_Z3gooi");
157c67ccf5fSWei Mi auto &GooSamples =
158c67ccf5fSWei Mi FooSamples.functionSamplesAt(LineLocation(7, 0))[GooName.str()];
159c67ccf5fSWei Mi GooSamples.setName(GooName);
160c67ccf5fSWei Mi GooSamples.addTotalSamples(502);
161c67ccf5fSWei Mi GooSamples.addBodySamples(3, 0, 502);
162c67ccf5fSWei Mi
163c67ccf5fSWei Mi // Add inline instance with name "_Z3hooi".
164c67ccf5fSWei Mi StringRef HooName("_Z3hooi");
165c67ccf5fSWei Mi auto &HooSamples =
166c67ccf5fSWei Mi GooSamples.functionSamplesAt(LineLocation(9, 0))[HooName.str()];
167c67ccf5fSWei Mi HooSamples.setName(HooName);
168c67ccf5fSWei Mi HooSamples.addTotalSamples(317);
169c67ccf5fSWei Mi HooSamples.addBodySamples(4, 0, 317);
170c67ccf5fSWei Mi
17151abea74SNathan Slingerland StringRef BarName("_Z3bari");
17251abea74SNathan Slingerland FunctionSamples BarSamples;
17357d1dda5SDehao Chen BarSamples.setName(BarName);
17451abea74SNathan Slingerland BarSamples.addTotalSamples(20301);
17551abea74SNathan Slingerland BarSamples.addHeadSamples(1437);
17651abea74SNathan Slingerland BarSamples.addBodySamples(1, 0, 1437);
177a0c0857eSWei Mi // Test how reader/writer handles unmangled names.
178a0c0857eSWei Mi StringRef MconstructName("_M_construct<char *>");
179a0c0857eSWei Mi StringRef StringviewName("string_view<std::allocator<char> >");
180a0c0857eSWei Mi BarSamples.addCalledTargetSamples(1, 0, MconstructName, 1000);
181a0c0857eSWei Mi BarSamples.addCalledTargetSamples(1, 0, StringviewName, 437);
18251abea74SNathan Slingerland
18309dcfe68SWei Mi StringRef BazName("_Z3bazi");
18409dcfe68SWei Mi FunctionSamples BazSamples;
18509dcfe68SWei Mi BazSamples.setName(BazName);
18609dcfe68SWei Mi BazSamples.addTotalSamples(12557);
18709dcfe68SWei Mi BazSamples.addHeadSamples(1257);
18809dcfe68SWei Mi BazSamples.addBodySamples(1, 0, 12557);
18909dcfe68SWei Mi
1908c8ec1f6SWei Mi StringRef BooName("_Z3booi");
1918c8ec1f6SWei Mi FunctionSamples BooSamples;
1928c8ec1f6SWei Mi BooSamples.setName(BooName);
1938c8ec1f6SWei Mi BooSamples.addTotalSamples(1232);
1948c8ec1f6SWei Mi BooSamples.addHeadSamples(1);
1958c8ec1f6SWei Mi BooSamples.addBodySamples(1, 0, 1232);
1966a14325dSWei Mi
197b9db7036SHongtao Yu SampleProfileMap Profiles;
19851abea74SNathan Slingerland Profiles[FooName] = std::move(FooSamples);
19951abea74SNathan Slingerland Profiles[BarName] = std::move(BarSamples);
20009dcfe68SWei Mi Profiles[BazName] = std::move(BazSamples);
2018c8ec1f6SWei Mi Profiles[BooName] = std::move(BooSamples);
2028c8ec1f6SWei Mi
2038c8ec1f6SWei Mi Module M("my_module", Context);
2048c8ec1f6SWei Mi FunctionType *fn_type =
2058c8ec1f6SWei Mi FunctionType::get(Type::getVoidTy(Context), {}, false);
2068c8ec1f6SWei Mi
207fad75598SSergej Jaskiewicz TempFile RemapFile(createRemapFile());
2088c8ec1f6SWei Mi if (Remap) {
2098c8ec1f6SWei Mi FooName = "_Z4fauxi";
2108c8ec1f6SWei Mi BarName = "_Z3barl";
211c67ccf5fSWei Mi GooName = "_Z3gool";
212c67ccf5fSWei Mi HooName = "_Z3hool";
2138c8ec1f6SWei Mi }
2148c8ec1f6SWei Mi
2158c8ec1f6SWei Mi M.getOrInsertFunction(FooName, fn_type);
2168c8ec1f6SWei Mi M.getOrInsertFunction(BarName, fn_type);
2178c8ec1f6SWei Mi M.getOrInsertFunction(BooName, fn_type);
21851abea74SNathan Slingerland
219798e59b8SWei Mi ProfileSymbolList List;
220798e59b8SWei Mi if (Format == SampleProfileFormat::SPF_Ext_Binary) {
221798e59b8SWei Mi List.add("zoo", true);
222798e59b8SWei Mi List.add("moo", true);
223798e59b8SWei Mi }
224798e59b8SWei Mi Writer->setProfileSymbolList(&List);
225798e59b8SWei Mi
22651abea74SNathan Slingerland std::error_code EC;
22751abea74SNathan Slingerland EC = Writer->write(Profiles);
22851abea74SNathan Slingerland ASSERT_TRUE(NoError(EC));
22951abea74SNathan Slingerland
23051abea74SNathan Slingerland Writer->getOutputStream().flush();
23151abea74SNathan Slingerland
232fad75598SSergej Jaskiewicz readProfile(M, ProfileFile.path(), RemapFile.path());
23351abea74SNathan Slingerland EC = Reader->read();
23451abea74SNathan Slingerland ASSERT_TRUE(NoError(EC));
23551abea74SNathan Slingerland
236798e59b8SWei Mi if (Format == SampleProfileFormat::SPF_Ext_Binary) {
237798e59b8SWei Mi std::unique_ptr<ProfileSymbolList> ReaderList =
238798e59b8SWei Mi Reader->getProfileSymbolList();
239798e59b8SWei Mi ReaderList->contains("zoo");
240798e59b8SWei Mi ReaderList->contains("moo");
241798e59b8SWei Mi }
242798e59b8SWei Mi
24328436358SRichard Smith FunctionSamples *ReadFooSamples = Reader->getSamplesFor(FooName);
24428436358SRichard Smith ASSERT_TRUE(ReadFooSamples != nullptr);
245ebad6788SWei Mi if (!UseMD5) {
2460b832095SRichard Smith ASSERT_EQ("_Z3fooi", ReadFooSamples->getName());
24784980f42SSimon Pilgrim }
24828436358SRichard Smith ASSERT_EQ(7711u, ReadFooSamples->getTotalSamples());
24928436358SRichard Smith ASSERT_EQ(610u, ReadFooSamples->getHeadSamples());
25028436358SRichard Smith
251c67ccf5fSWei Mi // Try to find a FunctionSamples with GooName at given callsites containing
252c67ccf5fSWei Mi // inline instance for GooName. Test the correct FunctionSamples can be
253c67ccf5fSWei Mi // found with Remapper support.
254c67ccf5fSWei Mi const FunctionSamples *ReadGooSamples =
255c67ccf5fSWei Mi ReadFooSamples->findFunctionSamplesAt(LineLocation(7, 0), GooName,
256c67ccf5fSWei Mi Reader->getRemapper());
257c67ccf5fSWei Mi ASSERT_TRUE(ReadGooSamples != nullptr);
258c67ccf5fSWei Mi ASSERT_EQ(502u, ReadGooSamples->getTotalSamples());
259c67ccf5fSWei Mi
260c67ccf5fSWei Mi // Try to find a FunctionSamples with GooName at given callsites containing
261c67ccf5fSWei Mi // no inline instance for GooName. Test no FunctionSamples will be
262c67ccf5fSWei Mi // found with Remapper support.
263c67ccf5fSWei Mi const FunctionSamples *ReadGooSamplesAgain =
264c67ccf5fSWei Mi ReadFooSamples->findFunctionSamplesAt(LineLocation(9, 0), GooName,
265c67ccf5fSWei Mi Reader->getRemapper());
266c67ccf5fSWei Mi ASSERT_TRUE(ReadGooSamplesAgain == nullptr);
267c67ccf5fSWei Mi
268c67ccf5fSWei Mi // The inline instance of Hoo is inside of the inline instance of Goo.
269c67ccf5fSWei Mi // Try to find a FunctionSamples with HooName at given callsites containing
270c67ccf5fSWei Mi // inline instance for HooName. Test the correct FunctionSamples can be
271c67ccf5fSWei Mi // found with Remapper support.
272c67ccf5fSWei Mi const FunctionSamples *ReadHooSamples =
273c67ccf5fSWei Mi ReadGooSamples->findFunctionSamplesAt(LineLocation(9, 0), HooName,
274c67ccf5fSWei Mi Reader->getRemapper());
275c67ccf5fSWei Mi ASSERT_TRUE(ReadHooSamples != nullptr);
276c67ccf5fSWei Mi ASSERT_EQ(317u, ReadHooSamples->getTotalSamples());
277c67ccf5fSWei Mi
27828436358SRichard Smith FunctionSamples *ReadBarSamples = Reader->getSamplesFor(BarName);
27928436358SRichard Smith ASSERT_TRUE(ReadBarSamples != nullptr);
280ebad6788SWei Mi if (!UseMD5) {
2810b832095SRichard Smith ASSERT_EQ("_Z3bari", ReadBarSamples->getName());
28284980f42SSimon Pilgrim }
28328436358SRichard Smith ASSERT_EQ(20301u, ReadBarSamples->getTotalSamples());
28428436358SRichard Smith ASSERT_EQ(1437u, ReadBarSamples->getHeadSamples());
285984ab0f1SWei Mi ErrorOr<SampleRecord::CallTargetMap> CTMap =
28628436358SRichard Smith ReadBarSamples->findCallTargetMapAt(1, 0);
287984ab0f1SWei Mi ASSERT_FALSE(CTMap.getError());
288a0c0857eSWei Mi
28909dcfe68SWei Mi // Because _Z3bazi is not defined in module M, expect _Z3bazi's profile
29009dcfe68SWei Mi // is not loaded when the profile is ExtBinary or Compact format because
29109dcfe68SWei Mi // these formats support loading function profiles on demand.
29209dcfe68SWei Mi FunctionSamples *ReadBazSamples = Reader->getSamplesFor(BazName);
29309dcfe68SWei Mi if (Format == SampleProfileFormat::SPF_Ext_Binary ||
29409dcfe68SWei Mi Format == SampleProfileFormat::SPF_Compact_Binary) {
29509dcfe68SWei Mi ASSERT_TRUE(ReadBazSamples == nullptr);
2968c8ec1f6SWei Mi ASSERT_EQ(3u, Reader->getProfiles().size());
29709dcfe68SWei Mi } else {
29809dcfe68SWei Mi ASSERT_TRUE(ReadBazSamples != nullptr);
29909dcfe68SWei Mi ASSERT_EQ(12557u, ReadBazSamples->getTotalSamples());
3008c8ec1f6SWei Mi ASSERT_EQ(4u, Reader->getProfiles().size());
30109dcfe68SWei Mi }
30209dcfe68SWei Mi
3038c8ec1f6SWei Mi FunctionSamples *ReadBooSamples = Reader->getSamplesFor(BooName);
3048c8ec1f6SWei Mi ASSERT_TRUE(ReadBooSamples != nullptr);
3058c8ec1f6SWei Mi ASSERT_EQ(1232u, ReadBooSamples->getTotalSamples());
3068c8ec1f6SWei Mi
307a0c0857eSWei Mi std::string MconstructGUID;
308a0c0857eSWei Mi StringRef MconstructRep =
309ebad6788SWei Mi getRepInFormat(MconstructName, UseMD5, MconstructGUID);
310a0c0857eSWei Mi std::string StringviewGUID;
311a0c0857eSWei Mi StringRef StringviewRep =
312ebad6788SWei Mi getRepInFormat(StringviewName, UseMD5, StringviewGUID);
313a0c0857eSWei Mi ASSERT_EQ(1000u, CTMap.get()[MconstructRep]);
314a0c0857eSWei Mi ASSERT_EQ(437u, CTMap.get()[StringviewRep]);
31540ee23dbSEaswaran Raman
3167c4f25d2SEaswaran Raman
3177cefdb81SEaswaran Raman ProfileSummary &Summary = Reader->getSummary();
31810b57ca6SWei Mi Summary.setPartialProfile(true);
319b5c59d77SHiroshi Yamauchi verifyProfileSummary(Summary, M, true, false);
3207c4f25d2SEaswaran Raman
32110b57ca6SWei Mi Summary.setPartialProfile(false);
322b5c59d77SHiroshi Yamauchi verifyProfileSummary(Summary, M, true, false);
32326628d30SEaswaran Raman
324b5c59d77SHiroshi Yamauchi verifyProfileSummary(Summary, M, false, false);
325b5c59d77SHiroshi Yamauchi
326b5c59d77SHiroshi Yamauchi Summary.setPartialProfile(true);
327b5c59d77SHiroshi Yamauchi Summary.setPartialProfileRatio(0.5);
328b5c59d77SHiroshi Yamauchi verifyProfileSummary(Summary, M, true, true);
32951abea74SNathan Slingerland }
3309f96f1f1SThan McIntosh
addFunctionSamples__anon99df410f0111::SampleProfTest331b9db7036SHongtao Yu void addFunctionSamples(SampleProfileMap *Smap, const char *Fname,
3329f96f1f1SThan McIntosh uint64_t TotalSamples, uint64_t HeadSamples) {
3339f96f1f1SThan McIntosh StringRef Name(Fname);
3349f96f1f1SThan McIntosh FunctionSamples FcnSamples;
3359f96f1f1SThan McIntosh FcnSamples.setName(Name);
3369f96f1f1SThan McIntosh FcnSamples.addTotalSamples(TotalSamples);
3379f96f1f1SThan McIntosh FcnSamples.addHeadSamples(HeadSamples);
3389f96f1f1SThan McIntosh FcnSamples.addBodySamples(1, 0, HeadSamples);
3399f96f1f1SThan McIntosh (*Smap)[Name] = FcnSamples;
3409f96f1f1SThan McIntosh }
3419f96f1f1SThan McIntosh
setupFcnSamplesForElisionTest__anon99df410f0111::SampleProfTest342b9db7036SHongtao Yu SampleProfileMap setupFcnSamplesForElisionTest(StringRef Policy) {
343b9db7036SHongtao Yu SampleProfileMap Smap;
3449f96f1f1SThan McIntosh addFunctionSamples(&Smap, "foo", uint64_t(20301), uint64_t(1437));
3459f96f1f1SThan McIntosh if (Policy == "" || Policy == "all")
3469f96f1f1SThan McIntosh return Smap;
3479f96f1f1SThan McIntosh addFunctionSamples(&Smap, "foo.bar", uint64_t(20303), uint64_t(1439));
3489f96f1f1SThan McIntosh if (Policy == "selected")
3499f96f1f1SThan McIntosh return Smap;
3509f96f1f1SThan McIntosh addFunctionSamples(&Smap, "foo.llvm.2465", uint64_t(20305), uint64_t(1441));
3519f96f1f1SThan McIntosh return Smap;
3529f96f1f1SThan McIntosh }
3539f96f1f1SThan McIntosh
createFunctionWithSampleProfileElisionPolicy__anon99df410f0111::SampleProfTest3549f96f1f1SThan McIntosh void createFunctionWithSampleProfileElisionPolicy(Module *M,
3559f96f1f1SThan McIntosh const char *Fname,
3569f96f1f1SThan McIntosh StringRef Policy) {
3579f96f1f1SThan McIntosh FunctionType *FnType =
3589f96f1f1SThan McIntosh FunctionType::get(Type::getVoidTy(Context), {}, false);
3599f96f1f1SThan McIntosh auto Inserted = M->getOrInsertFunction(Fname, FnType);
3609f96f1f1SThan McIntosh auto Fcn = cast<Function>(Inserted.getCallee());
3619f96f1f1SThan McIntosh if (Policy != "")
3629f96f1f1SThan McIntosh Fcn->addFnAttr("sample-profile-suffix-elision-policy", Policy);
3639f96f1f1SThan McIntosh }
3649f96f1f1SThan McIntosh
setupModuleForElisionTest__anon99df410f0111::SampleProfTest3659f96f1f1SThan McIntosh void setupModuleForElisionTest(Module *M, StringRef Policy) {
3669f96f1f1SThan McIntosh createFunctionWithSampleProfileElisionPolicy(M, "foo", Policy);
3679f96f1f1SThan McIntosh createFunctionWithSampleProfileElisionPolicy(M, "foo.bar", Policy);
3689f96f1f1SThan McIntosh createFunctionWithSampleProfileElisionPolicy(M, "foo.llvm.2465", Policy);
3699f96f1f1SThan McIntosh }
3709f96f1f1SThan McIntosh
testSuffixElisionPolicy__anon99df410f0111::SampleProfTest3719f96f1f1SThan McIntosh void testSuffixElisionPolicy(SampleProfileFormat Format, StringRef Policy,
3729f96f1f1SThan McIntosh const StringMap<uint64_t> &Expected) {
373fad75598SSergej Jaskiewicz TempFile ProfileFile("profile", "", "", /*Unique*/ true);
3749f96f1f1SThan McIntosh
3759f96f1f1SThan McIntosh Module M("my_module", Context);
3769f96f1f1SThan McIntosh setupModuleForElisionTest(&M, Policy);
377b9db7036SHongtao Yu SampleProfileMap ProfMap = setupFcnSamplesForElisionTest(Policy);
3789f96f1f1SThan McIntosh
3799f96f1f1SThan McIntosh // write profile
380fad75598SSergej Jaskiewicz createWriter(Format, ProfileFile.path());
381fad75598SSergej Jaskiewicz std::error_code EC;
3829f96f1f1SThan McIntosh EC = Writer->write(ProfMap);
3839f96f1f1SThan McIntosh ASSERT_TRUE(NoError(EC));
3849f96f1f1SThan McIntosh Writer->getOutputStream().flush();
3859f96f1f1SThan McIntosh
3869f96f1f1SThan McIntosh // read profile
387fad75598SSergej Jaskiewicz readProfile(M, ProfileFile.path());
3889f96f1f1SThan McIntosh EC = Reader->read();
3899f96f1f1SThan McIntosh ASSERT_TRUE(NoError(EC));
3909f96f1f1SThan McIntosh
3919f96f1f1SThan McIntosh for (auto I = Expected.begin(); I != Expected.end(); ++I) {
3929f96f1f1SThan McIntosh uint64_t Esamples = uint64_t(-1);
3939f96f1f1SThan McIntosh FunctionSamples *Samples = Reader->getSamplesFor(I->getKey());
3949f96f1f1SThan McIntosh if (Samples != nullptr)
3959f96f1f1SThan McIntosh Esamples = Samples->getTotalSamples();
3969f96f1f1SThan McIntosh ASSERT_EQ(I->getValue(), Esamples);
3979f96f1f1SThan McIntosh }
3989f96f1f1SThan McIntosh }
39951abea74SNathan Slingerland };
40051abea74SNathan Slingerland
TEST_F(SampleProfTest,roundtrip_text_profile)40151abea74SNathan Slingerland TEST_F(SampleProfTest, roundtrip_text_profile) {
402ebad6788SWei Mi testRoundTrip(SampleProfileFormat::SPF_Text, false, false);
40351abea74SNathan Slingerland }
40451abea74SNathan Slingerland
TEST_F(SampleProfTest,roundtrip_raw_binary_profile)405a0c0857eSWei Mi TEST_F(SampleProfTest, roundtrip_raw_binary_profile) {
406ebad6788SWei Mi testRoundTrip(SampleProfileFormat::SPF_Binary, false, false);
407a0c0857eSWei Mi }
408a0c0857eSWei Mi
TEST_F(SampleProfTest,roundtrip_compact_binary_profile)409a0c0857eSWei Mi TEST_F(SampleProfTest, roundtrip_compact_binary_profile) {
410ebad6788SWei Mi testRoundTrip(SampleProfileFormat::SPF_Compact_Binary, false, true);
41128436358SRichard Smith }
41228436358SRichard Smith
TEST_F(SampleProfTest,roundtrip_ext_binary_profile)413be907324SWei Mi TEST_F(SampleProfTest, roundtrip_ext_binary_profile) {
414ebad6788SWei Mi testRoundTrip(SampleProfileFormat::SPF_Ext_Binary, false, false);
415ebad6788SWei Mi }
416ebad6788SWei Mi
TEST_F(SampleProfTest,roundtrip_md5_ext_binary_profile)417ebad6788SWei Mi TEST_F(SampleProfTest, roundtrip_md5_ext_binary_profile) {
418ebad6788SWei Mi testRoundTrip(SampleProfileFormat::SPF_Ext_Binary, false, true);
419be907324SWei Mi }
420be907324SWei Mi
TEST_F(SampleProfTest,remap_text_profile)42128436358SRichard Smith TEST_F(SampleProfTest, remap_text_profile) {
422ebad6788SWei Mi testRoundTrip(SampleProfileFormat::SPF_Text, true, false);
42328436358SRichard Smith }
42428436358SRichard Smith
TEST_F(SampleProfTest,remap_raw_binary_profile)42528436358SRichard Smith TEST_F(SampleProfTest, remap_raw_binary_profile) {
426ebad6788SWei Mi testRoundTrip(SampleProfileFormat::SPF_Binary, true, false);
42751abea74SNathan Slingerland }
42851abea74SNathan Slingerland
TEST_F(SampleProfTest,remap_ext_binary_profile)429be907324SWei Mi TEST_F(SampleProfTest, remap_ext_binary_profile) {
430ebad6788SWei Mi testRoundTrip(SampleProfileFormat::SPF_Ext_Binary, true, false);
431be907324SWei Mi }
432be907324SWei Mi
TEST_F(SampleProfTest,sample_overflow_saturation)43348dd080cSNathan Slingerland TEST_F(SampleProfTest, sample_overflow_saturation) {
43448dd080cSNathan Slingerland const uint64_t Max = std::numeric_limits<uint64_t>::max();
43548dd080cSNathan Slingerland sampleprof_error Result;
43648dd080cSNathan Slingerland
43748dd080cSNathan Slingerland FunctionSamples FooSamples;
43848dd080cSNathan Slingerland Result = FooSamples.addTotalSamples(1);
43948dd080cSNathan Slingerland ASSERT_EQ(Result, sampleprof_error::success);
44048dd080cSNathan Slingerland
44148dd080cSNathan Slingerland Result = FooSamples.addHeadSamples(1);
44248dd080cSNathan Slingerland ASSERT_EQ(Result, sampleprof_error::success);
44348dd080cSNathan Slingerland
44448dd080cSNathan Slingerland Result = FooSamples.addBodySamples(10, 0, 1);
44548dd080cSNathan Slingerland ASSERT_EQ(Result, sampleprof_error::success);
44648dd080cSNathan Slingerland
44748dd080cSNathan Slingerland Result = FooSamples.addTotalSamples(Max);
44848dd080cSNathan Slingerland ASSERT_EQ(Result, sampleprof_error::counter_overflow);
44948dd080cSNathan Slingerland ASSERT_EQ(FooSamples.getTotalSamples(), Max);
45048dd080cSNathan Slingerland
45148dd080cSNathan Slingerland Result = FooSamples.addHeadSamples(Max);
45248dd080cSNathan Slingerland ASSERT_EQ(Result, sampleprof_error::counter_overflow);
45348dd080cSNathan Slingerland ASSERT_EQ(FooSamples.getHeadSamples(), Max);
45448dd080cSNathan Slingerland
45548dd080cSNathan Slingerland Result = FooSamples.addBodySamples(10, 0, Max);
45648dd080cSNathan Slingerland ASSERT_EQ(Result, sampleprof_error::counter_overflow);
45748dd080cSNathan Slingerland ErrorOr<uint64_t> BodySamples = FooSamples.findSamplesAt(10, 0);
45848dd080cSNathan Slingerland ASSERT_FALSE(BodySamples.getError());
45948dd080cSNathan Slingerland ASSERT_EQ(BodySamples.get(), Max);
46048dd080cSNathan Slingerland }
46148dd080cSNathan Slingerland
TEST_F(SampleProfTest,default_suffix_elision_text)4629f96f1f1SThan McIntosh TEST_F(SampleProfTest, default_suffix_elision_text) {
4639f96f1f1SThan McIntosh // Default suffix elision policy: strip everything after first dot.
4649f96f1f1SThan McIntosh // This implies that all suffix variants will map to "foo", so
4659f96f1f1SThan McIntosh // we don't expect to see any entries for them in the sample
4669f96f1f1SThan McIntosh // profile.
4679f96f1f1SThan McIntosh StringMap<uint64_t> Expected;
4689f96f1f1SThan McIntosh Expected["foo"] = uint64_t(20301);
4699f96f1f1SThan McIntosh Expected["foo.bar"] = uint64_t(-1);
4709f96f1f1SThan McIntosh Expected["foo.llvm.2465"] = uint64_t(-1);
4719f96f1f1SThan McIntosh testSuffixElisionPolicy(SampleProfileFormat::SPF_Text, "", Expected);
4729f96f1f1SThan McIntosh }
4739f96f1f1SThan McIntosh
TEST_F(SampleProfTest,default_suffix_elision_compact_binary)4749f96f1f1SThan McIntosh TEST_F(SampleProfTest, default_suffix_elision_compact_binary) {
4759f96f1f1SThan McIntosh // Default suffix elision policy: strip everything after first dot.
4769f96f1f1SThan McIntosh // This implies that all suffix variants will map to "foo", so
4779f96f1f1SThan McIntosh // we don't expect to see any entries for them in the sample
4789f96f1f1SThan McIntosh // profile.
4799f96f1f1SThan McIntosh StringMap<uint64_t> Expected;
4809f96f1f1SThan McIntosh Expected["foo"] = uint64_t(20301);
4819f96f1f1SThan McIntosh Expected["foo.bar"] = uint64_t(-1);
4829f96f1f1SThan McIntosh Expected["foo.llvm.2465"] = uint64_t(-1);
4839f96f1f1SThan McIntosh testSuffixElisionPolicy(SampleProfileFormat::SPF_Compact_Binary, "",
4849f96f1f1SThan McIntosh Expected);
4859f96f1f1SThan McIntosh }
4869f96f1f1SThan McIntosh
TEST_F(SampleProfTest,selected_suffix_elision_text)4879f96f1f1SThan McIntosh TEST_F(SampleProfTest, selected_suffix_elision_text) {
4889f96f1f1SThan McIntosh // Profile is created and searched using the "selected"
4899f96f1f1SThan McIntosh // suffix elision policy: we only strip a .XXX suffix if
4909f96f1f1SThan McIntosh // it matches a pattern known to be generated by the compiler
4919f96f1f1SThan McIntosh // (e.g. ".llvm.<digits>").
4929f96f1f1SThan McIntosh StringMap<uint64_t> Expected;
4939f96f1f1SThan McIntosh Expected["foo"] = uint64_t(20301);
4949f96f1f1SThan McIntosh Expected["foo.bar"] = uint64_t(20303);
4959f96f1f1SThan McIntosh Expected["foo.llvm.2465"] = uint64_t(-1);
4969f96f1f1SThan McIntosh testSuffixElisionPolicy(SampleProfileFormat::SPF_Text, "selected", Expected);
4979f96f1f1SThan McIntosh }
4989f96f1f1SThan McIntosh
TEST_F(SampleProfTest,selected_suffix_elision_compact_binary)4999f96f1f1SThan McIntosh TEST_F(SampleProfTest, selected_suffix_elision_compact_binary) {
5009f96f1f1SThan McIntosh // Profile is created and searched using the "selected"
5019f96f1f1SThan McIntosh // suffix elision policy: we only strip a .XXX suffix if
5029f96f1f1SThan McIntosh // it matches a pattern known to be generated by the compiler
5039f96f1f1SThan McIntosh // (e.g. ".llvm.<digits>").
5049f96f1f1SThan McIntosh StringMap<uint64_t> Expected;
5059f96f1f1SThan McIntosh Expected["foo"] = uint64_t(20301);
5069f96f1f1SThan McIntosh Expected["foo.bar"] = uint64_t(20303);
5079f96f1f1SThan McIntosh Expected["foo.llvm.2465"] = uint64_t(-1);
5089f96f1f1SThan McIntosh testSuffixElisionPolicy(SampleProfileFormat::SPF_Compact_Binary, "selected",
5099f96f1f1SThan McIntosh Expected);
5109f96f1f1SThan McIntosh }
5119f96f1f1SThan McIntosh
TEST_F(SampleProfTest,none_suffix_elision_text)5129f96f1f1SThan McIntosh TEST_F(SampleProfTest, none_suffix_elision_text) {
5139f96f1f1SThan McIntosh // Profile is created and searched using the "none"
5149f96f1f1SThan McIntosh // suffix elision policy: no stripping of suffixes at all.
5159f96f1f1SThan McIntosh // Here we expect to see all variants in the profile.
5169f96f1f1SThan McIntosh StringMap<uint64_t> Expected;
5179f96f1f1SThan McIntosh Expected["foo"] = uint64_t(20301);
5189f96f1f1SThan McIntosh Expected["foo.bar"] = uint64_t(20303);
5199f96f1f1SThan McIntosh Expected["foo.llvm.2465"] = uint64_t(20305);
5209f96f1f1SThan McIntosh testSuffixElisionPolicy(SampleProfileFormat::SPF_Text, "none", Expected);
5219f96f1f1SThan McIntosh }
5229f96f1f1SThan McIntosh
TEST_F(SampleProfTest,none_suffix_elision_compact_binary)5239f96f1f1SThan McIntosh TEST_F(SampleProfTest, none_suffix_elision_compact_binary) {
5249f96f1f1SThan McIntosh // Profile is created and searched using the "none"
5259f96f1f1SThan McIntosh // suffix elision policy: no stripping of suffixes at all.
5269f96f1f1SThan McIntosh // Here we expect to see all variants in the profile.
5279f96f1f1SThan McIntosh StringMap<uint64_t> Expected;
5289f96f1f1SThan McIntosh Expected["foo"] = uint64_t(20301);
5299f96f1f1SThan McIntosh Expected["foo.bar"] = uint64_t(20303);
5309f96f1f1SThan McIntosh Expected["foo.llvm.2465"] = uint64_t(20305);
5319f96f1f1SThan McIntosh testSuffixElisionPolicy(SampleProfileFormat::SPF_Compact_Binary, "none",
5329f96f1f1SThan McIntosh Expected);
5339f96f1f1SThan McIntosh }
5349f96f1f1SThan McIntosh
53551abea74SNathan Slingerland } // end anonymous namespace
536