1//===- bolt/Core/DynoStats.h - Dynamic execution stats ----------*- C++ -*-===//
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// Keep track of statistics about the trace of execution captured in BOLT
10// profile.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef BOLT_CORE_DYNO_STATS_H
15#define BOLT_CORE_DYNO_STATS_H
16
17#include "llvm/ADT/ArrayRef.h"
18#include "llvm/MC/MCInstPrinter.h"
19#include "llvm/Support/raw_ostream.h"
20#include <map>
21#include <unordered_map>
22
23namespace llvm {
24
25namespace bolt {
26class BinaryFunction;
27
28/// Class encapsulating runtime statistics about an execution unit.
29class DynoStats {
30
31#define REAL_DYNO_STATS \
32 D(FORWARD_COND_BRANCHES, "executed forward branches", Fn) \
33 D(FORWARD_COND_BRANCHES_TAKEN, "taken forward branches", Fn) \
34 D(BACKWARD_COND_BRANCHES, "executed backward branches", Fn) \
35 D(BACKWARD_COND_BRANCHES_TAKEN, "taken backward branches", Fn) \
36 D(UNCOND_BRANCHES, "executed unconditional branches", Fn) \
37 D(FUNCTION_CALLS, "all function calls", Fn) \
38 D(INDIRECT_CALLS, "indirect calls", Fn) \
39 D(PLT_CALLS, "PLT calls", Fn) \
40 D(INSTRUCTIONS, "executed instructions", Fn) \
41 D(LOADS, "executed load instructions", Fn) \
42 D(STORES, "executed store instructions", Fn) \
43 D(JUMP_TABLE_BRANCHES, "taken jump table branches", Fn) \
44 D(UNKNOWN_INDIRECT_BRANCHES, "taken unknown indirect branches", Fn) \
45 D(ALL_BRANCHES, "total branches", Fadd(ALL_CONDITIONAL, UNCOND_BRANCHES)) \
46 D(ALL_TAKEN, "taken branches", Fadd(TAKEN_CONDITIONAL, UNCOND_BRANCHES)) \
47 D(NONTAKEN_CONDITIONAL, "non-taken conditional branches", \
48 Fsub(ALL_CONDITIONAL, TAKEN_CONDITIONAL)) \
49 D(TAKEN_CONDITIONAL, "taken conditional branches", \
50 Fadd(FORWARD_COND_BRANCHES_TAKEN, BACKWARD_COND_BRANCHES_TAKEN)) \
51 D(ALL_CONDITIONAL, "all conditional branches", \
52 Fadd(FORWARD_COND_BRANCHES, BACKWARD_COND_BRANCHES)) \
53 D(VENEER_CALLS_AARCH64, "linker-inserted veneer calls", Fn)
54
55#define DYNO_STATS \
56 D(FIRST_DYNO_STAT, "<reserved>", 0) \
57 REAL_DYNO_STATS \
58 D(LAST_DYNO_STAT, "<reserved>", 0)
59
60public:
61#define D(name, ...) name,
62 enum Category : uint8_t { DYNO_STATS };
63#undef D
64
65private:
66 uint64_t Stats[LAST_DYNO_STAT + 1];
67 bool PrintAArch64Stats;
68
69#define D(name, desc, ...) desc,
70 static constexpr const char *Desc[] = { DYNO_STATS };
71#undef D
72
73public:
74 DynoStats(bool PrintAArch64Stats) {
75 this->PrintAArch64Stats = PrintAArch64Stats;
76 for (auto Stat = FIRST_DYNO_STAT + 0; Stat < LAST_DYNO_STAT; ++Stat)
77 Stats[Stat] = 0;
78 }
79
80 uint64_t &operator[](size_t I) {
81 assert(I > FIRST_DYNO_STAT && I < LAST_DYNO_STAT && "index out of bounds");
82 return Stats[I];
83 }
84
85 uint64_t operator[](size_t I) const {
86 switch (I) {
87#define D(name, desc, func) \
88 case name: \
89 return func;
90#define Fn Stats[I]
91#define Fadd(a, b) operator[](a) + operator[](b)
92#define Fsub(a, b) operator[](a) - operator[](b)
93#define F(a) operator[](a)
94#define Radd(a, b) (a + b)
95#define Rsub(a, b) (a - b)
96 DYNO_STATS
97#undef Rsub
98#undef Radd
99#undef F
100#undef Fsub
101#undef Fadd
102#undef Fn
103#undef D
104 default:
105 llvm_unreachable("index out of bounds");
106 }
107 return 0;
108 }
109
110 void print(raw_ostream &OS, const DynoStats *Other = nullptr,
111 MCInstPrinter *Printer = nullptr) const;
112
113 void operator+=(const DynoStats &Other);
114 bool operator<(const DynoStats &Other) const;
115 bool operator==(const DynoStats &Other) const;
116 bool operator!=(const DynoStats &Other) const { return !operator==(Other); }
117 bool lessThan(const DynoStats &Other, ArrayRef<Category> Keys) const;
118
119 static const char *Description(const Category C) { return Desc[C]; }
120
121 /// Maps instruction opcodes to:
122 /// 1. Accumulated executed instruction counts.
123 /// 2. a multimap that records highest execution counts, function names,
124 /// and BB offsets where instructions of these opcodes occur.
125 using MaxOpcodeHistogramTy =
126 std::multimap<uint64_t, std::pair<StringRef, uint32_t>>;
127 using OpcodeHistogramTy =
128 std::unordered_map<unsigned, std::pair<uint64_t, MaxOpcodeHistogramTy>>;
129 using OpcodeStatTy = OpcodeHistogramTy::value_type;
130
131 OpcodeHistogramTy OpcodeHistogram;
132};
133
134inline raw_ostream &operator<<(raw_ostream &OS, const DynoStats &Stats) {
135 Stats.print(OS, Other: nullptr);
136 return OS;
137}
138
139DynoStats operator+(const DynoStats &A, const DynoStats &B);
140
141/// Return dynostats for the function.
142///
143/// The function relies on branch instructions being in-sync with CFG for
144/// branch instructions stats. Thus it is better to call it after
145/// fixBranches().
146DynoStats getDynoStats(BinaryFunction &BF);
147
148/// Return program-wide dynostats.
149template <typename FuncsType>
150inline DynoStats getDynoStats(FuncsType &Funcs, bool IsAArch64) {
151 DynoStats dynoStats(IsAArch64);
152 for (auto &BFI : Funcs) {
153 auto &BF = BFI.second;
154 if (BF.isSimple())
155 dynoStats += getDynoStats(BF);
156 }
157 return dynoStats;
158}
159
160/// Call a function with optional before and after dynostats printing.
161template <typename FnType, typename FuncsType>
162inline void callWithDynoStats(raw_ostream &OS, FnType &&Func, FuncsType &Funcs,
163 StringRef Phase, const bool Flag,
164 bool IsAArch64) {
165 DynoStats DynoStatsBefore(IsAArch64);
166 if (Flag)
167 DynoStatsBefore = getDynoStats(Funcs, IsAArch64);
168
169 Func();
170
171 if (Flag) {
172 const DynoStats DynoStatsAfter = getDynoStats(Funcs, IsAArch64);
173 const bool Changed = (DynoStatsAfter != DynoStatsBefore);
174 OS << "BOLT-INFO: program-wide dynostats after running " << Phase
175 << (Changed ? "" : " (no change)") << ":\n\n"
176 << DynoStatsBefore << '\n';
177 if (Changed)
178 DynoStatsAfter.print(OS, Other: &DynoStatsBefore);
179 OS << '\n';
180 }
181}
182
183} // namespace bolt
184} // namespace llvm
185
186#endif
187

source code of bolt/include/bolt/Core/DynoStats.h