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
19using namespace llvm;
20using namespace llvm::jitlink;
21using namespace llvm::orc;
22
23static 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(Val: false));
28
29static 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(Val: false));
34
35class StatsPlugin : public ObjectLinkingLayer::Plugin {
36public:
37 static void enableIfNeeded(Session &S, bool UsingOrcRuntime) {
38 std::unique_ptr<StatsPlugin> Instance;
39 auto GetStats = [&]() -> StatsPlugin & {
40 if (!Instance)
41 Instance.reset(p: 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(P: std::move(Instance));
53 }
54
55 ~StatsPlugin() { publish(OS&: dbgs()); }
56
57 void publish(raw_ostream &OS);
58
59 void modifyPassConfig(MaterializationResponsibility &MR, LinkGraph &G,
60 PassConfiguration &PassConfig) override {
61 PassConfig.PrePrunePasses.push_back(
62 x: [this](LinkGraph &G) { return recordPrePruneStats(G); });
63 PassConfig.PostFixupPasses.push_back(
64 x: [this](LinkGraph &G) { return recordPostFixupStats(G); });
65 }
66
67 Error notifyFailed(MaterializationResponsibility &MR) override {
68 return Error::success();
69 }
70
71 Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override {
72 return Error::success();
73 }
74
75 void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey,
76 ResourceKey SrcKey) override {}
77
78private:
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
91void 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
107static 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
114Error 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
123Error 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
131namespace llvm {
132void enableStatistics(Session &S, bool UsingOrcRuntime) {
133 StatsPlugin::enableIfNeeded(S, UsingOrcRuntime);
134}
135} // namespace llvm
136