docs: synchronized String evaluateInterval() {
          // During shutdown, threadpool may have been nulled out. In that case, don't bother analyzing.
          // (We could log this in FFDC, but it isn't clear that it's worth doing so.)
          if (threadPool == null)
              return "threadPool == null";
  
          int poolSize = threadPool.getPoolSize();
  
          // Bail when there are no threads in the pool (unlikely)
          if (poolSize <= 0) {
              return "poolSize <= 0";
          }
  
          // we can't even think about adjusting the pool size until the underlying executor has aggressively
          // grown the pool to the coreThreads value, so if that hasn't happened yet we should just bail
          if (poolSize < coreThreads) {
              return "poolSize < coreThreads";
          }
  
          long currentTime = System.currentTimeMillis();
          long completedWork = threadPool.getCompletedTaskCount();
  
          // Calculate work done for the current interval
          long deltaTime = Math.max(currentTime - lastTimerPop, interval);
          long deltaCompleted = completedWork - previousCompleted;
          double throughput = 1000.0 * deltaCompleted / deltaTime;
          try {
              queueDepth = threadPool.getQueue().size();
              boolean queueEmpty = (queueDepth <= 0);
  
              // Count the number of consecutive times we've seen an empty queue
              if (!queueEmpty) {
                  consecutiveQueueEmptyCount = 0;
              } else if (lastAction != LastAction.SHRINK) { // 9/5/2012
                  consecutiveQueueEmptyCount++;
              }
  
              // update cpu utilization info
              boolean cpuHigh = false;
  
              processCpuUtil = CpuInfo.getJavaCpuUsage();
              systemCpuUtil = CpuInfo.getSystemCpuUsage();
              cpuUtil = Math.max(systemCpuUtil, processCpuUtil);
  
              if (cpuUtil > highCpu) {
                  cpuHigh = true;
              }
  
              // Handle pausing the task if the pool has been idle
              if (manageIdlePool(threadPool, deltaCompleted)) {
                  return "monitoring paused";
              }
  
              if (resolveHang(deltaCompleted, queueEmpty, poolSize)) {
                  /**
                   * Sleep the controller thread briefly after increasing the poolsize
                   * then update task count before returning to reduce the likelihood
                   * of a false negative hang check next cycle due to a few non-hung
                   * tasks executing on the newly created threads
                   */
                  try {
                      Thread.sleep(10);
                  } catch (Exception ex) {
                      // do nothing
                  }
                  completedWork = threadPool.getCompletedTaskCount();
                  return "action take to resolve hang";
              }
  
              if (checkTargetPoolSize(poolSize)) {
                  return "poolSize != targetPoolSize";
              }
  
              controllerCycle++;
              ThroughputDistribution currentStats = getThroughputDistribution(poolSize, true);
  
              // handleOutliers will mark this 'true' if it resets the distribution
              distributionReset = false;
  
              // Reset statistics based on abnormal data points
              if (handleOutliers(currentStats, throughput)) {
                  return "aberrant workload";
              }
  
              // If the distribution was reset we don't need to add the datapoint because
              // handleOutliers already did that.
              // If throughput was 0 we will not include that datapoint
              if (!distributionReset && throughput > 0) {
                  currentStats.addDataPoint(throughput, controllerCycle);
              }
  
              boolean lowTput = false;
              if (queueDepth == 0 && throughput < poolSize * lowTputThreadsRatio) {
                  lowTput = true;
                  if (tc.isEventEnabled()) {
                      Tr.event(tc, "low tput flag set: throughput: " + throughput + ", poolSize: "
                                   + poolSize + ", queueDepth: " + queueDepth,
                               threadPool);
                  }
              }
  
              setPoolIncrementDecrement(poolSize);
  
              double forecast = currentStats.getMovingAverage();
              double shrinkScore = getShrinkScore(poolSize, forecast, throughput, cpuHigh, lowTput);
              double growScore = getGrowScore(poolSize, forecast, throughput, cpuHigh, lowTput);
  
              // Adjust the poolsize only if one of the scores is both larger than the scoreFilterLevel
              // and sufficiently larger than the other score. These conditions reduce poolsize fluctuation
              // which might arise due to a weak or noisy signal from the historical throughput data.
              int poolAdjustment = 0;
              if (growScore >= growScoreFilterLevel && (growScore - growShrinkDiffFilter) > shrinkScore) {
                  poolAdjustment = poolIncrement;
              } else if (shrinkScore >= shrinkScoreFilterLevel && (shrinkScore - growShrinkDiffFilter) > growScore) {
                  poolAdjustment = -poolDecrement;
              }
  
              // Force some random variation into the pool size algorithm
              poolAdjustment = forceVariation(poolSize, poolAdjustment, deltaCompleted, lowTput);
  
              // Format an event level trace point with the most useful data
              if (tc.isEventEnabled()) {
                  Tr.event(tc, "Interval data", toIntervalData(throughput, forecast, shrinkScore, growScore, poolSize, poolAdjustment));
              }
  
              // Change the pool size and save the result, will check it at start of next control cycle
              targetPoolSize = adjustPoolSize(poolSize, poolAdjustment);
  
          } finally {
              lastTimerPop = currentTime;
              previousCompleted = completedWork;
              previousThroughput = throughput;
          }
          return "";
      }