1 //=-- Profilesummary.cpp - Profile summary support --------------------------=// 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 support for converting profile summary data from/to 10 // metadata. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "llvm/IR/ProfileSummary.h" 15 #include "llvm/IR/Constants.h" 16 #include "llvm/IR/DerivedTypes.h" 17 #include "llvm/IR/Metadata.h" 18 #include "llvm/IR/Type.h" 19 #include "llvm/Support/Casting.h" 20 #include "llvm/Support/Format.h" 21 22 using namespace llvm; 23 24 // Return an MDTuple with two elements. The first element is a string Key and 25 // the second is a uint64_t Value. 26 static Metadata *getKeyValMD(LLVMContext &Context, const char *Key, 27 uint64_t Val) { 28 Type *Int64Ty = Type::getInt64Ty(Context); 29 Metadata *Ops[2] = {MDString::get(Context, Key), 30 ConstantAsMetadata::get(ConstantInt::get(Int64Ty, Val))}; 31 return MDTuple::get(Context, Ops); 32 } 33 34 static Metadata *getKeyFPValMD(LLVMContext &Context, const char *Key, 35 double Val) { 36 Type *DoubleTy = Type::getDoubleTy(Context); 37 Metadata *Ops[2] = {MDString::get(Context, Key), 38 ConstantAsMetadata::get(ConstantFP::get(DoubleTy, Val))}; 39 return MDTuple::get(Context, Ops); 40 } 41 42 // Return an MDTuple with two elements. The first element is a string Key and 43 // the second is a string Value. 44 static Metadata *getKeyValMD(LLVMContext &Context, const char *Key, 45 const char *Val) { 46 Metadata *Ops[2] = {MDString::get(Context, Key), MDString::get(Context, Val)}; 47 return MDTuple::get(Context, Ops); 48 } 49 50 // This returns an MDTuple representing the detiled summary. The tuple has two 51 // elements: a string "DetailedSummary" and an MDTuple representing the value 52 // of the detailed summary. Each element of this tuple is again an MDTuple whose 53 // elements are the (Cutoff, MinCount, NumCounts) triplet of the 54 // DetailedSummaryEntry. 55 Metadata *ProfileSummary::getDetailedSummaryMD(LLVMContext &Context) { 56 std::vector<Metadata *> Entries; 57 Type *Int32Ty = Type::getInt32Ty(Context); 58 Type *Int64Ty = Type::getInt64Ty(Context); 59 for (auto &Entry : DetailedSummary) { 60 Metadata *EntryMD[3] = { 61 ConstantAsMetadata::get(ConstantInt::get(Int32Ty, Entry.Cutoff)), 62 ConstantAsMetadata::get(ConstantInt::get(Int64Ty, Entry.MinCount)), 63 ConstantAsMetadata::get(ConstantInt::get(Int32Ty, Entry.NumCounts))}; 64 Entries.push_back(MDTuple::get(Context, EntryMD)); 65 } 66 Metadata *Ops[2] = {MDString::get(Context, "DetailedSummary"), 67 MDTuple::get(Context, Entries)}; 68 return MDTuple::get(Context, Ops); 69 } 70 71 // This returns an MDTuple representing this ProfileSummary object. The first 72 // entry of this tuple is another MDTuple of two elements: a string 73 // "ProfileFormat" and a string representing the format ("InstrProf" or 74 // "SampleProfile"). The rest of the elements of the outer MDTuple are specific 75 // to the kind of profile summary as returned by getFormatSpecificMD. 76 // IsPartialProfile is an optional field and \p AddPartialField will decide 77 // whether to add a field for it. 78 // PartialProfileRatio is an optional field and \p AddPartialProfileRatioField 79 // will decide whether to add a field for it. 80 Metadata *ProfileSummary::getMD(LLVMContext &Context, bool AddPartialField, 81 bool AddPartialProfileRatioField) { 82 const char *KindStr[3] = {"InstrProf", "CSInstrProf", "SampleProfile"}; 83 SmallVector<Metadata *, 16> Components; 84 Components.push_back(getKeyValMD(Context, "ProfileFormat", KindStr[PSK])); 85 Components.push_back(getKeyValMD(Context, "TotalCount", getTotalCount())); 86 Components.push_back(getKeyValMD(Context, "MaxCount", getMaxCount())); 87 Components.push_back( 88 getKeyValMD(Context, "MaxInternalCount", getMaxInternalCount())); 89 Components.push_back( 90 getKeyValMD(Context, "MaxFunctionCount", getMaxFunctionCount())); 91 Components.push_back(getKeyValMD(Context, "NumCounts", getNumCounts())); 92 Components.push_back(getKeyValMD(Context, "NumFunctions", getNumFunctions())); 93 if (AddPartialField) 94 Components.push_back( 95 getKeyValMD(Context, "IsPartialProfile", isPartialProfile())); 96 if (AddPartialProfileRatioField) 97 Components.push_back(getKeyFPValMD(Context, "PartialProfileRatio", 98 getPartialProfileRatio())); 99 Components.push_back(getDetailedSummaryMD(Context)); 100 return MDTuple::get(Context, Components); 101 } 102 103 // Get the value metadata for the input MD/Key. 104 static ConstantAsMetadata *getValMD(MDTuple *MD, const char *Key) { 105 if (!MD) 106 return nullptr; 107 if (MD->getNumOperands() != 2) 108 return nullptr; 109 MDString *KeyMD = dyn_cast<MDString>(MD->getOperand(0)); 110 ConstantAsMetadata *ValMD = dyn_cast<ConstantAsMetadata>(MD->getOperand(1)); 111 if (!KeyMD || !ValMD) 112 return nullptr; 113 if (!KeyMD->getString().equals(Key)) 114 return nullptr; 115 return ValMD; 116 } 117 118 // Parse an MDTuple representing (Key, Val) pair. 119 static bool getVal(MDTuple *MD, const char *Key, uint64_t &Val) { 120 if (auto *ValMD = getValMD(MD, Key)) { 121 Val = cast<ConstantInt>(ValMD->getValue())->getZExtValue(); 122 return true; 123 } 124 return false; 125 } 126 127 static bool getVal(MDTuple *MD, const char *Key, double &Val) { 128 if (auto *ValMD = getValMD(MD, Key)) { 129 Val = cast<ConstantFP>(ValMD->getValue())->getValueAPF().convertToDouble(); 130 return true; 131 } 132 return false; 133 } 134 135 // Check if an MDTuple represents a (Key, Val) pair. 136 static bool isKeyValuePair(MDTuple *MD, const char *Key, const char *Val) { 137 if (!MD || MD->getNumOperands() != 2) 138 return false; 139 MDString *KeyMD = dyn_cast<MDString>(MD->getOperand(0)); 140 MDString *ValMD = dyn_cast<MDString>(MD->getOperand(1)); 141 if (!KeyMD || !ValMD) 142 return false; 143 if (!KeyMD->getString().equals(Key) || !ValMD->getString().equals(Val)) 144 return false; 145 return true; 146 } 147 148 // Parse an MDTuple representing detailed summary. 149 static bool getSummaryFromMD(MDTuple *MD, SummaryEntryVector &Summary) { 150 if (!MD || MD->getNumOperands() != 2) 151 return false; 152 MDString *KeyMD = dyn_cast<MDString>(MD->getOperand(0)); 153 if (!KeyMD || !KeyMD->getString().equals("DetailedSummary")) 154 return false; 155 MDTuple *EntriesMD = dyn_cast<MDTuple>(MD->getOperand(1)); 156 if (!EntriesMD) 157 return false; 158 for (auto &&MDOp : EntriesMD->operands()) { 159 MDTuple *EntryMD = dyn_cast<MDTuple>(MDOp); 160 if (!EntryMD || EntryMD->getNumOperands() != 3) 161 return false; 162 ConstantAsMetadata *Op0 = 163 dyn_cast<ConstantAsMetadata>(EntryMD->getOperand(0)); 164 ConstantAsMetadata *Op1 = 165 dyn_cast<ConstantAsMetadata>(EntryMD->getOperand(1)); 166 ConstantAsMetadata *Op2 = 167 dyn_cast<ConstantAsMetadata>(EntryMD->getOperand(2)); 168 169 if (!Op0 || !Op1 || !Op2) 170 return false; 171 Summary.emplace_back(cast<ConstantInt>(Op0->getValue())->getZExtValue(), 172 cast<ConstantInt>(Op1->getValue())->getZExtValue(), 173 cast<ConstantInt>(Op2->getValue())->getZExtValue()); 174 } 175 return true; 176 } 177 178 // Get the value of an optional field. Increment 'Idx' if it was present. Return 179 // true if we can move onto the next field. 180 template <typename ValueType> 181 static bool getOptionalVal(MDTuple *Tuple, unsigned &Idx, const char *Key, 182 ValueType &Value) { 183 if (getVal(dyn_cast<MDTuple>(Tuple->getOperand(Idx)), Key, Value)) { 184 Idx++; 185 // Need to make sure when the key is present, we won't step over the bound 186 // of Tuple operand array. Since (non-optional) DetailedSummary always comes 187 // last, the next entry in the tuple operand array must exist. 188 return Idx < Tuple->getNumOperands(); 189 } 190 // It was absent, keep going. 191 return true; 192 } 193 194 ProfileSummary *ProfileSummary::getFromMD(Metadata *MD) { 195 MDTuple *Tuple = dyn_cast_or_null<MDTuple>(MD); 196 if (!Tuple || Tuple->getNumOperands() < 8 || Tuple->getNumOperands() > 10) 197 return nullptr; 198 199 unsigned I = 0; 200 auto &FormatMD = Tuple->getOperand(I++); 201 ProfileSummary::Kind SummaryKind; 202 if (isKeyValuePair(dyn_cast_or_null<MDTuple>(FormatMD), "ProfileFormat", 203 "SampleProfile")) 204 SummaryKind = PSK_Sample; 205 else if (isKeyValuePair(dyn_cast_or_null<MDTuple>(FormatMD), "ProfileFormat", 206 "InstrProf")) 207 SummaryKind = PSK_Instr; 208 else if (isKeyValuePair(dyn_cast_or_null<MDTuple>(FormatMD), "ProfileFormat", 209 "CSInstrProf")) 210 SummaryKind = PSK_CSInstr; 211 else 212 return nullptr; 213 214 uint64_t NumCounts, TotalCount, NumFunctions, MaxFunctionCount, MaxCount, 215 MaxInternalCount; 216 if (!getVal(dyn_cast<MDTuple>(Tuple->getOperand(I++)), "TotalCount", 217 TotalCount)) 218 return nullptr; 219 if (!getVal(dyn_cast<MDTuple>(Tuple->getOperand(I++)), "MaxCount", MaxCount)) 220 return nullptr; 221 if (!getVal(dyn_cast<MDTuple>(Tuple->getOperand(I++)), "MaxInternalCount", 222 MaxInternalCount)) 223 return nullptr; 224 if (!getVal(dyn_cast<MDTuple>(Tuple->getOperand(I++)), "MaxFunctionCount", 225 MaxFunctionCount)) 226 return nullptr; 227 if (!getVal(dyn_cast<MDTuple>(Tuple->getOperand(I++)), "NumCounts", 228 NumCounts)) 229 return nullptr; 230 if (!getVal(dyn_cast<MDTuple>(Tuple->getOperand(I++)), "NumFunctions", 231 NumFunctions)) 232 return nullptr; 233 234 // Optional fields. Need to initialize because the fields are optional. 235 uint64_t IsPartialProfile = 0; 236 if (!getOptionalVal(Tuple, I, "IsPartialProfile", IsPartialProfile)) 237 return nullptr; 238 double PartialProfileRatio = 0; 239 if (!getOptionalVal(Tuple, I, "PartialProfileRatio", PartialProfileRatio)) 240 return nullptr; 241 242 SummaryEntryVector Summary; 243 if (!getSummaryFromMD(dyn_cast<MDTuple>(Tuple->getOperand(I++)), Summary)) 244 return nullptr; 245 return new ProfileSummary(SummaryKind, std::move(Summary), TotalCount, 246 MaxCount, MaxInternalCount, MaxFunctionCount, 247 NumCounts, NumFunctions, IsPartialProfile, 248 PartialProfileRatio); 249 } 250 251 void ProfileSummary::printSummary(raw_ostream &OS) const { 252 OS << "Total functions: " << NumFunctions << "\n"; 253 OS << "Maximum function count: " << MaxFunctionCount << "\n"; 254 OS << "Maximum block count: " << MaxCount << "\n"; 255 OS << "Total number of blocks: " << NumCounts << "\n"; 256 OS << "Total count: " << TotalCount << "\n"; 257 } 258 259 void ProfileSummary::printDetailedSummary(raw_ostream &OS) const { 260 OS << "Detailed summary:\n"; 261 for (const auto &Entry : DetailedSummary) { 262 OS << Entry.NumCounts << " blocks with count >= " << Entry.MinCount 263 << " account for " 264 << format("%0.6g", (float)Entry.Cutoff / Scale * 100) 265 << " percentage of the total counts.\n"; 266 } 267 } 268