20% speedup of unionSorted()
Added getUnsafe and addUnsafe, two methods that skip checks. The checks are not needed in unionSorted, because we made sure the code works correctly. getUnsafe still has the checks, but as assertions. The speedup is roughly 20%. Here are some results for calling union 2^16 times for two random sorted lists with 16k elements: Duration: 20170 -> 16857 (83.57%) Instructions: 138.277.743.679 -> 108.474.027.213 (78.4%) Instructions per cycle: 2,33 -> 2,18 Branches: 30.248.330.644 -> 19.908.207.057 (65.8%) Branch Misses: 3.012.427 -> 3.477.433 Cycles per list element: 65.93 -> 51.72 (78.4%) Created with (the test program is not committed) on a Core2Duo 8600: perf stat -d -d -d --delay 2000 java -cp bin/test:bin/main org.lucares.collections.Test 16000 16
This commit is contained in:
@@ -200,6 +200,22 @@ public final class IntList implements Serializable, Cloneable {
|
|||||||
size++;
|
size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsafe version of {@link #add(int)} that does not call
|
||||||
|
* {@link #ensureCapacity(int)}. The caller has to make sure that the list has
|
||||||
|
* capacity.
|
||||||
|
*
|
||||||
|
* @param value the value to add
|
||||||
|
*/
|
||||||
|
private void addUnsafe(final int value) {
|
||||||
|
data[size] = value;
|
||||||
|
|
||||||
|
if (sorted) {
|
||||||
|
sorted = size == 0 ? sorted : data[size - 1] <= data[size];
|
||||||
|
}
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts {@code values} at position {@code pos} into the list.
|
* Inserts {@code values} at position {@code pos} into the list.
|
||||||
*
|
*
|
||||||
@@ -554,6 +570,19 @@ public final class IntList implements Serializable, Cloneable {
|
|||||||
return data[pos];
|
return data[pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsafe version of {@link #get(int)} that does not check for out of bounds
|
||||||
|
* access if assertions are disabled. The caller has to make sure that pos is
|
||||||
|
* not negative and smaller than {@link #size()}.
|
||||||
|
*
|
||||||
|
* @param pos position of the element to return
|
||||||
|
* @return the element at position {@code pos}
|
||||||
|
*/
|
||||||
|
private int getUnsafe(final int pos) {
|
||||||
|
assert pos >= 0 && pos < size : "index out of bounds at " + pos;
|
||||||
|
return data[pos];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@code length} elements starting at {@code from}.
|
* Returns the {@code length} elements starting at {@code from}.
|
||||||
*
|
*
|
||||||
@@ -1091,30 +1120,30 @@ public final class IntList implements Serializable, Cloneable {
|
|||||||
|
|
||||||
while (l < aSize && r < bSize) {
|
while (l < aSize && r < bSize) {
|
||||||
|
|
||||||
final int lv = a.get(l);
|
final int lv = a.getUnsafe(l);
|
||||||
final int rv = b.get(r);
|
final int rv = b.getUnsafe(r);
|
||||||
|
|
||||||
if (lv < rv) {
|
if (lv < rv) {
|
||||||
result.add(lv);
|
result.addUnsafe(lv);
|
||||||
l++;
|
l++;
|
||||||
while (l < aSize && lv == a.get(l)) {
|
while (l < aSize && lv == a.getUnsafe(l)) {
|
||||||
l++;
|
l++;
|
||||||
}
|
}
|
||||||
} else if (lv > rv) {
|
} else if (lv > rv) {
|
||||||
result.add(rv);
|
result.addUnsafe(rv);
|
||||||
r++;
|
r++;
|
||||||
while (r < bSize && rv == b.get(r)) {
|
while (r < bSize && rv == b.getUnsafe(r)) {
|
||||||
r++;
|
r++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.add(lv);
|
result.addUnsafe(lv);
|
||||||
l++;
|
l++;
|
||||||
r++;
|
r++;
|
||||||
|
|
||||||
while (l < aSize && lv == a.get(l)) {
|
while (l < aSize && lv == a.getUnsafe(l)) {
|
||||||
l++;
|
l++;
|
||||||
}
|
}
|
||||||
while (r < bSize && rv == b.get(r)) {
|
while (r < bSize && rv == b.getUnsafe(r)) {
|
||||||
r++;
|
r++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1122,15 +1151,17 @@ public final class IntList implements Serializable, Cloneable {
|
|||||||
|
|
||||||
// add remaining values from list a, if any exist
|
// add remaining values from list a, if any exist
|
||||||
for (; l < aSize; l++) {
|
for (; l < aSize; l++) {
|
||||||
if (l == 0 || a.get(l) != a.get(l - 1)) {
|
final int valueAtPosL = a.getUnsafe(l);
|
||||||
result.add(a.get(l));
|
if (l == 0 || valueAtPosL != a.getUnsafe(l - 1)) {
|
||||||
|
result.addUnsafe(valueAtPosL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add remaining values from list b, if any exist
|
// add remaining values from list b, if any exist
|
||||||
for (; r < bSize; r++) {
|
for (; r < bSize; r++) {
|
||||||
if (r == 0 || b.get(r) != b.get(r - 1)) {
|
final int valueAtPosR = b.getUnsafe(r);
|
||||||
result.add(b.get(r));
|
if (r == 0 || valueAtPosR != b.getUnsafe(r - 1)) {
|
||||||
|
result.addUnsafe(valueAtPosR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -190,6 +190,22 @@ public final class LongList implements Serializable, Cloneable {
|
|||||||
size++;
|
size++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsafe version of {@link #add(long)} that does not call
|
||||||
|
* {@link #ensureCapacity(long)}. The caller has to make sure that the list has
|
||||||
|
* capacity.
|
||||||
|
*
|
||||||
|
* @param value the value to add
|
||||||
|
*/
|
||||||
|
private void addUnsafe(final long value) {
|
||||||
|
data[size] = value;
|
||||||
|
|
||||||
|
if (sorted) {
|
||||||
|
sorted = size == 0 ? sorted : data[size - 1] <= data[size];
|
||||||
|
}
|
||||||
|
size++;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts {@code values} at position {@code pos} into the list.
|
* Inserts {@code values} at position {@code pos} into the list.
|
||||||
*
|
*
|
||||||
@@ -559,6 +575,19 @@ public final class LongList implements Serializable, Cloneable {
|
|||||||
return data[pos];
|
return data[pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsafe version of {@link #get(long)} that does not check for out of bounds
|
||||||
|
* access if assertions are disabled. The caller has to make sure that pos is
|
||||||
|
* not negative and smaller than {@link #size()}.
|
||||||
|
*
|
||||||
|
* @param pos position of the element to return
|
||||||
|
* @return the element at position {@code pos}
|
||||||
|
*/
|
||||||
|
private long getUnsafe(final int pos) {
|
||||||
|
assert pos >= 0 && pos < size : "index out of bounds at " + pos;
|
||||||
|
return data[pos];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@code length} elements starting at {@code from}.
|
* Returns the {@code length} elements starting at {@code from}.
|
||||||
*
|
*
|
||||||
@@ -1090,30 +1119,30 @@ public final class LongList implements Serializable, Cloneable {
|
|||||||
|
|
||||||
while (l < aSize && r < bSize) {
|
while (l < aSize && r < bSize) {
|
||||||
|
|
||||||
final long lv = a.get(l);
|
final long lv = a.getUnsafe(l);
|
||||||
final long rv = b.get(r);
|
final long rv = b.getUnsafe(r);
|
||||||
|
|
||||||
if (lv < rv) {
|
if (lv < rv) {
|
||||||
result.add(lv);
|
result.addUnsafe(lv);
|
||||||
l++;
|
l++;
|
||||||
while (l < aSize && lv == a.get(l)) {
|
while (l < aSize && lv == a.getUnsafe(l)) {
|
||||||
l++;
|
l++;
|
||||||
}
|
}
|
||||||
} else if (lv > rv) {
|
} else if (lv > rv) {
|
||||||
result.add(rv);
|
result.addUnsafe(rv);
|
||||||
r++;
|
r++;
|
||||||
while (r < bSize && rv == b.get(r)) {
|
while (r < bSize && rv == b.getUnsafe(r)) {
|
||||||
r++;
|
r++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result.add(lv);
|
result.addUnsafe(lv);
|
||||||
l++;
|
l++;
|
||||||
r++;
|
r++;
|
||||||
|
|
||||||
while (l < aSize && lv == a.get(l)) {
|
while (l < aSize && lv == a.getUnsafe(l)) {
|
||||||
l++;
|
l++;
|
||||||
}
|
}
|
||||||
while (r < bSize && rv == b.get(r)) {
|
while (r < bSize && rv == b.getUnsafe(r)) {
|
||||||
r++;
|
r++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1121,15 +1150,17 @@ public final class LongList implements Serializable, Cloneable {
|
|||||||
|
|
||||||
// add remaining values from list a, if any exist
|
// add remaining values from list a, if any exist
|
||||||
for (; l < aSize; l++) {
|
for (; l < aSize; l++) {
|
||||||
if (l == 0 || a.get(l) != a.get(l - 1)) {
|
final long valueAtPosL = a.getUnsafe(l);
|
||||||
result.add(a.get(l));
|
if (l == 0 || valueAtPosL != a.getUnsafe(l - 1)) {
|
||||||
|
result.addUnsafe(valueAtPosL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add remaining values from list b, if any exist
|
// add remaining values from list b, if any exist
|
||||||
for (; r < bSize; r++) {
|
for (; r < bSize; r++) {
|
||||||
if (r == 0 || b.get(r) != b.get(r - 1)) {
|
final long valueAtPosR = b.getUnsafe(r);
|
||||||
result.add(b.get(r));
|
if (r == 0 || valueAtPosR != b.getUnsafe(r - 1)) {
|
||||||
|
result.addUnsafe(valueAtPosR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user