Do not use a pseudo random for tree traversal
Motivation: If we make allocateRun/SubpageSimple() always try the left node first and make allocateRun/Subpage() always tries the right node first, it is more likely that allocateRun/Subpage() will find a node with ST_UNUSED sooner. Modifications: - Make allocateRunSimple() and allocateSubpageSimple() always try the left node first. - Make allocateRun() and allocateSubpage() always try the right node first. - Remove randome Result: We get the same performance without using random numbers.
This commit is contained in:
parent
1d0a79e11e
commit
ea0eb4fdab
@ -20,11 +20,7 @@ final class PoolChunk<T> {
|
|||||||
private static final int ST_UNUSED = 0;
|
private static final int ST_UNUSED = 0;
|
||||||
private static final int ST_BRANCH = 1;
|
private static final int ST_BRANCH = 1;
|
||||||
private static final int ST_ALLOCATED = 2;
|
private static final int ST_ALLOCATED = 2;
|
||||||
private static final int ST_ALLOCATED_SUBPAGE = ST_ALLOCATED | 1;
|
private static final int ST_ALLOCATED_SUBPAGE = 3;
|
||||||
|
|
||||||
private static final long multiplier = 0x5DEECE66DL;
|
|
||||||
private static final long addend = 0xBL;
|
|
||||||
private static final long mask = (1L << 48) - 1;
|
|
||||||
|
|
||||||
final PoolArena<T> arena;
|
final PoolArena<T> arena;
|
||||||
final T memory;
|
final T memory;
|
||||||
@ -40,8 +36,6 @@ final class PoolChunk<T> {
|
|||||||
private final int chunkSize;
|
private final int chunkSize;
|
||||||
private final int maxSubpageAllocs;
|
private final int maxSubpageAllocs;
|
||||||
|
|
||||||
private long random = (System.nanoTime() ^ multiplier) & mask;
|
|
||||||
|
|
||||||
private int freeBytes;
|
private int freeBytes;
|
||||||
|
|
||||||
PoolChunkList<T> parent;
|
PoolChunkList<T> parent;
|
||||||
@ -123,22 +117,13 @@ final class PoolChunk<T> {
|
|||||||
case ST_UNUSED:
|
case ST_UNUSED:
|
||||||
return allocateRunSimple(normCapacity, curIdx, val);
|
return allocateRunSimple(normCapacity, curIdx, val);
|
||||||
case ST_BRANCH:
|
case ST_BRANCH:
|
||||||
|
// Try the right node first because it is more likely to be ST_UNUSED.
|
||||||
|
// It is because allocateRunSimple() always chooses the left node.
|
||||||
final int nextIdxLeft = curIdx << 1;
|
final int nextIdxLeft = curIdx << 1;
|
||||||
final int nextValLeft = memoryMap[nextIdxLeft];
|
|
||||||
final boolean recurseLeft;
|
|
||||||
switch (nextValLeft & 3) {
|
|
||||||
case ST_UNUSED:
|
|
||||||
return allocateRunSimple(normCapacity, nextIdxLeft, nextValLeft);
|
|
||||||
case ST_BRANCH:
|
|
||||||
recurseLeft = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
recurseLeft = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final int nextIdxRight = nextIdxLeft ^ 1;
|
final int nextIdxRight = nextIdxLeft ^ 1;
|
||||||
final int nextValRight = memoryMap[nextIdxRight];
|
final int nextValRight = memoryMap[nextIdxRight];
|
||||||
final boolean recurseRight;
|
final boolean recurseRight;
|
||||||
|
|
||||||
switch (nextValRight & 3) {
|
switch (nextValRight & 3) {
|
||||||
case ST_UNUSED:
|
case ST_UNUSED:
|
||||||
return allocateRunSimple(normCapacity, nextIdxRight, nextValRight);
|
return allocateRunSimple(normCapacity, nextIdxRight, nextValRight);
|
||||||
@ -149,15 +134,28 @@ final class PoolChunk<T> {
|
|||||||
recurseRight = false;
|
recurseRight = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recurseLeft) {
|
final int nextValLeft = memoryMap[nextIdxLeft];
|
||||||
long res = branchRun(normCapacity, nextIdxLeft);
|
final boolean recurseLeft;
|
||||||
|
|
||||||
|
switch (nextValLeft & 3) {
|
||||||
|
case ST_UNUSED:
|
||||||
|
return allocateRunSimple(normCapacity, nextIdxLeft, nextValLeft);
|
||||||
|
case ST_BRANCH:
|
||||||
|
recurseLeft = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
recurseLeft = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recurseRight) {
|
||||||
|
long res = branchRun(normCapacity, nextIdxRight);
|
||||||
if (res > 0) {
|
if (res > 0) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (recurseRight) {
|
if (recurseLeft) {
|
||||||
return branchRun(normCapacity, nextIdxRight);
|
return branchRun(normCapacity, nextIdxLeft);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,7 +191,7 @@ final class PoolChunk<T> {
|
|||||||
return curIdx;
|
return curIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
int nextIdx = curIdx << 1 ^ nextRandom();
|
int nextIdx = curIdx << 1;
|
||||||
int unusedIdx = nextIdx ^ 1;
|
int unusedIdx = nextIdx ^ 1;
|
||||||
|
|
||||||
memoryMap[curIdx] = val & ~3 | ST_BRANCH;
|
memoryMap[curIdx] = val & ~3 | ST_BRANCH;
|
||||||
@ -207,29 +205,29 @@ final class PoolChunk<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private long allocateSubpage(int normCapacity, int curIdx, int val) {
|
private long allocateSubpage(int normCapacity, int curIdx, int val) {
|
||||||
int state = val & 3;
|
switch (val & 3) {
|
||||||
if (state == ST_BRANCH) {
|
case ST_UNUSED:
|
||||||
int nextIdx = curIdx << 1 ^ nextRandom();
|
return allocateSubpageSimple(normCapacity, curIdx, val);
|
||||||
long res = branchSubpage(normCapacity, nextIdx);
|
case ST_BRANCH:
|
||||||
if (res > 0) {
|
// Try the right node first because it is more likely to be ST_UNUSED.
|
||||||
return res;
|
// It is because allocateSubpageSimple() always chooses the left node.
|
||||||
}
|
final int nextIdxLeft = curIdx << 1;
|
||||||
|
final int nextIdxRight = nextIdxLeft ^ 1;
|
||||||
|
|
||||||
return branchSubpage(normCapacity, nextIdx ^ 1);
|
long res = branchSubpage(normCapacity, nextIdxRight);
|
||||||
}
|
if (res > 0) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
if (state == ST_UNUSED) {
|
return branchSubpage(normCapacity, nextIdxLeft);
|
||||||
return allocateSubpageSimple(normCapacity, curIdx, val);
|
case ST_ALLOCATED_SUBPAGE:
|
||||||
}
|
PoolSubpage<T> subpage = subpages[subpageIdx(curIdx)];
|
||||||
|
int elemSize = subpage.elemSize;
|
||||||
|
if (normCapacity != elemSize) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (state == ST_ALLOCATED_SUBPAGE) {
|
return subpage.allocate();
|
||||||
PoolSubpage<T> subpage = subpages[subpageIdx(curIdx)];
|
|
||||||
int elemSize = subpage.elemSize;
|
|
||||||
if (normCapacity != elemSize) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return subpage.allocate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
@ -253,7 +251,7 @@ final class PoolChunk<T> {
|
|||||||
return subpage.allocate();
|
return subpage.allocate();
|
||||||
}
|
}
|
||||||
|
|
||||||
int nextIdx = curIdx << 1 ^ nextRandom();
|
int nextIdx = curIdx << 1;
|
||||||
int unusedIdx = nextIdx ^ 1;
|
int unusedIdx = nextIdx ^ 1;
|
||||||
|
|
||||||
memoryMap[curIdx] = val & ~3 | ST_BRANCH;
|
memoryMap[curIdx] = val & ~3 | ST_BRANCH;
|
||||||
@ -363,11 +361,6 @@ final class PoolChunk<T> {
|
|||||||
return memoryMapIdx - maxSubpageAllocs;
|
return memoryMapIdx - maxSubpageAllocs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int nextRandom() {
|
|
||||||
random = random * multiplier + addend & mask;
|
|
||||||
return (int) (random >>> 47) & 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder buf = new StringBuilder();
|
StringBuilder buf = new StringBuilder();
|
||||||
buf.append("Chunk(");
|
buf.append("Chunk(");
|
||||||
|
Loading…
Reference in New Issue
Block a user