[docs] Fix build-docs.sh
[llvm-project.git] / llvm / unittests / Analysis / MemoryProfileInfoTest.cpp
bloba3549aca81e514c69aa9cc2b11e39427b2d3e619
1 //===- MemoryProfileInfoTest.cpp - Memory Profile Info Unit Tests-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Analysis/MemoryProfileInfo.h"
10 #include "llvm/AsmParser/Parser.h"
11 #include "llvm/IR/Instructions.h"
12 #include "llvm/IR/LLVMContext.h"
13 #include "llvm/IR/Module.h"
14 #include "llvm/Support/CommandLine.h"
15 #include "llvm/Support/SourceMgr.h"
16 #include "gtest/gtest.h"
17 #include <cstring>
19 using namespace llvm;
20 using namespace llvm::memprof;
22 extern cl::opt<float> MemProfAccessesPerByteColdThreshold;
23 extern cl::opt<unsigned> MemProfMinLifetimeColdThreshold;
25 namespace {
27 class MemoryProfileInfoTest : public testing::Test {
28 protected:
29 std::unique_ptr<Module> makeLLVMModule(LLVMContext &C, const char *IR) {
30 SMDiagnostic Err;
31 std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
32 if (!Mod)
33 Err.print("MemoryProfileInfoTest", errs());
34 return Mod;
37 // This looks for a call that has the given value name, which
38 // is the name of the value being assigned the call return value.
39 CallBase *findCall(Function &F, const char *Name = nullptr) {
40 for (auto &BB : F)
41 for (auto &I : BB)
42 if (auto *CB = dyn_cast<CallBase>(&I))
43 if (!Name || CB->getName() == Name)
44 return CB;
45 return nullptr;
49 // Test getAllocType helper.
50 // Basic checks on the allocation type for values just above and below
51 // the thresholds.
52 TEST_F(MemoryProfileInfoTest, GetAllocType) {
53 // Long lived with more accesses per byte than threshold is not cold.
54 EXPECT_EQ(
55 getAllocType(/*MaxAccessCount=*/MemProfAccessesPerByteColdThreshold + 1,
56 /*MinSize=*/1,
57 /*MinLifetime=*/MemProfMinLifetimeColdThreshold * 1000 + 1),
58 AllocationType::NotCold);
59 // Long lived with less accesses per byte than threshold is cold.
60 EXPECT_EQ(
61 getAllocType(/*MaxAccessCount=*/MemProfAccessesPerByteColdThreshold - 1,
62 /*MinSize=*/1,
63 /*MinLifetime=*/MemProfMinLifetimeColdThreshold * 1000 + 1),
64 AllocationType::Cold);
65 // Short lived with more accesses per byte than threshold is not cold.
66 EXPECT_EQ(
67 getAllocType(/*MaxAccessCount=*/MemProfAccessesPerByteColdThreshold + 1,
68 /*MinSize=*/1,
69 /*MinLifetime=*/MemProfMinLifetimeColdThreshold * 1000 - 1),
70 AllocationType::NotCold);
71 // Short lived with less accesses per byte than threshold is not cold.
72 EXPECT_EQ(
73 getAllocType(/*MaxAccessCount=*/MemProfAccessesPerByteColdThreshold - 1,
74 /*MinSize=*/1,
75 /*MinLifetime=*/MemProfMinLifetimeColdThreshold * 1000 - 1),
76 AllocationType::NotCold);
79 // Test buildCallstackMetadata helper.
80 TEST_F(MemoryProfileInfoTest, BuildCallStackMD) {
81 LLVMContext C;
82 MDNode *CallStack = buildCallstackMetadata({1, 2, 3}, C);
83 ASSERT_EQ(CallStack->getNumOperands(), 3u);
84 unsigned ExpectedId = 1;
85 for (auto &Op : CallStack->operands()) {
86 auto *StackId = mdconst::dyn_extract<ConstantInt>(Op);
87 EXPECT_EQ(StackId->getZExtValue(), ExpectedId++);
91 // Test CallStackTrie::addCallStack interface taking allocation type and list of
92 // call stack ids.
93 // Check that allocations with a single allocation type along all call stacks
94 // get an attribute instead of memprof metadata.
95 TEST_F(MemoryProfileInfoTest, Attribute) {
96 LLVMContext C;
97 std::unique_ptr<Module> M = makeLLVMModule(C,
98 R"IR(
99 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
100 target triple = "x86_64-pc-linux-gnu"
101 define i32* @test() {
102 entry:
103 %call1 = call noalias dereferenceable_or_null(40) i8* @malloc(i64 noundef 40)
104 %0 = bitcast i8* %call1 to i32*
105 %call2 = call noalias dereferenceable_or_null(40) i8* @malloc(i64 noundef 40)
106 %1 = bitcast i8* %call2 to i32*
107 ret i32* %1
109 declare dso_local noalias noundef i8* @malloc(i64 noundef)
110 )IR");
112 Function *Func = M->getFunction("test");
114 // First call has all cold contexts.
115 CallStackTrie Trie1;
116 Trie1.addCallStack(AllocationType::Cold, {1, 2});
117 Trie1.addCallStack(AllocationType::Cold, {1, 3, 4});
118 CallBase *Call1 = findCall(*Func, "call1");
119 Trie1.buildAndAttachMIBMetadata(Call1);
121 EXPECT_FALSE(Call1->hasMetadata(LLVMContext::MD_memprof));
122 EXPECT_TRUE(Call1->hasFnAttr("memprof"));
123 EXPECT_EQ(Call1->getFnAttr("memprof").getValueAsString(), "cold");
125 // Second call has all non-cold contexts.
126 CallStackTrie Trie2;
127 Trie2.addCallStack(AllocationType::NotCold, {5, 6});
128 Trie2.addCallStack(AllocationType::NotCold, {5, 7, 8});
129 CallBase *Call2 = findCall(*Func, "call2");
130 Trie2.buildAndAttachMIBMetadata(Call2);
132 EXPECT_FALSE(Call2->hasMetadata(LLVMContext::MD_memprof));
133 EXPECT_TRUE(Call2->hasFnAttr("memprof"));
134 EXPECT_EQ(Call2->getFnAttr("memprof").getValueAsString(), "notcold");
137 // Test CallStackTrie::addCallStack interface taking allocation type and list of
138 // call stack ids.
139 // Test that an allocation call reached by both cold and non cold call stacks
140 // gets memprof metadata representing the different allocation type contexts.
141 TEST_F(MemoryProfileInfoTest, ColdAndNotColdMIB) {
142 LLVMContext C;
143 std::unique_ptr<Module> M = makeLLVMModule(C,
144 R"IR(
145 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
146 target triple = "x86_64-pc-linux-gnu"
147 define i32* @test() {
148 entry:
149 %call = call noalias dereferenceable_or_null(40) i8* @malloc(i64 noundef 40)
150 %0 = bitcast i8* %call to i32*
151 ret i32* %0
153 declare dso_local noalias noundef i8* @malloc(i64 noundef)
154 )IR");
156 Function *Func = M->getFunction("test");
158 CallStackTrie Trie;
159 Trie.addCallStack(AllocationType::Cold, {1, 2});
160 Trie.addCallStack(AllocationType::NotCold, {1, 3});
162 CallBase *Call = findCall(*Func, "call");
163 Trie.buildAndAttachMIBMetadata(Call);
165 EXPECT_FALSE(Call->hasFnAttr("memprof"));
166 EXPECT_TRUE(Call->hasMetadata(LLVMContext::MD_memprof));
167 MDNode *MemProfMD = Call->getMetadata(LLVMContext::MD_memprof);
168 ASSERT_EQ(MemProfMD->getNumOperands(), 2u);
169 for (auto &MIBOp : MemProfMD->operands()) {
170 MDNode *MIB = dyn_cast<MDNode>(MIBOp);
171 MDNode *StackMD = getMIBStackNode(MIB);
172 ASSERT_NE(StackMD, nullptr);
173 ASSERT_EQ(StackMD->getNumOperands(), 2u);
174 auto *StackId = mdconst::dyn_extract<ConstantInt>(StackMD->getOperand(0));
175 ASSERT_EQ(StackId->getZExtValue(), 1u);
176 StackId = mdconst::dyn_extract<ConstantInt>(StackMD->getOperand(1));
177 if (StackId->getZExtValue() == 2u)
178 EXPECT_EQ(getMIBAllocType(MIB), AllocationType::Cold);
179 else {
180 ASSERT_EQ(StackId->getZExtValue(), 3u);
181 EXPECT_EQ(getMIBAllocType(MIB), AllocationType::NotCold);
186 // Test CallStackTrie::addCallStack interface taking allocation type and list of
187 // call stack ids.
188 // Test that an allocation call reached by multiple call stacks has memprof
189 // metadata with the contexts trimmed to the minimum context required to
190 // identify the allocation type.
191 TEST_F(MemoryProfileInfoTest, TrimmedMIBContext) {
192 LLVMContext C;
193 std::unique_ptr<Module> M = makeLLVMModule(C,
194 R"IR(
195 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
196 target triple = "x86_64-pc-linux-gnu"
197 define i32* @test() {
198 entry:
199 %call = call noalias dereferenceable_or_null(40) i8* @malloc(i64 noundef 40)
200 %0 = bitcast i8* %call to i32*
201 ret i32* %0
203 declare dso_local noalias noundef i8* @malloc(i64 noundef)
204 )IR");
206 Function *Func = M->getFunction("test");
208 CallStackTrie Trie;
209 // We should be able to trim the following two and combine into a single MIB
210 // with the cold context {1, 2}.
211 Trie.addCallStack(AllocationType::Cold, {1, 2, 3});
212 Trie.addCallStack(AllocationType::Cold, {1, 2, 4});
213 // We should be able to trim the following two and combine into a single MIB
214 // with the non-cold context {1, 5}.
215 Trie.addCallStack(AllocationType::NotCold, {1, 5, 6});
216 Trie.addCallStack(AllocationType::NotCold, {1, 5, 7});
218 CallBase *Call = findCall(*Func, "call");
219 Trie.buildAndAttachMIBMetadata(Call);
221 EXPECT_FALSE(Call->hasFnAttr("memprof"));
222 EXPECT_TRUE(Call->hasMetadata(LLVMContext::MD_memprof));
223 MDNode *MemProfMD = Call->getMetadata(LLVMContext::MD_memprof);
224 ASSERT_EQ(MemProfMD->getNumOperands(), 2u);
225 for (auto &MIBOp : MemProfMD->operands()) {
226 MDNode *MIB = dyn_cast<MDNode>(MIBOp);
227 MDNode *StackMD = getMIBStackNode(MIB);
228 ASSERT_NE(StackMD, nullptr);
229 ASSERT_EQ(StackMD->getNumOperands(), 2u);
230 auto *StackId = mdconst::dyn_extract<ConstantInt>(StackMD->getOperand(0));
231 EXPECT_EQ(StackId->getZExtValue(), 1u);
232 StackId = mdconst::dyn_extract<ConstantInt>(StackMD->getOperand(1));
233 if (StackId->getZExtValue() == 2u)
234 EXPECT_EQ(getMIBAllocType(MIB), AllocationType::Cold);
235 else {
236 ASSERT_EQ(StackId->getZExtValue(), 5u);
237 EXPECT_EQ(getMIBAllocType(MIB), AllocationType::NotCold);
242 // Test CallStackTrie::addCallStack interface taking memprof MIB metadata.
243 // Check that allocations annotated with memprof metadata with a single
244 // allocation type get simplified to an attribute.
245 TEST_F(MemoryProfileInfoTest, SimplifyMIBToAttribute) {
246 LLVMContext C;
247 std::unique_ptr<Module> M = makeLLVMModule(C,
248 R"IR(
249 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
250 target triple = "x86_64-pc-linux-gnu"
251 define i32* @test() {
252 entry:
253 %call1 = call noalias dereferenceable_or_null(40) i8* @malloc(i64 noundef 40), !memprof !0
254 %0 = bitcast i8* %call1 to i32*
255 %call2 = call noalias dereferenceable_or_null(40) i8* @malloc(i64 noundef 40), !memprof !3
256 %1 = bitcast i8* %call2 to i32*
257 ret i32* %1
259 declare dso_local noalias noundef i8* @malloc(i64 noundef)
260 !0 = !{!1}
261 !1 = !{!2, !"cold"}
262 !2 = !{i64 1, i64 2, i64 3}
263 !3 = !{!4}
264 !4 = !{!5, !"notcold"}
265 !5 = !{i64 4, i64 5, i64 6, i64 7}
266 )IR");
268 Function *Func = M->getFunction("test");
270 // First call has all cold contexts.
271 CallStackTrie Trie1;
272 CallBase *Call1 = findCall(*Func, "call1");
273 MDNode *MemProfMD1 = Call1->getMetadata(LLVMContext::MD_memprof);
274 ASSERT_EQ(MemProfMD1->getNumOperands(), 1u);
275 MDNode *MIB1 = dyn_cast<MDNode>(MemProfMD1->getOperand(0));
276 Trie1.addCallStack(MIB1);
277 Trie1.buildAndAttachMIBMetadata(Call1);
279 EXPECT_TRUE(Call1->hasFnAttr("memprof"));
280 EXPECT_EQ(Call1->getFnAttr("memprof").getValueAsString(), "cold");
282 // Second call has all non-cold contexts.
283 CallStackTrie Trie2;
284 CallBase *Call2 = findCall(*Func, "call2");
285 MDNode *MemProfMD2 = Call2->getMetadata(LLVMContext::MD_memprof);
286 ASSERT_EQ(MemProfMD2->getNumOperands(), 1u);
287 MDNode *MIB2 = dyn_cast<MDNode>(MemProfMD2->getOperand(0));
288 Trie2.addCallStack(MIB2);
289 Trie2.buildAndAttachMIBMetadata(Call2);
291 EXPECT_TRUE(Call2->hasFnAttr("memprof"));
292 EXPECT_EQ(Call2->getFnAttr("memprof").getValueAsString(), "notcold");
295 // Test CallStackTrie::addCallStack interface taking memprof MIB metadata.
296 // Test that allocations annotated with memprof metadata with multiple call
297 // stacks gets new memprof metadata with the contexts trimmed to the minimum
298 // context required to identify the allocation type.
299 TEST_F(MemoryProfileInfoTest, ReTrimMIBContext) {
300 LLVMContext C;
301 std::unique_ptr<Module> M = makeLLVMModule(C,
302 R"IR(
303 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
304 target triple = "x86_64-pc-linux-gnu"
305 define i32* @test() {
306 entry:
307 %call = call noalias dereferenceable_or_null(40) i8* @malloc(i64 noundef 40), !memprof !0
308 %0 = bitcast i8* %call to i32*
309 ret i32* %0
311 declare dso_local noalias noundef i8* @malloc(i64 noundef)
312 !0 = !{!1, !3, !5, !7}
313 !1 = !{!2, !"cold"}
314 !2 = !{i64 1, i64 2, i64 3}
315 !3 = !{!4, !"cold"}
316 !4 = !{i64 1, i64 2, i64 4}
317 !5 = !{!6, !"notcold"}
318 !6 = !{i64 1, i64 5, i64 6}
319 !7 = !{!8, !"notcold"}
320 !8 = !{i64 1, i64 5, i64 7}
321 )IR");
323 Function *Func = M->getFunction("test");
325 CallStackTrie Trie;
326 ASSERT_TRUE(Trie.empty());
327 CallBase *Call = findCall(*Func, "call");
328 MDNode *MemProfMD = Call->getMetadata(LLVMContext::MD_memprof);
329 for (auto &MIBOp : MemProfMD->operands()) {
330 MDNode *MIB = dyn_cast<MDNode>(MIBOp);
331 Trie.addCallStack(MIB);
333 ASSERT_FALSE(Trie.empty());
334 Trie.buildAndAttachMIBMetadata(Call);
336 // We should be able to trim the first two and combine into a single MIB
337 // with the cold context {1, 2}.
338 // We should be able to trim the second two and combine into a single MIB
339 // with the non-cold context {1, 5}.
341 EXPECT_FALSE(Call->hasFnAttr("memprof"));
342 EXPECT_TRUE(Call->hasMetadata(LLVMContext::MD_memprof));
343 MemProfMD = Call->getMetadata(LLVMContext::MD_memprof);
344 ASSERT_EQ(MemProfMD->getNumOperands(), 2u);
345 for (auto &MIBOp : MemProfMD->operands()) {
346 MDNode *MIB = dyn_cast<MDNode>(MIBOp);
347 MDNode *StackMD = getMIBStackNode(MIB);
348 ASSERT_NE(StackMD, nullptr);
349 ASSERT_EQ(StackMD->getNumOperands(), 2u);
350 auto *StackId = mdconst::dyn_extract<ConstantInt>(StackMD->getOperand(0));
351 EXPECT_EQ(StackId->getZExtValue(), 1u);
352 StackId = mdconst::dyn_extract<ConstantInt>(StackMD->getOperand(1));
353 if (StackId->getZExtValue() == 2u)
354 EXPECT_EQ(getMIBAllocType(MIB), AllocationType::Cold);
355 else {
356 ASSERT_EQ(StackId->getZExtValue(), 5u);
357 EXPECT_EQ(getMIBAllocType(MIB), AllocationType::NotCold);
362 } // end anonymous namespace