1*700637cbSDimitry Andric //=-- MemProfCommon.cpp - MemProf common utilities ---------------=//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // This file contains MemProf common utilities.
10*700637cbSDimitry Andric //
11*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
12*700637cbSDimitry Andric
13*700637cbSDimitry Andric #include "llvm/ProfileData/MemProfCommon.h"
14*700637cbSDimitry Andric #include "llvm/ProfileData/MemProf.h"
15*700637cbSDimitry Andric #include "llvm/Support/BLAKE3.h"
16*700637cbSDimitry Andric #include "llvm/Support/CommandLine.h"
17*700637cbSDimitry Andric #include "llvm/Support/Compiler.h"
18*700637cbSDimitry Andric #include "llvm/Support/HashBuilder.h"
19*700637cbSDimitry Andric
20*700637cbSDimitry Andric using namespace llvm;
21*700637cbSDimitry Andric using namespace llvm::memprof;
22*700637cbSDimitry Andric
23*700637cbSDimitry Andric // Upper bound on lifetime access density (accesses per byte per lifetime sec)
24*700637cbSDimitry Andric // for marking an allocation cold.
25*700637cbSDimitry Andric LLVM_ABI cl::opt<float> MemProfLifetimeAccessDensityColdThreshold(
26*700637cbSDimitry Andric "memprof-lifetime-access-density-cold-threshold", cl::init(0.05),
27*700637cbSDimitry Andric cl::Hidden,
28*700637cbSDimitry Andric cl::desc("The threshold the lifetime access density (accesses per byte per "
29*700637cbSDimitry Andric "lifetime sec) must be under to consider an allocation cold"));
30*700637cbSDimitry Andric
31*700637cbSDimitry Andric // Lower bound on lifetime to mark an allocation cold (in addition to accesses
32*700637cbSDimitry Andric // per byte per sec above). This is to avoid pessimizing short lived objects.
33*700637cbSDimitry Andric LLVM_ABI cl::opt<unsigned> MemProfAveLifetimeColdThreshold(
34*700637cbSDimitry Andric "memprof-ave-lifetime-cold-threshold", cl::init(200), cl::Hidden,
35*700637cbSDimitry Andric cl::desc("The average lifetime (s) for an allocation to be considered "
36*700637cbSDimitry Andric "cold"));
37*700637cbSDimitry Andric
38*700637cbSDimitry Andric // Lower bound on average lifetime accesses density (total life time access
39*700637cbSDimitry Andric // density / alloc count) for marking an allocation hot.
40*700637cbSDimitry Andric LLVM_ABI cl::opt<unsigned> MemProfMinAveLifetimeAccessDensityHotThreshold(
41*700637cbSDimitry Andric "memprof-min-ave-lifetime-access-density-hot-threshold", cl::init(1000),
42*700637cbSDimitry Andric cl::Hidden,
43*700637cbSDimitry Andric cl::desc("The minimum TotalLifetimeAccessDensity / AllocCount for an "
44*700637cbSDimitry Andric "allocation to be considered hot"));
45*700637cbSDimitry Andric
46*700637cbSDimitry Andric LLVM_ABI cl::opt<bool>
47*700637cbSDimitry Andric MemProfUseHotHints("memprof-use-hot-hints", cl::init(false), cl::Hidden,
48*700637cbSDimitry Andric cl::desc("Enable use of hot hints (only supported for "
49*700637cbSDimitry Andric "unambigously hot allocations)"));
50*700637cbSDimitry Andric
getAllocType(uint64_t TotalLifetimeAccessDensity,uint64_t AllocCount,uint64_t TotalLifetime)51*700637cbSDimitry Andric AllocationType llvm::memprof::getAllocType(uint64_t TotalLifetimeAccessDensity,
52*700637cbSDimitry Andric uint64_t AllocCount,
53*700637cbSDimitry Andric uint64_t TotalLifetime) {
54*700637cbSDimitry Andric // The access densities are multiplied by 100 to hold 2 decimal places of
55*700637cbSDimitry Andric // precision, so need to divide by 100.
56*700637cbSDimitry Andric if (((float)TotalLifetimeAccessDensity) / AllocCount / 100 <
57*700637cbSDimitry Andric MemProfLifetimeAccessDensityColdThreshold
58*700637cbSDimitry Andric // Lifetime is expected to be in ms, so convert the threshold to ms.
59*700637cbSDimitry Andric && ((float)TotalLifetime) / AllocCount >=
60*700637cbSDimitry Andric MemProfAveLifetimeColdThreshold * 1000)
61*700637cbSDimitry Andric return AllocationType::Cold;
62*700637cbSDimitry Andric
63*700637cbSDimitry Andric // The access densities are multiplied by 100 to hold 2 decimal places of
64*700637cbSDimitry Andric // precision, so need to divide by 100.
65*700637cbSDimitry Andric if (MemProfUseHotHints &&
66*700637cbSDimitry Andric ((float)TotalLifetimeAccessDensity) / AllocCount / 100 >
67*700637cbSDimitry Andric MemProfMinAveLifetimeAccessDensityHotThreshold)
68*700637cbSDimitry Andric return AllocationType::Hot;
69*700637cbSDimitry Andric
70*700637cbSDimitry Andric return AllocationType::NotCold;
71*700637cbSDimitry Andric }
72*700637cbSDimitry Andric
computeFullStackId(ArrayRef<Frame> CallStack)73*700637cbSDimitry Andric uint64_t llvm::memprof::computeFullStackId(ArrayRef<Frame> CallStack) {
74*700637cbSDimitry Andric llvm::HashBuilder<llvm::TruncatedBLAKE3<8>, llvm::endianness::little>
75*700637cbSDimitry Andric HashBuilder;
76*700637cbSDimitry Andric for (auto &F : CallStack)
77*700637cbSDimitry Andric HashBuilder.add(F.Function, F.LineOffset, F.Column);
78*700637cbSDimitry Andric llvm::BLAKE3Result<8> Hash = HashBuilder.final();
79*700637cbSDimitry Andric uint64_t Id;
80*700637cbSDimitry Andric std::memcpy(&Id, Hash.data(), sizeof(Hash));
81*700637cbSDimitry Andric return Id;
82*700637cbSDimitry Andric }
83