SampleContextTracker.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. //===- SampleContextTracker.cpp - Context-sensitive Profile Tracker -------===//
  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 implements the SampleContextTracker used by CSSPGO.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "llvm/Transforms/IPO/SampleContextTracker.h"
  13. #include "llvm/ADT/StringMap.h"
  14. #include "llvm/ADT/StringRef.h"
  15. #include "llvm/IR/DebugInfoMetadata.h"
  16. #include "llvm/IR/Instructions.h"
  17. #include "llvm/ProfileData/SampleProf.h"
  18. #include <map>
  19. #include <queue>
  20. #include <vector>
  21. using namespace llvm;
  22. using namespace sampleprof;
  23. #define DEBUG_TYPE "sample-context-tracker"
  24. namespace llvm {
  25. ContextTrieNode *ContextTrieNode::getChildContext(const LineLocation &CallSite,
  26. StringRef CalleeName) {
  27. if (CalleeName.empty())
  28. return getHottestChildContext(CallSite);
  29. uint32_t Hash = nodeHash(CalleeName, CallSite);
  30. auto It = AllChildContext.find(Hash);
  31. if (It != AllChildContext.end())
  32. return &It->second;
  33. return nullptr;
  34. }
  35. ContextTrieNode *
  36. ContextTrieNode::getHottestChildContext(const LineLocation &CallSite) {
  37. // CSFDO-TODO: This could be slow, change AllChildContext so we can
  38. // do point look up for child node by call site alone.
  39. // Retrieve the child node with max count for indirect call
  40. ContextTrieNode *ChildNodeRet = nullptr;
  41. uint64_t MaxCalleeSamples = 0;
  42. for (auto &It : AllChildContext) {
  43. ContextTrieNode &ChildNode = It.second;
  44. if (ChildNode.CallSiteLoc != CallSite)
  45. continue;
  46. FunctionSamples *Samples = ChildNode.getFunctionSamples();
  47. if (!Samples)
  48. continue;
  49. if (Samples->getTotalSamples() > MaxCalleeSamples) {
  50. ChildNodeRet = &ChildNode;
  51. MaxCalleeSamples = Samples->getTotalSamples();
  52. }
  53. }
  54. return ChildNodeRet;
  55. }
  56. ContextTrieNode &ContextTrieNode::moveToChildContext(
  57. const LineLocation &CallSite, ContextTrieNode &&NodeToMove,
  58. StringRef ContextStrToRemove, bool DeleteNode) {
  59. uint32_t Hash = nodeHash(NodeToMove.getFuncName(), CallSite);
  60. assert(!AllChildContext.count(Hash) && "Node to remove must exist");
  61. LineLocation OldCallSite = NodeToMove.CallSiteLoc;
  62. ContextTrieNode &OldParentContext = *NodeToMove.getParentContext();
  63. AllChildContext[Hash] = NodeToMove;
  64. ContextTrieNode &NewNode = AllChildContext[Hash];
  65. NewNode.CallSiteLoc = CallSite;
  66. // Walk through nodes in the moved the subtree, and update
  67. // FunctionSamples' context as for the context promotion.
  68. // We also need to set new parant link for all children.
  69. std::queue<ContextTrieNode *> NodeToUpdate;
  70. NewNode.setParentContext(this);
  71. NodeToUpdate.push(&NewNode);
  72. while (!NodeToUpdate.empty()) {
  73. ContextTrieNode *Node = NodeToUpdate.front();
  74. NodeToUpdate.pop();
  75. FunctionSamples *FSamples = Node->getFunctionSamples();
  76. if (FSamples) {
  77. FSamples->getContext().promoteOnPath(ContextStrToRemove);
  78. FSamples->getContext().setState(SyntheticContext);
  79. LLVM_DEBUG(dbgs() << " Context promoted to: " << FSamples->getContext()
  80. << "\n");
  81. }
  82. for (auto &It : Node->getAllChildContext()) {
  83. ContextTrieNode *ChildNode = &It.second;
  84. ChildNode->setParentContext(Node);
  85. NodeToUpdate.push(ChildNode);
  86. }
  87. }
  88. // Original context no longer needed, destroy if requested.
  89. if (DeleteNode)
  90. OldParentContext.removeChildContext(OldCallSite, NewNode.getFuncName());
  91. return NewNode;
  92. }
  93. void ContextTrieNode::removeChildContext(const LineLocation &CallSite,
  94. StringRef CalleeName) {
  95. uint32_t Hash = nodeHash(CalleeName, CallSite);
  96. // Note this essentially calls dtor and destroys that child context
  97. AllChildContext.erase(Hash);
  98. }
  99. std::map<uint32_t, ContextTrieNode> &ContextTrieNode::getAllChildContext() {
  100. return AllChildContext;
  101. }
  102. const StringRef ContextTrieNode::getFuncName() const { return FuncName; }
  103. FunctionSamples *ContextTrieNode::getFunctionSamples() const {
  104. return FuncSamples;
  105. }
  106. void ContextTrieNode::setFunctionSamples(FunctionSamples *FSamples) {
  107. FuncSamples = FSamples;
  108. }
  109. LineLocation ContextTrieNode::getCallSiteLoc() const { return CallSiteLoc; }
  110. ContextTrieNode *ContextTrieNode::getParentContext() const {
  111. return ParentContext;
  112. }
  113. void ContextTrieNode::setParentContext(ContextTrieNode *Parent) {
  114. ParentContext = Parent;
  115. }
  116. void ContextTrieNode::dump() {
  117. dbgs() << "Node: " << FuncName << "\n"
  118. << " Callsite: " << CallSiteLoc << "\n"
  119. << " Children:\n";
  120. for (auto &It : AllChildContext) {
  121. dbgs() << " Node: " << It.second.getFuncName() << "\n";
  122. }
  123. }
  124. uint32_t ContextTrieNode::nodeHash(StringRef ChildName,
  125. const LineLocation &Callsite) {
  126. // We still use child's name for child hash, this is
  127. // because for children of root node, we don't have
  128. // different line/discriminator, and we'll rely on name
  129. // to differentiate children.
  130. uint32_t NameHash = std::hash<std::string>{}(ChildName.str());
  131. uint32_t LocId = (Callsite.LineOffset << 16) | Callsite.Discriminator;
  132. return NameHash + (LocId << 5) + LocId;
  133. }
  134. ContextTrieNode *ContextTrieNode::getOrCreateChildContext(
  135. const LineLocation &CallSite, StringRef CalleeName, bool AllowCreate) {
  136. uint32_t Hash = nodeHash(CalleeName, CallSite);
  137. auto It = AllChildContext.find(Hash);
  138. if (It != AllChildContext.end()) {
  139. assert(It->second.getFuncName() == CalleeName &&
  140. "Hash collision for child context node");
  141. return &It->second;
  142. }
  143. if (!AllowCreate)
  144. return nullptr;
  145. AllChildContext[Hash] = ContextTrieNode(this, CalleeName, nullptr, CallSite);
  146. return &AllChildContext[Hash];
  147. }
  148. // Profiler tracker than manages profiles and its associated context
  149. SampleContextTracker::SampleContextTracker(
  150. StringMap<FunctionSamples> &Profiles) {
  151. for (auto &FuncSample : Profiles) {
  152. FunctionSamples *FSamples = &FuncSample.second;
  153. SampleContext Context(FuncSample.first(), RawContext);
  154. LLVM_DEBUG(dbgs() << "Tracking Context for function: " << Context << "\n");
  155. if (!Context.isBaseContext())
  156. FuncToCtxtProfileSet[Context.getNameWithoutContext()].insert(FSamples);
  157. ContextTrieNode *NewNode = getOrCreateContextPath(Context, true);
  158. assert(!NewNode->getFunctionSamples() &&
  159. "New node can't have sample profile");
  160. NewNode->setFunctionSamples(FSamples);
  161. }
  162. }
  163. FunctionSamples *
  164. SampleContextTracker::getCalleeContextSamplesFor(const CallBase &Inst,
  165. StringRef CalleeName) {
  166. LLVM_DEBUG(dbgs() << "Getting callee context for instr: " << Inst << "\n");
  167. DILocation *DIL = Inst.getDebugLoc();
  168. if (!DIL)
  169. return nullptr;
  170. // For indirect call, CalleeName will be empty, in which case the context
  171. // profile for callee with largest total samples will be returned.
  172. ContextTrieNode *CalleeContext = getCalleeContextFor(DIL, CalleeName);
  173. if (CalleeContext) {
  174. FunctionSamples *FSamples = CalleeContext->getFunctionSamples();
  175. LLVM_DEBUG(if (FSamples) {
  176. dbgs() << " Callee context found: " << FSamples->getContext() << "\n";
  177. });
  178. return FSamples;
  179. }
  180. return nullptr;
  181. }
  182. std::vector<const FunctionSamples *>
  183. SampleContextTracker::getIndirectCalleeContextSamplesFor(
  184. const DILocation *DIL) {
  185. std::vector<const FunctionSamples *> R;
  186. if (!DIL)
  187. return R;
  188. ContextTrieNode *CallerNode = getContextFor(DIL);
  189. LineLocation CallSite = FunctionSamples::getCallSiteIdentifier(DIL);
  190. for (auto &It : CallerNode->getAllChildContext()) {
  191. ContextTrieNode &ChildNode = It.second;
  192. if (ChildNode.getCallSiteLoc() != CallSite)
  193. continue;
  194. if (FunctionSamples *CalleeSamples = ChildNode.getFunctionSamples())
  195. R.push_back(CalleeSamples);
  196. }
  197. return R;
  198. }
  199. FunctionSamples *
  200. SampleContextTracker::getContextSamplesFor(const DILocation *DIL) {
  201. assert(DIL && "Expect non-null location");
  202. ContextTrieNode *ContextNode = getContextFor(DIL);
  203. if (!ContextNode)
  204. return nullptr;
  205. // We may have inlined callees during pre-LTO compilation, in which case
  206. // we need to rely on the inline stack from !dbg to mark context profile
  207. // as inlined, instead of `MarkContextSamplesInlined` during inlining.
  208. // Sample profile loader walks through all instructions to get profile,
  209. // which calls this function. So once that is done, all previously inlined
  210. // context profile should be marked properly.
  211. FunctionSamples *Samples = ContextNode->getFunctionSamples();
  212. if (Samples && ContextNode->getParentContext() != &RootContext)
  213. Samples->getContext().setState(InlinedContext);
  214. return Samples;
  215. }
  216. FunctionSamples *
  217. SampleContextTracker::getContextSamplesFor(const SampleContext &Context) {
  218. ContextTrieNode *Node = getContextFor(Context);
  219. if (!Node)
  220. return nullptr;
  221. return Node->getFunctionSamples();
  222. }
  223. SampleContextTracker::ContextSamplesTy &
  224. SampleContextTracker::getAllContextSamplesFor(const Function &Func) {
  225. StringRef CanonName = FunctionSamples::getCanonicalFnName(Func);
  226. return FuncToCtxtProfileSet[CanonName];
  227. }
  228. SampleContextTracker::ContextSamplesTy &
  229. SampleContextTracker::getAllContextSamplesFor(StringRef Name) {
  230. return FuncToCtxtProfileSet[Name];
  231. }
  232. FunctionSamples *SampleContextTracker::getBaseSamplesFor(const Function &Func,
  233. bool MergeContext) {
  234. StringRef CanonName = FunctionSamples::getCanonicalFnName(Func);
  235. return getBaseSamplesFor(CanonName, MergeContext);
  236. }
  237. FunctionSamples *SampleContextTracker::getBaseSamplesFor(StringRef Name,
  238. bool MergeContext) {
  239. LLVM_DEBUG(dbgs() << "Getting base profile for function: " << Name << "\n");
  240. // Base profile is top-level node (child of root node), so try to retrieve
  241. // existing top-level node for given function first. If it exists, it could be
  242. // that we've merged base profile before, or there's actually context-less
  243. // profile from the input (e.g. due to unreliable stack walking).
  244. ContextTrieNode *Node = getTopLevelContextNode(Name);
  245. if (MergeContext) {
  246. LLVM_DEBUG(dbgs() << " Merging context profile into base profile: " << Name
  247. << "\n");
  248. // We have profile for function under different contexts,
  249. // create synthetic base profile and merge context profiles
  250. // into base profile.
  251. for (auto *CSamples : FuncToCtxtProfileSet[Name]) {
  252. SampleContext &Context = CSamples->getContext();
  253. ContextTrieNode *FromNode = getContextFor(Context);
  254. if (FromNode == Node)
  255. continue;
  256. // Skip inlined context profile and also don't re-merge any context
  257. if (Context.hasState(InlinedContext) || Context.hasState(MergedContext))
  258. continue;
  259. ContextTrieNode &ToNode = promoteMergeContextSamplesTree(*FromNode);
  260. assert((!Node || Node == &ToNode) && "Expect only one base profile");
  261. Node = &ToNode;
  262. }
  263. }
  264. // Still no profile even after merge/promotion (if allowed)
  265. if (!Node)
  266. return nullptr;
  267. return Node->getFunctionSamples();
  268. }
  269. void SampleContextTracker::markContextSamplesInlined(
  270. const FunctionSamples *InlinedSamples) {
  271. assert(InlinedSamples && "Expect non-null inlined samples");
  272. LLVM_DEBUG(dbgs() << "Marking context profile as inlined: "
  273. << InlinedSamples->getContext() << "\n");
  274. InlinedSamples->getContext().setState(InlinedContext);
  275. }
  276. void SampleContextTracker::promoteMergeContextSamplesTree(
  277. const Instruction &Inst, StringRef CalleeName) {
  278. LLVM_DEBUG(dbgs() << "Promoting and merging context tree for instr: \n"
  279. << Inst << "\n");
  280. // Get the caller context for the call instruction, we don't use callee
  281. // name from call because there can be context from indirect calls too.
  282. DILocation *DIL = Inst.getDebugLoc();
  283. ContextTrieNode *CallerNode = getContextFor(DIL);
  284. if (!CallerNode)
  285. return;
  286. // Get the context that needs to be promoted
  287. LineLocation CallSite = FunctionSamples::getCallSiteIdentifier(DIL);
  288. // For indirect call, CalleeName will be empty, in which case we need to
  289. // promote all non-inlined child context profiles.
  290. if (CalleeName.empty()) {
  291. for (auto &It : CallerNode->getAllChildContext()) {
  292. ContextTrieNode *NodeToPromo = &It.second;
  293. if (CallSite != NodeToPromo->getCallSiteLoc())
  294. continue;
  295. FunctionSamples *FromSamples = NodeToPromo->getFunctionSamples();
  296. if (FromSamples && FromSamples->getContext().hasState(InlinedContext))
  297. continue;
  298. promoteMergeContextSamplesTree(*NodeToPromo);
  299. }
  300. return;
  301. }
  302. // Get the context for the given callee that needs to be promoted
  303. ContextTrieNode *NodeToPromo =
  304. CallerNode->getChildContext(CallSite, CalleeName);
  305. if (!NodeToPromo)
  306. return;
  307. promoteMergeContextSamplesTree(*NodeToPromo);
  308. }
  309. ContextTrieNode &SampleContextTracker::promoteMergeContextSamplesTree(
  310. ContextTrieNode &NodeToPromo) {
  311. // Promote the input node to be directly under root. This can happen
  312. // when we decided to not inline a function under context represented
  313. // by the input node. The promote and merge is then needed to reflect
  314. // the context profile in the base (context-less) profile.
  315. FunctionSamples *FromSamples = NodeToPromo.getFunctionSamples();
  316. assert(FromSamples && "Shouldn't promote a context without profile");
  317. LLVM_DEBUG(dbgs() << " Found context tree root to promote: "
  318. << FromSamples->getContext() << "\n");
  319. assert(!FromSamples->getContext().hasState(InlinedContext) &&
  320. "Shouldn't promote inlined context profile");
  321. StringRef ContextStrToRemove = FromSamples->getContext().getCallingContext();
  322. return promoteMergeContextSamplesTree(NodeToPromo, RootContext,
  323. ContextStrToRemove);
  324. }
  325. void SampleContextTracker::dump() {
  326. dbgs() << "Context Profile Tree:\n";
  327. std::queue<ContextTrieNode *> NodeQueue;
  328. NodeQueue.push(&RootContext);
  329. while (!NodeQueue.empty()) {
  330. ContextTrieNode *Node = NodeQueue.front();
  331. NodeQueue.pop();
  332. Node->dump();
  333. for (auto &It : Node->getAllChildContext()) {
  334. ContextTrieNode *ChildNode = &It.second;
  335. NodeQueue.push(ChildNode);
  336. }
  337. }
  338. }
  339. ContextTrieNode *
  340. SampleContextTracker::getContextFor(const SampleContext &Context) {
  341. return getOrCreateContextPath(Context, false);
  342. }
  343. ContextTrieNode *
  344. SampleContextTracker::getCalleeContextFor(const DILocation *DIL,
  345. StringRef CalleeName) {
  346. assert(DIL && "Expect non-null location");
  347. ContextTrieNode *CallContext = getContextFor(DIL);
  348. if (!CallContext)
  349. return nullptr;
  350. // When CalleeName is empty, the child context profile with max
  351. // total samples will be returned.
  352. return CallContext->getChildContext(
  353. FunctionSamples::getCallSiteIdentifier(DIL), CalleeName);
  354. }
  355. ContextTrieNode *SampleContextTracker::getContextFor(const DILocation *DIL) {
  356. assert(DIL && "Expect non-null location");
  357. SmallVector<std::pair<LineLocation, StringRef>, 10> S;
  358. // Use C++ linkage name if possible.
  359. const DILocation *PrevDIL = DIL;
  360. for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) {
  361. StringRef Name = PrevDIL->getScope()->getSubprogram()->getLinkageName();
  362. if (Name.empty())
  363. Name = PrevDIL->getScope()->getSubprogram()->getName();
  364. S.push_back(
  365. std::make_pair(FunctionSamples::getCallSiteIdentifier(DIL),
  366. PrevDIL->getScope()->getSubprogram()->getLinkageName()));
  367. PrevDIL = DIL;
  368. }
  369. // Push root node, note that root node like main may only
  370. // a name, but not linkage name.
  371. StringRef RootName = PrevDIL->getScope()->getSubprogram()->getLinkageName();
  372. if (RootName.empty())
  373. RootName = PrevDIL->getScope()->getSubprogram()->getName();
  374. S.push_back(std::make_pair(LineLocation(0, 0), RootName));
  375. ContextTrieNode *ContextNode = &RootContext;
  376. int I = S.size();
  377. while (--I >= 0 && ContextNode) {
  378. LineLocation &CallSite = S[I].first;
  379. StringRef &CalleeName = S[I].second;
  380. ContextNode = ContextNode->getChildContext(CallSite, CalleeName);
  381. }
  382. if (I < 0)
  383. return ContextNode;
  384. return nullptr;
  385. }
  386. ContextTrieNode *
  387. SampleContextTracker::getOrCreateContextPath(const SampleContext &Context,
  388. bool AllowCreate) {
  389. ContextTrieNode *ContextNode = &RootContext;
  390. StringRef ContextRemain = Context;
  391. StringRef ChildContext;
  392. StringRef CalleeName;
  393. LineLocation CallSiteLoc(0, 0);
  394. while (ContextNode && !ContextRemain.empty()) {
  395. auto ContextSplit = SampleContext::splitContextString(ContextRemain);
  396. ChildContext = ContextSplit.first;
  397. ContextRemain = ContextSplit.second;
  398. LineLocation NextCallSiteLoc(0, 0);
  399. SampleContext::decodeContextString(ChildContext, CalleeName,
  400. NextCallSiteLoc);
  401. // Create child node at parent line/disc location
  402. if (AllowCreate) {
  403. ContextNode =
  404. ContextNode->getOrCreateChildContext(CallSiteLoc, CalleeName);
  405. } else {
  406. ContextNode = ContextNode->getChildContext(CallSiteLoc, CalleeName);
  407. }
  408. CallSiteLoc = NextCallSiteLoc;
  409. }
  410. assert((!AllowCreate || ContextNode) &&
  411. "Node must exist if creation is allowed");
  412. return ContextNode;
  413. }
  414. ContextTrieNode *SampleContextTracker::getTopLevelContextNode(StringRef FName) {
  415. return RootContext.getChildContext(LineLocation(0, 0), FName);
  416. }
  417. ContextTrieNode &SampleContextTracker::addTopLevelContextNode(StringRef FName) {
  418. assert(!getTopLevelContextNode(FName) && "Node to add must not exist");
  419. return *RootContext.getOrCreateChildContext(LineLocation(0, 0), FName);
  420. }
  421. void SampleContextTracker::mergeContextNode(ContextTrieNode &FromNode,
  422. ContextTrieNode &ToNode,
  423. StringRef ContextStrToRemove) {
  424. FunctionSamples *FromSamples = FromNode.getFunctionSamples();
  425. FunctionSamples *ToSamples = ToNode.getFunctionSamples();
  426. if (FromSamples && ToSamples) {
  427. // Merge/duplicate FromSamples into ToSamples
  428. ToSamples->merge(*FromSamples);
  429. ToSamples->getContext().setState(SyntheticContext);
  430. FromSamples->getContext().setState(MergedContext);
  431. } else if (FromSamples) {
  432. // Transfer FromSamples from FromNode to ToNode
  433. ToNode.setFunctionSamples(FromSamples);
  434. FromSamples->getContext().setState(SyntheticContext);
  435. FromSamples->getContext().promoteOnPath(ContextStrToRemove);
  436. FromNode.setFunctionSamples(nullptr);
  437. }
  438. }
  439. ContextTrieNode &SampleContextTracker::promoteMergeContextSamplesTree(
  440. ContextTrieNode &FromNode, ContextTrieNode &ToNodeParent,
  441. StringRef ContextStrToRemove) {
  442. assert(!ContextStrToRemove.empty() && "Context to remove can't be empty");
  443. // Ignore call site location if destination is top level under root
  444. LineLocation NewCallSiteLoc = LineLocation(0, 0);
  445. LineLocation OldCallSiteLoc = FromNode.getCallSiteLoc();
  446. ContextTrieNode &FromNodeParent = *FromNode.getParentContext();
  447. ContextTrieNode *ToNode = nullptr;
  448. bool MoveToRoot = (&ToNodeParent == &RootContext);
  449. if (!MoveToRoot) {
  450. NewCallSiteLoc = OldCallSiteLoc;
  451. }
  452. // Locate destination node, create/move if not existing
  453. ToNode = ToNodeParent.getChildContext(NewCallSiteLoc, FromNode.getFuncName());
  454. if (!ToNode) {
  455. // Do not delete node to move from its parent here because
  456. // caller is iterating over children of that parent node.
  457. ToNode = &ToNodeParent.moveToChildContext(
  458. NewCallSiteLoc, std::move(FromNode), ContextStrToRemove, false);
  459. } else {
  460. // Destination node exists, merge samples for the context tree
  461. mergeContextNode(FromNode, *ToNode, ContextStrToRemove);
  462. LLVM_DEBUG(dbgs() << " Context promoted and merged to: "
  463. << ToNode->getFunctionSamples()->getContext() << "\n");
  464. // Recursively promote and merge children
  465. for (auto &It : FromNode.getAllChildContext()) {
  466. ContextTrieNode &FromChildNode = It.second;
  467. promoteMergeContextSamplesTree(FromChildNode, *ToNode,
  468. ContextStrToRemove);
  469. }
  470. // Remove children once they're all merged
  471. FromNode.getAllChildContext().clear();
  472. }
  473. // For root of subtree, remove itself from old parent too
  474. if (MoveToRoot)
  475. FromNodeParent.removeChildContext(OldCallSiteLoc, ToNode->getFuncName());
  476. return *ToNode;
  477. }
  478. // Replace call graph edges with dynamic call edges from the profile.
  479. void SampleContextTracker::addCallGraphEdges(CallGraph &CG,
  480. StringMap<Function *> &SymbolMap) {
  481. // Add profile call edges to the call graph.
  482. std::queue<ContextTrieNode *> NodeQueue;
  483. NodeQueue.push(&RootContext);
  484. while (!NodeQueue.empty()) {
  485. ContextTrieNode *Node = NodeQueue.front();
  486. NodeQueue.pop();
  487. Function *F = SymbolMap.lookup(Node->getFuncName());
  488. for (auto &I : Node->getAllChildContext()) {
  489. ContextTrieNode *ChildNode = &I.second;
  490. NodeQueue.push(ChildNode);
  491. if (F && !F->isDeclaration()) {
  492. Function *Callee = SymbolMap.lookup(ChildNode->getFuncName());
  493. if (Callee && !Callee->isDeclaration())
  494. CG[F]->addCalledFunction(nullptr, CG[Callee]);
  495. }
  496. }
  497. }
  498. }
  499. } // namespace llvm