Skip to content

Fix VirtualThreadPool benchmark methodology issue (#16174)#16370

Open
anushkagupta200615-jpg wants to merge 1 commit into
apache:3.3from
anushkagupta200615-jpg:fix-virtual-thread-pool-16174
Open

Fix VirtualThreadPool benchmark methodology issue (#16174)#16370
anushkagupta200615-jpg wants to merge 1 commit into
apache:3.3from
anushkagupta200615-jpg:fix-virtual-thread-pool-16174

Conversation

@anushkagupta200615-jpg

Copy link
Copy Markdown

What is the purpose of the change?

Fixes #16174

This PR addresses the benchmark methodology issue and the root cause of the VirtualThreadPool configuration bug introduced in #16055.

Problem:

  1. Broken keepAliveTime: The pooled virtual thread implementation used keepAliveTime = 0L MILLISECONDS. Because of this, non-core threads died immediately after completing a task. This defeated the entire purpose of the pooled mode (as outlined in [Feature] Refactor VirtualThreadPool to use a pooled virtual thread model #16042), which is to keep threads warm so that libraries like FastJSON and Aerospike can reuse their heavy ThreadLocal byte buffers across requests.
  2. Flawed Benchmark: The benchmark in the original PR used a flawed two-latch synchronization pattern. It awaited the startGate (which was already zero) instead of the completionLatch. As a result, the timing window closed before the tasks were actually completed, masking the keepAlive overhead and falsely inflating the performance metrics of the pooled executor.

Solution:

  • Fixed keepAliveTime: Updated VirtualThreadPool to use 60L SECONDS for keepAliveTime in the pooled branch. This ensures warm virtual threads survive long enough to reuse their ThreadLocal caches between subsequent requests.
  • Added Regression Guards: Enhanced VirtualThreadPoolTest to verify that keepAliveTime > 0 and added a test getExecutor4_threadLocalReuseInPooledMode proving that ThreadLocal state is actually preserved and reused across sequential tasks on the pooled executor.
  • Added Correct Benchmark Test: Introduced VirtualThreadPoolBenchmarkTest.java that uses the correct two-latch pattern (awaiting the completion latch) to strictly verify that all submitted tasks run to completion within the benchmark window for both pooled and unpooled modes.

Checklist

  • Make sure there is a GitHub_issue field for the change.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Write necessary unit-test to verify your logic correction. If the new feature or significant change is committed, please remember to add sample in dubbo samples project.
  • Make sure gitHub actions can pass. Why the workflow is failing and how to fix it?

@codecov-commenter

codecov-commenter commented Jul 4, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 60.84%. Comparing base (ed0e11e) to head (2cac90c).

Additional details and impacted files
@@             Coverage Diff              @@
##                3.3   #16370      +/-   ##
============================================
- Coverage     60.86%   60.84%   -0.03%     
+ Complexity    11768    11762       -6     
============================================
  Files          1953     1953              
  Lines         89260    89260              
  Branches      13471    13471              
============================================
- Hits          54329    54307      -22     
- Misses        29350    29360      +10     
- Partials       5581     5593      +12     
Flag Coverage Δ
integration-tests-java21 32.08% <ø> (-0.01%) ⬇️
integration-tests-java8 32.14% <ø> (-0.06%) ⬇️
samples-tests-java21 32.20% <ø> (+0.04%) ⬆️
samples-tests-java8 29.81% <ø> (-0.03%) ⬇️
unit-tests-java11 59.10% <ø> (+0.01%) ⬆️
unit-tests-java17 58.56% <ø> (-0.02%) ⬇️
unit-tests-java21 58.56% <ø> (+<0.01%) ⬆️
unit-tests-java25 58.53% <ø> (-0.01%) ⬇️
unit-tests-java8 59.13% <ø> (-0.02%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@zrlw zrlw requested review from RainYuY and heliang666s July 7, 2026 03:04
@zrlw

zrlw commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

@funky-eyes PTAL

@zrlw zrlw left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes the pooled VirtualThreadPool configuration to keep excess virtual threads alive long enough for ThreadLocal reuse, and adds regression tests to prevent the benchmark methodology and keep-alive settings from regressing.

Changes:

  • Update pooled-mode ThreadPoolExecutor keep-alive from 0ms to 60s via a shared constant and TimeUnit.SECONDS.
  • Strengthen VirtualThreadPoolTest with keep-alive assertions and a pooled-mode ThreadLocal reuse regression test.
  • Add VirtualThreadPoolBenchmarkTest to enforce the correct two-latch benchmark synchronization pattern (await completion latch, not start gate).

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.

File Description
dubbo-plugin/dubbo-plugin-loom/src/main/java/org/apache/dubbo/common/threadpool/support/loom/VirtualThreadPool.java Fix pooled-mode keep-alive configuration and document pooled vs unpooled behavior.
dubbo-plugin/dubbo-plugin-loom/src/test/java/org/apache/dubbo/common/threadpool/support/loom/VirtualThreadPoolTest.java Add keep-alive regression guard and validate pooled-mode ThreadLocal reuse behavior.
dubbo-plugin/dubbo-plugin-loom/src/test/java/org/apache/dubbo/common/threadpool/support/loom/VirtualThreadPoolBenchmarkTest.java Add correctness tests to prevent future benchmark latch/timing regressions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +129 to +131
ThreadPool threadPool = new VirtualThreadPool();
Executor executor = threadPool.getExecutor(url);

// Correct: await completionLatch (latch 2), NOT startGate (latch 1).
// Awaiting startGate here would return immediately (it is already at 0) and make
// the measurement appear artificially fast - exactly the flaw in #16174.
completionLatch.await();
Comment on lines +88 to +93
URL url = URL.valueOf("dubbo://10.20.130.230:20880/context/path");
ThreadPool threadPool = new VirtualThreadPool();
Executor executor = threadPool.getExecutor(url);

runBenchmark(executor, TASK_COUNT, "unpooled");
}
Comment on lines +106 to +112
URL url = URL.valueOf("dubbo://10.20.130.230:20880/context/path?" + THREADS_VIRTUAL_CORE + "="
+ Runtime.getRuntime().availableProcessors());
ThreadPool threadPool = new VirtualThreadPool();
Executor executor = threadPool.getExecutor(url);

runBenchmark(executor, TASK_COUNT, "pooled");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] Request to revisit VirtualThreadPool optimization: Potential benchmark methodology issue

4 participants