Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / bolt / lib / Profile / YAMLProfileWriter.cpp
blob3326d1d8f55965b23f8619d100e725a82666a231
1 //===- bolt/Profile/YAMLProfileWriter.cpp - YAML profile serializer -------===//
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 //===----------------------------------------------------------------------===//
9 #include "bolt/Profile/YAMLProfileWriter.h"
10 #include "bolt/Core/BinaryBasicBlock.h"
11 #include "bolt/Core/BinaryFunction.h"
12 #include "bolt/Profile/ProfileReaderBase.h"
13 #include "bolt/Profile/ProfileYAMLMapping.h"
14 #include "bolt/Rewrite/RewriteInstance.h"
15 #include "llvm/Support/CommandLine.h"
16 #include "llvm/Support/FileSystem.h"
17 #include "llvm/Support/raw_ostream.h"
19 #undef DEBUG_TYPE
20 #define DEBUG_TYPE "bolt-prof"
22 namespace opts {
23 extern llvm::cl::opt<bool> ProfileUseDFS;
24 } // namespace opts
26 namespace llvm {
27 namespace bolt {
29 namespace {
30 void convert(const BinaryFunction &BF,
31 yaml::bolt::BinaryFunctionProfile &YamlBF) {
32 const BinaryContext &BC = BF.getBinaryContext();
34 const uint16_t LBRProfile = BF.getProfileFlags() & BinaryFunction::PF_LBR;
36 // Prepare function and block hashes
37 BF.computeHash(opts::ProfileUseDFS);
38 BF.computeBlockHashes();
40 YamlBF.Name = BF.getPrintName();
41 YamlBF.Id = BF.getFunctionNumber();
42 YamlBF.Hash = BF.getHash();
43 YamlBF.NumBasicBlocks = BF.size();
44 YamlBF.ExecCount = BF.getKnownExecutionCount();
46 BinaryFunction::BasicBlockOrderType Order;
47 llvm::copy(opts::ProfileUseDFS ? BF.dfs() : BF.getLayout().blocks(),
48 std::back_inserter(Order));
50 for (const BinaryBasicBlock *BB : Order) {
51 yaml::bolt::BinaryBasicBlockProfile YamlBB;
52 YamlBB.Index = BB->getLayoutIndex();
53 YamlBB.NumInstructions = BB->getNumNonPseudos();
54 YamlBB.Hash = BB->getHash();
56 if (!LBRProfile) {
57 YamlBB.EventCount = BB->getKnownExecutionCount();
58 if (YamlBB.EventCount)
59 YamlBF.Blocks.emplace_back(YamlBB);
60 continue;
63 YamlBB.ExecCount = BB->getKnownExecutionCount();
65 for (const MCInst &Instr : *BB) {
66 if (!BC.MIB->isCall(Instr) && !BC.MIB->isIndirectBranch(Instr))
67 continue;
69 SmallVector<std::pair<StringRef, yaml::bolt::CallSiteInfo>> CSTargets;
70 yaml::bolt::CallSiteInfo CSI;
71 std::optional<uint32_t> Offset = BC.MIB->getOffset(Instr);
72 if (!Offset || *Offset < BB->getInputOffset())
73 continue;
74 CSI.Offset = *Offset - BB->getInputOffset();
76 if (BC.MIB->isIndirectCall(Instr) || BC.MIB->isIndirectBranch(Instr)) {
77 const auto ICSP = BC.MIB->tryGetAnnotationAs<IndirectCallSiteProfile>(
78 Instr, "CallProfile");
79 if (!ICSP)
80 continue;
81 for (const IndirectCallProfile &CSP : ICSP.get()) {
82 StringRef TargetName = "";
83 CSI.DestId = 0; // designated for unknown functions
84 CSI.EntryDiscriminator = 0;
85 if (CSP.Symbol) {
86 const BinaryFunction *Callee = BC.getFunctionForSymbol(CSP.Symbol);
87 if (Callee) {
88 CSI.DestId = Callee->getFunctionNumber();
89 TargetName = Callee->getOneName();
92 CSI.Count = CSP.Count;
93 CSI.Mispreds = CSP.Mispreds;
94 CSTargets.emplace_back(TargetName, CSI);
96 } else { // direct call or a tail call
97 uint64_t EntryID = 0;
98 CSI.DestId = 0;
99 StringRef TargetName = "";
100 const MCSymbol *CalleeSymbol = BC.MIB->getTargetSymbol(Instr);
101 const BinaryFunction *const Callee =
102 BC.getFunctionForSymbol(CalleeSymbol, &EntryID);
103 if (Callee) {
104 CSI.DestId = Callee->getFunctionNumber();
105 CSI.EntryDiscriminator = EntryID;
106 TargetName = Callee->getOneName();
109 if (BC.MIB->getConditionalTailCall(Instr)) {
110 auto CTCCount =
111 BC.MIB->tryGetAnnotationAs<uint64_t>(Instr, "CTCTakenCount");
112 if (CTCCount) {
113 CSI.Count = *CTCCount;
114 auto CTCMispreds =
115 BC.MIB->tryGetAnnotationAs<uint64_t>(Instr, "CTCMispredCount");
116 if (CTCMispreds)
117 CSI.Mispreds = *CTCMispreds;
119 } else {
120 auto Count = BC.MIB->tryGetAnnotationAs<uint64_t>(Instr, "Count");
121 if (Count)
122 CSI.Count = *Count;
125 if (CSI.Count)
126 CSTargets.emplace_back(TargetName, CSI);
128 // Sort targets in a similar way to getBranchData, see Location::operator<
129 llvm::sort(CSTargets, [](const auto &RHS, const auto &LHS) {
130 if (RHS.first != LHS.first)
131 return RHS.first < LHS.first;
132 return RHS.second.Offset < LHS.second.Offset;
134 for (auto &KV : CSTargets)
135 YamlBB.CallSites.push_back(KV.second);
138 // Skip printing if there's no profile data for non-entry basic block.
139 // Include landing pads with non-zero execution count.
140 if (YamlBB.CallSites.empty() && !BB->isEntryPoint() &&
141 !(BB->isLandingPad() && BB->getKnownExecutionCount() != 0)) {
142 // Include blocks having successors or predecessors with positive counts.
143 uint64_t SuccessorExecCount = 0;
144 for (const BinaryBasicBlock::BinaryBranchInfo &BranchInfo :
145 BB->branch_info())
146 SuccessorExecCount += BranchInfo.Count;
147 uint64_t PredecessorExecCount = 0;
148 for (auto Pred : BB->predecessors())
149 PredecessorExecCount += Pred->getBranchInfo(*BB).Count;
150 if (!SuccessorExecCount && !PredecessorExecCount)
151 continue;
154 auto BranchInfo = BB->branch_info_begin();
155 for (const BinaryBasicBlock *Successor : BB->successors()) {
156 yaml::bolt::SuccessorInfo YamlSI;
157 YamlSI.Index = Successor->getLayoutIndex();
158 YamlSI.Count = BranchInfo->Count;
159 YamlSI.Mispreds = BranchInfo->MispredictedCount;
161 YamlBB.Successors.emplace_back(YamlSI);
163 ++BranchInfo;
166 YamlBF.Blocks.emplace_back(YamlBB);
169 } // end anonymous namespace
171 std::error_code YAMLProfileWriter::writeProfile(const RewriteInstance &RI) {
172 const BinaryContext &BC = RI.getBinaryContext();
173 const auto &Functions = BC.getBinaryFunctions();
175 std::error_code EC;
176 OS = std::make_unique<raw_fd_ostream>(Filename, EC, sys::fs::OF_None);
177 if (EC) {
178 errs() << "BOLT-WARNING: " << EC.message() << " : unable to open "
179 << Filename << " for output.\n";
180 return EC;
183 yaml::bolt::BinaryProfile BP;
185 // Fill out the header info.
186 BP.Header.Version = 1;
187 BP.Header.FileName = std::string(BC.getFilename());
188 std::optional<StringRef> BuildID = BC.getFileBuildID();
189 BP.Header.Id = BuildID ? std::string(*BuildID) : "<unknown>";
190 BP.Header.Origin = std::string(RI.getProfileReader()->getReaderName());
191 BP.Header.IsDFSOrder = opts::ProfileUseDFS;
193 StringSet<> EventNames = RI.getProfileReader()->getEventNames();
194 if (!EventNames.empty()) {
195 std::string Sep;
196 for (const StringMapEntry<std::nullopt_t> &EventEntry : EventNames) {
197 BP.Header.EventNames += Sep + EventEntry.first().str();
198 Sep = ",";
202 // Make sure the profile is consistent across all functions.
203 uint16_t ProfileFlags = BinaryFunction::PF_NONE;
204 for (const auto &BFI : Functions) {
205 const BinaryFunction &BF = BFI.second;
206 if (BF.hasProfile() && !BF.empty()) {
207 assert(BF.getProfileFlags() != BinaryFunction::PF_NONE);
208 if (ProfileFlags == BinaryFunction::PF_NONE)
209 ProfileFlags = BF.getProfileFlags();
211 assert(BF.getProfileFlags() == ProfileFlags &&
212 "expected consistent profile flags across all functions");
215 BP.Header.Flags = ProfileFlags;
217 // Add all function objects.
218 for (const auto &BFI : Functions) {
219 const BinaryFunction &BF = BFI.second;
220 if (BF.hasProfile()) {
221 if (!BF.hasValidProfile() && !RI.getProfileReader()->isTrustedSource())
222 continue;
224 yaml::bolt::BinaryFunctionProfile YamlBF;
225 convert(BF, YamlBF);
226 BP.Functions.emplace_back(YamlBF);
230 // Write the profile.
231 yaml::Output Out(*OS, nullptr, 0);
232 Out << BP;
234 return std::error_code();
237 } // namespace bolt
238 } // namespace llvm