xref: /llvm-project/bolt/lib/Profile/YAMLProfileWriter.cpp (revision 06e08696248ac01754c87c22cc8a4b797ef46430)
12f09f445SMaksim Panchenko //===- bolt/Profile/YAMLProfileWriter.cpp - YAML profile serializer -------===//
2a34c753fSRafael Auler //
3a34c753fSRafael Auler // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a34c753fSRafael Auler // See https://llvm.org/LICENSE.txt for license information.
5a34c753fSRafael Auler // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a34c753fSRafael Auler //
7a34c753fSRafael Auler //===----------------------------------------------------------------------===//
8a34c753fSRafael Auler 
9a34c753fSRafael Auler #include "bolt/Profile/YAMLProfileWriter.h"
10a34c753fSRafael Auler #include "bolt/Core/BinaryBasicBlock.h"
11a34c753fSRafael Auler #include "bolt/Core/BinaryFunction.h"
122d3c827cSAmir Ayupov #include "bolt/Profile/BoltAddressTranslation.h"
1397025bd9SAmir Ayupov #include "bolt/Profile/DataAggregator.h"
14a34c753fSRafael Auler #include "bolt/Profile/ProfileReaderBase.h"
15a34c753fSRafael Auler #include "bolt/Rewrite/RewriteInstance.h"
16c820bd3eSAmir Ayupov #include "bolt/Utils/CommandLineOpts.h"
17c00c62c1SAmir Ayupov #include "llvm/MC/MCPseudoProbe.h"
1869b7e257SAmir Ayupov #include "llvm/Support/CommandLine.h"
19a34c753fSRafael Auler #include "llvm/Support/FileSystem.h"
20a34c753fSRafael Auler #include "llvm/Support/raw_ostream.h"
21a34c753fSRafael Auler 
22a34c753fSRafael Auler #undef  DEBUG_TYPE
23a34c753fSRafael Auler #define DEBUG_TYPE "bolt-prof"
24a34c753fSRafael Auler 
2569b7e257SAmir Ayupov namespace opts {
26c820bd3eSAmir Ayupov using namespace llvm;
27c820bd3eSAmir Ayupov extern cl::opt<bool> ProfileUseDFS;
28c820bd3eSAmir Ayupov cl::opt<bool> ProfileWritePseudoProbes(
29c820bd3eSAmir Ayupov     "profile-write-pseudo-probes",
30c820bd3eSAmir Ayupov     cl::desc("Use pseudo probes in profile generation"), cl::Hidden,
31c820bd3eSAmir Ayupov     cl::cat(BoltOptCategory));
3269b7e257SAmir Ayupov } // namespace opts
3369b7e257SAmir Ayupov 
34a34c753fSRafael Auler namespace llvm {
35a34c753fSRafael Auler namespace bolt {
36a34c753fSRafael Auler 
372d3c827cSAmir Ayupov const BinaryFunction *YAMLProfileWriter::setCSIDestination(
382d3c827cSAmir Ayupov     const BinaryContext &BC, yaml::bolt::CallSiteInfo &CSI,
392d3c827cSAmir Ayupov     const MCSymbol *Symbol, const BoltAddressTranslation *BAT,
402d3c827cSAmir Ayupov     uint32_t Offset) {
41385e3e26SAmir Ayupov   CSI.DestId = 0; // designated for unknown functions
42385e3e26SAmir Ayupov   CSI.EntryDiscriminator = 0;
432d3c827cSAmir Ayupov 
44385e3e26SAmir Ayupov   if (Symbol) {
45385e3e26SAmir Ayupov     uint64_t EntryID = 0;
462d3c827cSAmir Ayupov     if (const BinaryFunction *Callee =
47385e3e26SAmir Ayupov             BC.getFunctionForSymbol(Symbol, &EntryID)) {
482d3c827cSAmir Ayupov       if (BAT && BAT->isBATFunction(Callee->getAddress()))
492d3c827cSAmir Ayupov         std::tie(Callee, EntryID) = BAT->translateSymbol(BC, *Symbol, Offset);
50935b946bSAmir Ayupov       else if (const BinaryBasicBlock *BB =
51935b946bSAmir Ayupov                    Callee->getBasicBlockContainingOffset(Offset))
52935b946bSAmir Ayupov         BC.getFunctionForSymbol(Callee->getSecondaryEntryPointSymbol(*BB),
53935b946bSAmir Ayupov                                 &EntryID);
54385e3e26SAmir Ayupov       CSI.DestId = Callee->getFunctionNumber();
55385e3e26SAmir Ayupov       CSI.EntryDiscriminator = EntryID;
56385e3e26SAmir Ayupov       return Callee;
57385e3e26SAmir Ayupov     }
58385e3e26SAmir Ayupov   }
59385e3e26SAmir Ayupov   return nullptr;
60385e3e26SAmir Ayupov }
61385e3e26SAmir Ayupov 
62c00c62c1SAmir Ayupov std::vector<YAMLProfileWriter::InlineTreeNode>
63c00c62c1SAmir Ayupov YAMLProfileWriter::collectInlineTree(
64c00c62c1SAmir Ayupov     const MCPseudoProbeDecoder &Decoder,
65c00c62c1SAmir Ayupov     const MCDecodedPseudoProbeInlineTree &Root) {
66c00c62c1SAmir Ayupov   auto getHash = [&](const MCDecodedPseudoProbeInlineTree &Node) {
67c00c62c1SAmir Ayupov     return Decoder.getFuncDescForGUID(Node.Guid)->FuncHash;
68c00c62c1SAmir Ayupov   };
69c00c62c1SAmir Ayupov   std::vector<InlineTreeNode> InlineTree(
70c00c62c1SAmir Ayupov       {InlineTreeNode{&Root, Root.Guid, getHash(Root), 0, 0}});
71c00c62c1SAmir Ayupov   uint32_t ParentId = 0;
72c00c62c1SAmir Ayupov   while (ParentId != InlineTree.size()) {
73c00c62c1SAmir Ayupov     const MCDecodedPseudoProbeInlineTree *Cur = InlineTree[ParentId].InlineTree;
74c00c62c1SAmir Ayupov     for (const MCDecodedPseudoProbeInlineTree &Child : Cur->getChildren())
75c00c62c1SAmir Ayupov       InlineTree.emplace_back(
76c00c62c1SAmir Ayupov           InlineTreeNode{&Child, Child.Guid, getHash(Child), ParentId,
77c00c62c1SAmir Ayupov                          std::get<1>(Child.getInlineSite())});
78c00c62c1SAmir Ayupov     ++ParentId;
79c00c62c1SAmir Ayupov   }
80c00c62c1SAmir Ayupov 
81c00c62c1SAmir Ayupov   return InlineTree;
82c00c62c1SAmir Ayupov }
83c00c62c1SAmir Ayupov 
84cd774c87SAmir Ayupov std::tuple<yaml::bolt::ProfilePseudoProbeDesc,
85cd774c87SAmir Ayupov            YAMLProfileWriter::InlineTreeDesc>
86c00c62c1SAmir Ayupov YAMLProfileWriter::convertPseudoProbeDesc(const MCPseudoProbeDecoder &Decoder) {
87cd774c87SAmir Ayupov   yaml::bolt::ProfilePseudoProbeDesc Desc;
88c00c62c1SAmir Ayupov   InlineTreeDesc InlineTree;
89c00c62c1SAmir Ayupov 
90c00c62c1SAmir Ayupov   for (const MCDecodedPseudoProbeInlineTree &TopLev :
91c00c62c1SAmir Ayupov        Decoder.getDummyInlineRoot().getChildren())
92c00c62c1SAmir Ayupov     InlineTree.TopLevelGUIDToInlineTree[TopLev.Guid] = &TopLev;
93c00c62c1SAmir Ayupov 
94c00c62c1SAmir Ayupov   for (const auto &FuncDesc : Decoder.getGUID2FuncDescMap())
95c00c62c1SAmir Ayupov     ++InlineTree.HashIdxMap[FuncDesc.FuncHash];
96c00c62c1SAmir Ayupov 
97c00c62c1SAmir Ayupov   InlineTree.GUIDIdxMap.reserve(Decoder.getGUID2FuncDescMap().size());
98c00c62c1SAmir Ayupov   for (const auto &Node : Decoder.getInlineTreeVec())
99c00c62c1SAmir Ayupov     ++InlineTree.GUIDIdxMap[Node.Guid];
100c00c62c1SAmir Ayupov 
101c00c62c1SAmir Ayupov   std::vector<std::pair<uint32_t, uint64_t>> GUIDFreqVec;
102c00c62c1SAmir Ayupov   GUIDFreqVec.reserve(InlineTree.GUIDIdxMap.size());
103c00c62c1SAmir Ayupov   for (const auto [GUID, Cnt] : InlineTree.GUIDIdxMap)
104c00c62c1SAmir Ayupov     GUIDFreqVec.emplace_back(Cnt, GUID);
105c00c62c1SAmir Ayupov   llvm::sort(GUIDFreqVec);
106c00c62c1SAmir Ayupov 
107c00c62c1SAmir Ayupov   std::vector<std::pair<uint32_t, uint64_t>> HashFreqVec;
108c00c62c1SAmir Ayupov   HashFreqVec.reserve(InlineTree.HashIdxMap.size());
109c00c62c1SAmir Ayupov   for (const auto [Hash, Cnt] : InlineTree.HashIdxMap)
110c00c62c1SAmir Ayupov     HashFreqVec.emplace_back(Cnt, Hash);
111c00c62c1SAmir Ayupov   llvm::sort(HashFreqVec);
112c00c62c1SAmir Ayupov 
113c00c62c1SAmir Ayupov   uint32_t Index = 0;
114c00c62c1SAmir Ayupov   Desc.Hash.reserve(HashFreqVec.size());
115c00c62c1SAmir Ayupov   for (uint64_t Hash : llvm::make_second_range(llvm::reverse(HashFreqVec))) {
116c00c62c1SAmir Ayupov     Desc.Hash.emplace_back(Hash);
117c00c62c1SAmir Ayupov     InlineTree.HashIdxMap[Hash] = Index++;
118c00c62c1SAmir Ayupov   }
119c00c62c1SAmir Ayupov 
120c00c62c1SAmir Ayupov   Index = 0;
121c00c62c1SAmir Ayupov   Desc.GUID.reserve(GUIDFreqVec.size());
122c00c62c1SAmir Ayupov   for (uint64_t GUID : llvm::make_second_range(llvm::reverse(GUIDFreqVec))) {
123c00c62c1SAmir Ayupov     Desc.GUID.emplace_back(GUID);
124c00c62c1SAmir Ayupov     InlineTree.GUIDIdxMap[GUID] = Index++;
125c00c62c1SAmir Ayupov     uint64_t Hash = Decoder.getFuncDescForGUID(GUID)->FuncHash;
126c00c62c1SAmir Ayupov     Desc.GUIDHashIdx.emplace_back(InlineTree.HashIdxMap[Hash]);
127c00c62c1SAmir Ayupov   }
128c00c62c1SAmir Ayupov 
129c00c62c1SAmir Ayupov   return {Desc, InlineTree};
130c00c62c1SAmir Ayupov }
131c00c62c1SAmir Ayupov 
132c00c62c1SAmir Ayupov std::vector<yaml::bolt::PseudoProbeInfo>
133c00c62c1SAmir Ayupov YAMLProfileWriter::convertNodeProbes(NodeIdToProbes &NodeProbes) {
134c00c62c1SAmir Ayupov   struct BlockProbeInfoHasher {
135c00c62c1SAmir Ayupov     size_t operator()(const yaml::bolt::PseudoProbeInfo &BPI) const {
136c00c62c1SAmir Ayupov       auto HashCombine = [](auto &Range) {
137c00c62c1SAmir Ayupov         return llvm::hash_combine_range(Range.begin(), Range.end());
138c00c62c1SAmir Ayupov       };
139c00c62c1SAmir Ayupov       return llvm::hash_combine(HashCombine(BPI.BlockProbes),
140c00c62c1SAmir Ayupov                                 HashCombine(BPI.CallProbes),
141c00c62c1SAmir Ayupov                                 HashCombine(BPI.IndCallProbes));
142c00c62c1SAmir Ayupov     }
143c00c62c1SAmir Ayupov   };
144c00c62c1SAmir Ayupov 
145c00c62c1SAmir Ayupov   // Check identical BlockProbeInfo structs and merge them
146c00c62c1SAmir Ayupov   std::unordered_map<yaml::bolt::PseudoProbeInfo, std::vector<uint32_t>,
147c00c62c1SAmir Ayupov                      BlockProbeInfoHasher>
148c00c62c1SAmir Ayupov       BPIToNodes;
149c00c62c1SAmir Ayupov   for (auto &[NodeId, Probes] : NodeProbes) {
150c00c62c1SAmir Ayupov     yaml::bolt::PseudoProbeInfo BPI;
151c00c62c1SAmir Ayupov     BPI.BlockProbes = std::vector(Probes[0].begin(), Probes[0].end());
152c00c62c1SAmir Ayupov     BPI.IndCallProbes = std::vector(Probes[1].begin(), Probes[1].end());
153c00c62c1SAmir Ayupov     BPI.CallProbes = std::vector(Probes[2].begin(), Probes[2].end());
154c00c62c1SAmir Ayupov     BPIToNodes[BPI].push_back(NodeId);
155c00c62c1SAmir Ayupov   }
156c00c62c1SAmir Ayupov 
157c00c62c1SAmir Ayupov   auto handleMask = [](const auto &Ids, auto &Vec, auto &Mask) {
158c00c62c1SAmir Ayupov     for (auto Id : Ids)
159c00c62c1SAmir Ayupov       if (Id > 64)
160c00c62c1SAmir Ayupov         Vec.emplace_back(Id);
161c00c62c1SAmir Ayupov       else
162c00c62c1SAmir Ayupov         Mask |= 1ull << (Id - 1);
163c00c62c1SAmir Ayupov   };
164c00c62c1SAmir Ayupov 
165c00c62c1SAmir Ayupov   // Add to YAML with merged nodes/block mask optimizations
166c00c62c1SAmir Ayupov   std::vector<yaml::bolt::PseudoProbeInfo> YamlProbes;
167c00c62c1SAmir Ayupov   YamlProbes.reserve(BPIToNodes.size());
168c00c62c1SAmir Ayupov   for (const auto &[BPI, Nodes] : BPIToNodes) {
169c00c62c1SAmir Ayupov     auto &YamlBPI = YamlProbes.emplace_back(yaml::bolt::PseudoProbeInfo());
170c00c62c1SAmir Ayupov     YamlBPI.CallProbes = BPI.CallProbes;
171c00c62c1SAmir Ayupov     YamlBPI.IndCallProbes = BPI.IndCallProbes;
172c00c62c1SAmir Ayupov     if (Nodes.size() == 1)
173c00c62c1SAmir Ayupov       YamlBPI.InlineTreeIndex = Nodes.front();
174c00c62c1SAmir Ayupov     else
175c00c62c1SAmir Ayupov       YamlBPI.InlineTreeNodes = Nodes;
176c00c62c1SAmir Ayupov     handleMask(BPI.BlockProbes, YamlBPI.BlockProbes, YamlBPI.BlockMask);
177c00c62c1SAmir Ayupov   }
178c00c62c1SAmir Ayupov   return YamlProbes;
179c00c62c1SAmir Ayupov }
180c00c62c1SAmir Ayupov 
181c00c62c1SAmir Ayupov std::tuple<std::vector<yaml::bolt::InlineTreeNode>,
182c00c62c1SAmir Ayupov            YAMLProfileWriter::InlineTreeMapTy>
183c00c62c1SAmir Ayupov YAMLProfileWriter::convertBFInlineTree(const MCPseudoProbeDecoder &Decoder,
184c00c62c1SAmir Ayupov                                        const InlineTreeDesc &InlineTree,
185c00c62c1SAmir Ayupov                                        uint64_t GUID) {
186c00c62c1SAmir Ayupov   DenseMap<const MCDecodedPseudoProbeInlineTree *, uint32_t> InlineTreeNodeId;
187c00c62c1SAmir Ayupov   std::vector<yaml::bolt::InlineTreeNode> YamlInlineTree;
188c00c62c1SAmir Ayupov   auto It = InlineTree.TopLevelGUIDToInlineTree.find(GUID);
189c00c62c1SAmir Ayupov   if (It == InlineTree.TopLevelGUIDToInlineTree.end())
190c00c62c1SAmir Ayupov     return {YamlInlineTree, InlineTreeNodeId};
191c00c62c1SAmir Ayupov   const MCDecodedPseudoProbeInlineTree *Root = It->second;
192c00c62c1SAmir Ayupov   assert(Root && "Malformed TopLevelGUIDToInlineTree");
193c00c62c1SAmir Ayupov   uint32_t Index = 0;
194c00c62c1SAmir Ayupov   uint32_t PrevParent = 0;
195c00c62c1SAmir Ayupov   uint32_t PrevGUIDIdx = 0;
196c00c62c1SAmir Ayupov   for (const auto &Node : collectInlineTree(Decoder, *Root)) {
197c00c62c1SAmir Ayupov     InlineTreeNodeId[Node.InlineTree] = Index++;
198c00c62c1SAmir Ayupov     auto GUIDIdxIt = InlineTree.GUIDIdxMap.find(Node.GUID);
199c00c62c1SAmir Ayupov     assert(GUIDIdxIt != InlineTree.GUIDIdxMap.end() && "Malformed GUIDIdxMap");
200c00c62c1SAmir Ayupov     uint32_t GUIDIdx = GUIDIdxIt->second;
201c00c62c1SAmir Ayupov     if (GUIDIdx == PrevGUIDIdx)
202c00c62c1SAmir Ayupov       GUIDIdx = UINT32_MAX;
203c00c62c1SAmir Ayupov     else
204c00c62c1SAmir Ayupov       PrevGUIDIdx = GUIDIdx;
205c00c62c1SAmir Ayupov     YamlInlineTree.emplace_back(yaml::bolt::InlineTreeNode{
206*06e08696SKazu Hirata         Node.ParentId - PrevParent, Node.InlineSite, GUIDIdx, 0, 0});
207c00c62c1SAmir Ayupov     PrevParent = Node.ParentId;
208c00c62c1SAmir Ayupov   }
209c00c62c1SAmir Ayupov   return {YamlInlineTree, InlineTreeNodeId};
210c00c62c1SAmir Ayupov }
211c00c62c1SAmir Ayupov 
212061b4089SAmir Ayupov yaml::bolt::BinaryFunctionProfile
2132d3c827cSAmir Ayupov YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS,
214c00c62c1SAmir Ayupov                            const InlineTreeDesc &InlineTree,
2152d3c827cSAmir Ayupov                            const BoltAddressTranslation *BAT) {
216061b4089SAmir Ayupov   yaml::bolt::BinaryFunctionProfile YamlBF;
217a34c753fSRafael Auler   const BinaryContext &BC = BF.getBinaryContext();
2184d19676dSAmir Ayupov   const MCPseudoProbeDecoder *PseudoProbeDecoder =
219c820bd3eSAmir Ayupov       opts::ProfileWritePseudoProbes ? BC.getPseudoProbeDecoder() : nullptr;
220a34c753fSRafael Auler 
221a34c753fSRafael Auler   const uint16_t LBRProfile = BF.getProfileFlags() & BinaryFunction::PF_LBR;
222a34c753fSRafael Auler 
2233e3a926bSspupyrev   // Prepare function and block hashes
224061b4089SAmir Ayupov   BF.computeHash(UseDFS);
2253e3a926bSspupyrev   BF.computeBlockHashes();
2263e3a926bSspupyrev 
22797025bd9SAmir Ayupov   YamlBF.Name = DataAggregator::getLocationName(BF, BAT);
228a34c753fSRafael Auler   YamlBF.Id = BF.getFunctionNumber();
2293e3a926bSspupyrev   YamlBF.Hash = BF.getHash();
230a34c753fSRafael Auler   YamlBF.NumBasicBlocks = BF.size();
231a34c753fSRafael Auler   YamlBF.ExecCount = BF.getKnownExecutionCount();
232c00c62c1SAmir Ayupov   DenseMap<const MCDecodedPseudoProbeInlineTree *, uint32_t> InlineTreeNodeId;
233c00c62c1SAmir Ayupov   if (PseudoProbeDecoder && BF.getGUID()) {
234c00c62c1SAmir Ayupov     std::tie(YamlBF.InlineTree, InlineTreeNodeId) =
235c00c62c1SAmir Ayupov         convertBFInlineTree(*PseudoProbeDecoder, InlineTree, BF.getGUID());
2369b007a19SAmir Ayupov   }
237a34c753fSRafael Auler 
23869b7e257SAmir Ayupov   BinaryFunction::BasicBlockOrderType Order;
239061b4089SAmir Ayupov   llvm::copy(UseDFS ? BF.dfs() : BF.getLayout().blocks(),
24069b7e257SAmir Ayupov              std::back_inserter(Order));
24169b7e257SAmir Ayupov 
2424be3083bSshaw young   const FunctionLayout Layout = BF.getLayout();
2434be3083bSshaw young   Layout.updateLayoutIndices(Order);
2444be3083bSshaw young 
24569b7e257SAmir Ayupov   for (const BinaryBasicBlock *BB : Order) {
246a34c753fSRafael Auler     yaml::bolt::BinaryBasicBlockProfile YamlBB;
247a34c753fSRafael Auler     YamlBB.Index = BB->getLayoutIndex();
248a34c753fSRafael Auler     YamlBB.NumInstructions = BB->getNumNonPseudos();
2493e3a926bSspupyrev     YamlBB.Hash = BB->getHash();
250a34c753fSRafael Auler 
251a34c753fSRafael Auler     if (!LBRProfile) {
252a34c753fSRafael Auler       YamlBB.EventCount = BB->getKnownExecutionCount();
253a34c753fSRafael Auler       if (YamlBB.EventCount)
254a34c753fSRafael Auler         YamlBF.Blocks.emplace_back(YamlBB);
255a34c753fSRafael Auler       continue;
256a34c753fSRafael Auler     }
257a34c753fSRafael Auler 
258a34c753fSRafael Auler     YamlBB.ExecCount = BB->getKnownExecutionCount();
259a34c753fSRafael Auler 
260a34c753fSRafael Auler     for (const MCInst &Instr : *BB) {
261a34c753fSRafael Auler       if (!BC.MIB->isCall(Instr) && !BC.MIB->isIndirectBranch(Instr))
262a34c753fSRafael Auler         continue;
263a34c753fSRafael Auler 
2646c873155SAmir Ayupov       SmallVector<std::pair<StringRef, yaml::bolt::CallSiteInfo>> CSTargets;
265a34c753fSRafael Auler       yaml::bolt::CallSiteInfo CSI;
2662563fd63SAmir Ayupov       std::optional<uint32_t> Offset = BC.MIB->getOffset(Instr);
267a9cd49d5SAmir Ayupov       if (!Offset || *Offset < BB->getInputOffset())
268a34c753fSRafael Auler         continue;
269a9cd49d5SAmir Ayupov       CSI.Offset = *Offset - BB->getInputOffset();
270a34c753fSRafael Auler 
271a34c753fSRafael Auler       if (BC.MIB->isIndirectCall(Instr) || BC.MIB->isIndirectBranch(Instr)) {
272f18fcdabSAmir Ayupov         const auto ICSP = BC.MIB->tryGetAnnotationAs<IndirectCallSiteProfile>(
27340c2e0faSMaksim Panchenko             Instr, "CallProfile");
274a34c753fSRafael Auler         if (!ICSP)
275a34c753fSRafael Auler           continue;
276a34c753fSRafael Auler         for (const IndirectCallProfile &CSP : ICSP.get()) {
2776c873155SAmir Ayupov           StringRef TargetName = "";
2782d3c827cSAmir Ayupov           const BinaryFunction *Callee =
2792d3c827cSAmir Ayupov               setCSIDestination(BC, CSI, CSP.Symbol, BAT);
280385e3e26SAmir Ayupov           if (Callee)
2816c873155SAmir Ayupov             TargetName = Callee->getOneName();
282a34c753fSRafael Auler           CSI.Count = CSP.Count;
283a34c753fSRafael Auler           CSI.Mispreds = CSP.Mispreds;
2846c873155SAmir Ayupov           CSTargets.emplace_back(TargetName, CSI);
285a34c753fSRafael Auler         }
286a34c753fSRafael Auler       } else { // direct call or a tail call
2876c873155SAmir Ayupov         StringRef TargetName = "";
288a34c753fSRafael Auler         const MCSymbol *CalleeSymbol = BC.MIB->getTargetSymbol(Instr);
289a34c753fSRafael Auler         const BinaryFunction *const Callee =
2902d3c827cSAmir Ayupov             setCSIDestination(BC, CSI, CalleeSymbol, BAT);
291385e3e26SAmir Ayupov         if (Callee)
2926c873155SAmir Ayupov           TargetName = Callee->getOneName();
293a34c753fSRafael Auler 
294de0abc09SAmir Ayupov         auto getAnnotationWithDefault = [&](const MCInst &Inst, StringRef Ann) {
295de0abc09SAmir Ayupov           return BC.MIB->getAnnotationWithDefault(Instr, Ann, 0ull);
296de0abc09SAmir Ayupov         };
297a34c753fSRafael Auler         if (BC.MIB->getConditionalTailCall(Instr)) {
298de0abc09SAmir Ayupov           CSI.Count = getAnnotationWithDefault(Instr, "CTCTakenCount");
299de0abc09SAmir Ayupov           CSI.Mispreds = getAnnotationWithDefault(Instr, "CTCMispredCount");
300a34c753fSRafael Auler         } else {
301de0abc09SAmir Ayupov           CSI.Count = getAnnotationWithDefault(Instr, "Count");
302a34c753fSRafael Auler         }
303a34c753fSRafael Auler 
304a34c753fSRafael Auler         if (CSI.Count)
3056c873155SAmir Ayupov           CSTargets.emplace_back(TargetName, CSI);
306a34c753fSRafael Auler       }
3076c873155SAmir Ayupov       // Sort targets in a similar way to getBranchData, see Location::operator<
3086c873155SAmir Ayupov       llvm::sort(CSTargets, [](const auto &RHS, const auto &LHS) {
3096c873155SAmir Ayupov         if (RHS.first != LHS.first)
3106c873155SAmir Ayupov           return RHS.first < LHS.first;
3116c873155SAmir Ayupov         return RHS.second.Offset < LHS.second.Offset;
3126c873155SAmir Ayupov       });
3136c873155SAmir Ayupov       for (auto &KV : CSTargets)
3146c873155SAmir Ayupov         YamlBB.CallSites.push_back(KV.second);
315a34c753fSRafael Auler     }
316a34c753fSRafael Auler 
317a34c753fSRafael Auler     // Skip printing if there's no profile data for non-entry basic block.
318a34c753fSRafael Auler     // Include landing pads with non-zero execution count.
31940c2e0faSMaksim Panchenko     if (YamlBB.CallSites.empty() && !BB->isEntryPoint() &&
320a34c753fSRafael Auler         !(BB->isLandingPad() && BB->getKnownExecutionCount() != 0)) {
3213e3a926bSspupyrev       // Include blocks having successors or predecessors with positive counts.
322a34c753fSRafael Auler       uint64_t SuccessorExecCount = 0;
323a34c753fSRafael Auler       for (const BinaryBasicBlock::BinaryBranchInfo &BranchInfo :
324def464aaSAmir Ayupov            BB->branch_info())
325a34c753fSRafael Auler         SuccessorExecCount += BranchInfo.Count;
3263e3a926bSspupyrev       uint64_t PredecessorExecCount = 0;
3273e3a926bSspupyrev       for (auto Pred : BB->predecessors())
3283e3a926bSspupyrev         PredecessorExecCount += Pred->getBranchInfo(*BB).Count;
3293e3a926bSspupyrev       if (!SuccessorExecCount && !PredecessorExecCount)
330a34c753fSRafael Auler         continue;
331a34c753fSRafael Auler     }
332a34c753fSRafael Auler 
333a34c753fSRafael Auler     auto BranchInfo = BB->branch_info_begin();
334a34c753fSRafael Auler     for (const BinaryBasicBlock *Successor : BB->successors()) {
335a34c753fSRafael Auler       yaml::bolt::SuccessorInfo YamlSI;
336a34c753fSRafael Auler       YamlSI.Index = Successor->getLayoutIndex();
337a34c753fSRafael Auler       YamlSI.Count = BranchInfo->Count;
338a34c753fSRafael Auler       YamlSI.Mispreds = BranchInfo->MispredictedCount;
339a34c753fSRafael Auler 
340a34c753fSRafael Auler       YamlBB.Successors.emplace_back(YamlSI);
341a34c753fSRafael Auler 
342a34c753fSRafael Auler       ++BranchInfo;
343a34c753fSRafael Auler     }
344a34c753fSRafael Auler 
345c905db67SAmir Ayupov     if (PseudoProbeDecoder) {
346c905db67SAmir Ayupov       const AddressProbesMap &ProbeMap =
347c905db67SAmir Ayupov           PseudoProbeDecoder->getAddress2ProbesMap();
348c905db67SAmir Ayupov       const uint64_t FuncAddr = BF.getAddress();
349c905db67SAmir Ayupov       const std::pair<uint64_t, uint64_t> &BlockRange =
350c905db67SAmir Ayupov           BB->getInputAddressRange();
351c00c62c1SAmir Ayupov       const std::pair<uint64_t, uint64_t> BlockAddrRange = {
352c00c62c1SAmir Ayupov           FuncAddr + BlockRange.first, FuncAddr + BlockRange.second};
353c00c62c1SAmir Ayupov       auto Probes = ProbeMap.find(BlockAddrRange.first, BlockAddrRange.second);
354c00c62c1SAmir Ayupov       YamlBB.PseudoProbes = writeBlockProbes(Probes, InlineTreeNodeId);
355c905db67SAmir Ayupov     }
356c905db67SAmir Ayupov 
357a34c753fSRafael Auler     YamlBF.Blocks.emplace_back(YamlBB);
358a34c753fSRafael Auler   }
359061b4089SAmir Ayupov   return YamlBF;
360a34c753fSRafael Auler }
361a34c753fSRafael Auler 
36240c2e0faSMaksim Panchenko std::error_code YAMLProfileWriter::writeProfile(const RewriteInstance &RI) {
363a34c753fSRafael Auler   const BinaryContext &BC = RI.getBinaryContext();
364a34c753fSRafael Auler   const auto &Functions = BC.getBinaryFunctions();
365a34c753fSRafael Auler 
366a34c753fSRafael Auler   std::error_code EC;
367a34c753fSRafael Auler   OS = std::make_unique<raw_fd_ostream>(Filename, EC, sys::fs::OF_None);
368a34c753fSRafael Auler   if (EC) {
369a34c753fSRafael Auler     errs() << "BOLT-WARNING: " << EC.message() << " : unable to open "
370a34c753fSRafael Auler            << Filename << " for output.\n";
371a34c753fSRafael Auler     return EC;
372a34c753fSRafael Auler   }
373a34c753fSRafael Auler 
374a34c753fSRafael Auler   yaml::bolt::BinaryProfile BP;
375a34c753fSRafael Auler 
376a34c753fSRafael Auler   // Fill out the header info.
377a34c753fSRafael Auler   BP.Header.Version = 1;
378a34c753fSRafael Auler   BP.Header.FileName = std::string(BC.getFilename());
379e8f5743eSAmir Ayupov   std::optional<StringRef> BuildID = BC.getFileBuildID();
380a34c753fSRafael Auler   BP.Header.Id = BuildID ? std::string(*BuildID) : "<unknown>";
381a34c753fSRafael Auler   BP.Header.Origin = std::string(RI.getProfileReader()->getReaderName());
3821e0d08e8SAmir Ayupov   BP.Header.IsDFSOrder = opts::ProfileUseDFS;
383b039ccc6SAmir Ayupov   BP.Header.HashFunction = HashFunction::Default;
384a34c753fSRafael Auler 
385a34c753fSRafael Auler   StringSet<> EventNames = RI.getProfileReader()->getEventNames();
386a34c753fSRafael Auler   if (!EventNames.empty()) {
387ce3b687bSKazu Hirata     std::string Sep;
38834bcadc3SKazu Hirata     for (const StringMapEntry<std::nullopt_t> &EventEntry : EventNames) {
389a34c753fSRafael Auler       BP.Header.EventNames += Sep + EventEntry.first().str();
390a34c753fSRafael Auler       Sep = ",";
391a34c753fSRafael Auler     }
392a34c753fSRafael Auler   }
393a34c753fSRafael Auler 
394a34c753fSRafael Auler   // Make sure the profile is consistent across all functions.
395a34c753fSRafael Auler   uint16_t ProfileFlags = BinaryFunction::PF_NONE;
396a34c753fSRafael Auler   for (const auto &BFI : Functions) {
397a34c753fSRafael Auler     const BinaryFunction &BF = BFI.second;
398a34c753fSRafael Auler     if (BF.hasProfile() && !BF.empty()) {
399a34c753fSRafael Auler       assert(BF.getProfileFlags() != BinaryFunction::PF_NONE);
400def464aaSAmir Ayupov       if (ProfileFlags == BinaryFunction::PF_NONE)
401a34c753fSRafael Auler         ProfileFlags = BF.getProfileFlags();
402def464aaSAmir Ayupov 
403a34c753fSRafael Auler       assert(BF.getProfileFlags() == ProfileFlags &&
404a34c753fSRafael Auler              "expected consistent profile flags across all functions");
405a34c753fSRafael Auler     }
406a34c753fSRafael Auler   }
407a34c753fSRafael Auler   BP.Header.Flags = ProfileFlags;
408a34c753fSRafael Auler 
409c00c62c1SAmir Ayupov   // Add probe inline tree nodes.
410c00c62c1SAmir Ayupov   InlineTreeDesc InlineTree;
411c00c62c1SAmir Ayupov   if (const MCPseudoProbeDecoder *Decoder =
412c00c62c1SAmir Ayupov           opts::ProfileWritePseudoProbes ? BC.getPseudoProbeDecoder() : nullptr)
413c00c62c1SAmir Ayupov     std::tie(BP.PseudoProbeDesc, InlineTree) = convertPseudoProbeDesc(*Decoder);
414c00c62c1SAmir Ayupov 
415a34c753fSRafael Auler   // Add all function objects.
416a34c753fSRafael Auler   for (const auto &BFI : Functions) {
417a34c753fSRafael Auler     const BinaryFunction &BF = BFI.second;
418a34c753fSRafael Auler     if (BF.hasProfile()) {
419a34c753fSRafael Auler       if (!BF.hasValidProfile() && !RI.getProfileReader()->isTrustedSource())
420a34c753fSRafael Auler         continue;
421a34c753fSRafael Auler 
422c00c62c1SAmir Ayupov       BP.Functions.emplace_back(convert(BF, opts::ProfileUseDFS, InlineTree));
423a34c753fSRafael Auler     }
424a34c753fSRafael Auler   }
425a34c753fSRafael Auler 
426a34c753fSRafael Auler   // Write the profile.
427a34c753fSRafael Auler   yaml::Output Out(*OS, nullptr, 0);
428a34c753fSRafael Auler   Out << BP;
429a34c753fSRafael Auler 
430a34c753fSRafael Auler   return std::error_code();
431a34c753fSRafael Auler }
432a34c753fSRafael Auler 
433a34c753fSRafael Auler } // namespace bolt
434a34c753fSRafael Auler } // namespace llvm
435