InstrProfCorrelator.cpp 11 KB

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