diff options
Diffstat (limited to 'llvm/lib/Transforms/IPO/SampleContextTracker.cpp')
| -rw-r--r-- | llvm/lib/Transforms/IPO/SampleContextTracker.cpp | 164 |
1 files changed, 101 insertions, 63 deletions
diff --git a/llvm/lib/Transforms/IPO/SampleContextTracker.cpp b/llvm/lib/Transforms/IPO/SampleContextTracker.cpp index 55b88ac14da5..bae9a1e27e75 100644 --- a/llvm/lib/Transforms/IPO/SampleContextTracker.cpp +++ b/llvm/lib/Transforms/IPO/SampleContextTracker.cpp @@ -32,7 +32,7 @@ ContextTrieNode *ContextTrieNode::getChildContext(const LineLocation &CallSite, if (CalleeName.empty()) return getHottestChildContext(CallSite); - uint32_t Hash = nodeHash(CalleeName, CallSite); + uint64_t Hash = nodeHash(CalleeName, CallSite); auto It = AllChildContext.find(Hash); if (It != AllChildContext.end()) return &It->second; @@ -64,8 +64,8 @@ ContextTrieNode::getHottestChildContext(const LineLocation &CallSite) { ContextTrieNode &ContextTrieNode::moveToChildContext( const LineLocation &CallSite, ContextTrieNode &&NodeToMove, - StringRef ContextStrToRemove, bool DeleteNode) { - uint32_t Hash = nodeHash(NodeToMove.getFuncName(), CallSite); + uint32_t ContextFramesToRemove, bool DeleteNode) { + uint64_t Hash = nodeHash(NodeToMove.getFuncName(), CallSite); assert(!AllChildContext.count(Hash) && "Node to remove must exist"); LineLocation OldCallSite = NodeToMove.CallSiteLoc; ContextTrieNode &OldParentContext = *NodeToMove.getParentContext(); @@ -86,10 +86,10 @@ ContextTrieNode &ContextTrieNode::moveToChildContext( FunctionSamples *FSamples = Node->getFunctionSamples(); if (FSamples) { - FSamples->getContext().promoteOnPath(ContextStrToRemove); + FSamples->getContext().promoteOnPath(ContextFramesToRemove); FSamples->getContext().setState(SyntheticContext); - LLVM_DEBUG(dbgs() << " Context promoted to: " << FSamples->getContext() - << "\n"); + LLVM_DEBUG(dbgs() << " Context promoted to: " + << FSamples->getContext().toString() << "\n"); } for (auto &It : Node->getAllChildContext()) { @@ -108,12 +108,12 @@ ContextTrieNode &ContextTrieNode::moveToChildContext( void ContextTrieNode::removeChildContext(const LineLocation &CallSite, StringRef CalleeName) { - uint32_t Hash = nodeHash(CalleeName, CallSite); + uint64_t Hash = nodeHash(CalleeName, CallSite); // Note this essentially calls dtor and destroys that child context AllChildContext.erase(Hash); } -std::map<uint32_t, ContextTrieNode> &ContextTrieNode::getAllChildContext() { +std::map<uint64_t, ContextTrieNode> &ContextTrieNode::getAllChildContext() { return AllChildContext; } @@ -127,6 +127,15 @@ void ContextTrieNode::setFunctionSamples(FunctionSamples *FSamples) { FuncSamples = FSamples; } +Optional<uint32_t> ContextTrieNode::getFunctionSize() const { return FuncSize; } + +void ContextTrieNode::addFunctionSize(uint32_t FSize) { + if (!FuncSize.hasValue()) + FuncSize = 0; + + FuncSize = FuncSize.getValue() + FSize; +} + LineLocation ContextTrieNode::getCallSiteLoc() const { return CallSiteLoc; } ContextTrieNode *ContextTrieNode::getParentContext() const { @@ -137,9 +146,10 @@ void ContextTrieNode::setParentContext(ContextTrieNode *Parent) { ParentContext = Parent; } -void ContextTrieNode::dump() { +void ContextTrieNode::dumpNode() { dbgs() << "Node: " << FuncName << "\n" << " Callsite: " << CallSiteLoc << "\n" + << " Size: " << FuncSize << "\n" << " Children:\n"; for (auto &It : AllChildContext) { @@ -147,20 +157,38 @@ void ContextTrieNode::dump() { } } -uint32_t ContextTrieNode::nodeHash(StringRef ChildName, +void ContextTrieNode::dumpTree() { + dbgs() << "Context Profile Tree:\n"; + std::queue<ContextTrieNode *> NodeQueue; + NodeQueue.push(this); + + while (!NodeQueue.empty()) { + ContextTrieNode *Node = NodeQueue.front(); + NodeQueue.pop(); + Node->dumpNode(); + + for (auto &It : Node->getAllChildContext()) { + ContextTrieNode *ChildNode = &It.second; + NodeQueue.push(ChildNode); + } + } +} + +uint64_t ContextTrieNode::nodeHash(StringRef ChildName, const LineLocation &Callsite) { // We still use child's name for child hash, this is // because for children of root node, we don't have // different line/discriminator, and we'll rely on name // to differentiate children. - uint32_t NameHash = std::hash<std::string>{}(ChildName.str()); - uint32_t LocId = (Callsite.LineOffset << 16) | Callsite.Discriminator; + uint64_t NameHash = std::hash<std::string>{}(ChildName.str()); + uint64_t LocId = + (((uint64_t)Callsite.LineOffset) << 32) | Callsite.Discriminator; return NameHash + (LocId << 5) + LocId; } ContextTrieNode *ContextTrieNode::getOrCreateChildContext( const LineLocation &CallSite, StringRef CalleeName, bool AllowCreate) { - uint32_t Hash = nodeHash(CalleeName, CallSite); + uint64_t Hash = nodeHash(CalleeName, CallSite); auto It = AllChildContext.find(Hash); if (It != AllChildContext.end()) { assert(It->second.getFuncName() == CalleeName && @@ -177,13 +205,16 @@ ContextTrieNode *ContextTrieNode::getOrCreateChildContext( // Profiler tracker than manages profiles and its associated context SampleContextTracker::SampleContextTracker( - StringMap<FunctionSamples> &Profiles) { + SampleProfileMap &Profiles, + const DenseMap<uint64_t, StringRef> *GUIDToFuncNameMap) + : GUIDToFuncNameMap(GUIDToFuncNameMap) { for (auto &FuncSample : Profiles) { FunctionSamples *FSamples = &FuncSample.second; - SampleContext Context(FuncSample.first(), RawContext); - LLVM_DEBUG(dbgs() << "Tracking Context for function: " << Context << "\n"); + SampleContext Context = FuncSample.first; + LLVM_DEBUG(dbgs() << "Tracking Context for function: " << Context.toString() + << "\n"); if (!Context.isBaseContext()) - FuncToCtxtProfiles[Context.getNameWithoutContext()].push_back(FSamples); + FuncToCtxtProfiles[Context.getName()].insert(FSamples); ContextTrieNode *NewNode = getOrCreateContextPath(Context, true); assert(!NewNode->getFunctionSamples() && "New node can't have sample profile"); @@ -200,6 +231,10 @@ SampleContextTracker::getCalleeContextSamplesFor(const CallBase &Inst, return nullptr; CalleeName = FunctionSamples::getCanonicalFnName(CalleeName); + // Convert real function names to MD5 names, if the input profile is + // MD5-based. + std::string FGUID; + CalleeName = getRepInFormat(CalleeName, FunctionSamples::UseMD5, FGUID); // For indirect call, CalleeName will be empty, in which case the context // profile for callee with largest total samples will be returned. @@ -207,7 +242,8 @@ SampleContextTracker::getCalleeContextSamplesFor(const CallBase &Inst, if (CalleeContext) { FunctionSamples *FSamples = CalleeContext->getFunctionSamples(); LLVM_DEBUG(if (FSamples) { - dbgs() << " Callee context found: " << FSamples->getContext() << "\n"; + dbgs() << " Callee context found: " << FSamples->getContext().toString() + << "\n"; }); return FSamples; } @@ -285,6 +321,11 @@ FunctionSamples *SampleContextTracker::getBaseSamplesFor(const Function &Func, FunctionSamples *SampleContextTracker::getBaseSamplesFor(StringRef Name, bool MergeContext) { LLVM_DEBUG(dbgs() << "Getting base profile for function: " << Name << "\n"); + // Convert real function names to MD5 names, if the input profile is + // MD5-based. + std::string FGUID; + Name = getRepInFormat(Name, FunctionSamples::UseMD5, FGUID); + // Base profile is top-level node (child of root node), so try to retrieve // existing top-level node for given function first. If it exists, it could be // that we've merged base profile before, or there's actually context-less @@ -299,14 +340,14 @@ FunctionSamples *SampleContextTracker::getBaseSamplesFor(StringRef Name, // into base profile. for (auto *CSamples : FuncToCtxtProfiles[Name]) { SampleContext &Context = CSamples->getContext(); - ContextTrieNode *FromNode = getContextFor(Context); - if (FromNode == Node) - continue; - // Skip inlined context profile and also don't re-merge any context if (Context.hasState(InlinedContext) || Context.hasState(MergedContext)) continue; + ContextTrieNode *FromNode = getContextFor(Context); + if (FromNode == Node) + continue; + ContextTrieNode &ToNode = promoteMergeContextSamplesTree(*FromNode); assert((!Node || Node == &ToNode) && "Expect only one base profile"); Node = &ToNode; @@ -324,7 +365,7 @@ void SampleContextTracker::markContextSamplesInlined( const FunctionSamples *InlinedSamples) { assert(InlinedSamples && "Expect non-null inlined samples"); LLVM_DEBUG(dbgs() << "Marking context profile as inlined: " - << InlinedSamples->getContext() << "\n"); + << InlinedSamples->getContext().toString() << "\n"); InlinedSamples->getContext().setState(InlinedContext); } @@ -376,30 +417,23 @@ ContextTrieNode &SampleContextTracker::promoteMergeContextSamplesTree( FunctionSamples *FromSamples = NodeToPromo.getFunctionSamples(); assert(FromSamples && "Shouldn't promote a context without profile"); LLVM_DEBUG(dbgs() << " Found context tree root to promote: " - << FromSamples->getContext() << "\n"); + << FromSamples->getContext().toString() << "\n"); assert(!FromSamples->getContext().hasState(InlinedContext) && "Shouldn't promote inlined context profile"); - StringRef ContextStrToRemove = FromSamples->getContext().getCallingContext(); + uint32_t ContextFramesToRemove = + FromSamples->getContext().getContextFrames().size() - 1; return promoteMergeContextSamplesTree(NodeToPromo, RootContext, - ContextStrToRemove); + ContextFramesToRemove); } -void SampleContextTracker::dump() { - dbgs() << "Context Profile Tree:\n"; - std::queue<ContextTrieNode *> NodeQueue; - NodeQueue.push(&RootContext); - - while (!NodeQueue.empty()) { - ContextTrieNode *Node = NodeQueue.front(); - NodeQueue.pop(); - Node->dump(); +void SampleContextTracker::dump() { RootContext.dumpTree(); } - for (auto &It : Node->getAllChildContext()) { - ContextTrieNode *ChildNode = &It.second; - NodeQueue.push(ChildNode); - } - } +StringRef SampleContextTracker::getFuncNameFor(ContextTrieNode *Node) const { + if (!FunctionSamples::UseMD5) + return Node->getFuncName(); + assert(GUIDToFuncNameMap && "GUIDToFuncNameMap needs to be populated first"); + return GUIDToFuncNameMap->lookup(std::stoull(Node->getFuncName().data())); } ContextTrieNode * @@ -444,11 +478,22 @@ ContextTrieNode *SampleContextTracker::getContextFor(const DILocation *DIL) { RootName = PrevDIL->getScope()->getSubprogram()->getName(); S.push_back(std::make_pair(LineLocation(0, 0), RootName)); + // Convert real function names to MD5 names, if the input profile is + // MD5-based. + std::list<std::string> MD5Names; + if (FunctionSamples::UseMD5) { + for (auto &Location : S) { + MD5Names.emplace_back(); + getRepInFormat(Location.second, FunctionSamples::UseMD5, MD5Names.back()); + Location.second = MD5Names.back(); + } + } + ContextTrieNode *ContextNode = &RootContext; int I = S.size(); while (--I >= 0 && ContextNode) { LineLocation &CallSite = S[I].first; - StringRef &CalleeName = S[I].second; + StringRef CalleeName = S[I].second; ContextNode = ContextNode->getChildContext(CallSite, CalleeName); } @@ -462,27 +507,18 @@ ContextTrieNode * SampleContextTracker::getOrCreateContextPath(const SampleContext &Context, bool AllowCreate) { ContextTrieNode *ContextNode = &RootContext; - StringRef ContextRemain = Context; - StringRef ChildContext; - StringRef CalleeName; LineLocation CallSiteLoc(0, 0); - while (ContextNode && !ContextRemain.empty()) { - auto ContextSplit = SampleContext::splitContextString(ContextRemain); - ChildContext = ContextSplit.first; - ContextRemain = ContextSplit.second; - LineLocation NextCallSiteLoc(0, 0); - SampleContext::decodeContextString(ChildContext, CalleeName, - NextCallSiteLoc); - + for (auto &Callsite : Context.getContextFrames()) { // Create child node at parent line/disc location if (AllowCreate) { ContextNode = - ContextNode->getOrCreateChildContext(CallSiteLoc, CalleeName); + ContextNode->getOrCreateChildContext(CallSiteLoc, Callsite.FuncName); } else { - ContextNode = ContextNode->getChildContext(CallSiteLoc, CalleeName); + ContextNode = + ContextNode->getChildContext(CallSiteLoc, Callsite.FuncName); } - CallSiteLoc = NextCallSiteLoc; + CallSiteLoc = Callsite.Location; } assert((!AllowCreate || ContextNode) && @@ -502,7 +538,7 @@ ContextTrieNode &SampleContextTracker::addTopLevelContextNode(StringRef FName) { void SampleContextTracker::mergeContextNode(ContextTrieNode &FromNode, ContextTrieNode &ToNode, - StringRef ContextStrToRemove) { + uint32_t ContextFramesToRemove) { FunctionSamples *FromSamples = FromNode.getFunctionSamples(); FunctionSamples *ToSamples = ToNode.getFunctionSamples(); if (FromSamples && ToSamples) { @@ -510,19 +546,21 @@ void SampleContextTracker::mergeContextNode(ContextTrieNode &FromNode, ToSamples->merge(*FromSamples); ToSamples->getContext().setState(SyntheticContext); FromSamples->getContext().setState(MergedContext); + if (FromSamples->getContext().hasAttribute(ContextShouldBeInlined)) + ToSamples->getContext().setAttribute(ContextShouldBeInlined); } else if (FromSamples) { // Transfer FromSamples from FromNode to ToNode ToNode.setFunctionSamples(FromSamples); FromSamples->getContext().setState(SyntheticContext); - FromSamples->getContext().promoteOnPath(ContextStrToRemove); + FromSamples->getContext().promoteOnPath(ContextFramesToRemove); FromNode.setFunctionSamples(nullptr); } } ContextTrieNode &SampleContextTracker::promoteMergeContextSamplesTree( ContextTrieNode &FromNode, ContextTrieNode &ToNodeParent, - StringRef ContextStrToRemove) { - assert(!ContextStrToRemove.empty() && "Context to remove can't be empty"); + uint32_t ContextFramesToRemove) { + assert(ContextFramesToRemove && "Context to remove can't be empty"); // Ignore call site location if destination is top level under root LineLocation NewCallSiteLoc = LineLocation(0, 0); @@ -540,21 +578,21 @@ ContextTrieNode &SampleContextTracker::promoteMergeContextSamplesTree( // Do not delete node to move from its parent here because // caller is iterating over children of that parent node. ToNode = &ToNodeParent.moveToChildContext( - NewCallSiteLoc, std::move(FromNode), ContextStrToRemove, false); + NewCallSiteLoc, std::move(FromNode), ContextFramesToRemove, false); } else { // Destination node exists, merge samples for the context tree - mergeContextNode(FromNode, *ToNode, ContextStrToRemove); + mergeContextNode(FromNode, *ToNode, ContextFramesToRemove); LLVM_DEBUG({ if (ToNode->getFunctionSamples()) dbgs() << " Context promoted and merged to: " - << ToNode->getFunctionSamples()->getContext() << "\n"; + << ToNode->getFunctionSamples()->getContext().toString() << "\n"; }); // Recursively promote and merge children for (auto &It : FromNode.getAllChildContext()) { ContextTrieNode &FromChildNode = It.second; promoteMergeContextSamplesTree(FromChildNode, *ToNode, - ContextStrToRemove); + ContextFramesToRemove); } // Remove children once they're all merged |
