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.
This commit is contained in:
Norman Maurer 2016-04-06 20:05:23 +02:00
parent 2ae97946dd
commit cfa258e096
2 changed files with 38 additions and 9 deletions

View File

@ -98,12 +98,12 @@ abstract class PoolArena<T> implements PoolArenaMetric {
smallSubpagePools[i] = newSubpagePoolHead(pageSize);
}
q100 = new PoolChunkList<T>(null, 100, Integer.MAX_VALUE);
q075 = new PoolChunkList<T>(q100, 75, 100);
q050 = new PoolChunkList<T>(q075, 50, 100);
q025 = new PoolChunkList<T>(q050, 25, 75);
q000 = new PoolChunkList<T>(q025, 1, 50);
qInit = new PoolChunkList<T>(q000, Integer.MIN_VALUE, 25);
q100 = new PoolChunkList<T>(null, 100, Integer.MAX_VALUE, chunkSize);
q075 = new PoolChunkList<T>(q100, 75, 100, chunkSize);
q050 = new PoolChunkList<T>(q075, 50, 100, chunkSize);
q025 = new PoolChunkList<T>(q050, 25, 75, chunkSize);
q000 = new PoolChunkList<T>(q025, 1, 50, chunkSize);
qInit = new PoolChunkList<T>(q000, Integer.MIN_VALUE, 25, chunkSize);
q100.prevList(q075);
q075.prevList(q050);

View File

@ -30,6 +30,7 @@ final class PoolChunkList<T> implements PoolChunkListMetric {
private final PoolChunkList<T> nextList;
private final int minUsage;
private final int maxUsage;
private final int maxCapacity;
private PoolChunk<T> head;
@ -39,10 +40,32 @@ final class PoolChunkList<T> implements PoolChunkListMetric {
// TODO: Test if adding padding helps under contention
//private long pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7;
PoolChunkList(PoolChunkList<T> nextList, int minUsage, int maxUsage) {
PoolChunkList(PoolChunkList<T> 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<T> prevList) {
@ -51,7 +74,9 @@ final class PoolChunkList<T> implements PoolChunkListMetric {
}
boolean allocate(PooledByteBuf<T> 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<T> implements PoolChunkListMetric {
@Override
public int minUsage() {
return max(1, minUsage);
return minUsage0(minUsage);
}
@Override
@ -160,6 +185,10 @@ final class PoolChunkList<T> implements PoolChunkListMetric {
return min(maxUsage, 100);
}
private static int minUsage0(int value) {
return max(1, value);
}
@Override
public Iterator<PoolChunkMetric> iterator() {
if (head == null) {