Home / Class/ UtilizationMonitor Class — netty Architecture

UtilizationMonitor Class — netty Architecture

Architecture documentation for the UtilizationMonitor class in AutoScalingEventExecutorChooserFactory.java from the netty codebase.

Entity Profile

Dependency Diagram

graph TD
  d9aa57c9_e2b2_7790_035b_2a28f5df0c47["UtilizationMonitor"]
  409fa4eb_44da_665a_7f39_b9b5f929789e["AutoScalingEventExecutorChooserFactory.java"]
  d9aa57c9_e2b2_7790_035b_2a28f5df0c47 -->|defined in| 409fa4eb_44da_665a_7f39_b9b5f929789e
  0051a9bb_2eac_9138_da01_67fb084baff0["run()"]
  d9aa57c9_e2b2_7790_035b_2a28f5df0c47 -->|method| 0051a9bb_2eac_9138_da01_67fb084baff0
  c54d4b63_d04e_6ce4_af65_d57b7c4c37f3["rebuildActiveExecutors()"]
  d9aa57c9_e2b2_7790_035b_2a28f5df0c47 -->|method| c54d4b63_d04e_6ce4_af65_d57b7c4c37f3

Relationship Graph

Source Code

common/src/main/java/io/netty/util/concurrent/AutoScalingEventExecutorChooserFactory.java lines 268–419

        private final class UtilizationMonitor implements Runnable {
            private final List<SingleThreadEventExecutor> consistentlyIdleChildren = new ArrayList<>(maxChildren);
            private long lastCheckTimeNanos;

            @Override
            public void run() {
                if (executors.length == 0 || executors[0].isShuttingDown()) {
                    // The group is shutting down, so no scaling decisions should be made.
                    // The lifecycle listener on the terminationFuture will handle the final cancellation.
                    return;
                }

                // Calculate the actual elapsed time since the last run.
                final long now = executors[0].ticker().nanoTime();
                long totalTime;

                if (lastCheckTimeNanos == 0) {
                    // On the first run, use the configured period as a baseline to avoid skipping the cycle.
                    totalTime = utilizationCheckPeriodNanos;
                } else {
                    // On subsequent runs, calculate the actual elapsed time.
                    totalTime = now - lastCheckTimeNanos;
                }

                // Always update the timestamp for the next cycle.
                lastCheckTimeNanos = now;

                if (totalTime <= 0) {
                    // Skip this cycle if the clock has issues or the interval is invalid.
                    return;
                }

                int consistentlyBusyChildren = 0;
                consistentlyIdleChildren.clear();

                final AutoScalingState currentState = state.get();

                for (int i = 0; i < executors.length; i++) {
                    EventExecutor child = executors[i];
                    if (!(child instanceof SingleThreadEventExecutor)) {
                        continue;
                    }

                    SingleThreadEventExecutor eventExecutor = (SingleThreadEventExecutor) child;

                    double utilization = 0.0;
                    if (!eventExecutor.isSuspended()) {
                        long activeTime = eventExecutor.getAndResetAccumulatedActiveTimeNanos();

                        if (activeTime == 0) {
                            long lastActivity = eventExecutor.getLastActivityTimeNanos();
                            long idleTime = now - lastActivity;

                            // If the event loop has been idle for less time than our utilization window,
                            // it means it was active for the remainder of that window.
                            if (idleTime < totalTime) {
                                activeTime = totalTime - idleTime;
                            }
                            // If idleTime >= totalTime, it was idle for the whole window, so activeTime remains 0.
                        }

                        utilization = Math.min(1.0, (double) activeTime / totalTime);

                        if (utilization < scaleDownThreshold) {
                            // Utilization is low, increment idle counter and reset busy counter.
                            int idleCycles = eventExecutor.getAndIncrementIdleCycles();
                            eventExecutor.resetBusyCycles();
                            if (idleCycles >= scalingPatienceCycles &&
                                eventExecutor.getNumOfRegisteredChannels() <= 0) {
                                consistentlyIdleChildren.add(eventExecutor);
                            }
                        } else if (utilization > scaleUpThreshold) {
                            // Utilization is high, increment busy counter and reset idle counter.
                            int busyCycles = eventExecutor.getAndIncrementBusyCycles();
                            eventExecutor.resetIdleCycles();
                            if (busyCycles >= scalingPatienceCycles) {
                                consistentlyBusyChildren++;
                            }
                        } else {
                            // Utilization is in the normal range, reset counters.
                            eventExecutor.resetIdleCycles();

Frequently Asked Questions

What is the UtilizationMonitor class?
UtilizationMonitor is a class in the netty codebase, defined in common/src/main/java/io/netty/util/concurrent/AutoScalingEventExecutorChooserFactory.java.
Where is UtilizationMonitor defined?
UtilizationMonitor is defined in common/src/main/java/io/netty/util/concurrent/AutoScalingEventExecutorChooserFactory.java at line 268.

Analyze Your Own Codebase

Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.

Try Supermodel Free