1*7c36b416SLang Hames //===-- llvm-jitlink-statistics.cpp -- gathers/reports JIT-linking stats --===//
2*7c36b416SLang Hames //
3*7c36b416SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*7c36b416SLang Hames // See https://llvm.org/LICENSE.txt for license information.
5*7c36b416SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*7c36b416SLang Hames //
7*7c36b416SLang Hames //===----------------------------------------------------------------------===//
8*7c36b416SLang Hames //
9*7c36b416SLang Hames // This file contains the code for enabling, gathering and reporting
10*7c36b416SLang Hames // llvm-jitlink statistics.
11*7c36b416SLang Hames //
12*7c36b416SLang Hames //===----------------------------------------------------------------------===//
13*7c36b416SLang Hames
14*7c36b416SLang Hames #include "llvm-jitlink.h"
15*7c36b416SLang Hames #include "llvm/Support/CommandLine.h"
16*7c36b416SLang Hames
17*7c36b416SLang Hames #define DEBUG_TYPE "llvm_jitlink"
18*7c36b416SLang Hames
19*7c36b416SLang Hames using namespace llvm;
20*7c36b416SLang Hames using namespace llvm::jitlink;
21*7c36b416SLang Hames using namespace llvm::orc;
22*7c36b416SLang Hames
23*7c36b416SLang Hames static cl::opt<bool> ShowPrePruneTotalBlockSize(
24*7c36b416SLang Hames "pre-prune-total-block-size",
25*7c36b416SLang Hames cl::desc("Total size of all blocks (including zero-fill) in all "
26*7c36b416SLang Hames "graphs (pre-pruning)"),
27*7c36b416SLang Hames cl::init(false));
28*7c36b416SLang Hames
29*7c36b416SLang Hames static cl::opt<bool> ShowPostFixupTotalBlockSize(
30*7c36b416SLang Hames "post-fixup-total-block-size",
31*7c36b416SLang Hames cl::desc("Total size of all blocks (including zero-fill) in all "
32*7c36b416SLang Hames "graphs (post-fixup)"),
33*7c36b416SLang Hames cl::init(false));
34*7c36b416SLang Hames
35*7c36b416SLang Hames class StatsPlugin : public ObjectLinkingLayer::Plugin {
36*7c36b416SLang Hames public:
enableIfNeeded(Session & S,bool UsingOrcRuntime)37*7c36b416SLang Hames static void enableIfNeeded(Session &S, bool UsingOrcRuntime) {
38*7c36b416SLang Hames std::unique_ptr<StatsPlugin> Instance;
39*7c36b416SLang Hames auto GetStats = [&]() -> StatsPlugin & {
40*7c36b416SLang Hames if (!Instance)
41*7c36b416SLang Hames Instance.reset(new StatsPlugin(UsingOrcRuntime));
42*7c36b416SLang Hames return *Instance;
43*7c36b416SLang Hames };
44*7c36b416SLang Hames
45*7c36b416SLang Hames if (ShowPrePruneTotalBlockSize)
46*7c36b416SLang Hames GetStats().PrePruneTotalBlockSize = 0;
47*7c36b416SLang Hames
48*7c36b416SLang Hames if (ShowPostFixupTotalBlockSize)
49*7c36b416SLang Hames GetStats().PostFixupTotalBlockSize = 0;
50*7c36b416SLang Hames
51*7c36b416SLang Hames if (Instance)
52*7c36b416SLang Hames S.ObjLayer.addPlugin(std::move(Instance));
53*7c36b416SLang Hames }
54*7c36b416SLang Hames
~StatsPlugin()55*7c36b416SLang Hames ~StatsPlugin() { publish(dbgs()); }
56*7c36b416SLang Hames
57*7c36b416SLang Hames void publish(raw_ostream &OS);
58*7c36b416SLang Hames
modifyPassConfig(MaterializationResponsibility & MR,LinkGraph & G,PassConfiguration & PassConfig)59*7c36b416SLang Hames void modifyPassConfig(MaterializationResponsibility &MR, LinkGraph &G,
60*7c36b416SLang Hames PassConfiguration &PassConfig) override {
61*7c36b416SLang Hames PassConfig.PrePrunePasses.push_back(
62*7c36b416SLang Hames [this](LinkGraph &G) { return recordPrePruneStats(G); });
63*7c36b416SLang Hames PassConfig.PostFixupPasses.push_back(
64*7c36b416SLang Hames [this](LinkGraph &G) { return recordPostFixupStats(G); });
65*7c36b416SLang Hames }
66*7c36b416SLang Hames
notifyFailed(MaterializationResponsibility & MR)67*7c36b416SLang Hames Error notifyFailed(MaterializationResponsibility &MR) override {
68*7c36b416SLang Hames return Error::success();
69*7c36b416SLang Hames }
70*7c36b416SLang Hames
notifyRemovingResources(JITDylib & JD,ResourceKey K)71*7c36b416SLang Hames Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
72*7c36b416SLang Hames return Error::success();
73*7c36b416SLang Hames }
74*7c36b416SLang Hames
notifyTransferringResources(JITDylib & JD,ResourceKey DstKey,ResourceKey SrcKey)75*7c36b416SLang Hames void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
76*7c36b416SLang Hames ResourceKey SrcKey) override {}
77*7c36b416SLang Hames
78*7c36b416SLang Hames private:
StatsPlugin(bool UsingOrcRuntime)79*7c36b416SLang Hames StatsPlugin(bool UsingOrcRuntime) : UsingOrcRuntime(UsingOrcRuntime) {}
80*7c36b416SLang Hames Error recordPrePruneStats(jitlink::LinkGraph &G);
81*7c36b416SLang Hames Error recordPostFixupStats(jitlink::LinkGraph &G);
82*7c36b416SLang Hames
83*7c36b416SLang Hames bool UsingOrcRuntime;
84*7c36b416SLang Hames
85*7c36b416SLang Hames std::mutex M;
86*7c36b416SLang Hames std::optional<uint64_t> PrePruneTotalBlockSize;
87*7c36b416SLang Hames std::optional<uint64_t> PostFixupTotalBlockSize;
88*7c36b416SLang Hames std::optional<DenseMap<size_t, size_t>> EdgeCountDetails;
89*7c36b416SLang Hames };
90*7c36b416SLang Hames
publish(raw_ostream & OS)91*7c36b416SLang Hames void StatsPlugin::publish(raw_ostream &OS) {
92*7c36b416SLang Hames
93*7c36b416SLang Hames if (UsingOrcRuntime)
94*7c36b416SLang Hames OS << "Note: Session stats include runtime and entry point lookup, but "
95*7c36b416SLang Hames "not JITDylib initialization/deinitialization.\n";
96*7c36b416SLang Hames
97*7c36b416SLang Hames OS << "Statistics:\n";
98*7c36b416SLang Hames if (PrePruneTotalBlockSize)
99*7c36b416SLang Hames OS << " Total size of all blocks before pruning: "
100*7c36b416SLang Hames << *PrePruneTotalBlockSize << "\n";
101*7c36b416SLang Hames
102*7c36b416SLang Hames if (PostFixupTotalBlockSize)
103*7c36b416SLang Hames OS << " Total size of all blocks after fixups: "
104*7c36b416SLang Hames << *PostFixupTotalBlockSize << "\n";
105*7c36b416SLang Hames }
106*7c36b416SLang Hames
computeTotalBlockSizes(LinkGraph & G)107*7c36b416SLang Hames static uint64_t computeTotalBlockSizes(LinkGraph &G) {
108*7c36b416SLang Hames uint64_t TotalSize = 0;
109*7c36b416SLang Hames for (auto *B : G.blocks())
110*7c36b416SLang Hames TotalSize += B->getSize();
111*7c36b416SLang Hames return TotalSize;
112*7c36b416SLang Hames }
113*7c36b416SLang Hames
recordPrePruneStats(LinkGraph & G)114*7c36b416SLang Hames Error StatsPlugin::recordPrePruneStats(LinkGraph &G) {
115*7c36b416SLang Hames std::lock_guard<std::mutex> Lock(M);
116*7c36b416SLang Hames
117*7c36b416SLang Hames if (PrePruneTotalBlockSize)
118*7c36b416SLang Hames *PrePruneTotalBlockSize += computeTotalBlockSizes(G);
119*7c36b416SLang Hames
120*7c36b416SLang Hames return Error::success();
121*7c36b416SLang Hames }
122*7c36b416SLang Hames
recordPostFixupStats(LinkGraph & G)123*7c36b416SLang Hames Error StatsPlugin::recordPostFixupStats(LinkGraph &G) {
124*7c36b416SLang Hames std::lock_guard<std::mutex> Lock(M);
125*7c36b416SLang Hames
126*7c36b416SLang Hames if (PostFixupTotalBlockSize)
127*7c36b416SLang Hames *PostFixupTotalBlockSize += computeTotalBlockSizes(G);
128*7c36b416SLang Hames return Error::success();
129*7c36b416SLang Hames }
130*7c36b416SLang Hames
131*7c36b416SLang Hames namespace llvm {
enableStatistics(Session & S,bool UsingOrcRuntime)132*7c36b416SLang Hames void enableStatistics(Session &S, bool UsingOrcRuntime) {
133*7c36b416SLang Hames StatsPlugin::enableIfNeeded(S, UsingOrcRuntime);
134*7c36b416SLang Hames }
135*7c36b416SLang Hames } // namespace llvm
136