From cfa258e096bf93cceac424c55779cf0e4f1cde66 Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Wed, 6 Apr 2016 20:05:23 +0200 Subject: [PATCH] PoolChunkList.allocate(...) should return false without the need to walk all the contained PoolChunks when the requested capacity is too big. Motivation: PoolChunkList.allocate(...) should return false without the need to walk all the contained PoolChunks when the requested capacity is larger then the capacity that can be allocated out of the PoolChunks in respect to the minUsage() and maxUsage() of the PoolChunkList. Modifications: Precompute the maximal capacity that can be allocated out of the PoolChunks that are contained in the PoolChunkList and use this to fast return from the allocate(...) method if an allocation capacity larger then that is requested. Result: Faster detection of allocations that can not be handled by the PoolChunkList and so faster allocations in general via the PoolArena. --- .../main/java/io/netty/buffer/PoolArena.java | 12 +++---- .../java/io/netty/buffer/PoolChunkList.java | 35 +++++++++++++++++-- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/buffer/src/main/java/io/netty/buffer/PoolArena.java b/buffer/src/main/java/io/netty/buffer/PoolArena.java index 5cb06249a1..e5d799d486 100644 --- a/buffer/src/main/java/io/netty/buffer/PoolArena.java +++ b/buffer/src/main/java/io/netty/buffer/PoolArena.java @@ -98,12 +98,12 @@ abstract class PoolArena implements PoolArenaMetric { smallSubpagePools[i] = newSubpagePoolHead(pageSize); } - q100 = new PoolChunkList(null, 100, Integer.MAX_VALUE); - q075 = new PoolChunkList(q100, 75, 100); - q050 = new PoolChunkList(q075, 50, 100); - q025 = new PoolChunkList(q050, 25, 75); - q000 = new PoolChunkList(q025, 1, 50); - qInit = new PoolChunkList(q000, Integer.MIN_VALUE, 25); + q100 = new PoolChunkList(null, 100, Integer.MAX_VALUE, chunkSize); + q075 = new PoolChunkList(q100, 75, 100, chunkSize); + q050 = new PoolChunkList(q075, 50, 100, chunkSize); + q025 = new PoolChunkList(q050, 25, 75, chunkSize); + q000 = new PoolChunkList(q025, 1, 50, chunkSize); + qInit = new PoolChunkList(q000, Integer.MIN_VALUE, 25, chunkSize); q100.prevList(q075); q075.prevList(q050); diff --git a/buffer/src/main/java/io/netty/buffer/PoolChunkList.java b/buffer/src/main/java/io/netty/buffer/PoolChunkList.java index da5eb9029c..9573dedddc 100644 --- a/buffer/src/main/java/io/netty/buffer/PoolChunkList.java +++ b/buffer/src/main/java/io/netty/buffer/PoolChunkList.java @@ -30,6 +30,7 @@ final class PoolChunkList implements PoolChunkListMetric { private final PoolChunkList nextList; private final int minUsage; private final int maxUsage; + private final int maxCapacity; private PoolChunk head; @@ -39,10 +40,32 @@ final class PoolChunkList implements PoolChunkListMetric { // TODO: Test if adding padding helps under contention //private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7; - PoolChunkList(PoolChunkList nextList, int minUsage, int maxUsage) { + PoolChunkList(PoolChunkList nextList, int minUsage, int maxUsage, int chunkSize) { + assert minUsage <= maxUsage; this.nextList = nextList; this.minUsage = minUsage; this.maxUsage = maxUsage; + maxCapacity = calculateMaxCapacity(minUsage, chunkSize); + } + + /** + * Calculates the maximum capacity of a buffer that will ever be possible to allocate out of the {@link PoolChunk}s + * that belong to the {@link PoolChunkList} with the given {@code minUsage} and {@code maxUsage} settings. + */ + private static int calculateMaxCapacity(int minUsage, int chunkSize) { + minUsage = minUsage0(minUsage); + + if (minUsage == 100) { + // If the minUsage is 100 we can not allocate anything out of this list. + return 0; + } + + // Calculate the maximum amount of bytes that can be allocated from a PoolChunk in this PoolChunkList. + // + // As an example: + // - If a PoolChunkList has minUsage == 25 we are allowed to allocate at most 75% of the chunkSize because + // this is the maximum amount available in any PoolChunk in this PoolChunkList. + return (int) (chunkSize * (100L - minUsage) / 100L); } void prevList(PoolChunkList prevList) { @@ -51,7 +74,9 @@ final class PoolChunkList implements PoolChunkListMetric { } boolean allocate(PooledByteBuf buf, int reqCapacity, int normCapacity) { - if (head == null) { + if (head == null || normCapacity > maxCapacity) { + // Either this PoolChunkList is empty or the requested capacity is larger then the capacity which can + // be handled by the PoolChunks that are contained in this PoolChunkList. return false; } @@ -152,7 +177,7 @@ final class PoolChunkList implements PoolChunkListMetric { @Override public int minUsage() { - return max(1, minUsage); + return minUsage0(minUsage); } @Override @@ -160,6 +185,10 @@ final class PoolChunkList implements PoolChunkListMetric { return min(maxUsage, 100); } + private static int minUsage0(int value) { + return max(1, value); + } + @Override public Iterator iterator() { if (head == null) {