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