InstrProfCorrelator.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351
  1. //===-- InstrProfCorrelator.cpp -------------------------------------------===//
  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. #include "llvm/ProfileData/InstrProfCorrelator.h"
  9. #include "llvm/DebugInfo/DIContext.h"
  10. #include "llvm/DebugInfo/DWARF/DWARFContext.h"
  11. #include "llvm/DebugInfo/DWARF/DWARFDie.h"
  12. #include "llvm/DebugInfo/DWARF/DWARFExpression.h"
  13. #include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
  14. #include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h"
  15. #include "llvm/DebugInfo/DWARF/DWARFUnit.h"
  16. #include "llvm/Object/MachO.h"
  17. #include "llvm/Support/Debug.h"
  18. #include <optional>
  19. #define DEBUG_TYPE "correlator"
  20. using namespace llvm;
  21. /// Get the __llvm_prf_cnts section.
  22. Expected<object::SectionRef> getCountersSection(const object::ObjectFile &Obj) {
  23. for (auto &Section : Obj.sections())
  24. if (auto SectionName = Section.getName())
  25. if (SectionName.get() == INSTR_PROF_CNTS_SECT_NAME)
  26. return Section;
  27. return make_error<InstrProfError>(
  28. instrprof_error::unable_to_correlate_profile,
  29. "could not find counter section (" INSTR_PROF_CNTS_SECT_NAME ")");
  30. }
  31. const char *InstrProfCorrelator::FunctionNameAttributeName = "Function Name";
  32. const char *InstrProfCorrelator::CFGHashAttributeName = "CFG Hash";
  33. const char *InstrProfCorrelator::NumCountersAttributeName = "Num Counters";
  34. llvm::Expected<std::unique_ptr<InstrProfCorrelator::Context>>
  35. InstrProfCorrelator::Context::get(std::unique_ptr<MemoryBuffer> Buffer,
  36. const object::ObjectFile &Obj) {
  37. auto CountersSection = getCountersSection(Obj);
  38. if (auto Err = CountersSection.takeError())
  39. return std::move(Err);
  40. auto C = std::make_unique<Context>();
  41. C->Buffer = std::move(Buffer);
  42. C->CountersSectionStart = CountersSection->getAddress();
  43. C->CountersSectionEnd = C->CountersSectionStart + CountersSection->getSize();
  44. C->ShouldSwapBytes = Obj.isLittleEndian() != sys::IsLittleEndianHost;
  45. return Expected<std::unique_ptr<Context>>(std::move(C));
  46. }
  47. llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
  48. InstrProfCorrelator::get(StringRef DebugInfoFilename) {
  49. auto DsymObjectsOrErr =
  50. object::MachOObjectFile::findDsymObjectMembers(DebugInfoFilename);
  51. if (auto Err = DsymObjectsOrErr.takeError())
  52. return std::move(Err);
  53. if (!DsymObjectsOrErr->empty()) {
  54. // TODO: Enable profile correlation when there are multiple objects in a
  55. // dSYM bundle.
  56. if (DsymObjectsOrErr->size() > 1)
  57. return make_error<InstrProfError>(
  58. instrprof_error::unable_to_correlate_profile,
  59. "using multiple objects is not yet supported");
  60. DebugInfoFilename = *DsymObjectsOrErr->begin();
  61. }
  62. auto BufferOrErr =
  63. errorOrToExpected(MemoryBuffer::getFile(DebugInfoFilename));
  64. if (auto Err = BufferOrErr.takeError())
  65. return std::move(Err);
  66. return get(std::move(*BufferOrErr));
  67. }
  68. llvm::Expected<std::unique_ptr<InstrProfCorrelator>>
  69. InstrProfCorrelator::get(std::unique_ptr<MemoryBuffer> Buffer) {
  70. auto BinOrErr = object::createBinary(*Buffer);
  71. if (auto Err = BinOrErr.takeError())
  72. return std::move(Err);
  73. if (auto *Obj = dyn_cast<object::ObjectFile>(BinOrErr->get())) {
  74. auto CtxOrErr = Context::get(std::move(Buffer), *Obj);
  75. if (auto Err = CtxOrErr.takeError())
  76. return std::move(Err);
  77. auto T = Obj->makeTriple();
  78. if (T.isArch64Bit())
  79. return InstrProfCorrelatorImpl<uint64_t>::get(std::move(*CtxOrErr), *Obj);
  80. if (T.isArch32Bit())
  81. return InstrProfCorrelatorImpl<uint32_t>::get(std::move(*CtxOrErr), *Obj);
  82. }
  83. return make_error<InstrProfError>(
  84. instrprof_error::unable_to_correlate_profile, "not an object file");
  85. }
  86. std::optional<size_t> InstrProfCorrelator::getDataSize() const {
  87. if (auto *C = dyn_cast<InstrProfCorrelatorImpl<uint32_t>>(this)) {
  88. return C->getDataSize();
  89. } else if (auto *C = dyn_cast<InstrProfCorrelatorImpl<uint64_t>>(this)) {
  90. return C->getDataSize();
  91. }
  92. return {};
  93. }
  94. namespace llvm {
  95. template <>
  96. InstrProfCorrelatorImpl<uint32_t>::InstrProfCorrelatorImpl(
  97. std::unique_ptr<InstrProfCorrelator::Context> Ctx)
  98. : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_32Bit,
  99. std::move(Ctx)) {}
  100. template <>
  101. InstrProfCorrelatorImpl<uint64_t>::InstrProfCorrelatorImpl(
  102. std::unique_ptr<InstrProfCorrelator::Context> Ctx)
  103. : InstrProfCorrelatorImpl(InstrProfCorrelatorKind::CK_64Bit,
  104. std::move(Ctx)) {}
  105. template <>
  106. bool InstrProfCorrelatorImpl<uint32_t>::classof(const InstrProfCorrelator *C) {
  107. return C->getKind() == InstrProfCorrelatorKind::CK_32Bit;
  108. }
  109. template <>
  110. bool InstrProfCorrelatorImpl<uint64_t>::classof(const InstrProfCorrelator *C) {
  111. return C->getKind() == InstrProfCorrelatorKind::CK_64Bit;
  112. }
  113. } // end namespace llvm
  114. template <class IntPtrT>
  115. llvm::Expected<std::unique_ptr<InstrProfCorrelatorImpl<IntPtrT>>>
  116. InstrProfCorrelatorImpl<IntPtrT>::get(
  117. std::unique_ptr<InstrProfCorrelator::Context> Ctx,
  118. const object::ObjectFile &Obj) {
  119. if (Obj.isELF() || Obj.isMachO()) {
  120. auto DICtx = DWARFContext::create(Obj);
  121. return std::make_unique<DwarfInstrProfCorrelator<IntPtrT>>(std::move(DICtx),
  122. std::move(Ctx));
  123. }
  124. return make_error<InstrProfError>(
  125. instrprof_error::unable_to_correlate_profile,
  126. "unsupported debug info format (only DWARF is supported)");
  127. }
  128. template <class IntPtrT>
  129. Error InstrProfCorrelatorImpl<IntPtrT>::correlateProfileData() {
  130. assert(Data.empty() && Names.empty() && NamesVec.empty());
  131. correlateProfileDataImpl();
  132. if (Data.empty() || NamesVec.empty())
  133. return make_error<InstrProfError>(
  134. instrprof_error::unable_to_correlate_profile,
  135. "could not find any profile metadata in debug info");
  136. auto Result =
  137. collectPGOFuncNameStrings(NamesVec, /*doCompression=*/false, Names);
  138. CounterOffsets.clear();
  139. NamesVec.clear();
  140. return Result;
  141. }
  142. template <> struct yaml::MappingTraits<InstrProfCorrelator::CorrelationData> {
  143. static void mapping(yaml::IO &io,
  144. InstrProfCorrelator::CorrelationData &Data) {
  145. io.mapRequired("Probes", Data.Probes);
  146. }
  147. };
  148. template <> struct yaml::MappingTraits<InstrProfCorrelator::Probe> {
  149. static void mapping(yaml::IO &io, InstrProfCorrelator::Probe &P) {
  150. io.mapRequired("Function Name", P.FunctionName);
  151. io.mapOptional("Linkage Name", P.LinkageName);
  152. io.mapRequired("CFG Hash", P.CFGHash);
  153. io.mapRequired("Counter Offset", P.CounterOffset);
  154. io.mapRequired("Num Counters", P.NumCounters);
  155. io.mapOptional("File", P.FilePath);
  156. io.mapOptional("Line", P.LineNumber);
  157. }
  158. };
  159. template <> struct yaml::SequenceElementTraits<InstrProfCorrelator::Probe> {
  160. static const bool flow = false;
  161. };
  162. template <class IntPtrT>
  163. Error InstrProfCorrelatorImpl<IntPtrT>::dumpYaml(raw_ostream &OS) {
  164. InstrProfCorrelator::CorrelationData Data;
  165. correlateProfileDataImpl(&Data);
  166. if (Data.Probes.empty())
  167. return make_error<InstrProfError>(
  168. instrprof_error::unable_to_correlate_profile,
  169. "could not find any profile metadata in debug info");
  170. yaml::Output YamlOS(OS);
  171. YamlOS << Data;
  172. return Error::success();
  173. }
  174. template <class IntPtrT>
  175. void InstrProfCorrelatorImpl<IntPtrT>::addProbe(StringRef FunctionName,
  176. uint64_t CFGHash,
  177. IntPtrT CounterOffset,
  178. IntPtrT FunctionPtr,
  179. uint32_t NumCounters) {
  180. // Check if a probe was already added for this counter offset.
  181. if (!CounterOffsets.insert(CounterOffset).second)
  182. return;
  183. Data.push_back({
  184. maybeSwap<uint64_t>(IndexedInstrProf::ComputeHash(FunctionName)),
  185. maybeSwap<uint64_t>(CFGHash),
  186. // In this mode, CounterPtr actually stores the section relative address
  187. // of the counter.
  188. maybeSwap<IntPtrT>(CounterOffset),
  189. maybeSwap<IntPtrT>(FunctionPtr),
  190. // TODO: Value profiling is not yet supported.
  191. /*ValuesPtr=*/maybeSwap<IntPtrT>(0),
  192. maybeSwap<uint32_t>(NumCounters),
  193. /*NumValueSites=*/{maybeSwap<uint16_t>(0), maybeSwap<uint16_t>(0)},
  194. });
  195. NamesVec.push_back(FunctionName.str());
  196. }
  197. template <class IntPtrT>
  198. std::optional<uint64_t>
  199. DwarfInstrProfCorrelator<IntPtrT>::getLocation(const DWARFDie &Die) const {
  200. auto Locations = Die.getLocations(dwarf::DW_AT_location);
  201. if (!Locations) {
  202. consumeError(Locations.takeError());
  203. return {};
  204. }
  205. auto &DU = *Die.getDwarfUnit();
  206. auto AddressSize = DU.getAddressByteSize();
  207. for (auto &Location : *Locations) {
  208. DataExtractor Data(Location.Expr, DICtx->isLittleEndian(), AddressSize);
  209. DWARFExpression Expr(Data, AddressSize);
  210. for (auto &Op : Expr) {
  211. if (Op.getCode() == dwarf::DW_OP_addr) {
  212. return Op.getRawOperand(0);
  213. } else if (Op.getCode() == dwarf::DW_OP_addrx) {
  214. uint64_t Index = Op.getRawOperand(0);
  215. if (auto SA = DU.getAddrOffsetSectionItem(Index))
  216. return SA->Address;
  217. }
  218. }
  219. }
  220. return {};
  221. }
  222. template <class IntPtrT>
  223. bool DwarfInstrProfCorrelator<IntPtrT>::isDIEOfProbe(const DWARFDie &Die) {
  224. const auto &ParentDie = Die.getParent();
  225. if (!Die.isValid() || !ParentDie.isValid() || Die.isNULL())
  226. return false;
  227. if (Die.getTag() != dwarf::DW_TAG_variable)
  228. return false;
  229. if (!ParentDie.isSubprogramDIE())
  230. return false;
  231. if (!Die.hasChildren())
  232. return false;
  233. if (const char *Name = Die.getName(DINameKind::ShortName))
  234. return StringRef(Name).startswith(getInstrProfCountersVarPrefix());
  235. return false;
  236. }
  237. template <class IntPtrT>
  238. void DwarfInstrProfCorrelator<IntPtrT>::correlateProfileDataImpl(
  239. InstrProfCorrelator::CorrelationData *Data) {
  240. auto maybeAddProbe = [&](DWARFDie Die) {
  241. if (!isDIEOfProbe(Die))
  242. return;
  243. std::optional<const char *> FunctionName;
  244. std::optional<uint64_t> CFGHash;
  245. std::optional<uint64_t> CounterPtr = getLocation(Die);
  246. auto FnDie = Die.getParent();
  247. auto FunctionPtr = dwarf::toAddress(FnDie.find(dwarf::DW_AT_low_pc));
  248. std::optional<uint64_t> NumCounters;
  249. for (const DWARFDie &Child : Die.children()) {
  250. if (Child.getTag() != dwarf::DW_TAG_LLVM_annotation)
  251. continue;
  252. auto AnnotationFormName = Child.find(dwarf::DW_AT_name);
  253. auto AnnotationFormValue = Child.find(dwarf::DW_AT_const_value);
  254. if (!AnnotationFormName || !AnnotationFormValue)
  255. continue;
  256. auto AnnotationNameOrErr = AnnotationFormName->getAsCString();
  257. if (auto Err = AnnotationNameOrErr.takeError()) {
  258. consumeError(std::move(Err));
  259. continue;
  260. }
  261. StringRef AnnotationName = *AnnotationNameOrErr;
  262. if (AnnotationName.compare(
  263. InstrProfCorrelator::FunctionNameAttributeName) == 0) {
  264. if (auto EC =
  265. AnnotationFormValue->getAsCString().moveInto(FunctionName))
  266. consumeError(std::move(EC));
  267. } else if (AnnotationName.compare(
  268. InstrProfCorrelator::CFGHashAttributeName) == 0) {
  269. CFGHash = AnnotationFormValue->getAsUnsignedConstant();
  270. } else if (AnnotationName.compare(
  271. InstrProfCorrelator::NumCountersAttributeName) == 0) {
  272. NumCounters = AnnotationFormValue->getAsUnsignedConstant();
  273. }
  274. }
  275. if (!FunctionName || !CFGHash || !CounterPtr || !NumCounters) {
  276. LLVM_DEBUG(dbgs() << "Incomplete DIE for probe\n\tFunctionName: "
  277. << FunctionName << "\n\tCFGHash: " << CFGHash
  278. << "\n\tCounterPtr: " << CounterPtr
  279. << "\n\tNumCounters: " << NumCounters);
  280. LLVM_DEBUG(Die.dump(dbgs()));
  281. return;
  282. }
  283. uint64_t CountersStart = this->Ctx->CountersSectionStart;
  284. uint64_t CountersEnd = this->Ctx->CountersSectionEnd;
  285. if (*CounterPtr < CountersStart || *CounterPtr >= CountersEnd) {
  286. LLVM_DEBUG(
  287. dbgs() << "CounterPtr out of range for probe\n\tFunction Name: "
  288. << FunctionName << "\n\tExpected: [0x"
  289. << Twine::utohexstr(CountersStart) << ", 0x"
  290. << Twine::utohexstr(CountersEnd) << ")\n\tActual: 0x"
  291. << Twine::utohexstr(*CounterPtr));
  292. LLVM_DEBUG(Die.dump(dbgs()));
  293. return;
  294. }
  295. if (!FunctionPtr) {
  296. LLVM_DEBUG(dbgs() << "Could not find address of " << *FunctionName
  297. << "\n");
  298. LLVM_DEBUG(Die.dump(dbgs()));
  299. }
  300. IntPtrT CounterOffset = *CounterPtr - CountersStart;
  301. if (Data) {
  302. InstrProfCorrelator::Probe P;
  303. P.FunctionName = *FunctionName;
  304. if (auto Name = FnDie.getName(DINameKind::LinkageName))
  305. P.LinkageName = Name;
  306. P.CFGHash = *CFGHash;
  307. P.CounterOffset = CounterOffset;
  308. P.NumCounters = *NumCounters;
  309. auto FilePath = FnDie.getDeclFile(
  310. DILineInfoSpecifier::FileLineInfoKind::RelativeFilePath);
  311. if (!FilePath.empty())
  312. P.FilePath = FilePath;
  313. if (auto LineNumber = FnDie.getDeclLine())
  314. P.LineNumber = LineNumber;
  315. Data->Probes.push_back(P);
  316. } else {
  317. this->addProbe(*FunctionName, *CFGHash, CounterOffset,
  318. FunctionPtr.value_or(0), *NumCounters);
  319. }
  320. };
  321. for (auto &CU : DICtx->normal_units())
  322. for (const auto &Entry : CU->dies())
  323. maybeAddProbe(DWARFDie(CU.get(), &Entry));
  324. for (auto &CU : DICtx->dwo_units())
  325. for (const auto &Entry : CU->dies())
  326. maybeAddProbe(DWARFDie(CU.get(), &Entry));
  327. }