JIT: don't compute edge weights if not optimizing (dotnet/coreclr#19736)
authorAndy Ayers <andya@microsoft.com>
Thu, 30 Aug 2018 15:01:46 +0000 (08:01 -0700)
committerGitHub <noreply@github.com>
Thu, 30 Aug 2018 15:01:46 +0000 (08:01 -0700)
We were spending a bit less than 1% of jit time computing edge weights
for minopts an debug codegen, but then never using them.

Also when optimizing we wanted to just compute edge weights but ran
through a bit more code than that.

Restructure the code so it's clearer what runs when, and bypass the
edge weight computations for minopts and debug codegen.

Commit migrated from https://github.com/dotnet/coreclr/commit/d43347e043beb3ae64c8db55f72708c1ce60511e

src/coreclr/src/jit/compiler.cpp
src/coreclr/src/jit/compiler.h
src/coreclr/src/jit/flowgraph.cpp

index 7eb1ad2..b89bda3 100644 (file)
@@ -4630,8 +4630,8 @@ void Compiler::compCompile(void** methodCodePtr, ULONG* methodCodeSize, JitFlags
     /* From this point on the flowgraph information such as bbNum,
      * bbRefs or bbPreds has to be kept updated */
 
-    // Compute the edge weights (if we have profile data)
-    fgComputeEdgeWeights();
+    // Compute the block and edge weights
+    fgComputeBlockAndEdgeWeights();
     EndPhase(PHASE_COMPUTE_EDGE_WEIGHTS);
 
 #if FEATURE_EH_FUNCLETS
index cb1ca16..24ade25 100644 (file)
@@ -4638,6 +4638,9 @@ public:
 #ifdef DEBUG
     void fgPrintEdgeWeights();
 #endif
+    void                 fgComputeBlockAndEdgeWeights();
+    BasicBlock::weight_t fgComputeMissingBlockWeights();
+    void fgComputeCalledCount(BasicBlock::weight_t returnWeight);
     void fgComputeEdgeWeights();
 
     void fgReorderBlocks();
index 872fc1d..4a7a0ae 100644 (file)
@@ -12994,50 +12994,64 @@ bool Compiler::fgMightHaveLoop()
     return false;
 }
 
-void Compiler::fgComputeEdgeWeights()
+//-------------------------------------------------------------
+// fgComputeBlockAndEdgeWeights: determine weights for blocks
+//   and optionally for edges
+//
+void Compiler::fgComputeBlockAndEdgeWeights()
 {
-#ifdef DEBUG
+    JITDUMP("*************** In fgComputeBlockAndEdgeWeights()\n");
+
+    const bool usingProfileWeights = fgIsUsingProfileWeights();
+    const bool isOptimizing        = !opts.MinOpts() && !opts.compDbgCode;
+
+    fgHaveValidEdgeWeights = false;
+    fgCalledCount          = BB_UNITY_WEIGHT;
+
+#if DEBUG
     if (verbose)
     {
-        printf("*************** In fgComputeEdgeWeights()\n");
+        fgDispBasicBlocks();
+        printf("\n");
     }
 #endif // DEBUG
 
-    if (fgIsUsingProfileWeights() == false)
+    const BasicBlock::weight_t returnWeight = fgComputeMissingBlockWeights();
+
+    if (usingProfileWeights)
     {
-#ifdef DEBUG
-        if (verbose)
-        {
-            printf("fgComputeEdgeWeights() we do not have any profile data so we are not using the edge weights\n");
-        }
-#endif // DEBUG
-        fgHaveValidEdgeWeights = false;
-        fgCalledCount          = BB_UNITY_WEIGHT;
+        fgComputeCalledCount(returnWeight);
+    }
+    else
+    {
+        JITDUMP(" -- no profile data, so using default called count\n");
     }
 
-#if DEBUG
-    if (verbose)
+    if (isOptimizing)
     {
-        fgDispBasicBlocks();
-        printf("\n");
+        fgComputeEdgeWeights();
     }
-#endif // DEBUG
+    else
+    {
+        JITDUMP(" -- not optimizing, so not computing edge weights\n");
+    }
+}
 
-    BasicBlock* bSrc;
-    BasicBlock* bDst;
-    flowList*   edge;
-    unsigned    iterations               = 0;
-    unsigned    goodEdgeCountCurrent     = 0;
-    unsigned    goodEdgeCountPrevious    = 0;
-    bool        inconsistentProfileData  = false;
-    bool        hasIncompleteEdgeWeights = false;
-    unsigned    numEdges                 = 0;
-    bool        usedSlop                 = false;
-    bool        changed;
-    bool        modified;
+//-------------------------------------------------------------
+// fgComputeMissingBlockWeights: determine weights for blocks
+//   that were not profiled and do not yet have weights.
+//
+// Returns:
+//   sum of weights for all return and throw blocks in the method
 
+BasicBlock::weight_t Compiler::fgComputeMissingBlockWeights()
+{
+    BasicBlock*          bSrc;
+    BasicBlock*          bDst;
+    unsigned             iterations = 0;
+    bool                 changed;
+    bool                 modified = false;
     BasicBlock::weight_t returnWeight;
-    BasicBlock::weight_t slop;
 
     // If we have any blocks that did not have profile derived weight
     // we will try to fix their weight up here
@@ -13144,68 +13158,96 @@ void Compiler::fgComputeEdgeWeights()
 #if DEBUG
     if (verbose && modified)
     {
-        printf("fgComputeEdgeWeights() adjusted the weight of some blocks\n");
+        printf("fgComputeMissingBlockWeights() adjusted the weight of some blocks\n");
         fgDispBasicBlocks();
         printf("\n");
     }
 #endif
 
+    return returnWeight;
+}
+
+//-------------------------------------------------------------
+// fgComputeCalledCount: when profile information is in use,
+//   compute fgCalledCount
+//
+// Argument:
+//   returnWeight - sum of weights for all return and throw blocks
+
+void Compiler::fgComputeCalledCount(BasicBlock::weight_t returnWeight)
+{
     // When we are not using profile data we have already setup fgCalledCount
     // only set it here if we are using profile data
-    //
-    if (fgIsUsingProfileWeights())
-    {
-        BasicBlock* firstILBlock = fgFirstBB; // The first block for IL code (i.e. for the IL code at offset 0)
+    assert(fgIsUsingProfileWeights());
 
-        // Do we have an internal block as our first Block?
-        if (firstILBlock->bbFlags & BBF_INTERNAL)
-        {
-            // Skip past any/all BBF_INTERNAL blocks that may have been added before the first real IL block.
-            //
-            while (firstILBlock->bbFlags & BBF_INTERNAL)
-            {
-                firstILBlock = firstILBlock->bbNext;
-            }
-            // The 'firstILBlock' is now expected to have a profile-derived weight
-            assert(firstILBlock->hasProfileWeight());
-        }
+    BasicBlock* firstILBlock = fgFirstBB; // The first block for IL code (i.e. for the IL code at offset 0)
 
-        // If the first block only has one ref then we use it's weight for fgCalledCount.
-        // Otherwise we have backedge's into the first block, so instead we use the sum
-        // of the return block weights for fgCalledCount.
-        //
-        // If the profile data has a 0 for the returnWeight
-        // (i.e. the function never returns because it always throws)
-        // then just use the first block weight rather than 0.
+    // Do we have an internal block as our first Block?
+    if (firstILBlock->bbFlags & BBF_INTERNAL)
+    {
+        // Skip past any/all BBF_INTERNAL blocks that may have been added before the first real IL block.
         //
-        if ((firstILBlock->countOfInEdges() == 1) || (returnWeight == 0))
-        {
-            assert(firstILBlock->hasProfileWeight()); // This should always be a profile-derived weight
-            fgCalledCount = firstILBlock->bbWeight;
-        }
-        else
+        while (firstILBlock->bbFlags & BBF_INTERNAL)
         {
-            fgCalledCount = returnWeight;
+            firstILBlock = firstILBlock->bbNext;
         }
+        // The 'firstILBlock' is now expected to have a profile-derived weight
+        assert(firstILBlock->hasProfileWeight());
+    }
 
-        // If we allocated a scratch block as the first BB then we need
-        // to set its profile-derived weight to be fgCalledCount
-        if (fgFirstBBisScratch())
+    // If the first block only has one ref then we use it's weight for fgCalledCount.
+    // Otherwise we have backedge's into the first block, so instead we use the sum
+    // of the return block weights for fgCalledCount.
+    //
+    // If the profile data has a 0 for the returnWeight
+    // (i.e. the function never returns because it always throws)
+    // then just use the first block weight rather than 0.
+    //
+    if ((firstILBlock->countOfInEdges() == 1) || (returnWeight == 0))
+    {
+        assert(firstILBlock->hasProfileWeight()); // This should always be a profile-derived weight
+        fgCalledCount = firstILBlock->bbWeight;
+    }
+    else
+    {
+        fgCalledCount = returnWeight;
+    }
+
+    // If we allocated a scratch block as the first BB then we need
+    // to set its profile-derived weight to be fgCalledCount
+    if (fgFirstBBisScratch())
+    {
+        fgFirstBB->setBBProfileWeight(fgCalledCount);
+        if (fgFirstBB->bbWeight == 0)
         {
-            fgFirstBB->setBBProfileWeight(fgCalledCount);
-            if (fgFirstBB->bbWeight == 0)
-            {
-                fgFirstBB->bbFlags |= BBF_RUN_RARELY;
-            }
+            fgFirstBB->bbFlags |= BBF_RUN_RARELY;
         }
+    }
 
 #if DEBUG
-        if (verbose)
-        {
-            printf("We are using the Profile Weights and fgCalledCount is %d.\n", fgCalledCount);
-        }
-#endif
+    if (verbose)
+    {
+        printf("We are using the Profile Weights and fgCalledCount is %d.\n", fgCalledCount);
     }
+#endif
+}
+
+//-------------------------------------------------------------
+// fgComputeEdgeWeights: compute edge weights from block weights
+
+void Compiler::fgComputeEdgeWeights()
+{
+    BasicBlock*          bSrc;
+    BasicBlock*          bDst;
+    flowList*            edge;
+    BasicBlock::weight_t slop;
+    unsigned             goodEdgeCountCurrent     = 0;
+    unsigned             goodEdgeCountPrevious    = 0;
+    bool                 inconsistentProfileData  = false;
+    bool                 hasIncompleteEdgeWeights = false;
+    bool                 usedSlop                 = false;
+    unsigned             numEdges                 = 0;
+    unsigned             iterations               = 0;
 
     // Now we will compute the initial flEdgeWeightMin and flEdgeWeightMax values
     for (bDst = fgFirstBB; bDst != nullptr; bDst = bDst->bbNext)