From bc8f02788f37af0f03c9672903595b2f2f57d161 Mon Sep 17 00:00:00 2001 From: Tahg Date: Tue, 6 Dec 2011 08:52:45 -0500 Subject: [PATCH] Performance update to remove several very high counts of temp object creation --- .../net/minecraft/server/EntityLiving.java | 4 +- .../net/minecraft/server/EntityTracker.java | 8 +- .../net/minecraft/server/MinecraftServer.java | 2 +- .../net/minecraft/server/SpawnerCreature.java | 48 +++++-- src/main/java/net/minecraft/server/World.java | 26 ++-- .../org/bukkit/craftbukkit/CraftServer.java | 2 +- .../bukkit/craftbukkit/util/EntryBase.java | 8 ++ .../util/LongAbstractHashtable.java | 115 +++++++++++++++++ .../org/bukkit/craftbukkit/util/LongHash.java | 6 +- .../bukkit/craftbukkit/util/LongHashset.java | 25 ++++ .../craftbukkit/util/LongHashtable.java | 120 ++---------------- 11 files changed, 223 insertions(+), 141 deletions(-) create mode 100644 src/main/java/org/bukkit/craftbukkit/util/EntryBase.java create mode 100644 src/main/java/org/bukkit/craftbukkit/util/LongAbstractHashtable.java diff --git a/src/main/java/net/minecraft/server/EntityLiving.java b/src/main/java/net/minecraft/server/EntityLiving.java index aa11ced144..e09b519e57 100644 --- a/src/main/java/net/minecraft/server/EntityLiving.java +++ b/src/main/java/net/minecraft/server/EntityLiving.java @@ -175,7 +175,9 @@ public abstract class EntityLiving extends Entity { this.extinguish(); } else { - this.setAirTicks(maxAirTicks); // CraftBukkit - update maxAirTicks if no longer 300 + if (this.getAirTicks() != 300) { + this.setAirTicks(maxAirTicks); + } } this.aw = this.ax; diff --git a/src/main/java/net/minecraft/server/EntityTracker.java b/src/main/java/net/minecraft/server/EntityTracker.java index a1bd32245c..37a5cd1519 100644 --- a/src/main/java/net/minecraft/server/EntityTracker.java +++ b/src/main/java/net/minecraft/server/EntityTracker.java @@ -11,9 +11,9 @@ public class EntityTracker { private IntHashMap trackedEntities = new IntHashMap(); private MinecraftServer c; private int d; - private int e; + private World e; // CraftBukkit - change type - public EntityTracker(MinecraftServer minecraftserver, int i) { + public EntityTracker(MinecraftServer minecraftserver, World i) { // CraftBukkit - change method signature this.c = minecraftserver; this.e = i; this.d = minecraftserver.serverConfigurationManager.a(); @@ -94,7 +94,7 @@ public class EntityTracker { this.a.add(entitytrackerentry); this.trackedEntities.a(entity.id, entitytrackerentry); - entitytrackerentry.scanPlayers(this.c.getWorldServer(this.e).players); + entitytrackerentry.scanPlayers(this.e.players); // CraftBukkit } } @@ -127,7 +127,7 @@ public class EntityTracker { while (iterator.hasNext()) { EntityTrackerEntry entitytrackerentry = (EntityTrackerEntry) iterator.next(); - entitytrackerentry.track(this.c.getWorldServer(this.e).players); + entitytrackerentry.track(this.e.players); // CraftBukkit if (entitytrackerentry.m && entitytrackerentry.tracker instanceof EntityPlayer) { arraylist.add((EntityPlayer) entitytrackerentry.tracker); } diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index d8ae52743d..cea2ffb24c 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -267,7 +267,7 @@ public class MinecraftServer implements Runnable, ICommandListener, IMinecraftSe this.server.getPluginManager().callEvent(new WorldInitEvent(world.getWorld())); - world.tracker = new EntityTracker(this, dimension); + world.tracker = new EntityTracker(this, world); // CraftBukkit world.addIWorldAccess(new WorldManager(this, world)); world.difficulty = this.propertyManager.getInt("difficulty", 1); world.setSpawnFlags(this.propertyManager.getBoolean("spawn-monsters", true), this.spawnAnimals); diff --git a/src/main/java/net/minecraft/server/SpawnerCreature.java b/src/main/java/net/minecraft/server/SpawnerCreature.java index 28a8b03a71..bbb64f050b 100644 --- a/src/main/java/net/minecraft/server/SpawnerCreature.java +++ b/src/main/java/net/minecraft/server/SpawnerCreature.java @@ -1,5 +1,6 @@ package net.minecraft.server; +import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; @@ -7,11 +8,28 @@ import java.util.List; import java.util.Random; // CraftBukkit +import org.bukkit.craftbukkit.util.LongAbstractHashtable; +import org.bukkit.craftbukkit.util.EntryBase; +import org.bukkit.craftbukkit.util.LongHash; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; public final class SpawnerCreature { - private static HashMap b = new HashMap(); + // private static HashMap b = new HashMap(); // CraftBukkit -- moved local to spawnEntities + static private class ChunkEntry extends EntryBase { + public boolean spawn; + public ChunkEntry (int x, int z, boolean spawn) { + super(LongHash.toLong(x, z)); + this.spawn = spawn; + } + int getX() { + return LongHash.msw(key); + } + int getZ() { + return LongHash.lsw(key); + } + } + protected static final Class[] a = new Class[] { EntitySpider.class, EntityZombie.class, EntitySkeleton.class}; public SpawnerCreature() {} @@ -28,7 +46,9 @@ public final class SpawnerCreature { if (!flag && !flag1) { return 0; } else { - b.clear(); + // b.clear(); // CraftBukkit + LongAbstractHashtable chunkCoords; // CraftBukkit + chunkCoords = new LongAbstractHashtable() {}; int i; int j; @@ -43,19 +63,22 @@ public final class SpawnerCreature { for (int l = -b0; l <= b0; ++l) { for (int i1 = -b0; i1 <= b0; ++i1) { boolean flag2 = l == -b0 || l == b0 || i1 == -b0 || i1 == b0; - ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(l + k, i1 + j); + // CraftBukkit start + long chunkCoord = LongHash.toLong(l + k, i1 + j); if (!flag2) { - b.put(chunkcoordintpair, Boolean.valueOf(false)); - } else if (!b.containsKey(chunkcoordintpair)) { - b.put(chunkcoordintpair, Boolean.valueOf(true)); + chunkCoords.put(new ChunkEntry(l + k, i1 + j, false)); + } else if (!chunkCoords.containsKey(chunkCoord)) { + chunkCoords.put(new ChunkEntry(l + k, i1 + j, true)); } + // CraftBukkit end } } } i = 0; ChunkCoordinates chunkcoordinates = world.getSpawn(); + ArrayList entries = chunkCoords.entries(); // CraftBukkit EnumCreatureType[] aenumcreaturetype = EnumCreatureType.values(); j = aenumcreaturetype.length; @@ -63,15 +86,14 @@ public final class SpawnerCreature { for (int j1 = 0; j1 < j; ++j1) { EnumCreatureType enumcreaturetype = aenumcreaturetype[j1]; - if ((!enumcreaturetype.d() || flag1) && (enumcreaturetype.d() || flag) && world.a(enumcreaturetype.a()) <= enumcreaturetype.b() * b.size() / 256) { - Iterator iterator = b.keySet().iterator(); + + if ((!enumcreaturetype.d() || flag1) && (enumcreaturetype.d() || flag) && world.a(enumcreaturetype.a()) <= enumcreaturetype.b() * entries.size() / 256) { label108: - while (iterator.hasNext()) { - ChunkCoordIntPair chunkcoordintpair1 = (ChunkCoordIntPair) iterator.next(); - - if (!((Boolean) b.get(chunkcoordintpair1)).booleanValue()) { - ChunkPosition chunkposition = a(world, chunkcoordintpair1.x * 16, chunkcoordintpair1.z * 16); + for (EntryBase base : entries) { + ChunkEntry entry = (SpawnerCreature.ChunkEntry) base; + if (!entry.spawn) { + ChunkPosition chunkposition = a(world, LongHash.msw(entry.getX()) * 16, entry.getZ() * 16); int k1 = chunkposition.x; int l1 = chunkposition.y; int i2 = chunkposition.z; diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java index 805bb210ed..ea939f8661 100644 --- a/src/main/java/net/minecraft/server/World.java +++ b/src/main/java/net/minecraft/server/World.java @@ -14,6 +14,8 @@ import java.util.UUID; import org.bukkit.Bukkit; import org.bukkit.Location; +import org.bukkit.craftbukkit.util.LongHash; +import org.bukkit.craftbukkit.util.LongHashset; import org.bukkit.generator.ChunkGenerator; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; @@ -74,7 +76,7 @@ public class World implements IBlockAccess { private boolean S; public boolean allowMonsters; // CraftBukkit - private -> public public boolean allowAnimals; // CraftBukkit - private -> public - private Set T; + private LongHashset T; // CraftBukkit private int U; int[] H; private List V; @@ -145,7 +147,7 @@ public class World implements IBlockAccess { this.R = new ArrayList(); this.allowMonsters = true; this.allowAnimals = true; - this.T = new HashSet(); + this.T = new LongHashset(); // CraftBukkit this.U = this.random.nextInt(12000); this.H = new int['\u8000']; this.V = new ArrayList(); @@ -1856,7 +1858,7 @@ public class World implements IBlockAccess { } protected void k() { - this.T.clear(); + // this.T.clear(); // CraftBukkit -- removed // MethodProfiler.a("buildList"); // CraftBukkit -- not in production code int i; @@ -1870,7 +1872,7 @@ public class World implements IBlockAccess { for (j = -b0; j <= b0; ++j) { for (int i1 = -b0; i1 <= b0; ++i1) { - this.T.add(new ChunkCoordIntPair(j + k, i1 + l)); + this.T.add(LongHash.toLong(j + k, i1 + l)); // CraftBukkit } } } @@ -1883,15 +1885,19 @@ public class World implements IBlockAccess { int j1 = 0; // MethodProfiler.a(); // CraftBukkit -- not in production code - Iterator iterator = this.T.iterator(); + // Iterator iterator = this.T.iterator(); CraftBukkit == removed - while (iterator.hasNext()) { - ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) iterator.next(); - int k1 = chunkcoordintpair.x * 16; + // CraftBukkit start + for (long chunkCoord : this.T.popAll()) { + int chunkX = LongHash.msw(chunkCoord); + int chunkZ = LongHash.lsw(chunkCoord); + // ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) iterator.next(); + int k1 = chunkX * 16; - j = chunkcoordintpair.z * 16; + j = chunkZ * 16; // MethodProfiler.a("getChunk"); // CraftBukkit -- not in production code - Chunk chunk = this.getChunkAt(chunkcoordintpair.x, chunkcoordintpair.z); + Chunk chunk = this.getChunkAt(chunkX, chunkZ); + // CraftBukkit end // MethodProfiler.b("tickChunk"); // CraftBukkit -- not in production code chunk.i(); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index f0d4b58a89..45d74964aa 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -535,7 +535,7 @@ public final class CraftServer implements Server { internal.worldMaps = console.worlds.get(0).worldMaps; - internal.tracker = new EntityTracker(console, dimension); + internal.tracker = new EntityTracker(console, internal); // CraftBukkit internal.addIWorldAccess((IWorldAccess) new WorldManager(console, internal)); internal.difficulty = 1; internal.setSpawnFlags(true, true); diff --git a/src/main/java/org/bukkit/craftbukkit/util/EntryBase.java b/src/main/java/org/bukkit/craftbukkit/util/EntryBase.java new file mode 100644 index 0000000000..1167ce934e --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/util/EntryBase.java @@ -0,0 +1,8 @@ +package org.bukkit.craftbukkit.util; + +public class EntryBase { + protected long key; + public EntryBase(long key) { + this.key = key; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/util/LongAbstractHashtable.java b/src/main/java/org/bukkit/craftbukkit/util/LongAbstractHashtable.java new file mode 100644 index 0000000000..2da732cce2 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/util/LongAbstractHashtable.java @@ -0,0 +1,115 @@ +package org.bukkit.craftbukkit.util; + +import net.minecraft.server.Chunk; +import net.minecraft.server.MinecraftServer; + +import java.util.ArrayList; + +import static org.bukkit.craftbukkit.util.Java15Compat.Arrays_copyOf; + +public abstract class LongAbstractHashtable extends LongHash { + + EntryBase[][][] values = new EntryBase[256][][]; + EntryBase cache = null; + + public void put(int msw, int lsw, EntryBase entry) { + put(entry); + } + + public EntryBase getEntry(int msw, int lsw) { + return getEntry(toLong(msw, lsw)); + } + + public synchronized void put(EntryBase entry) { + int mainIdx = (int) (entry.key & 255); + EntryBase[][] outer = this.values[mainIdx]; + if (outer == null) this.values[mainIdx] = outer = new EntryBase[256][]; + + int outerIdx = (int) ((entry.key >> 32) & 255); + EntryBase[] inner = outer[outerIdx]; + + if (inner == null) { + outer[outerIdx] = inner = new EntryBase[5]; + inner[0] = this.cache = entry; + } else { + int i; + for (i = 0; i < inner.length; i++) { + if (inner[i] == null || inner[i].key == entry.key) { + inner[i] = this.cache = entry; + return; + } + } + + outer[outerIdx] = inner = Arrays_copyOf(inner, i + i); + inner[i] = entry; + } + } + + public synchronized EntryBase getEntry(long key) { + return containsKey(key) ? cache : null; + } + + public synchronized boolean containsKey(long key) { + if (this.cache != null && cache.key == key) return true; + + int outerIdx = (int) ((key >> 32) & 255); + EntryBase[][] outer = this.values[(int) (key & 255)]; + if (outer == null) return false; + + EntryBase[] inner = outer[outerIdx]; + if (inner == null) return false; + + for (int i = 0; i < inner.length; i++) { + EntryBase e = inner[i]; + if (e == null) { + return false; + } else if (e.key == key) { + this.cache = e; + return true; + } + } + return false; + } + + public synchronized void remove(long key) { + EntryBase[][] outer = this.values[(int) (key & 255)]; + if (outer == null) return; + + EntryBase[] inner = outer[(int) ((key >> 32) & 255)]; + if (inner == null) return; + + for (int i = 0; i < inner.length; i++) { + if (inner[i] == null) continue; + + if (inner[i].key == key) { + for (i++; i < inner.length; i++) { + if (inner[i] == null) break; + inner[i-1] = inner[i]; + } + + inner[i-1] = null; + this.cache = null; + return; + } + } + } + + public synchronized ArrayList entries() { + ArrayList ret = new ArrayList(); + + for (EntryBase[][] outer: this.values) { + if (outer == null) continue; + + for (EntryBase[] inner: outer) { + if (inner == null) continue; + + for (EntryBase entry: inner) { + if (entry == null) break; + + ret.add(entry); + } + } + } + return ret; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/util/LongHash.java b/src/main/java/org/bukkit/craftbukkit/util/LongHash.java index f903f2ea4c..5cb09ed796 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/LongHash.java +++ b/src/main/java/org/bukkit/craftbukkit/util/LongHash.java @@ -1,15 +1,15 @@ package org.bukkit.craftbukkit.util; public abstract class LongHash { - static long toLong(int msw, int lsw) { + public static long toLong(int msw, int lsw) { return ((long) msw << 32) + lsw - Integer.MIN_VALUE; } - static int msw(long l) { + public static int msw(long l) { return (int) (l >> 32); } - static int lsw(long l) { + public static int lsw(long l) { return (int) (l & 0xFFFFFFFF) + Integer.MIN_VALUE; } diff --git a/src/main/java/org/bukkit/craftbukkit/util/LongHashset.java b/src/main/java/org/bukkit/craftbukkit/util/LongHashset.java index 592f3254f6..0368aa6b5d 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/LongHashset.java +++ b/src/main/java/org/bukkit/craftbukkit/util/LongHashset.java @@ -125,6 +125,31 @@ public class LongHashset extends LongHash { return 0; } + public long[] popAll() { + int index = 0; + rl.lock(); + try { + long[] ret = new long[this.count]; + for (long[][] outer: this.values) { + if (outer == null) continue; + + for (int oIdx = outer.length - 1; oIdx >= 0; oIdx--) { + long[] inner = outer[oIdx]; + if (inner == null) continue; + + for (long entry: inner) { + ret[index++] = entry; + } + outer[oIdx] = null; + } + } + count = 0; + return ret; + } finally { + rl.unlock(); + } + } + public long[] keys() { int index = 0; rl.lock(); diff --git a/src/main/java/org/bukkit/craftbukkit/util/LongHashtable.java b/src/main/java/org/bukkit/craftbukkit/util/LongHashtable.java index b438e8faef..d3912e497e 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/LongHashtable.java +++ b/src/main/java/org/bukkit/craftbukkit/util/LongHashtable.java @@ -5,136 +5,40 @@ import net.minecraft.server.Chunk; import net.minecraft.server.MinecraftServer; import static org.bukkit.craftbukkit.util.Java15Compat.Arrays_copyOf; -public class LongHashtable extends LongHash { - Object[][][] values = new Object[256][][]; - Entry cache = null; +public class LongHashtable extends LongAbstractHashtable { public void put(int msw, int lsw, V value) { put(toLong(msw, lsw), value); - if (value instanceof Chunk) { - Chunk c = (Chunk) value; - if (msw != c.x || lsw != c.z) { - MinecraftServer.log.info("Chunk (" + c.x + ", " + c.z + ") stored at (" + msw + ", " + lsw + ")"); - Throwable x = new Throwable(); - x.fillInStackTrace(); - x.printStackTrace(); - } - } } public V get(int msw, int lsw) { - V value = get(toLong(msw, lsw)); - if (value instanceof Chunk) { - Chunk c = (Chunk) value; - if (msw != c.x || lsw != c.z) { - MinecraftServer.log.info("Chunk (" + c.x + ", " + c.z + ") stored at (" + msw + ", " + lsw + ")"); - Throwable x = new Throwable(); - x.fillInStackTrace(); - x.printStackTrace(); - } - } - return value; + return get(toLong(msw, lsw)); } public synchronized void put(long key, V value) { - int mainIdx = (int) (key & 255); - Object[][] outer = this.values[mainIdx]; - if (outer == null) this.values[mainIdx] = outer = new Object[256][]; - - int outerIdx = (int) ((key >> 32) & 255); - Object[] inner = outer[outerIdx]; - - if (inner == null) { - outer[outerIdx] = inner = new Object[5]; - inner[0] = this.cache = new Entry(key, value); - } else { - int i; - for (i = 0; i < inner.length; i++) { - if (inner[i] == null || ((Entry) inner[i]).key == key) { - inner[i] = this.cache = new Entry(key, value); - return; - } - } - - outer[outerIdx] = inner = Arrays_copyOf(inner, i + i); - inner[i] = new Entry(key, value); - } + put(new Entry(key, value)); } public synchronized V get(long key) { - return containsKey(key) ? (V) cache.value : null; - } - - public synchronized boolean containsKey(long key) { - if (this.cache != null && cache.key == key) return true; - - int outerIdx = (int) ((key >> 32) & 255); - Object[][] outer = this.values[(int) (key & 255)]; - if (outer == null) return false; - - Object[] inner = outer[outerIdx]; - if (inner == null) return false; - - for (int i = 0; i < inner.length; i++) { - Entry e = (Entry) inner[i]; - if (e == null) { - return false; - } else if (e.key == key) { - this.cache = e; - return true; - } - } - return false; - } - - public synchronized void remove(long key) { - Object[][] outer = this.values[(int) (key & 255)]; - if (outer == null) return; - - Object[] inner = outer[(int) ((key >> 32) & 255)]; - if (inner == null) return; - - for (int i = 0; i < inner.length; i++) { - if (inner[i] == null) continue; - - if (((Entry) inner[i]).key == key) { - for (i++; i < inner.length; i++) { - if (inner[i] == null) break; - inner[i-1] = inner[i]; - } - - inner[i-1] = null; - this.cache = null; - return; - } - } + Entry entry = ((Entry)getEntry(key)); + return entry != null ? entry.value : null; } public synchronized ArrayList values() { ArrayList ret = new ArrayList(); - for (Object[][] outer: this.values) { - if (outer == null) continue; + ArrayList entries = entries(); - for (Object[] inner: outer) { - if (inner == null) continue; - - for (Object entry: inner) { - if (entry == null) break; - - ret.add((V) ((Entry) entry).value); - } - } + for(EntryBase entry : entries) { + ret.add(((Entry)entry).value); } return ret; } - private class Entry { - long key; - Object value; - - Entry(long k, Object v) { - this.key = k; + private class Entry extends EntryBase { + V value; + Entry(long k, V v) { + super(k); this.value = v; } }