You’re misinformed, unless you actually notice a ‘stutter’ of a couple of nanoseconds. :clue:
Data size ~1,000 entities
testIterator[1321]: 37 micros
testIterator[1319]: 37 micros
testIterator[1314]: 31 micros
testCompactSweep[1321]: 11 micros
testCompactSweep[1319]: 12 micros
testCompactSweep[1314]: 11 micros
Data size ~10,000 entities
testIterator[13461]: 464 micros
testIterator[13476]: 418 micros
testIterator[13456]: 421 micros
testCompactSweep[13461]: 119 micros
testCompactSweep[13476]: 117 micros
testCompactSweep[13456]: 114 micros
Data size ~100,000 entities
testIterator[133683]: 24475 micros
testIterator[133671]: 23982 micros
testIterator[133729]: 22777 micros
testCompactSweep[133683]: 909 micros
testCompactSweep[133671]: 919 micros
testCompactSweep[133729]: 914 micros
Data size ~1,000,000 entities
testIterator[1337267]: 2,744,038 micros
testIterator[1337171]: 2,979,241 micros
testIterator[1337389]: 3,012,128 micros
testCompactSweep[1337267]: 12,898 micros
testCompactSweep[1337171]: 13,587 micros
testCompactSweep[1337389]: 12,240 micros
We can conclude that for these data-sizes, we have a 3x, 4x, 25x and 246x performance increase, which is obviously significant and shows the compact-sweep algorithm scales exceptionally well (linearly).
Here is the benchmark:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
public class EntityCollectionBenchmark {
static class Entity {
private int countdown;
private final int offspring;
public Entity(int maxAge, int offspring) {
this.countdown = maxAge;
this.offspring = offspring;
}
public boolean isDying() {
return countdown <= 0;
}
public void tick() {
countdown--;
}
}
public static void main(String[] args) {
testIterator(100 * 1337);
System.out.println();
testCompactSweep(100 * 1337);
}
private static void testIterator(int num) {
List<Entity> entities = new ArrayList<>();
final Random rndm = new Random(1234567890L);
for (int i = 0; i < num; i++) {
entities.add(new Entity(rndm.nextInt(256), rndm.nextInt(3)));
}
for (int i = 0; i < 100; i++) {
long t0 = System.nanoTime();
int spawnCount = 0;
for (Iterator<Entity> it = entities.iterator(); it.hasNext();) {
Entity entity = it.next();
if (entity.isDying()) {
spawnCount += entity.offspring;
it.remove();
} else {
entity.tick();
}
}
for (int q = 0; q < spawnCount; q++) {
entities.add(new Entity(rndm.nextInt(256), rndm.nextInt(3)));
}
long t1 = System.nanoTime();
if (i % 10 == 0) {
System.out.println("testIterator[" + entities.size() + "]: " + (t1 - t0) / 1000 + " micros");
}
}
}
private static void testCompactSweep(int num) {
Entity[] entities = new Entity[num * 2];
int entityCount = 0;
final Random rndm = new Random(1234567890L);
for (int i = 0; i < num; i++) {
entities[entityCount++] = new Entity(rndm.nextInt(256), rndm.nextInt(3));
}
for (int i = 0; i < 100; i++) {
long t0 = System.nanoTime();
int spawnCount = 0;
int entityRetainCount = 0;
for (int p = 0; p < entityCount; p++) {
Entity entity = entities[p];
if (entity.isDying()) {
spawnCount += entity.offspring;
} else {
entity.tick();
entities[entityRetainCount++] = entity;
}
}
for (int q = 0; q < spawnCount; q++) {
entities[entityRetainCount++] = new Entity(rndm.nextInt(256), rndm.nextInt(3));
}
if (entityRetainCount < entityCount) {
Arrays.fill(entities, entityRetainCount, entityCount, null);
}
entityCount = entityRetainCount;
long t1 = System.nanoTime();
if (i % 10 == 0) {
System.out.println("testCompactSweep[" + entityCount + "]: " + (t1 - t0) / 1000 + " micros");
}
}
}
}