Skip to content

Instantly share code, notes, and snippets.

@GotoFinal
Last active February 17, 2020 00:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save GotoFinal/2f057616f300045c7638bd11b250c20a to your computer and use it in GitHub Desktop.
Save GotoFinal/2f057616f300045c7638bd11b250c20a to your computer and use it in GitHub Desktop.
For blog
package dev.gotofinal;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import java.util.stream.Stream;
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@BenchmarkMode({Mode.SampleTime})
//@BenchmarkMode({Mode.SampleTime, Mode.AverageTime})
@Warmup(iterations = 5, time = 20, batchSize = 1)
@Measurement(iterations = 10, time = 10, batchSize = 1)
@Fork(value = 1, jvmArgs = {"-Xms2G", "-Xmx2G", "-XX:+AlwaysPreTouch"})
@State(Scope.Thread)
public class AllocBenchmark {
private static final int ITERATIONS = 10000;
private World world;
private Supplier<Position> positionGenerator;
private Supplier<Position> noAllocPositionGenerator;
private PositionGenerator noHeapPositionGenerator;
@Setup
public void setup(Blackhole blackhole) {
world = new World(blackhole);
positionGenerator = () -> {
ThreadLocalRandom random = ThreadLocalRandom.current();
double x = random.nextDouble(-10000000, 10000000);
double y = random.nextDouble(-10000000, 10000000);
double z = random.nextDouble(-10000000, 10000000);
return new Position(x, y, z);
};
Position pos = new Position(0, 0, 0);
noAllocPositionGenerator = () -> {
ThreadLocalRandom random = ThreadLocalRandom.current();
double x = random.nextDouble(-10000000, 10000000);
double y = random.nextDouble(-10000000, 10000000);
double z = random.nextDouble(-10000000, 10000000);
return pos.set(x, y, z);
};
noHeapPositionGenerator = new PositionGenerator();
}
@Benchmark
public void tick() throws Throwable {
Stream.generate(positionGenerator)
.limit(ITERATIONS)
.forEach(pos -> world.updateAt(pos));
}
@Benchmark
@Threads(-1)
public void tick_threaded() throws Throwable {
Stream.generate(positionGenerator)
.limit(ITERATIONS)
.forEach(pos -> world.updateAt(pos));
}
@Benchmark
@Threads(-1)
@Fork(value = 1, jvmArgs = {"-Xms20M", "-Xmx20M", "-XX:+AlwaysPreTouch"})
public void tick_threaded20M() throws Throwable {
Stream.generate(positionGenerator)
.limit(ITERATIONS)
.forEach(pos -> world.updateAt(pos));
}
@Benchmark
@Threads(-1)
@Fork(value = 1, jvmArgs = {"-Xms128M", "-Xmx128M", "-XX:+AlwaysPreTouch"})
public void tick_threaded128M() throws Throwable {
Stream.generate(positionGenerator)
.limit(ITERATIONS)
.forEach(pos -> world.updateAt(pos));
}
@Benchmark
public void tickNoAlloc() throws Throwable {
for (int i = 0; i < ITERATIONS; i++) {
world.updateAt_NoAlloc(noAllocPositionGenerator.get());
}
}
@Benchmark
public void tickNoHeap() throws Throwable {
for (int i = 0; i < ITERATIONS; i++) {
world.updateAt_NoHeap(noHeapPositionGenerator.nextX(), noHeapPositionGenerator.nextY(), noHeapPositionGenerator.nextZ());
}
}
@Benchmark
@Threads(-1)
public void tickNoHeap_threaded() throws Throwable {
IntStream.rangeClosed(0, ITERATIONS)
.forEach(pos -> world.updateAt_NoHeap(noHeapPositionGenerator.nextX(), noHeapPositionGenerator.nextY(), noHeapPositionGenerator.nextZ()));
}
@Fork(value = 1, jvmArgs = {"-Xms128M", "-Xmx128M", "-XX:+AlwaysPreTouch"})
@Threads(-1)
@Benchmark
public void tickNoHeap_threaded128M() throws Throwable {
IntStream.rangeClosed(0, ITERATIONS)
.forEach(pos -> world.updateAt_NoHeap(noHeapPositionGenerator.nextX(), noHeapPositionGenerator.nextY(), noHeapPositionGenerator.nextZ()));
}
@Fork(value = 1, jvmArgs = {"-Xms20M", "-Xmx20M", "-XX:+AlwaysPreTouch"})
@Threads(-1)
@Benchmark
public void tickNoHeap_threaded20M() throws Throwable {
IntStream.rangeClosed(0, ITERATIONS)
.forEach(pos -> world.updateAt_NoHeap(noHeapPositionGenerator.nextX(), noHeapPositionGenerator.nextY(), noHeapPositionGenerator.nextZ()));
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(AllocBenchmark.class.getName())
.build();
new Runner(opt).run();
}
}
class PositionGenerator {
double nextX() {
ThreadLocalRandom random = ThreadLocalRandom.current();
return random.nextDouble(-10000000, 10000000);
}
double nextY() {
ThreadLocalRandom random = ThreadLocalRandom.current();
return random.nextDouble(-10000000, 10000000);
}
double nextZ() {
ThreadLocalRandom random = ThreadLocalRandom.current();
return random.nextDouble(-10000000, 10000000);
}
}
class World {
private final Blackhole blackhole;
World(Blackhole blackhole) {
this.blackhole = blackhole;
}
public void updateAt(Position position) {
position.forAllNeighborsInRange(3, newPosition -> spawnMonsterIfNotPresent(newPosition)); // cube 7x7x7
spawnChestIfNotPresent(position);
}
public void updateAt_NoAlloc(Position position) {
spawnChestIfNotPresent(position);
double posX = position.getX();
double posY = position.getY();
double posZ = position.getZ();
for (int x = -3; x <= 3; x++) {
for (int y = -3; y <= 3; y++) {
for (int z = -3; z <= 3; z++) {
if (x == 0 && y == 0 && z == 0) continue;
spawnMonsterIfNotPresent(position.set(posX + x, posY + y, posZ + z));
}
}
}
}
public void updateAt_NoHeap(double posX, double posY, double posZ) {
spawnChestIfNotPresent(posX, posY, posZ);
for (int x = -3; x <= 3; x++) {
for (int y = -3; y <= 3; y++) {
for (int z = -3; z <= 3; z++) {
if (x == 0 && y == 0 && z == 0) continue;
spawnMonsterIfNotPresent(posX + x, posY + y, posZ + z);
}
}
}
}
private void spawnMonsterIfNotPresent(Position position) {
blackhole.consume(position);
}
private void spawnChestIfNotPresent(Position position) {
blackhole.consume(position);
}
private void spawnMonsterIfNotPresent(double x, double y, double z) {
blackhole.consume(x + y + z);
}
private void spawnChestIfNotPresent(double x, double y, double z) {
blackhole.consume(x + y + z);
}
}
class Position {
private double x;
private double y;
private double z;
Position(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getZ() {
return z;
}
public Position set(double x, double y, double z) {
this.x = x;
this.y = y;
this.z = z;
return this;
}
void forAllNeighborsInRange(int range, Consumer<Position> positionConsumer) {
IntStream.rangeClosed(-range, range).forEach(x -> {
IntStream.rangeClosed(-range, range).forEach(y -> {
IntStream.rangeClosed(-range, range).forEach(z -> {
if (x == 0 && y == 0 && z == 0) return;
positionConsumer.accept(new Position(this.x + x, this.y + y, this.z + z));
});
});
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment