Skip to content

Commit a2d3ae1

Browse files
mtrofinronlieb
authored andcommitted
[ctx_prof] CtxProfAnalysis (llvm#102084)
This is an immutable analysis that loads and makes the contextual profile available to other passes. This patch introduces the analysis and an analysis printer pass. Subsequent patches will introduce the APIs that IPO passes will call to modify the profile as result of their changes. Change-Id: I1a1047a73074f143a2df79afdbc06b075473feb8
1 parent 3976fa6 commit a2d3ae1

File tree

7 files changed

+159
-69
lines changed

7 files changed

+159
-69
lines changed

llvm/include/llvm/Analysis/CtxProfAnalysis.h

Lines changed: 4 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -9,47 +9,23 @@
99
#ifndef LLVM_ANALYSIS_CTXPROFANALYSIS_H
1010
#define LLVM_ANALYSIS_CTXPROFANALYSIS_H
1111

12-
#include "llvm/ADT/DenseMap.h"
1312
#include "llvm/IR/GlobalValue.h"
14-
#include "llvm/IR/InstrTypes.h"
15-
#include "llvm/IR/IntrinsicInst.h"
1613
#include "llvm/IR/PassManager.h"
1714
#include "llvm/ProfileData/PGOCtxProfReader.h"
15+
#include <map>
1816

1917
namespace llvm {
2018

2119
class CtxProfAnalysis;
2220

23-
// Setting initial capacity to 1 because all contexts must have at least 1
24-
// counter, and then, because all contexts belonging to a function have the same
25-
// size, there'll be at most one other heap allocation.
26-
using CtxProfFlatProfile =
27-
DenseMap<GlobalValue::GUID, SmallVector<uint64_t, 1>>;
28-
2921
/// The instrumented contextual profile, produced by the CtxProfAnalysis.
3022
class PGOContextualProfile {
31-
friend class CtxProfAnalysis;
32-
friend class CtxProfAnalysisPrinterPass;
33-
struct FunctionInfo {
34-
uint32_t NextCounterIndex = 0;
35-
uint32_t NextCallsiteIndex = 0;
36-
const std::string Name;
37-
38-
FunctionInfo(StringRef Name) : Name(Name) {}
39-
};
4023
std::optional<PGOCtxProfContext::CallTargetMapTy> Profiles;
41-
// For the GUIDs in this module, associate metadata about each function which
42-
// we'll need when we maintain the profiles during IPO transformations.
43-
DenseMap<GlobalValue::GUID, FunctionInfo> FuncInfo;
44-
45-
/// Get the GUID of this Function if it's defined in this module.
46-
GlobalValue::GUID getDefinedFunctionGUID(const Function &F) const;
47-
48-
// This is meant to be constructed from CtxProfAnalysis, which will also set
49-
// its state piecemeal.
50-
PGOContextualProfile() = default;
5124

5225
public:
26+
explicit PGOContextualProfile(PGOCtxProfContext::CallTargetMapTy &&Profiles)
27+
: Profiles(std::move(Profiles)) {}
28+
PGOContextualProfile() = default;
5329
PGOContextualProfile(const PGOContextualProfile &) = delete;
5430
PGOContextualProfile(PGOContextualProfile &&) = default;
5531

@@ -59,22 +35,6 @@ class PGOContextualProfile {
5935
return *Profiles;
6036
}
6137

62-
bool isFunctionKnown(const Function &F) const {
63-
return getDefinedFunctionGUID(F) != 0;
64-
}
65-
66-
uint32_t allocateNextCounterIndex(const Function &F) {
67-
assert(isFunctionKnown(F));
68-
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCounterIndex++;
69-
}
70-
71-
uint32_t allocateNextCallsiteIndex(const Function &F) {
72-
assert(isFunctionKnown(F));
73-
return FuncInfo.find(getDefinedFunctionGUID(F))->second.NextCallsiteIndex++;
74-
}
75-
76-
const CtxProfFlatProfile flatten() const;
77-
7838
bool invalidate(Module &, const PreservedAnalyses &PA,
7939
ModuleAnalysisManager::Invalidator &) {
8040
// Check whether the analysis has been explicitly invalidated. Otherwise,
@@ -94,8 +54,6 @@ class CtxProfAnalysis : public AnalysisInfoMixin<CtxProfAnalysis> {
9454
using Result = PGOContextualProfile;
9555

9656
PGOContextualProfile run(Module &M, ModuleAnalysisManager &MAM);
97-
98-
static InstrProfCallsite *getCallsiteInstrumentation(CallBase &CB);
9957
};
10058

10159
class CtxProfAnalysisPrinterPass
@@ -108,27 +66,5 @@ class CtxProfAnalysisPrinterPass
10866
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
10967
static bool isRequired() { return true; }
11068
};
111-
112-
/// Assign a GUID to functions as metadata. GUID calculation takes linkage into
113-
/// account, which may change especially through and after thinlto. By
114-
/// pre-computing and assigning as metadata, this mechanism is resilient to such
115-
/// changes (as well as name changes e.g. suffix ".llvm." additions).
116-
117-
// FIXME(mtrofin): we can generalize this mechanism to calculate a GUID early in
118-
// the pass pipeline, associate it with any Global Value, and then use it for
119-
// PGO and ThinLTO.
120-
// At that point, this should be moved elsewhere.
121-
class AssignGUIDPass : public PassInfoMixin<AssignGUIDPass> {
122-
public:
123-
explicit AssignGUIDPass() = default;
124-
125-
/// Assign a GUID *if* one is not already assign, as a function metadata named
126-
/// `GUIDMetadataName`.
127-
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
128-
static const char *GUIDMetadataName;
129-
// This should become GlobalValue::getGUID
130-
static uint64_t getGUID(const Function &F);
131-
};
132-
13369
} // namespace llvm
13470
#endif // LLVM_ANALYSIS_CTXPROFANALYSIS_H

llvm/lib/Analysis/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ add_llvm_component_library(LLVMAnalysis
4646
CostModel.cpp
4747
CodeMetrics.cpp
4848
ConstantFolding.cpp
49+
CtxProfAnalysis.cpp
4950
CycleAnalysis.cpp
5051
DDG.cpp
5152
DDGPrinter.cpp

llvm/lib/Analysis/CtxProfAnalysis.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//===- CtxProfAnalysis.cpp - contextual profile analysis ------------------===//
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+
//===----------------------------------------------------------------------===//
8+
//
9+
// Implementation of the contextual profile analysis, which maintains contextual
10+
// profiling info through IPO passes.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#include "llvm/Analysis/CtxProfAnalysis.h"
15+
#include "llvm/ADT/STLExtras.h"
16+
#include "llvm/IR/Analysis.h"
17+
#include "llvm/IR/Module.h"
18+
#include "llvm/IR/PassManager.h"
19+
#include "llvm/ProfileData/PGOCtxProfReader.h"
20+
#include "llvm/Support/JSON.h"
21+
#include "llvm/Support/MemoryBuffer.h"
22+
23+
#define DEBUG_TYPE "ctx_prof"
24+
25+
namespace llvm {
26+
namespace json {
27+
Value toJSON(const PGOCtxProfContext &P) {
28+
Object Ret;
29+
Ret["Guid"] = P.guid();
30+
Ret["Counters"] = Array(P.counters());
31+
if (P.callsites().empty())
32+
return Ret;
33+
auto AllCS =
34+
::llvm::map_range(P.callsites(), [](const auto &P) { return P.first; });
35+
auto MaxIt = ::llvm::max_element(AllCS);
36+
assert(MaxIt != AllCS.end() && "We should have a max value because the "
37+
"callsites collection is not empty.");
38+
Array CSites;
39+
// Iterate to, and including, the maximum index.
40+
for (auto I = 0U, Max = *MaxIt; I <= Max; ++I) {
41+
CSites.push_back(Array());
42+
Array &Targets = *CSites.back().getAsArray();
43+
if (P.hasCallsite(I))
44+
for (const auto &[_, Ctx] : P.callsite(I))
45+
Targets.push_back(toJSON(Ctx));
46+
}
47+
Ret["Callsites"] = std::move(CSites);
48+
49+
return Ret;
50+
}
51+
52+
Value toJSON(const PGOCtxProfContext::CallTargetMapTy &P) {
53+
Array Ret;
54+
for (const auto &[_, Ctx] : P)
55+
Ret.push_back(toJSON(Ctx));
56+
return Ret;
57+
}
58+
} // namespace json
59+
} // namespace llvm
60+
61+
using namespace llvm;
62+
63+
AnalysisKey CtxProfAnalysis::Key;
64+
65+
CtxProfAnalysis::Result CtxProfAnalysis::run(Module &M,
66+
ModuleAnalysisManager &MAM) {
67+
ErrorOr<std::unique_ptr<MemoryBuffer>> MB = MemoryBuffer::getFile(Profile);
68+
if (auto EC = MB.getError()) {
69+
M.getContext().emitError("could not open contextual profile file: " +
70+
EC.message());
71+
return {};
72+
}
73+
PGOCtxProfileReader Reader(MB.get()->getBuffer());
74+
auto MaybeCtx = Reader.loadContexts();
75+
if (!MaybeCtx) {
76+
M.getContext().emitError("contextual profile file is invalid: " +
77+
toString(MaybeCtx.takeError()));
78+
return {};
79+
}
80+
return Result(std::move(*MaybeCtx));
81+
}
82+
83+
PreservedAnalyses CtxProfAnalysisPrinterPass::run(Module &M,
84+
ModuleAnalysisManager &MAM) {
85+
CtxProfAnalysis::Result &C = MAM.getResult<CtxProfAnalysis>(M);
86+
if (!C) {
87+
M.getContext().emitError("Invalid CtxProfAnalysis");
88+
return PreservedAnalyses::all();
89+
}
90+
const auto JSONed = ::llvm::json::toJSON(C.profiles());
91+
92+
OS << formatv("{0:2}", JSONed);
93+
OS << "\n";
94+
return PreservedAnalyses::all();
95+
}

llvm/lib/Passes/PassBuilder.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "llvm/Analysis/CallGraph.h"
2929
#include "llvm/Analysis/CallPrinter.h"
3030
#include "llvm/Analysis/CostModel.h"
31+
#include "llvm/Analysis/CtxProfAnalysis.h"
3132
#include "llvm/Analysis/CycleAnalysis.h"
3233
#include "llvm/Analysis/DDG.h"
3334
#include "llvm/Analysis/DDGPrinter.h"

llvm/lib/Passes/PassRegistry.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ MODULE_ANALYSIS("callgraph", CallGraphAnalysis())
2222
MODULE_ANALYSIS("collector-metadata", CollectorMetadataAnalysis())
2323
MODULE_ANALYSIS("dxil-metadata", DXILMetadataAnalysis())
2424
MODULE_ANALYSIS("dxil-resource", DXILResourceAnalysis())
25+
MODULE_ANALYSIS("ctx-prof-analysis", CtxProfAnalysis(UseCtxProfile))
2526
MODULE_ANALYSIS("inline-advisor", InlineAdvisorAnalysis())
2627
MODULE_ANALYSIS("ir-similarity", IRSimilarityAnalysis())
2728
MODULE_ANALYSIS("lcg", LazyCallGraphAnalysis())
@@ -84,6 +85,7 @@ MODULE_PASS("insert-gcov-profiling", GCOVProfilerPass())
8485
MODULE_PASS("instrorderfile", InstrOrderFilePass())
8586
MODULE_PASS("instrprof", InstrProfilingLoweringPass())
8687
MODULE_PASS("ctx-instr-lower", PGOCtxProfLoweringPass())
88+
MODULE_PASS("print<ctx-prof-analysis>", CtxProfAnalysisPrinterPass(dbgs()))
8789
MODULE_PASS("invalidate<all>", InvalidateAllAnalysesPass())
8890
MODULE_PASS("iroutliner", IROutlinerPass())
8991
MODULE_PASS("jmc-instrumenter", JMCInstrumenterPass())
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
; RUN: split-file %s %t
2+
; RUN: llvm-ctxprof-util fromJSON --input=%t/profile.json --output=%t/profile.ctxprofdata
3+
; RUN: not opt -passes='require<ctx-prof-analysis>,print<ctx-prof-analysis>' \
4+
; RUN: %t/empty.ll -S 2>&1 | FileCheck %s --check-prefix=NO-FILE
5+
6+
; RUN: not opt -passes='require<ctx-prof-analysis>,print<ctx-prof-analysis>' \
7+
; RUN: -use-ctx-profile=does_not_exist.ctxprofdata %t/empty.ll -S 2>&1 | FileCheck %s --check-prefix=NO-FILE
8+
9+
; RUN: opt -passes='require<ctx-prof-analysis>,print<ctx-prof-analysis>' \
10+
; RUN: -use-ctx-profile=%t/profile.ctxprofdata %t/empty.ll -S 2> %t/output.json
11+
; RUN: diff %t/profile.json %t/output.json
12+
13+
; NO-FILE: error: could not open contextual profile file
14+
;
15+
; This is the reference profile, laid out in the format the json formatter will
16+
; output it from opt.
17+
;--- profile.json
18+
[
19+
{
20+
"Callsites": [
21+
[],
22+
[
23+
{
24+
"Counters": [
25+
4,
26+
5
27+
],
28+
"Guid": 2000
29+
},
30+
{
31+
"Counters": [
32+
6,
33+
7,
34+
8
35+
],
36+
"Guid": 18446744073709551613
37+
}
38+
]
39+
],
40+
"Counters": [
41+
1,
42+
2,
43+
3
44+
],
45+
"Guid": 1000
46+
},
47+
{
48+
"Counters": [
49+
5,
50+
9,
51+
10
52+
],
53+
"Guid": 18446744073709551612
54+
}
55+
]
56+
;--- empty.ll

revert_patches.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ contact: RonL
8686
---
8787
Reverts:
8888
1488fb415336 [PAC][AArch64] Lower ptrauth constants in code (#96879)
89-
[ctx_prof] CtxProfAnalysis (#102084)
9089
aca01bff0 [ctx_prof] CtxProfAnalysis: populate module data (#102930)
9190
0c876a486eb [nfc][ctx_prof] Remove the need for `PassBuilder` to know about `UseCtxProfile` (#104492)
9291
1e70122cbc18 [ctx_prof] API to get the instrumentation of a BB (#105468)

0 commit comments

Comments
 (0)