forked from netty/netty
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Make releasing objects back to Recycler faster (netty#13174)
Motivation: The Recycler implementation was changed in netty#11858 to rely on an MPSC queue implementation for delivering released objects back to their originating thread local pool. Typically, the release will often happen from the same thread that claimed the object, so the overhead of having a thread-safe release goes to waste. Modification: We add an unsynchronized ArrayDeque for batching claims out of the `pooledHandles`. This amortises `claim` calls. We then also re-introduce the concept of an owner thread (but by default only if said thread is a FastThreadLocalThread), and release directly into the claim `batch` if the release is from the owner thread. Result: The `RecyclerBenchmark.recyclerGetAndRecycle` benchmark sees a 27.4% improvement, and the `RecyclerBenchmark.producerConsumer` benchmark sees a 22.5% improvement. Fixes netty#13153 Co-authored-by: Norman Maurer <[email protected]>
- Loading branch information
1 parent
5ee9da5
commit 8a8337e
Showing
4 changed files
with
207 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
common/src/test/java/io/netty/util/RecyclerFastThreadLocalTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
/* | ||
* Copyright 2023 The Netty Project | ||
* | ||
* The Netty Project licenses this file to you under the Apache License, | ||
* version 2.0 (the "License"); you may not use this file except in compliance | ||
* with the License. You may obtain a copy of the License at: | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||
* License for the specific language governing permissions and limitations | ||
* under the License. | ||
*/ | ||
package io.netty.util; | ||
|
||
import io.netty.util.concurrent.FastThreadLocalThread; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.Timeout; | ||
import org.junit.jupiter.api.extension.ExtendWith; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
import java.util.concurrent.atomic.AtomicReference; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertFalse; | ||
|
||
@ExtendWith(RunInFastThreadLocalThreadExtension.class) | ||
public class RecyclerFastThreadLocalTest extends RecyclerTest { | ||
@NotNull | ||
@Override | ||
protected Thread newThread(Runnable runnable) { | ||
return new FastThreadLocalThread(runnable); | ||
} | ||
|
||
@Override | ||
@Test | ||
@Timeout(value = 5000, unit = TimeUnit.MILLISECONDS) | ||
public void testThreadCanBeCollectedEvenIfHandledObjectIsReferenced() throws Exception { | ||
final Recycler<HandledObject> recycler = newRecycler(1024); | ||
final AtomicBoolean collected = new AtomicBoolean(); | ||
final AtomicReference<HandledObject> reference = new AtomicReference<HandledObject>(); | ||
Thread thread = new FastThreadLocalThread(new Runnable() { | ||
@Override | ||
public void run() { | ||
HandledObject object = recycler.get(); | ||
// Store a reference to the HandledObject to ensure it is not collected when the run method finish. | ||
reference.set(object); | ||
} | ||
}) { | ||
@Override | ||
protected void finalize() throws Throwable { | ||
super.finalize(); | ||
collected.set(true); | ||
} | ||
}; | ||
assertFalse(collected.get()); | ||
thread.start(); | ||
thread.join(); | ||
|
||
// Null out so it can be collected. | ||
thread = null; | ||
|
||
// Loop until the Thread was collected. If we can not collect it the Test will fail due of a timeout. | ||
while (!collected.get()) { | ||
System.gc(); | ||
System.runFinalization(); | ||
Thread.sleep(50); | ||
} | ||
|
||
// Now call recycle after the Thread was collected to ensure this still works... | ||
reference.getAndSet(null).recycle(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.