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
1 changed files with 129 additions and 67 deletions

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>
Date: Mon, 29 Feb 2016 18:48:17 -0600
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
new file mode 100644
index 0000000..7a04770
index 0000000..9206569
--- /dev/null
+++ 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).
+ *
@ -659,7 +659,10 @@ index 0000000..7a04770
+ */
+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.collect.Maps;
+import com.google.common.collect.Sets;
+import org.bukkit.Bukkit;
+import org.bukkit.Chunk;
@ -683,7 +686,7 @@ index 0000000..7a04770
+import static co.aikar.timings.TimingsManager.MINUTE_REPORTS;
+import static co.aikar.util.JSONUtil.*;
+
+@SuppressWarnings({"deprecation", "SuppressionAnnotation"})
+@SuppressWarnings({"deprecation", "SuppressionAnnotation", "Convert2Lambda", "Anonymous2MethodRef"})
+public class TimingHistory {
+ public static long lastMinuteTime;
+ public static long timedTicks;
@ -691,23 +694,23 @@ index 0000000..7a04770
+ public static long entityTicks;
+ public static long tileEntityTicks;
+ public static long activatedEntityTicks;
+ static int worldIdPool = 1;
+ private static int worldIdPool = 1;
+ static Map<String, Integer> worldMap = LoadingMap.newHashMap(new Function<String, Integer>() {
+ @Override
+ public Integer apply(String input) {
+ return worldIdPool++;
+ }
+ });
+ final long endTime;
+ final long startTime;
+ final long totalTicks;
+ final long totalTime; // Represents all time spent running the server this history
+ final MinuteReport[] minuteReports;
+ private final long endTime;
+ private final long startTime;
+ private final long totalTicks;
+ private final long totalTime; // Represents all time spent running the server this history
+ private final MinuteReport[] minuteReports;
+
+ final TimingHistoryEntry[] entries;
+ private final TimingHistoryEntry[] entries;
+ final Set<Material> tileEntityTypeSet = Sets.newHashSet();
+ final Set<EntityType> entityTypeSet = Sets.newHashSet();
+ final Map<Object, Object> worlds;
+ private final Map<Object, Object> worlds;
+
+ TimingHistory() {
+ this.endTime = System.currentTimeMillis() / 1000;
@ -731,71 +734,129 @@ index 0000000..7a04770
+ 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
+ //noinspection unchecked
+ this.worlds = toObjectMapper(Bukkit.getWorlds(), new Function<World, JSONPair>() {
+ @Override
+ public JSONPair apply(World world) {
+ @Override
+ public JSONPair apply(World world) {
+ Map<RegionId, RegionData> regions = LoadingMap.newHashMap(RegionData.LOADER);
+
+ for (Chunk chunk : world.getLoadedChunks()) {
+ RegionData data = regions.get(new RegionId(chunk.getX(), chunk.getZ()));
+
+ for (Entity entity : chunk.getEntities()) {
+ data.entityCounts.get(entity.getType()).increment();
+ }
+
+ for (BlockState tileEntity : chunk.getTileEntities()) {
+ data.tileEntityCounts.get(tileEntity.getBlock().getType()).increment();
+ }
+ }
+ return pair(
+ worldMap.get(world.getName()),
+ toArrayMapper(world.getLoadedChunks(), new Function<Chunk, Object>() {
+ toArrayMapper(regions.values(),new Function<RegionData, Object>() {
+ @Override
+ public Object apply(Chunk chunk) {
+ entityCounts.clear();
+ tileEntityCounts.clear();
+
+ for (Entity entity : chunk.getEntities()) {
+ entityCounts.get(entity.getType()).increment();
+ }
+
+ for (BlockState tileEntity : chunk.getTileEntities()) {
+ tileEntityCounts.get(tileEntity.getBlock().getType()).increment();
+ }
+
+ if (tileEntityCounts.isEmpty() && entityCounts.isEmpty()) {
+ return null;
+ }
+ return toArray(
+ chunk.getX(),
+ chunk.getZ(),
+ toObjectMapper(entityCounts.entrySet(),
+ new Function<Map.Entry<EntityType, Counter>, JSONPair>() {
+ @Override
+ public JSONPair apply(Map.Entry<EntityType, Counter> entry) {
+ entityTypeSet.add(entry.getKey());
+ return pair(
+ String.valueOf(entry.getKey().getTypeId()),
+ entry.getValue().count()
+ );
+ public Object apply(RegionData input) {
+ return toArray(
+ input.regionId.x,
+ input.regionId.z,
+ toObjectMapper(input.entityCounts.entrySet(),
+ new Function<Map.Entry<EntityType, Counter>, JSONPair>() {
+ @Override
+ public JSONPair apply(Map.Entry<EntityType, Counter> entry) {
+ entityTypeSet.add(entry.getKey());
+ return pair(
+ String.valueOf(entry.getKey().getTypeId()),
+ entry.getValue().count()
+ );
+ }
+ }
+ }
+ ),
+ toObjectMapper(tileEntityCounts.entrySet(),
+ new Function<Map.Entry<Material, Counter>, JSONPair>() {
+ @Override
+ public JSONPair apply(Map.Entry<Material, Counter> entry) {
+ tileEntityTypeSet.add(entry.getKey());
+ return pair(
+ String.valueOf(entry.getKey().getId()),
+ entry.getValue().count()
+ );
+ ),
+ toObjectMapper(input.tileEntityCounts.entrySet(),
+ new Function<Map.Entry<Material, Counter>, JSONPair>() {
+ @Override
+ public JSONPair apply(Map.Entry<Material, Counter> entry) {
+ tileEntityTypeSet.add(entry.getKey());
+ return pair(
+ String.valueOf(entry.getKey().getId()),
+ entry.getValue().count()
+ );
+ }
+ }
+ }
+ )
+ );
+ )
+ );
+ }
+ })
+ );
+ }
+ });
+ }
+ 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) {
+ // Non full is simply for 1 minute reports
+ timedTicks = 0;
@ -863,7 +924,7 @@ index 0000000..7a04770
+ }
+ }
+
+ static class TicksRecord {
+ private static class TicksRecord {
+ final long timed;
+ final long player;
+ final long entity;
@ -880,7 +941,7 @@ index 0000000..7a04770
+
+ }
+
+ static class PingRecord {
+ private static class PingRecord {
+ final double avg;
+
+ PingRecord() {
@ -893,9 +954,10 @@ index 0000000..7a04770
+ }
+ }
+
+ static class Counter {
+ @SuppressWarnings("WeakerAccess")
+ public static class Counter {
+ int count = 0;
+ @SuppressWarnings({"rawtypes", "SuppressionAnnotation"})
+ @SuppressWarnings({"rawtypes", "SuppressionAnnotation", "Guava"})
+ static Function LOADER = new LoadingMap.Feeder<Counter>() {
+ @Override
+ public Counter apply() {