Update Timings to use Region based chunk reporting

This will drastically reduce file size on large servers and help
avoid the parser failing to load the report.

This will also reduce memory usage of timings data.
This commit is contained in:
Aikar 2016-04-05 01:20:25 -04:00
parent bce92696c6
commit 98ea811d9b

View file

@ -1,4 +1,4 @@
From ec3f78348b95c24b1e62101a871c43136432f5bb Mon Sep 17 00:00:00 2001 From 0b47a95a20c68bbc0620b0fb71ae2f5663619343 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co> From: Aikar <aikar@aikar.co>
Date: Mon, 29 Feb 2016 18:48:17 -0600 Date: Mon, 29 Feb 2016 18:48:17 -0600
Subject: [PATCH] Timings v2 Subject: [PATCH] Timings v2
@ -630,10 +630,10 @@ index 0000000..46c4e13
+} +}
diff --git a/src/main/java/co/aikar/timings/TimingHistory.java b/src/main/java/co/aikar/timings/TimingHistory.java diff --git a/src/main/java/co/aikar/timings/TimingHistory.java b/src/main/java/co/aikar/timings/TimingHistory.java
new file mode 100644 new file mode 100644
index 0000000..7a04770 index 0000000..9206569
--- /dev/null --- /dev/null
+++ b/src/main/java/co/aikar/timings/TimingHistory.java +++ b/src/main/java/co/aikar/timings/TimingHistory.java
@@ -0,0 +1,276 @@ @@ -0,0 +1,338 @@
+/* +/*
+ * This file is licensed under the MIT License (MIT). + * This file is licensed under the MIT License (MIT).
+ * + *
@ -659,7 +659,10 @@ index 0000000..7a04770
+ */ + */
+package co.aikar.timings; +package co.aikar.timings;
+ +
+import co.aikar.timings.TimingHistory.RegionData.RegionId;
+import co.aikar.util.JSONUtil;
+import com.google.common.base.Function; +import com.google.common.base.Function;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets; +import com.google.common.collect.Sets;
+import org.bukkit.Bukkit; +import org.bukkit.Bukkit;
+import org.bukkit.Chunk; +import org.bukkit.Chunk;
@ -683,7 +686,7 @@ index 0000000..7a04770
+import static co.aikar.timings.TimingsManager.MINUTE_REPORTS; +import static co.aikar.timings.TimingsManager.MINUTE_REPORTS;
+import static co.aikar.util.JSONUtil.*; +import static co.aikar.util.JSONUtil.*;
+ +
+@SuppressWarnings({"deprecation", "SuppressionAnnotation"}) +@SuppressWarnings({"deprecation", "SuppressionAnnotation", "Convert2Lambda", "Anonymous2MethodRef"})
+public class TimingHistory { +public class TimingHistory {
+ public static long lastMinuteTime; + public static long lastMinuteTime;
+ public static long timedTicks; + public static long timedTicks;
@ -691,23 +694,23 @@ index 0000000..7a04770
+ public static long entityTicks; + public static long entityTicks;
+ public static long tileEntityTicks; + public static long tileEntityTicks;
+ public static long activatedEntityTicks; + public static long activatedEntityTicks;
+ static int worldIdPool = 1; + private static int worldIdPool = 1;
+ static Map<String, Integer> worldMap = LoadingMap.newHashMap(new Function<String, Integer>() { + static Map<String, Integer> worldMap = LoadingMap.newHashMap(new Function<String, Integer>() {
+ @Override + @Override
+ public Integer apply(String input) { + public Integer apply(String input) {
+ return worldIdPool++; + return worldIdPool++;
+ } + }
+ }); + });
+ final long endTime; + private final long endTime;
+ final long startTime; + private final long startTime;
+ final long totalTicks; + private final long totalTicks;
+ final long totalTime; // Represents all time spent running the server this history + private final long totalTime; // Represents all time spent running the server this history
+ final MinuteReport[] minuteReports; + private final MinuteReport[] minuteReports;
+ +
+ final TimingHistoryEntry[] entries; + private final TimingHistoryEntry[] entries;
+ final Set<Material> tileEntityTypeSet = Sets.newHashSet(); + final Set<Material> tileEntityTypeSet = Sets.newHashSet();
+ final Set<EntityType> entityTypeSet = Sets.newHashSet(); + final Set<EntityType> entityTypeSet = Sets.newHashSet();
+ final Map<Object, Object> worlds; + private final Map<Object, Object> worlds;
+ +
+ TimingHistory() { + TimingHistory() {
+ this.endTime = System.currentTimeMillis() / 1000; + this.endTime = System.currentTimeMillis() / 1000;
@ -731,39 +734,34 @@ index 0000000..7a04770
+ entries[i++] = new TimingHistoryEntry(handler); + entries[i++] = new TimingHistoryEntry(handler);
+ } + }
+ +
+ final Map<EntityType, Counter> entityCounts = MRUMapCache.of(LoadingMap.of( +
+ new EnumMap<EntityType, Counter>(EntityType.class), Counter.LOADER
+ ));
+ final Map<Material, Counter> tileEntityCounts = MRUMapCache.of(LoadingMap.of(
+ new EnumMap<Material, Counter>(Material.class), Counter.LOADER
+ ));
+ // Information about all loaded chunks/entities + // Information about all loaded chunks/entities
+ //noinspection unchecked
+ this.worlds = toObjectMapper(Bukkit.getWorlds(), new Function<World, JSONPair>() { + this.worlds = toObjectMapper(Bukkit.getWorlds(), new Function<World, JSONPair>() {
+ @Override + @Override
+ public JSONPair apply(World world) { + public JSONPair apply(World world) {
+ return pair( + Map<RegionId, RegionData> regions = LoadingMap.newHashMap(RegionData.LOADER);
+ worldMap.get(world.getName()), +
+ toArrayMapper(world.getLoadedChunks(), new Function<Chunk, Object>() { + for (Chunk chunk : world.getLoadedChunks()) {
+ @Override + RegionData data = regions.get(new RegionId(chunk.getX(), chunk.getZ()));
+ public Object apply(Chunk chunk) {
+ entityCounts.clear();
+ tileEntityCounts.clear();
+ +
+ for (Entity entity : chunk.getEntities()) { + for (Entity entity : chunk.getEntities()) {
+ entityCounts.get(entity.getType()).increment(); + data.entityCounts.get(entity.getType()).increment();
+ } + }
+ +
+ for (BlockState tileEntity : chunk.getTileEntities()) { + for (BlockState tileEntity : chunk.getTileEntities()) {
+ tileEntityCounts.get(tileEntity.getBlock().getType()).increment(); + data.tileEntityCounts.get(tileEntity.getBlock().getType()).increment();
+ } + }
+
+ if (tileEntityCounts.isEmpty() && entityCounts.isEmpty()) {
+ return null;
+ } + }
+ return pair(
+ worldMap.get(world.getName()),
+ toArrayMapper(regions.values(),new Function<RegionData, Object>() {
+ @Override
+ public Object apply(RegionData input) {
+ return toArray( + return toArray(
+ chunk.getX(), + input.regionId.x,
+ chunk.getZ(), + input.regionId.z,
+ toObjectMapper(entityCounts.entrySet(), + toObjectMapper(input.entityCounts.entrySet(),
+ new Function<Map.Entry<EntityType, Counter>, JSONPair>() { + new Function<Map.Entry<EntityType, Counter>, JSONPair>() {
+ @Override + @Override
+ public JSONPair apply(Map.Entry<EntityType, Counter> entry) { + public JSONPair apply(Map.Entry<EntityType, Counter> entry) {
@ -775,7 +773,7 @@ index 0000000..7a04770
+ } + }
+ } + }
+ ), + ),
+ toObjectMapper(tileEntityCounts.entrySet(), + toObjectMapper(input.tileEntityCounts.entrySet(),
+ new Function<Map.Entry<Material, Counter>, JSONPair>() { + new Function<Map.Entry<Material, Counter>, JSONPair>() {
+ @Override + @Override
+ public JSONPair apply(Map.Entry<Material, Counter> entry) { + public JSONPair apply(Map.Entry<Material, Counter> entry) {
@ -794,8 +792,71 @@ index 0000000..7a04770
+ } + }
+ }); + });
+ } + }
+ static class RegionData {
+ private final RegionId regionId;
+ @SuppressWarnings("Guava")
+ static Function<RegionId, RegionData> LOADER = new Function<RegionId, RegionData>() {
+ @Override
+ public RegionData apply(RegionId id) {
+ return new RegionData(id);
+ }
+ };
+ RegionData(RegionId id) {
+ this.regionId = id;
+ }
+ +
+ public static void resetTicks(boolean fullReset) { + @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ RegionData that = (RegionData) o;
+
+ return regionId.equals(that.regionId);
+
+ }
+
+ @Override
+ public int hashCode() {
+ return regionId.hashCode();
+ }
+
+ @SuppressWarnings("unchecked")
+ final Map<EntityType, Counter> entityCounts = MRUMapCache.of(LoadingMap.of(
+ new EnumMap<EntityType, Counter>(EntityType.class), Counter.LOADER
+ ));
+ @SuppressWarnings("unchecked")
+ final Map<Material, Counter> tileEntityCounts = MRUMapCache.of(LoadingMap.of(
+ new EnumMap<Material, Counter>(Material.class), Counter.LOADER
+ ));
+
+ static class RegionId {
+ final int x, z;
+ final long regionId;
+ RegionId(int x, int z) {
+ this.x = x >> 5 << 5;
+ this.z = z >> 5 << 5;
+ this.regionId = ((long) (this.x) << 32) + (this.z >> 5 << 5) - Integer.MIN_VALUE;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ RegionId regionId1 = (RegionId) o;
+
+ return regionId == regionId1.regionId;
+
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) (regionId ^ (regionId >>> 32));
+ }
+ }
+ }
+ static void resetTicks(boolean fullReset) {
+ if (fullReset) { + if (fullReset) {
+ // Non full is simply for 1 minute reports + // Non full is simply for 1 minute reports
+ timedTicks = 0; + timedTicks = 0;
@ -863,7 +924,7 @@ index 0000000..7a04770
+ } + }
+ } + }
+ +
+ static class TicksRecord { + private static class TicksRecord {
+ final long timed; + final long timed;
+ final long player; + final long player;
+ final long entity; + final long entity;
@ -880,7 +941,7 @@ index 0000000..7a04770
+ +
+ } + }
+ +
+ static class PingRecord { + private static class PingRecord {
+ final double avg; + final double avg;
+ +
+ PingRecord() { + PingRecord() {
@ -893,9 +954,10 @@ index 0000000..7a04770
+ } + }
+ } + }
+ +
+ static class Counter { + @SuppressWarnings("WeakerAccess")
+ public static class Counter {
+ int count = 0; + int count = 0;
+ @SuppressWarnings({"rawtypes", "SuppressionAnnotation"}) + @SuppressWarnings({"rawtypes", "SuppressionAnnotation", "Guava"})
+ static Function LOADER = new LoadingMap.Feeder<Counter>() { + static Function LOADER = new LoadingMap.Feeder<Counter>() {
+ @Override + @Override
+ public Counter apply() { + public Counter apply() {