1 //===- bolt/Profile/ProfileYAMLMapping.h ------------------------*- 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 // Implement mapping between binary function profile and YAML representation. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #ifndef BOLT_PROFILE_PROFILEYAMLMAPPING_H 14 #define BOLT_PROFILE_PROFILEYAMLMAPPING_H 15 16 #include "bolt/Core/BinaryFunction.h" 17 #include "llvm/Support/YAMLTraits.h" 18 #include <vector> 19 20 using llvm::bolt::BinaryFunction; 21 22 namespace llvm { 23 namespace yaml { 24 25 namespace bolt { 26 struct CallSiteInfo { 27 llvm::yaml::Hex32 Offset{0}; 28 uint32_t DestId{0}; 29 uint32_t EntryDiscriminator{0}; /// multiple entry discriminator 30 uint64_t Count{0}; 31 uint64_t Mispreds{0}; 32 33 bool operator==(const CallSiteInfo &Other) const { 34 return Offset == Other.Offset && DestId == Other.DestId && 35 EntryDiscriminator == Other.EntryDiscriminator; 36 } 37 38 bool operator!=(const CallSiteInfo &Other) const { return !(*this == Other); } 39 40 bool operator<(const CallSiteInfo &Other) const { 41 if (Offset < Other.Offset) 42 return true; 43 if (Offset > Other.Offset) 44 return false; 45 46 if (DestId < Other.DestId) 47 return true; 48 if (DestId > Other.DestId) 49 return false; 50 51 if (EntryDiscriminator < Other.EntryDiscriminator) 52 return true; 53 54 return false; 55 } 56 }; 57 } // end namespace bolt 58 59 template <> struct MappingTraits<bolt::CallSiteInfo> { 60 static void mapping(IO &YamlIO, bolt::CallSiteInfo &CSI) { 61 YamlIO.mapRequired("off", CSI.Offset); 62 YamlIO.mapRequired("fid", CSI.DestId); 63 YamlIO.mapOptional("disc", CSI.EntryDiscriminator, (uint32_t)0); 64 YamlIO.mapRequired("cnt", CSI.Count); 65 YamlIO.mapOptional("mis", CSI.Mispreds, (uint64_t)0); 66 } 67 68 static const bool flow = true; 69 }; 70 71 namespace bolt { 72 struct SuccessorInfo { 73 uint32_t Index{0}; 74 uint64_t Count{0}; 75 uint64_t Mispreds{0}; 76 77 bool operator==(const SuccessorInfo &Other) const { 78 return Index == Other.Index; 79 } 80 bool operator!=(const SuccessorInfo &Other) const { 81 return !(*this == Other); 82 } 83 }; 84 } // end namespace bolt 85 86 template <> struct MappingTraits<bolt::SuccessorInfo> { 87 static void mapping(IO &YamlIO, bolt::SuccessorInfo &SI) { 88 YamlIO.mapRequired("bid", SI.Index); 89 YamlIO.mapRequired("cnt", SI.Count); 90 YamlIO.mapOptional("mis", SI.Mispreds, (uint64_t)0); 91 } 92 93 static const bool flow = true; 94 }; 95 96 namespace bolt { 97 struct PseudoProbeInfo { 98 uint32_t InlineTreeIndex = 0; 99 uint64_t BlockMask = 0; // bitset with probe indices from 1 to 64 100 std::vector<uint64_t> BlockProbes; // block probes with indices above 64 101 std::vector<uint64_t> CallProbes; 102 std::vector<uint64_t> IndCallProbes; 103 std::vector<uint32_t> InlineTreeNodes; 104 105 bool operator==(const PseudoProbeInfo &Other) const { 106 return InlineTreeIndex == Other.InlineTreeIndex && 107 BlockProbes == Other.BlockProbes && CallProbes == Other.CallProbes && 108 IndCallProbes == Other.IndCallProbes; 109 } 110 }; 111 } // end namespace bolt 112 113 template <> struct MappingTraits<bolt::PseudoProbeInfo> { 114 static void mapping(IO &YamlIO, bolt::PseudoProbeInfo &PI) { 115 YamlIO.mapOptional("blx", PI.BlockMask, 0); 116 YamlIO.mapOptional("blk", PI.BlockProbes, std::vector<uint64_t>()); 117 YamlIO.mapOptional("call", PI.CallProbes, std::vector<uint64_t>()); 118 YamlIO.mapOptional("icall", PI.IndCallProbes, std::vector<uint64_t>()); 119 YamlIO.mapOptional("id", PI.InlineTreeIndex, 0); 120 YamlIO.mapOptional("ids", PI.InlineTreeNodes, std::vector<uint32_t>()); 121 } 122 123 static const bool flow = true; 124 }; 125 } // end namespace yaml 126 } // end namespace llvm 127 128 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::bolt::CallSiteInfo) 129 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::bolt::SuccessorInfo) 130 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::bolt::PseudoProbeInfo) 131 132 namespace llvm { 133 namespace yaml { 134 135 namespace bolt { 136 struct BinaryBasicBlockProfile { 137 uint32_t Index{0}; 138 uint32_t NumInstructions{0}; 139 llvm::yaml::Hex64 Hash{0}; 140 uint64_t ExecCount{0}; 141 uint64_t EventCount{0}; 142 std::vector<CallSiteInfo> CallSites; 143 std::vector<SuccessorInfo> Successors; 144 std::vector<PseudoProbeInfo> PseudoProbes; 145 146 bool operator==(const BinaryBasicBlockProfile &Other) const { 147 return Index == Other.Index; 148 } 149 bool operator!=(const BinaryBasicBlockProfile &Other) const { 150 return !(*this == Other); 151 } 152 }; 153 } // end namespace bolt 154 155 template <> struct MappingTraits<bolt::BinaryBasicBlockProfile> { 156 static void mapping(IO &YamlIO, bolt::BinaryBasicBlockProfile &BBP) { 157 YamlIO.mapRequired("bid", BBP.Index); 158 YamlIO.mapRequired("insns", BBP.NumInstructions); 159 YamlIO.mapOptional("hash", BBP.Hash, (llvm::yaml::Hex64)0); 160 YamlIO.mapOptional("exec", BBP.ExecCount, (uint64_t)0); 161 YamlIO.mapOptional("events", BBP.EventCount, (uint64_t)0); 162 YamlIO.mapOptional("calls", BBP.CallSites, 163 std::vector<bolt::CallSiteInfo>()); 164 YamlIO.mapOptional("succ", BBP.Successors, 165 std::vector<bolt::SuccessorInfo>()); 166 YamlIO.mapOptional("probes", BBP.PseudoProbes, 167 std::vector<bolt::PseudoProbeInfo>()); 168 } 169 }; 170 171 namespace bolt { 172 struct InlineTreeNode { 173 uint32_t ParentIndexDelta; 174 uint32_t CallSiteProbe; 175 // Index in PseudoProbeDesc.GUID, UINT32_MAX for same as previous (omitted) 176 uint32_t GUIDIndex; 177 // Decoded contents, ParentIndexDelta becomes absolute value. 178 uint64_t GUID; 179 uint64_t Hash; 180 bool operator==(const InlineTreeNode &) const { return false; } 181 }; 182 } // end namespace bolt 183 184 template <> struct MappingTraits<bolt::InlineTreeNode> { 185 static void mapping(IO &YamlIO, bolt::InlineTreeNode &ITI) { 186 YamlIO.mapOptional("g", ITI.GUIDIndex, UINT32_MAX); 187 YamlIO.mapOptional("p", ITI.ParentIndexDelta, 0); 188 YamlIO.mapOptional("cs", ITI.CallSiteProbe, 0); 189 } 190 191 static const bool flow = true; 192 }; 193 } // end namespace yaml 194 } // end namespace llvm 195 196 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::bolt::BinaryBasicBlockProfile) 197 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::bolt::InlineTreeNode) 198 199 namespace llvm { 200 namespace yaml { 201 202 namespace bolt { 203 struct BinaryFunctionProfile { 204 std::string Name; 205 uint32_t NumBasicBlocks{0}; 206 uint32_t Id{0}; 207 llvm::yaml::Hex64 Hash{0}; 208 uint64_t ExecCount{0}; 209 std::vector<BinaryBasicBlockProfile> Blocks; 210 std::vector<InlineTreeNode> InlineTree; 211 bool Used{false}; 212 }; 213 } // end namespace bolt 214 215 template <> struct MappingTraits<bolt::BinaryFunctionProfile> { 216 static void mapping(IO &YamlIO, bolt::BinaryFunctionProfile &BFP) { 217 YamlIO.mapRequired("name", BFP.Name); 218 YamlIO.mapRequired("fid", BFP.Id); 219 YamlIO.mapRequired("hash", BFP.Hash); 220 YamlIO.mapRequired("exec", BFP.ExecCount); 221 YamlIO.mapRequired("nblocks", BFP.NumBasicBlocks); 222 YamlIO.mapOptional("blocks", BFP.Blocks, 223 std::vector<bolt::BinaryBasicBlockProfile>()); 224 YamlIO.mapOptional("inline_tree", BFP.InlineTree, 225 std::vector<bolt::InlineTreeNode>()); 226 } 227 }; 228 229 LLVM_YAML_STRONG_TYPEDEF(uint16_t, PROFILE_PF) 230 231 template <> struct ScalarBitSetTraits<PROFILE_PF> { 232 static void bitset(IO &io, PROFILE_PF &value) { 233 io.bitSetCase(value, "lbr", BinaryFunction::PF_LBR); 234 io.bitSetCase(value, "sample", BinaryFunction::PF_SAMPLE); 235 io.bitSetCase(value, "memevent", BinaryFunction::PF_MEMEVENT); 236 } 237 }; 238 239 template <> struct ScalarEnumerationTraits<llvm::bolt::HashFunction> { 240 using HashFunction = llvm::bolt::HashFunction; 241 static void enumeration(IO &io, HashFunction &value) { 242 io.enumCase(value, "std-hash", HashFunction::StdHash); 243 io.enumCase(value, "xxh3", HashFunction::XXH3); 244 } 245 }; 246 247 namespace bolt { 248 struct BinaryProfileHeader { 249 uint32_t Version{1}; 250 std::string FileName; // Name of the profiled binary. 251 std::string Id; // BuildID. 252 PROFILE_PF Flags{BinaryFunction::PF_NONE}; 253 // Type of the profile. 254 std::string Origin; // How the profile was obtained. 255 std::string EventNames; // Events used for sample profile. 256 bool IsDFSOrder{true}; // Whether using DFS block order in function profile 257 llvm::bolt::HashFunction HashFunction; // Hash used for BB/BF hashing 258 }; 259 } // end namespace bolt 260 261 template <> struct MappingTraits<bolt::BinaryProfileHeader> { 262 static void mapping(IO &YamlIO, bolt::BinaryProfileHeader &Header) { 263 YamlIO.mapRequired("profile-version", Header.Version); 264 YamlIO.mapRequired("binary-name", Header.FileName); 265 YamlIO.mapOptional("binary-build-id", Header.Id); 266 YamlIO.mapRequired("profile-flags", Header.Flags); 267 YamlIO.mapOptional("profile-origin", Header.Origin); 268 YamlIO.mapOptional("profile-events", Header.EventNames); 269 YamlIO.mapOptional("dfs-order", Header.IsDFSOrder); 270 YamlIO.mapOptional("hash-func", Header.HashFunction, 271 llvm::bolt::HashFunction::StdHash); 272 } 273 }; 274 275 namespace bolt { 276 struct ProfilePseudoProbeDesc { 277 std::vector<Hex64> GUID; 278 std::vector<Hex64> Hash; 279 std::vector<uint32_t> GUIDHashIdx; // Index of hash for that GUID in Hash 280 281 bool operator==(const ProfilePseudoProbeDesc &Other) const { 282 // Only treat empty Desc as equal 283 return GUID.empty() && Other.GUID.empty() && Hash.empty() && 284 Other.Hash.empty() && GUIDHashIdx.empty() && 285 Other.GUIDHashIdx.empty(); 286 } 287 }; 288 } // end namespace bolt 289 290 template <> struct MappingTraits<bolt::ProfilePseudoProbeDesc> { 291 static void mapping(IO &YamlIO, bolt::ProfilePseudoProbeDesc &PD) { 292 YamlIO.mapRequired("gs", PD.GUID); 293 YamlIO.mapRequired("gh", PD.GUIDHashIdx); 294 YamlIO.mapRequired("hs", PD.Hash); 295 } 296 }; 297 } // end namespace yaml 298 } // end namespace llvm 299 300 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::bolt::BinaryFunctionProfile) 301 LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::bolt::ProfilePseudoProbeDesc) 302 303 namespace llvm { 304 namespace yaml { 305 306 namespace bolt { 307 struct BinaryProfile { 308 BinaryProfileHeader Header; 309 std::vector<BinaryFunctionProfile> Functions; 310 ProfilePseudoProbeDesc PseudoProbeDesc; 311 }; 312 } // namespace bolt 313 314 template <> struct MappingTraits<bolt::BinaryProfile> { 315 static void mapping(IO &YamlIO, bolt::BinaryProfile &BP) { 316 YamlIO.mapRequired("header", BP.Header); 317 YamlIO.mapRequired("functions", BP.Functions); 318 YamlIO.mapOptional("pseudo_probe_desc", BP.PseudoProbeDesc, 319 bolt::ProfilePseudoProbeDesc()); 320 } 321 }; 322 323 } // end namespace yaml 324 } // end namespace llvm 325 326 #endif 327