LLVM: lib/Analysis/MemoryProfileInfo.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

16

17using namespace llvm;

19

20#define DEBUG_TYPE "memory-profile-info"

21

22

23

25 "memprof-lifetime-access-density-cold-threshold", cl::init(0.05),

27 cl::desc("The threshold the lifetime access density (accesses per byte per "

28 "lifetime sec) must be under to consider an allocation cold"));

29

30

31

34 cl::desc("The average lifetime (s) for an allocation to be considered "

35 "cold"));

36

37

38

40 "memprof-min-ave-lifetime-access-density-hot-threshold", cl::init(1000),

42 cl::desc("The minimum TotalLifetimeAccessDensity / AllocCount for an "

43 "allocation to be considered hot"));

44

47 cl::desc("Report total allocation sizes of hinted allocations"));

48

52

53

54 if (((float)TotalLifetimeAccessDensity) / AllocCount / 100 <

56

57 && ((float)TotalLifetime) / AllocCount >=

59 return AllocationType::Cold;

60

61

62

63 if (((float)TotalLifetimeAccessDensity) / AllocCount / 100 >

65 return AllocationType::Hot;

66

67 return AllocationType::NotCold;

68}

69

75 auto *StackValMD =

78 }

80}

81

84

85 return cast(MIB->getOperand(0));

86}

87

90

91

92

93 auto *MDS = dyn_cast(MIB->getOperand(1));

95 if (MDS->getString() == "cold") {

96 return AllocationType::Cold;

97 } else if (MDS->getString() == "hot") {

98 return AllocationType::Hot;

99 }

100 return AllocationType::NotCold;

101}

102

104 switch (Type) {

105 case AllocationType::NotCold:

106 return "notcold";

107 break;

108 case AllocationType::Cold:

109 return "cold";

110 break;

111 case AllocationType::Hot:

112 return "hot";

113 break;

114 default:

115 assert(false && "Unexpected alloc type");

116 }

118}

119

125}

126

128 const unsigned NumAllocTypes = llvm::popcount(AllocTypes);

129 assert(NumAllocTypes != 0);

130 return NumAllocTypes == 1;

131}

132

135 std::vector ContextSizeInfo) {

136 bool First = true;

137 CallStackTrieNode *Curr = nullptr;

138 for (auto StackId : StackIds) {

139

142 if (Alloc) {

143 assert(AllocStackId == StackId);

145 } else {

146 AllocStackId = StackId;

147 Alloc = new CallStackTrieNode(AllocType);

148 }

149 Curr = Alloc;

150 continue;

151 }

152

153 auto Next = Curr->Callers.find(StackId);

154 if (Next != Curr->Callers.end()) {

155 Curr = Next->second;

157 continue;

158 }

159

160 auto *New = new CallStackTrieNode(AllocType);

161 Curr->Callers[StackId] = New;

162 Curr = New;

163 }

165 Curr->ContextSizeInfo.insert(Curr->ContextSizeInfo.end(),

166 ContextSizeInfo.begin(), ContextSizeInfo.end());

167}

168

174 for (const auto &MIBStackIter : StackMD->operands()) {

175 auto *StackId = mdconst::dyn_extract(MIBStackIter);

177 CallStack.push_back(StackId->getZExtValue());

178 }

179 std::vector ContextSizeInfo;

180

186 mdconst::dyn_extract(ContextSizePair->getOperand(0))

187 ->getZExtValue();

189 mdconst::dyn_extract(ContextSizePair->getOperand(1))

190 ->getZExtValue();

191 ContextSizeInfo.push_back({FullStackId, TotalSize});

192 }

193 }

195}

196

204 if (!ContextSizeInfo.empty()) {

205 for (const auto &[FullStackId, TotalSize] : ContextSizeInfo) {

210 auto *ContextSizeMD = MDNode::get(Ctx, {FullStackIdMD, TotalSizeMD});

211 MIBPayload.push_back(ContextSizeMD);

212 }

213 }

215}

216

217void CallStackTrie::collectContextSizeInfo(

218 CallStackTrieNode *Node, std::vector &ContextSizeInfo) {

219 ContextSizeInfo.insert(ContextSizeInfo.end(), Node->ContextSizeInfo.begin(),

220 Node->ContextSizeInfo.end());

221 for (auto &Caller : Node->Callers)

222 collectContextSizeInfo(Caller.second, ContextSizeInfo);

223}

224

225

226

227

228bool CallStackTrie::buildMIBNodes(CallStackTrieNode *Node, LLVMContext &Ctx,

229 std::vector<uint64_t> &MIBCallStack,

230 std::vector<Metadata *> &MIBNodes,

231 bool CalleeHasAmbiguousCallerContext) {

232

233

235 std::vector ContextSizeInfo;

236 collectContextSizeInfo(Node, ContextSizeInfo);

238 Ctx, MIBCallStack, (AllocationType)Node->AllocTypes, ContextSizeInfo));

239 return true;

240 }

241

242

243

244 if (Node->Callers.empty()) {

245 bool NodeHasAmbiguousCallerContext = Node->Callers.size() > 1;

246 bool AddedMIBNodesForAllCallerContexts = true;

247 for (auto &Caller : Node->Callers) {

248 MIBCallStack.push_back(Caller.first);

249 AddedMIBNodesForAllCallerContexts &=

250 buildMIBNodes(Caller.second, Ctx, MIBCallStack, MIBNodes,

251 NodeHasAmbiguousCallerContext);

252

253 MIBCallStack.pop_back();

254 }

255 if (AddedMIBNodesForAllCallerContexts)

256 return true;

257

258

259 assert(!NodeHasAmbiguousCallerContext);

260 }

261

262

263

264

265

266

267

268

269

270

271

272 if (!CalleeHasAmbiguousCallerContext)

273 return false;

274 std::vector ContextSizeInfo;

275 collectContextSizeInfo(Node, ContextSizeInfo);

277 ContextSizeInfo));

278 return true;

279}

280

285 std::vector ContextSizeInfo;

286 collectContextSizeInfo(Alloc, ContextSizeInfo);

287 for (const auto &[FullStackId, TotalSize] : ContextSizeInfo) {

288 errs() << "MemProf hinting: Total size for full allocation context hash "

289 << FullStackId << " and " << Descriptor << " alloc type "

291 }

292 }

293}

294

295

296

297

301 "single");

302 return false;

303 }

305 std::vector<uint64_t> MIBCallStack;

306 MIBCallStack.push_back(AllocStackId);

307 std::vector<Metadata *> MIBNodes;

308 assert(!Alloc->Callers.empty() && "addCallStack has not been called yet");

309

310

311

312 if (buildMIBNodes(Alloc, Ctx, MIBCallStack, MIBNodes, false)) {

313 assert(MIBCallStack.size() == 1 &&

314 "Should only be left with Alloc's location in stack");

316 return true;

317 }

318

319

320

321

322

324 return false;

325}

326

327template <>

330 : N(N) {

331 if (N)

332 return;

333 Iter = End ? N->op_end() : N->op_begin();

334}

335

336template <>

340 ConstantInt *StackIdCInt = mdconst::dyn_extract(*Iter);

343}

344

347 return mdconst::dyn_extract(N->operands().back())

348 ->getZExtValue();

349}

350

352

353

354

355 if (A)

356 return A;

357 return B;

358}

359

361

362

363 if (A)

364 return A;

365 return B;

366}

static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")

static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")

This file contains the declarations for the subclasses of Constant, which represent the different fla...

cl::opt< float > MemProfLifetimeAccessDensityColdThreshold("memprof-lifetime-access-density-cold-threshold", cl::init(0.05), cl::Hidden, cl::desc("The threshold the lifetime access density (accesses per byte per " "lifetime sec) must be under to consider an allocation cold"))

cl::opt< unsigned > MemProfMinAveLifetimeAccessDensityHotThreshold("memprof-min-ave-lifetime-access-density-hot-threshold", cl::init(1000), cl::Hidden, cl::desc("The minimum TotalLifetimeAccessDensity / AllocCount for an " "allocation to be considered hot"))

cl::opt< bool > MemProfReportHintedSizes("memprof-report-hinted-sizes", cl::init(false), cl::Hidden, cl::desc("Report total allocation sizes of hinted allocations"))

static MDNode * createMIBNode(LLVMContext &Ctx, ArrayRef< uint64_t > MIBCallStack, AllocationType AllocType, ArrayRef< ContextTotalSize > ContextSizeInfo)

cl::opt< unsigned > MemProfAveLifetimeColdThreshold("memprof-ave-lifetime-cold-threshold", cl::init(200), cl::Hidden, cl::desc("The average lifetime (s) for an allocation to be considered " "cold"))

static void addAllocTypeAttribute(LLVMContext &Ctx, CallBase *CI, AllocationType AllocType)

assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())

ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...

bool empty() const

empty - Check if the array is empty.

static Attribute get(LLVMContext &Context, AttrKind Kind, uint64_t Val=0)

Return a uniquified Attribute object.

Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...

void addFnAttr(Attribute::AttrKind Kind)

Adds the attribute to the function.

This is the shared class of boolean and integer constants.

uint64_t getZExtValue() const

Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...

void setMetadata(unsigned KindID, MDNode *Node)

Set the metadata of the specified kind to the specified node.

This is an important class for using LLVM in a threaded context.

static MDNode * getMergedCallsiteMetadata(MDNode *A, MDNode *B)

const MDOperand & getOperand(unsigned I) const

ArrayRef< MDOperand > operands() const

static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)

unsigned getNumOperands() const

Return number of MDNode operands.

static MDNode * getMergedMemProfMetadata(MDNode *A, MDNode *B)

static MDString * get(LLVMContext &Context, StringRef Str)

void push_back(Metadata *MD)

Append an element to the tuple. This will resize the node.

void reserve(size_type N)

void push_back(const T &Elt)

This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.

StringRef - Represent a constant reference to a string, i.e.

The instances of the Type class are immutable: once they are created, they are never changed.

static IntegerType * getInt64Ty(LLVMContext &C)

LLVMContext & getContext() const

All values hold a context through their type.

void addCallStack(AllocationType AllocType, ArrayRef< uint64_t > StackIds, std::vector< ContextTotalSize > ContextSizeInfo={})

Add a call stack context with the given allocation type to the Trie.

void addSingleAllocTypeAttribute(CallBase *CI, AllocationType AT, StringRef Descriptor)

Add an attribute for the given allocation type to the call instruction.

bool buildAndAttachMIBMetadata(CallBase *CI)

Build and attach the minimal necessary MIB metadata.

Helper class to iterate through stack ids in both metadata (memprof MIB and callsite) and the corresp...

#define llvm_unreachable(msg)

Marks that the current location is not supposed to be reachable.

initializer< Ty > init(const Ty &Val)

MDNode * buildCallstackMetadata(ArrayRef< uint64_t > CallStack, LLVMContext &Ctx)

Build callstack metadata from the provided list of call stack ids.

AllocationType getAllocType(uint64_t TotalLifetimeAccessDensity, uint64_t AllocCount, uint64_t TotalLifetime)

Return the allocation type for a given set of memory profile values.

AllocationType getMIBAllocType(const MDNode *MIB)

Returns the allocation type from an MIB metadata node.

bool hasSingleAllocType(uint8_t AllocTypes)

True if the AllocTypes bitmask contains just a single type.

std::string getAllocTypeAttributeString(AllocationType Type)

Returns the string to use in attributes with the given type.

MDNode * getMIBStackNode(const MDNode *MIB)

Returns the stack node from an MIB metadata node.

This is an optimization pass for GlobalISel generic memory operations.

int popcount(T Value) noexcept

Count the number of set bits in a value.

raw_fd_ostream & errs()

This returns a reference to a raw_ostream for standard error.

@ First

Helpers to iterate all locations in the MemoryEffectsBase class.

CallStackIterator(const NodeT *N, bool End)