Add 'cold' attribute to functions
Duncan Sands
baldrick at free.fr
Fri May 17 07:01:17 PDT 2013
Hi Diego,
On 15/05/13 17:31, Diego Novillo wrote:
> On 2013-04-10 17:33 , Diego Novillo wrote:
>> This patch adds a new function attribute 'cold' to functions.
>
> Thanks for all the feedback. In fixing up the patch I noticed that there is a
> 'bindings/' directory where attributes seem to play a role. I'm not sure what
> this is. Not all the existing attributes seem to exist in these bindings.
>
> Should I add the following changes as well? There don't seem to be tests for
> these files (nothing I could find in a quick search, anyway).
>
> Main patch is attached. OK to commit?
> diff --git a/docs/LangRef.rst b/docs/LangRef.rst
> index 4d006f1..1c0864d 100644
> --- a/docs/LangRef.rst
> +++ b/docs/LangRef.rst
> @@ -807,6 +807,11 @@ example:
> This attribute indicates that the inliner should attempt to inline
> this function into callers whenever possible, ignoring any active
> inlining size threshold for this caller.
> +``cold``
> + This attribute indicates that this function is not called
> + frequently.
how about
not called frequently -> rarely called
or something else which indicates that 'cold' is only appropriate when the
function is hardly ever called, not when it's just not called *that* much.
When computing edge weights, basic blocks
> + post-dominated by a cold function are also considered to be cold;
post-dominated by a cold function -> post-dominated by a cold function call
This covers both calls to a cold function, and calls to a function where it is
the call that is marked cold but not the function.
> + and, thus, given low weight.
> ``nonlazybind``
> This attribute suppresses lazy symbol binding for the function. This
> may make calls to the function faster, at the cost of extra program
> diff --git a/include/llvm-c/Core.h b/include/llvm-c/Core.h
> index 6b62f33..085e533 100644
> --- a/include/llvm-c/Core.h
> +++ b/include/llvm-c/Core.h
> @@ -166,6 +166,7 @@ typedef enum {
> and the path forward agreed upon.
> LLVMAddressSafety = 1ULL << 32,
> LLVMStackProtectStrongAttribute = 1ULL<<33
> + LLVMCold = 1ULL << 40
Why the leap from 33 to 40? These numbers don't need to be the same as those
used in the bitcode (though I guess it doesn't hurt).
> */
> } LLVMAttribute;
>
> diff --git a/include/llvm/Analysis/BranchProbabilityInfo.h b/include/llvm/Analysis/BranchProbabilityInfo.h
> index 6c23f7c..8edbcaa 100644
> --- a/include/llvm/Analysis/BranchProbabilityInfo.h
> +++ b/include/llvm/Analysis/BranchProbabilityInfo.h
> @@ -131,11 +131,15 @@ private:
> /// \brief Track the set of blocks directly succeeded by a returning block.
> SmallPtrSet<BasicBlock *, 16> PostDominatedByUnreachable;
>
> + /// \brief Track the set of blocks eventually succeeded by a cold call.
eventually succeeded by a cold call -> that always lead to a cold call
> + SmallPtrSet<BasicBlock *, 16> PostDominatedByColdCall;
> +
> /// \brief Get sum of the block successors' weights.
> uint32_t getSumForBlock(const BasicBlock *BB) const;
>
> bool calcUnreachableHeuristics(BasicBlock *BB);
> bool calcMetadataWeights(BasicBlock *BB);
> + bool calcColdCallHeuristics(BasicBlock *BB);
> bool calcPointerHeuristics(BasicBlock *BB);
> bool calcLoopBranchHeuristics(BasicBlock *BB);
> bool calcZeroHeuristics(BasicBlock *BB);
> diff --git a/lib/Analysis/BranchProbabilityInfo.cpp b/lib/Analysis/BranchProbabilityInfo.cpp
> index 6c58856..769c47e 100644
> --- a/lib/Analysis/BranchProbabilityInfo.cpp
> +++ b/lib/Analysis/BranchProbabilityInfo.cpp
> @@ -69,6 +69,22 @@ static const uint32_t UR_TAKEN_WEIGHT = 1;
> /// easily subsume it.
> static const uint32_t UR_NONTAKEN_WEIGHT = 1024*1024 - 1;
>
> +/// \brief Weight for a branch taken going into a cold block.
> +///
> +/// This is the weight for a branch taken toward a block marked
> +/// cold. A block is marked cold if it's postdominated by a
> +/// block containing a call to a cold function. Cold functions
> +/// are those marked with attribute 'cold'.
> +static const uint32_t CC_TAKEN_WEIGHT = 4;
> +
> +/// \brief Weight for a branch not-taken into a cold block.
> +///
> +/// This is the weight for a branch not taken toward a block marked
> +/// cold. A block is marked cold if it's postdominated by a
> +/// block containing a call to a cold function. Cold functions
> +/// are those marked with attribute 'cold'.
I don't see the point in duplicating the explanation of what a cold block is.
Also, does this weight only apply when one of the successors is a cold block?
Is so, I think you should mention that.
> +static const uint32_t CC_NONTAKEN_WEIGHT = 64;
> +
> static const uint32_t PH_TAKEN_WEIGHT = 20;
> static const uint32_t PH_NONTAKEN_WEIGHT = 12;
>
> @@ -193,6 +209,63 @@ bool BranchProbabilityInfo::calcMetadataWeights(BasicBlock *BB) {
> return true;
> }
>
> +/// \brief Calculate edge weights for edges leading to cold blocks.
> +///
> +/// A cold block is one post-dominated by a block with a call to a
> +/// cold function. Those edges are unlikely to be taken, so we give
> +/// them relatively low weight.
> +///
> +/// Return true if we could compute the weights for cold eges. Return false,
eges -> edges
> +/// otherwise.
> +bool BranchProbabilityInfo::calcColdCallHeuristics(BasicBlock *BB) {
> + // If the block itself contains a cold function, add it to the
> + // set of blocks postdominated by a cold call.
> + for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
> + if (CallInst *CI = dyn_cast<CallInst>(I))
> + if (CI->hasFnAttr(Attribute::Cold))
> + PostDominatedByColdCall.insert(BB);
How about first checking whether the basic block in in the set already? Since
if it is then you can avoid a potentially expensive scan over the basic block.
If this is impossible, how about adding an assert to check that it never
happens.
> +
> + TerminatorInst *TI = BB->getTerminator();
> + if (TI->getNumSuccessors() == 0)
> + return false;
If BB itself is cold, is there any point spending time computing weights and so
on for the edges going out of it? How about just bailing out before this point
instead?
> + SmallVector<unsigned, 4> ColdEdges;
> + SmallVector<unsigned, 4> NormalEdges;
You could reserve TI->getNumSuccessors() space in these vectors. Just a
thought.
> +
> + for (succ_iterator I = succ_begin(BB), E = succ_end(BB); I != E; ++I)
> + if (PostDominatedByColdCall.count(*I))
> + ColdEdges.push_back(I.getSuccessorIndex());
> + else
> + NormalEdges.push_back(I.getSuccessorIndex());
> +
> + // If all successors are in the set of blocks post-dominated by cold calls,
> + // this block is in the set post-dominated by cold calls.
> + if (ColdEdges.size() == TI->getNumSuccessors())
> + PostDominatedByColdCall.insert(BB);
> +
> + // Skip probabilities if this block has a single successor.
> + if (TI->getNumSuccessors() == 1 || ColdEdges.empty())
> + return false;
> +
> + uint32_t ColdWeight =
> + std::max(CC_TAKEN_WEIGHT / (unsigned) ColdEdges.size(), MIN_WEIGHT);
> + for (SmallVector<unsigned, 4>::iterator I = ColdEdges.begin(),
> + E = ColdEdges.end();
> + I != E; ++I)
> + setEdgeWeight(BB, *I, ColdWeight);
> +
> + if (NormalEdges.empty())
> + return true;
> + uint32_t NormalWeight = std::max(
> + CC_NONTAKEN_WEIGHT / (unsigned) NormalEdges.size(), NORMAL_WEIGHT);
> + for (SmallVector<unsigned, 4>::iterator I = NormalEdges.begin(),
> + E = NormalEdges.end();
> + I != E; ++I)
> + setEdgeWeight(BB, *I, NormalWeight);
> +
> + return true;
> +}
> +
> // Calculate Edge Weights using "Pointer Heuristics". Predict a comparsion
> // between two pointer or pointer and NULL will fail.
> bool BranchProbabilityInfo::calcPointerHeuristics(BasicBlock *BB) {
Ciao, Duncan.
More information about the llvm-commits
mailing list