Skip to content

Commit b8d8e56

Browse files
reduce utilization EWMA to parallel polling: allow utilization to be polled by allocation
1 parent 4037ccf commit b8d8e56

File tree

8 files changed

+89
-238
lines changed

8 files changed

+89
-238
lines changed

server/src/internalClusterTest/java/org/elasticsearch/threadpool/SimpleThreadPoolIT.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,8 @@
4141
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
4242
import static org.elasticsearch.threadpool.ThreadPool.DEFAULT_INDEX_AUTOSCALING_EWMA_ALPHA;
4343
import static org.elasticsearch.threadpool.ThreadPool.DEFAULT_WRITE_THREAD_POOL_QUEUE_LATENCY_EWMA_ALPHA;
44-
import static org.elasticsearch.threadpool.ThreadPool.DEFAULT_WRITE_THREAD_POOL_THREAD_UTILIZATION_EWMA_ALPHA;
4544
import static org.elasticsearch.threadpool.ThreadPool.WRITE_THREAD_POOLS_EWMA_ALPHA_SETTING;
4645
import static org.elasticsearch.threadpool.ThreadPool.WRITE_THREAD_POOL_QUEUE_LATENCY_EWMA_ALPHA;
47-
import static org.elasticsearch.threadpool.ThreadPool.WRITE_THREAD_POOL_THREAD_UTILIZATION_EWMA_ALPHA;
4846
import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder;
4947
import static org.hamcrest.Matchers.contains;
5048
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
@@ -242,15 +240,12 @@ public void testWriteThreadpoolsEwmaAlphaSetting() {
242240
Settings settings = Settings.EMPTY;
243241
var executionEwmaAlpha = DEFAULT_INDEX_AUTOSCALING_EWMA_ALPHA;
244242
var queueLatencyEwmaAlpha = DEFAULT_WRITE_THREAD_POOL_QUEUE_LATENCY_EWMA_ALPHA;
245-
var threadUtilizationEwmaAlpha = DEFAULT_WRITE_THREAD_POOL_THREAD_UTILIZATION_EWMA_ALPHA;
246243
if (randomBoolean()) {
247244
executionEwmaAlpha = randomDoubleBetween(0.0, 1.0, true);
248245
queueLatencyEwmaAlpha = randomDoubleBetween(0.0, 1.0, true);
249-
threadUtilizationEwmaAlpha = randomDoubleBetween(0.0, 1.0, true);
250246
settings = Settings.builder()
251247
.put(WRITE_THREAD_POOLS_EWMA_ALPHA_SETTING.getKey(), executionEwmaAlpha)
252248
.put(WRITE_THREAD_POOL_QUEUE_LATENCY_EWMA_ALPHA.getKey(), queueLatencyEwmaAlpha)
253-
.put(WRITE_THREAD_POOL_THREAD_UTILIZATION_EWMA_ALPHA.getKey(), threadUtilizationEwmaAlpha)
254249
.build();
255250
}
256251
var nodeName = internalCluster().startNode(settings);
@@ -265,13 +260,10 @@ public void testWriteThreadpoolsEwmaAlphaSetting() {
265260
// Only the WRITE thread pool should enable further tracking.
266261
if (name.equals(ThreadPool.Names.WRITE) == false) {
267262
assertFalse(executor.trackingQueueLatencyEwma());
268-
assertFalse(executor.trackUtilizationEwma());
269263
} else {
270264
// Verify that the WRITE thread pool has extra tracking enabled.
271265
assertTrue(executor.trackingQueueLatencyEwma());
272-
assertTrue(executor.trackUtilizationEwma());
273266
assertThat(Double.compare(executor.getQueueLatencyEwmaAlpha(), queueLatencyEwmaAlpha), CoreMatchers.equalTo(0));
274-
assertThat(Double.compare(executor.getPoolUtilizationEwmaAlpha(), threadUtilizationEwmaAlpha), CoreMatchers.equalTo(0));
275267
}
276268
}
277269
}

server/src/main/java/org/elasticsearch/common/settings/ClusterSettings.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,6 @@ public void apply(Settings value, Settings current, Settings previous) {
548548
ThreadPool.SLOW_SCHEDULER_TASK_WARN_THRESHOLD_SETTING,
549549
ThreadPool.WRITE_THREAD_POOLS_EWMA_ALPHA_SETTING,
550550
ThreadPool.WRITE_THREAD_POOL_QUEUE_LATENCY_EWMA_ALPHA,
551-
ThreadPool.WRITE_THREAD_POOL_THREAD_UTILIZATION_EWMA_ALPHA,
552551
FastVectorHighlighter.SETTING_TV_HIGHLIGHT_MULTI_VALUE,
553552
Node.BREAKER_TYPE_KEY,
554553
OperationRouting.USE_ADAPTIVE_REPLICA_SELECTION_SETTING,

server/src/main/java/org/elasticsearch/common/util/concurrent/EsExecutors.java

Lines changed: 6 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -579,43 +579,30 @@ public void rejectedExecution(Runnable task, ThreadPoolExecutor executor) {
579579
public static class TaskTrackingConfig {
580580
public static final double DEFAULT_EXECUTION_TIME_EWMA_ALPHA_FOR_TEST = 0.3;
581581
public static final double DEFAULT_QUEUE_LATENCY_EWMA_ALPHA_FOR_TEST = 0.6;
582-
public static final double DEFAULT_POOL_UTILIZATION_EWMA_ALPHA_FOR_TEST = 0.6;
583582

584583
private final boolean trackExecutionTime;
585584
private final boolean trackOngoingTasks;
586585
private final boolean trackQueueLatencyEWMA;
587-
private final boolean trackPoolUtilizationEWMA;
588586
private final double executionTimeEwmaAlpha;
589587
private final double queueLatencyEWMAAlpha;
590-
private final double poolUtilizationEWMAAlpha;
591588

592589
public static final TaskTrackingConfig DO_NOT_TRACK = new TaskTrackingConfig(
593590
false,
594591
false,
595592
false,
596593
DEFAULT_EXECUTION_TIME_EWMA_ALPHA_FOR_TEST,
597-
DEFAULT_QUEUE_LATENCY_EWMA_ALPHA_FOR_TEST,
598-
DEFAULT_POOL_UTILIZATION_EWMA_ALPHA_FOR_TEST
594+
DEFAULT_QUEUE_LATENCY_EWMA_ALPHA_FOR_TEST
599595
);
600596
public static final TaskTrackingConfig DEFAULT = new TaskTrackingConfig(
601597
true,
602598
false,
603599
false,
604600
DEFAULT_EXECUTION_TIME_EWMA_ALPHA_FOR_TEST,
605-
DEFAULT_QUEUE_LATENCY_EWMA_ALPHA_FOR_TEST,
606-
DEFAULT_POOL_UTILIZATION_EWMA_ALPHA_FOR_TEST
601+
DEFAULT_QUEUE_LATENCY_EWMA_ALPHA_FOR_TEST
607602
);
608603

609604
public TaskTrackingConfig(boolean trackOngoingTasks, double executionTimeEWMAAlpha) {
610-
this(
611-
true,
612-
trackOngoingTasks,
613-
false,
614-
false,
615-
executionTimeEWMAAlpha,
616-
DEFAULT_QUEUE_LATENCY_EWMA_ALPHA_FOR_TEST,
617-
DEFAULT_POOL_UTILIZATION_EWMA_ALPHA_FOR_TEST
618-
);
605+
this(true, trackOngoingTasks, false, executionTimeEWMAAlpha, DEFAULT_QUEUE_LATENCY_EWMA_ALPHA_FOR_TEST);
619606
}
620607

621608
/**
@@ -624,47 +611,31 @@ public TaskTrackingConfig(boolean trackOngoingTasks, double executionTimeEWMAAlp
624611
public TaskTrackingConfig(
625612
boolean trackOngoingTasks,
626613
boolean trackQueueLatencyEWMA,
627-
boolean trackPoolUtilizationEWMA,
628614
double executionTimeEWMAAlpha,
629-
double queueLatencyEWMAAlpha,
630-
double poolUtilizationEWMAAlpha
615+
double queueLatencyEWMAAlpha
631616
) {
632-
this(
633-
true,
634-
trackOngoingTasks,
635-
trackQueueLatencyEWMA,
636-
trackPoolUtilizationEWMA,
637-
executionTimeEWMAAlpha,
638-
queueLatencyEWMAAlpha,
639-
poolUtilizationEWMAAlpha
640-
);
617+
this(true, trackOngoingTasks, trackQueueLatencyEWMA, executionTimeEWMAAlpha, queueLatencyEWMAAlpha);
641618
}
642619

643620
/**
644621
* @param trackExecutionTime Whether to track execution stats
645622
* @param trackOngoingTasks Whether to track ongoing task execution time, not just finished tasks
646623
* @param trackQueueLatencyEWMA Whether to track queue latency {@link org.elasticsearch.common.ExponentiallyWeightedMovingAverage}
647-
* @param trackPoolUtilizationEWMA Whether to track the EWMA for thread pool thread utilization (percent use).
648624
* @param executionTimeEWMAAlpha The alpha seed for execution time EWMA (ExponentiallyWeightedMovingAverage).
649625
* @param queueLatencyEWMAAlpha The alpha seed for task queue latency EWMA (ExponentiallyWeightedMovingAverage).
650-
* @param poolUtilizationEWMAAlpha The alpha seed for pool utilization EWMA (ExponentiallyWeightedMovingAverage).
651626
*/
652627
private TaskTrackingConfig(
653628
boolean trackExecutionTime,
654629
boolean trackOngoingTasks,
655630
boolean trackQueueLatencyEWMA,
656-
boolean trackPoolUtilizationEWMA,
657631
double executionTimeEWMAAlpha,
658-
double queueLatencyEWMAAlpha,
659-
double poolUtilizationEWMAAlpha
632+
double queueLatencyEWMAAlpha
660633
) {
661634
this.trackExecutionTime = trackExecutionTime;
662635
this.trackOngoingTasks = trackOngoingTasks;
663636
this.trackQueueLatencyEWMA = trackQueueLatencyEWMA;
664-
this.trackPoolUtilizationEWMA = trackPoolUtilizationEWMA;
665637
this.executionTimeEwmaAlpha = executionTimeEWMAAlpha;
666638
this.queueLatencyEWMAAlpha = queueLatencyEWMAAlpha;
667-
this.poolUtilizationEWMAAlpha = poolUtilizationEWMAAlpha;
668639
}
669640

670641
public boolean trackExecutionTime() {
@@ -679,21 +650,13 @@ public boolean trackQueueLatencyEWMA() {
679650
return trackQueueLatencyEWMA;
680651
}
681652

682-
public boolean trackPoolUtilizationEWMA() {
683-
return trackPoolUtilizationEWMA;
684-
}
685-
686653
public double getExecutionTimeEwmaAlpha() {
687654
return executionTimeEwmaAlpha;
688655
}
689656

690657
public double getQueueLatencyEwmaAlpha() {
691658
return queueLatencyEWMAAlpha;
692659
}
693-
694-
public double getPoolUtilizationEwmaAlpha() {
695-
return poolUtilizationEWMAAlpha;
696-
}
697660
}
698661

699662
}

server/src/main/java/org/elasticsearch/common/util/concurrent/TaskExecutionTimeTrackingEsThreadPoolExecutor.java

Lines changed: 25 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
import java.util.concurrent.RejectedExecutionHandler;
2828
import java.util.concurrent.ThreadFactory;
2929
import java.util.concurrent.TimeUnit;
30-
import java.util.concurrent.atomic.AtomicReference;
3130
import java.util.concurrent.atomic.LongAdder;
3231
import java.util.function.Function;
3332

@@ -48,14 +47,13 @@ public final class TaskExecutionTimeTrackingEsThreadPoolExecutor extends EsThrea
4847
private final boolean trackOngoingTasks;
4948
// The set of currently running tasks and the timestamp of when they started execution in the Executor.
5049
private final Map<Runnable, Long> ongoingTasks = new ConcurrentHashMap<>();
51-
private volatile long lastPollTime = System.nanoTime();
52-
private volatile long lastTotalExecutionTime = 0;
50+
private volatile long lastPollTimeAPM = System.nanoTime();
51+
private volatile long lastTotalExecutionTimeAPM = 0;
52+
private volatile long lastPollTimeNanosAllocation = System.nanoTime();
53+
private volatile long lastTotalExecutionTimeAllocation = 0;
5354
private final ExponentialBucketHistogram queueLatencyMillisHistogram = new ExponentialBucketHistogram(QUEUE_LATENCY_HISTOGRAM_BUCKETS);
5455
private final boolean trackQueueLatencyEWMA;
55-
private final boolean trackUtilizationEWMA;
5656
private final ExponentiallyWeightedMovingAverage queueLatencyMillisEWMA;
57-
private final ExponentiallyWeightedMovingAverage percentPoolUtilizationEWMA;
58-
private final AtomicReference<Double> lastUtilizationValue = new AtomicReference<>(0.0);
5957

6058
TaskExecutionTimeTrackingEsThreadPoolExecutor(
6159
String name,
@@ -77,8 +75,6 @@ public final class TaskExecutionTimeTrackingEsThreadPoolExecutor extends EsThrea
7775
this.trackOngoingTasks = trackingConfig.trackOngoingTasks();
7876
this.trackQueueLatencyEWMA = trackingConfig.trackQueueLatencyEWMA();
7977
this.queueLatencyMillisEWMA = new ExponentiallyWeightedMovingAverage(trackingConfig.getQueueLatencyEwmaAlpha(), 0);
80-
this.trackUtilizationEWMA = trackingConfig.trackPoolUtilizationEWMA();
81-
this.percentPoolUtilizationEWMA = new ExponentiallyWeightedMovingAverage(trackingConfig.getPoolUtilizationEwmaAlpha(), 0);
8278
}
8379

8480
public List<Instrument> setupMetrics(MeterRegistry meterRegistry, String threadPoolName) {
@@ -106,7 +102,7 @@ public List<Instrument> setupMetrics(MeterRegistry meterRegistry, String threadP
106102
ThreadPool.THREAD_POOL_METRIC_PREFIX + threadPoolName + THREAD_POOL_METRIC_NAME_UTILIZATION,
107103
"fraction of maximum thread time utilized for " + threadPoolName,
108104
"fraction",
109-
() -> new DoubleWithAttributes(pollUtilization(), Map.of())
105+
() -> new DoubleWithAttributes(pollUtilization(true, false), Map.of())
110106
)
111107
);
112108
}
@@ -147,13 +143,6 @@ public int getCurrentQueueSize() {
147143
return getQueue().size();
148144
}
149145

150-
public double getPercentPoolUtilizationEWMA() {
151-
if (trackUtilizationEWMA == false) {
152-
return 0;
153-
}
154-
return this.percentPoolUtilizationEWMA.getAverage();
155-
}
156-
157146
public double getQueuedTaskLatencyMillisEWMA() {
158147
if (trackQueueLatencyEWMA == false) {
159148
return 0;
@@ -162,38 +151,38 @@ public double getQueuedTaskLatencyMillisEWMA() {
162151
}
163152

164153
/**
165-
* Returns the fraction of the maximum possible thread time that was actually used since the last time
166-
* this method was called.
154+
* Returns the fraction of the maximum possible thread time that was actually used since the last time this method was called.
155+
* One of the two boolean parameters must be true, while the other false. There are two periodic pulling mechanisms that access
156+
* utilization reporting.
167157
*
168-
* @return the utilization as a fraction, in the range [0, 1]
158+
* @return the utilization as a fraction, in the range [0, 1]. This may return >1 if a task completed in the time range but started
159+
* earlier, contributing a larger execution time.
169160
*/
170-
public double pollUtilization() {
161+
public double pollUtilization(boolean forAPM, boolean forAllocation) {
162+
assert forAPM ^ forAllocation : "Can only collect one or the other, APM: " + forAPM + ", Allocation: " + forAllocation;
163+
171164
final long currentTotalExecutionTimeNanos = totalExecutionTime.sum();
172165
final long currentPollTimeNanos = System.nanoTime();
173166

174-
final long totalExecutionTimeSinceLastPollNanos = currentTotalExecutionTimeNanos - lastTotalExecutionTime;
175-
final long timeSinceLastPoll = currentPollTimeNanos - lastPollTime;
167+
final long totalExecutionTimeSinceLastPollNanos = currentTotalExecutionTimeNanos - (forAPM
168+
? lastTotalExecutionTimeAPM
169+
: lastTotalExecutionTimeAllocation);
170+
final long timeSinceLastPoll = currentPollTimeNanos - (forAPM ? lastPollTimeAPM : lastPollTimeNanosAllocation);
176171
final long maximumExecutionTimeSinceLastPollNanos = timeSinceLastPoll * getMaximumPoolSize();
177172
final double utilizationSinceLastPoll = (double) totalExecutionTimeSinceLastPollNanos / maximumExecutionTimeSinceLastPollNanos;
178173

179-
lastTotalExecutionTime = currentTotalExecutionTimeNanos;
180-
lastPollTime = currentPollTimeNanos;
181-
182-
if (trackUtilizationEWMA) {
183-
percentPoolUtilizationEWMA.addValue(utilizationSinceLastPoll);
184-
// Test only tracking.
185-
assert setUtilizationSinceLastPoll(utilizationSinceLastPoll);
174+
if (forAPM) {
175+
lastTotalExecutionTimeAPM = currentTotalExecutionTimeNanos;
176+
lastPollTimeAPM = currentPollTimeNanos;
177+
} else {
178+
assert forAllocation;
179+
lastTotalExecutionTimeAllocation = currentTotalExecutionTimeNanos;
180+
lastPollTimeNanosAllocation = currentPollTimeNanos;
186181
}
187182

188183
return utilizationSinceLastPoll;
189184
}
190185

191-
// Test only
192-
private boolean setUtilizationSinceLastPoll(double utilizationSinceLastPoll) {
193-
lastUtilizationValue.set(utilizationSinceLastPoll);
194-
return true;
195-
}
196-
197186
@Override
198187
protected void beforeExecute(Thread t, Runnable r) {
199188
if (trackOngoingTasks) {
@@ -209,9 +198,7 @@ protected void beforeExecute(Thread t, Runnable r) {
209198
queueLatencyMillisHistogram.addObservation(queueLatencyMillis);
210199

211200
if (trackQueueLatencyEWMA) {
212-
if (queueLatencyMillis > 0) {
213-
queueLatencyMillisEWMA.addValue(queueLatencyMillis);
214-
}
201+
queueLatencyMillisEWMA.addValue(queueLatencyMillis);
215202
}
216203
}
217204

@@ -257,9 +244,6 @@ protected void appendThreadPoolExecutorDetails(StringBuilder sb) {
257244
if (trackQueueLatencyEWMA) {
258245
sb.append("task queue EWMA = ").append(TimeValue.timeValueMillis((long) getQueuedTaskLatencyMillisEWMA())).append(", ");
259246
}
260-
if (trackUtilizationEWMA) {
261-
sb.append("thread pool utilization percentage EWMA = ").append(getPercentPoolUtilizationEWMA()).append(", ");
262-
}
263247
}
264248

265249
/**
@@ -283,18 +267,8 @@ public double getQueueLatencyEwmaAlpha() {
283267
return queueLatencyMillisEWMA.getAlpha();
284268
}
285269

286-
// Used for testing
287-
public double getPoolUtilizationEwmaAlpha() {
288-
return percentPoolUtilizationEWMA.getAlpha();
289-
}
290-
291270
// Used for testing
292271
public boolean trackingQueueLatencyEwma() {
293272
return trackQueueLatencyEWMA;
294273
}
295-
296-
// Used for testing
297-
public boolean trackUtilizationEwma() {
298-
return trackUtilizationEWMA;
299-
}
300274
}

server/src/main/java/org/elasticsearch/threadpool/DefaultBuiltInExecutorBuilders.java

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@
2222
import static java.util.Collections.unmodifiableMap;
2323
import static org.elasticsearch.threadpool.ThreadPool.WRITE_THREAD_POOLS_EWMA_ALPHA_SETTING;
2424
import static org.elasticsearch.threadpool.ThreadPool.WRITE_THREAD_POOL_QUEUE_LATENCY_EWMA_ALPHA;
25-
import static org.elasticsearch.threadpool.ThreadPool.WRITE_THREAD_POOL_THREAD_UTILIZATION_EWMA_ALPHA;
2625
import static org.elasticsearch.threadpool.ThreadPool.searchAutoscalingEWMA;
2726

2827
public class DefaultBuiltInExecutorBuilders implements BuiltInExecutorBuilders {
@@ -35,7 +34,6 @@ public Map<String, ExecutorBuilder> getBuilders(Settings settings, int allocated
3534
final int genericThreadPoolMax = ThreadPool.boundedBy(4 * allocatedProcessors, 128, 512);
3635
final double indexAutoscalingEWMA = WRITE_THREAD_POOLS_EWMA_ALPHA_SETTING.get(settings);
3736
final double queueLatencyEWMAAlpha = WRITE_THREAD_POOL_QUEUE_LATENCY_EWMA_ALPHA.get(settings);
38-
final double threadUtilizationEWMAAlpha = WRITE_THREAD_POOL_THREAD_UTILIZATION_EWMA_ALPHA.get(settings);
3937

4038
Map<String, ExecutorBuilder> result = new HashMap<>();
4139
result.put(
@@ -59,14 +57,7 @@ public Map<String, ExecutorBuilder> getBuilders(Settings settings, int allocated
5957
ThreadPool.Names.WRITE,
6058
allocatedProcessors,
6159
10000,
62-
new EsExecutors.TaskTrackingConfig(
63-
true,
64-
true,
65-
true,
66-
indexAutoscalingEWMA,
67-
queueLatencyEWMAAlpha,
68-
threadUtilizationEWMAAlpha
69-
)
60+
new EsExecutors.TaskTrackingConfig(true, true, indexAutoscalingEWMA, queueLatencyEWMAAlpha)
7061
)
7162
);
7263
int searchOrGetThreadPoolSize = ThreadPool.searchOrGetThreadPoolSize(allocatedProcessors);

0 commit comments

Comments
 (0)