weight_t bbWeight; // The dynamic execution weight of this block
+ // getCalledCount -- get the value used to normalize weights for this method
+ weight_t getCalledCount(Compiler* comp);
+
// getBBWeight -- get the normalized weight of this block
- unsigned getBBWeight(Compiler* comp);
+ weight_t getBBWeight(Compiler* comp);
// hasProfileWeight -- Returns true if this block's weight came from profile data
bool hasProfileWeight() const
// setBBWeight -- if the block weight is not derived from a profile,
// then set the weight to the input weight, making sure to not overflow BB_MAX_WEIGHT
// Note to set the weight from profile data, instead use setBBProfileWeight
- void setBBWeight(unsigned weight)
+ void setBBWeight(weight_t weight)
{
if (!hasProfileWeight())
{
// modifyBBWeight -- same as setBBWeight, but also make sure that if the block is rarely run, it stays that
// way, and if it's not rarely run then its weight never drops below 1.
- void modifyBBWeight(unsigned weight)
+ void modifyBBWeight(weight_t weight)
{
if (this->bbWeight != BB_ZERO_WEIGHT)
{
bool fgSlopUsedInEdgeWeights; // true if their was some slop used when computing the edge weights
bool fgRangeUsedInEdgeWeights; // true if some of the edgeWeight are expressed in Min..Max form
bool fgNeedsUpdateFlowGraph; // true if we need to run fgUpdateFlowGraph
- BasicBlock::weight_t fgCalledWeight; // count of the number of times this method was called
+ BasicBlock::weight_t fgCalledCount; // count of the number of times this method was called
// This is derived from the profile data
// or is BB_UNITY_WEIGHT when we don't have profile data
bool fgHaveProfileData();
bool fgGetProfileWeightForBasicBlock(IL_OFFSET offset, unsigned* weight);
+ void fgInstrumentMethod();
+public:
+ // fgIsUsingProfileWeights - returns true if we have real profile data for this method
+ // or if we have some fake profile data for the stress mode
bool fgIsUsingProfileWeights()
{
return (fgHaveProfileData() || fgStressBBProf());
}
- void fgInstrumentMethod();
+
+ // fgProfileRunsCount - returns total number of scenario runs for the profile data
+ // or BB_UNITY_WEIGHT when we aren't using profile data.
+ unsigned fgProfileRunsCount()
+ {
+ return fgIsUsingProfileWeights() ? fgNumProfileRuns : BB_UNITY_WEIGHT;
+ }
//-------- Insert a statement at the start or end of a basic block --------
//
if (emitComp->fgHaveProfileData())
{
- if (emitComp->fgCalledWeight > (BB_VERY_HOT_WEIGHT * emitComp->fgNumProfileRuns))
+ if (emitComp->fgCalledCount > (BB_VERY_HOT_WEIGHT * emitComp->fgProfileRunsCount()))
{
allocMemFlag = CORJIT_ALLOCMEM_FLG_16BYTE_ALIGN;
}
fgSlopUsedInEdgeWeights = false;
fgRangeUsedInEdgeWeights = true;
fgNeedsUpdateFlowGraph = false;
- fgCalledWeight = BB_ZERO_WEIGHT;
+ fgCalledCount = BB_ZERO_WEIGHT;
/* We haven't yet computed the dominator sets */
fgDomsComputed = false;
}
#endif // DEBUG
fgHaveValidEdgeWeights = false;
- fgCalledWeight = BB_UNITY_WEIGHT;
+ fgCalledCount = BB_UNITY_WEIGHT;
}
#if DEBUG
}
#endif
- // When we are not using profile data we have already setup fgCalledWeight
+ // When we are not using profile data we have already setup fgCalledCount
// only set it here if we are using profile data
//
if (fgIsUsingProfileWeights())
{
- // If the first block has one ref then it's weight is the fgCalledWeight
+ // If the first block has one ref then it's weight is the fgCalledCount
// otherwise we have backedge's into the first block so instead
// we use the sum of the return block weights.
// If the profile data has a 0 for the returnWeoght
//
if ((fgFirstBB->countOfInEdges() == 1) || (returnWeight == 0))
{
- fgCalledWeight = fgFirstBB->bbWeight;
+ fgCalledCount = fgFirstBB->bbWeight;
}
else
{
- fgCalledWeight = returnWeight;
+ fgCalledCount = returnWeight;
}
}
//
if (bDst == fgFirstBB)
{
- bDstWeight -= fgCalledWeight;
+ bDstWeight -= fgCalledCount;
}
for (edge = bDst->bbPreds; edge != nullptr; edge = edge->flNext)
//
if (bDst == fgFirstBB)
{
- bDstWeight -= fgCalledWeight;
+ bDstWeight -= fgCalledCount;
}
UINT64 minEdgeWeightSum = 0;
return false;
}
bool validWeights = fgHaveValidEdgeWeights;
- unsigned calledCount = max(fgCalledWeight, BB_UNITY_WEIGHT) / BB_UNITY_WEIGHT;
+ unsigned calledCount = max(fgCalledCount, BB_UNITY_WEIGHT) / BB_UNITY_WEIGHT;
double weightDivisor = (double)(calledCount * BB_UNITY_WEIGHT);
const char* escapedString;
const char* regionString = "NONE";
return genTypeSize(varType);
}
+// getCalledCount -- get the value used to normalized weights for this method
+// if we don't have profile data then getCalledCount will return BB_UNITY_WEIGHT (100)
+// otherwise it returns the number of times that profile data says the method was called.
+//
+BasicBlock::weight_t BasicBlock::getCalledCount(Compiler* comp)
+{
+ // when we don't have profile data then fgCalledCount will be BB_UNITY_WEIGHT (100)
+ BasicBlock::weight_t calledCount = comp->fgCalledCount;
+
+ // If we haven't yet reach the place where we setup fgCalledCount it could still be zero
+ // so return a reasonable value to use until we set it.
+ //
+ if (calledCount == 0)
+ {
+ if (comp->fgIsUsingProfileWeights())
+ {
+ // When we use profile data block counts we have exact counts,
+ // not multiples of BB_UNITY_WEIGHT (100)
+ calledCount = 1;
+ }
+ else
+ {
+ calledCount = comp->fgFirstBB->bbWeight;
+
+ if (calledCount == 0)
+ {
+ calledCount = BB_UNITY_WEIGHT;
+ }
+ }
+ }
+ return calledCount;
+}
+
// getBBWeight -- get the normalized weight of this block
-unsigned BasicBlock::getBBWeight(Compiler* comp)
+BasicBlock::weight_t BasicBlock::getBBWeight(Compiler* comp)
{
if (this->bbWeight == 0)
{
}
else
{
- unsigned calledWeight = comp->fgCalledWeight;
- if (calledWeight == 0)
- {
- calledWeight = comp->fgFirstBB->bbWeight;
- if (calledWeight == 0)
- {
- calledWeight = BB_UNITY_WEIGHT;
- }
- }
+ weight_t calledCount = getCalledCount(comp);
+
+ // Normalize the bbWeights by multiplying by BB_UNITY_WEIGHT and dividing by the calledCount.
+ //
+ // 1. For methods that do not have IBC data the called weight will always be 100 (BB_UNITY_WEIGHT)
+ // and the entry point bbWeight value is almost always 100 (BB_UNITY_WEIGHT)
+ // 2. For methods that do have IBC data the called weight is the actual number of calls
+ // from the IBC data and the entry point bbWeight value is almost always the actual
+ // number of calls from the IBC data.
+ //
+ // "almost always" - except for the rare case where a loop backedge jumps to BB01
+ //
+ // We also perform a rounding operation by adding half of the 'calledCount' before performing
+ // the division.
+ //
+ // Thus for both cases we will return 100 (BB_UNITY_WEIGHT) for the entry point BasicBlock
+ //
+ // Note that with a 100 (BB_UNITY_WEIGHT) values between 1 and 99 represent decimal fractions.
+ // (i.e. 33 represents 33% and 75 represents 75%, and values greater than 100 require
+ // some kind of loop backedge)
+ //
+
if (this->bbWeight < (BB_MAX_WEIGHT / BB_UNITY_WEIGHT))
{
- return max(1, (((this->bbWeight * BB_UNITY_WEIGHT) + (calledWeight / 2)) / calledWeight));
+ // Calculate the result using unsigned arithmetic
+ weight_t result = ((this->bbWeight * BB_UNITY_WEIGHT) + (calledCount / 2)) / calledCount;
+
+ // We don't allow a value of zero, as that would imply rarely run
+ return max(1, result);
}
else
{
- return (unsigned)((((double)this->bbWeight * (double)BB_UNITY_WEIGHT) / (double)calledWeight) + 0.5);
+ // Calculate the full result using floating point
+ double fullResult = ((double)this->bbWeight * (double)BB_UNITY_WEIGHT) / (double)calledCount;
+
+ if (fullResult < (double)BB_MAX_WEIGHT)
+ {
+ // Add 0.5 and truncate to unsigned
+ return (weight_t)(fullResult + 0.5);
+ }
+ else
+ {
+ return BB_MAX_WEIGHT;
+ }
}
}
}