From 3e06c41ce44ca07b04261036caabc1890cc17585 Mon Sep 17 00:00:00 2001 From: md_5 Date: Sun, 2 Jun 2013 11:19:41 +1000 Subject: [PATCH] Update timings patch for cleanup and better efficiency --- .../0003-Improved-Timings-System.patch | 400 ------------------ .../0003-Timings-Paste-Command.patch | 140 ++++++ .../0004-Add-nag-for-bad-plugins.patch | 27 -- Bukkit-Patches/0004-Enchanced-Timings.patch | 363 ++++++++++++++++ 4 files changed, 503 insertions(+), 427 deletions(-) delete mode 100644 Bukkit-Patches/0003-Improved-Timings-System.patch create mode 100644 Bukkit-Patches/0003-Timings-Paste-Command.patch delete mode 100644 Bukkit-Patches/0004-Add-nag-for-bad-plugins.patch create mode 100644 Bukkit-Patches/0004-Enchanced-Timings.patch diff --git a/Bukkit-Patches/0003-Improved-Timings-System.patch b/Bukkit-Patches/0003-Improved-Timings-System.patch deleted file mode 100644 index d527e11..0000000 --- a/Bukkit-Patches/0003-Improved-Timings-System.patch +++ /dev/null @@ -1,400 +0,0 @@ -From 43008572d75af40a56e3e6867325d4231f9a08da Mon Sep 17 00:00:00 2001 -From: Aikar -Date: Wed, 9 Jan 2013 22:18:26 -0500 -Subject: [PATCH] Improved Timings System - -Enables "Timings on Demand" so you can enable/disable timings without server restart. -Tracks timings on sync events a plugin registers (Single and Repeating) -Tracks how many ticks a timed area has caused the server to lose due to taking too long. -Enables automatically pasting to paste.ubuntu.com so you can quickly review the results on aikar.co/timings.php - -diff --git a/src/main/java/org/bukkit/CustomTimingsHandler.java b/src/main/java/org/bukkit/CustomTimingsHandler.java -new file mode 100644 -index 0000000..8c00824 ---- /dev/null -+++ b/src/main/java/org/bukkit/CustomTimingsHandler.java -@@ -0,0 +1,134 @@ -+package org.bukkit; -+ -+import org.bukkit.event.HandlerList; -+import org.bukkit.plugin.Plugin; -+import org.bukkit.plugin.RegisteredListener; -+import org.bukkit.plugin.TimedRegisteredListener; -+ -+import java.io.PrintStream; -+import java.util.concurrent.ConcurrentLinkedQueue; -+ -+/** -+ * Provides custom timing sections for /timings merged -+ */ -+public class CustomTimingsHandler { -+ -+ final public String name; -+ public long count = 0; -+ public long start = 0; -+ public long timingDepth = 0; -+ public long totalTime = 0; -+ public long curTickTotal = 0; -+ public long violations = 0; -+ CustomTimingsHandler parent = null; -+ -+ final public static ConcurrentLinkedQueue allList = new ConcurrentLinkedQueue(); -+ -+ public CustomTimingsHandler(String name) { -+ this.name = name; -+ allList.add(this); -+ } -+ public CustomTimingsHandler(String name, CustomTimingsHandler parent) { -+ this(name); -+ this.parent = parent; -+ } -+ -+ /** -+ * Prints the timings and extra data to the printstream -+ * @param printStream -+ */ -+ public static void printTimings(PrintStream printStream) { -+ printStream.println("Minecraft"); -+ for (CustomTimingsHandler timings : allList) { -+ long time = timings.totalTime; -+ long count = timings.count; -+ if (count == 0) continue; -+ long avg = time / count; -+ -+ printStream.println(" " + timings.name + " Time: " + time + " Count: " + count + " Avg: " + avg + " Violations: " + timings.violations); -+ } -+ printStream.println("# Version " + Bukkit.getVersion()); -+ int entities = 0; -+ int livingEntities = 0; -+ for (World world : Bukkit.getWorlds()) { -+ entities += world.getEntities().size(); -+ livingEntities += world.getLivingEntities().size(); -+ } -+ printStream.println("# Entities " + entities); -+ printStream.println("# LivingEntities " + livingEntities); -+ } -+ -+ /** -+ * Resets all timings -+ */ -+ public static void reload() { -+ if (!Bukkit.getServer().getPluginManager().useTimings()) return; -+ for (CustomTimingsHandler timings : allList) { -+ timings.reset(); -+ } -+ } -+ -+ /** -+ * Ticked every tick by CraftBukkit to count the number of times a timer caused TPS loss. -+ */ -+ public static void tick() { -+ if (!Bukkit.getServer().getPluginManager().useTimings()) return; -+ for (CustomTimingsHandler timings : allList) { -+ if (timings.curTickTotal > 50000000) { -+ timings.violations += Math.ceil(timings.curTickTotal / 50000000); -+ } -+ timings.curTickTotal = 0; -+ } -+ -+ for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) { -+ for (RegisteredListener listener : HandlerList.getRegisteredListeners(plugin)) { -+ if (listener instanceof TimedRegisteredListener) { -+ TimedRegisteredListener timings = (TimedRegisteredListener) listener; -+ if (timings.curTickTotal > 50000000) { -+ timings.violations += Math.ceil(timings.curTickTotal / 50000000); -+ } -+ timings.curTickTotal = 0; -+ } -+ } -+ } -+ } -+ -+ /** -+ * Starts timing to track a section of code. -+ */ -+ public void startTiming() { -+ if (!Bukkit.getServer().getPluginManager().useTimings()) return; -+ -+ if (++timingDepth != 1) { -+ return; // Already timing. -+ } -+ start = System.nanoTime(); -+ -+ if (parent != null && ++parent.timingDepth == 1) { -+ parent.start = start; -+ } -+ } -+ -+ public void stopTiming() { -+ if (!Bukkit.getServer().getPluginManager().useTimings()) return; -+ if (--timingDepth != 0 || start == 0) { -+ return; -+ } -+ long diff = System.nanoTime() - start; -+ totalTime += diff; -+ curTickTotal += diff; -+ count++; -+ start = 0; -+ if (parent != null) { -+ parent.stopTiming(); -+ } -+ } -+ -+ public void reset() { -+ count = 0; -+ violations = 0; -+ curTickTotal = 0; -+ totalTime = 0; -+ } -+} -+ -diff --git a/src/main/java/org/bukkit/command/defaults/ReloadCommand.java b/src/main/java/org/bukkit/command/defaults/ReloadCommand.java -index fb3c90f..89c8414 100644 ---- a/src/main/java/org/bukkit/command/defaults/ReloadCommand.java -+++ b/src/main/java/org/bukkit/command/defaults/ReloadCommand.java -@@ -6,6 +6,7 @@ import org.bukkit.Bukkit; - import org.bukkit.ChatColor; - import org.bukkit.command.Command; - import org.bukkit.command.CommandSender; -+import org.bukkit.CustomTimingsHandler; - - public class ReloadCommand extends BukkitCommand { - public ReloadCommand(String name) { -@@ -20,6 +21,7 @@ public class ReloadCommand extends BukkitCommand { - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; - -+ CustomTimingsHandler.reload(); // Spigot - Bukkit.reload(); - Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Reload complete."); - -diff --git a/src/main/java/org/bukkit/command/defaults/TimingsCommand.java b/src/main/java/org/bukkit/command/defaults/TimingsCommand.java -index 3c4ef89..7386322 100644 ---- a/src/main/java/org/bukkit/command/defaults/TimingsCommand.java -+++ b/src/main/java/org/bukkit/command/defaults/TimingsCommand.java -@@ -10,14 +10,22 @@ import org.apache.commons.lang.Validate; - import org.bukkit.Bukkit; - import org.bukkit.ChatColor; - import org.bukkit.command.CommandSender; -+import org.bukkit.CustomTimingsHandler; - import org.bukkit.event.Event; - import org.bukkit.event.HandlerList; - import org.bukkit.plugin.Plugin; - import org.bukkit.plugin.RegisteredListener; -+import org.bukkit.plugin.SimplePluginManager; // Spigot - import org.bukkit.plugin.TimedRegisteredListener; - import org.bukkit.util.StringUtil; - - import com.google.common.collect.ImmutableList; -+import java.io.ByteArrayOutputStream; -+import java.io.OutputStream; -+import java.net.HttpURLConnection; -+import java.net.URL; -+import java.net.URLEncoder; -+import java.util.logging.Level; - - public class TimingsCommand extends BukkitCommand { - private static final List TIMINGS_SUBCOMMANDS = ImmutableList.of("merged", "reset", "separate"); -@@ -26,24 +34,35 @@ public class TimingsCommand extends BukkitCommand { - public TimingsCommand(String name) { - super(name); - this.description = "Records timings for all plugin events"; -- this.usageMessage = "/timings "; -+ this.usageMessage = "/timings "; // Spigot - this.setPermission("bukkit.command.timings"); - } - - @Override - public boolean execute(CommandSender sender, String currentAlias, String[] args) { - if (!testPermission(sender)) return true; -- if (args.length != 1) { -+ if (args.length < 1) { // Spigot - sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); - return false; - } -- if (!sender.getServer().getPluginManager().useTimings()) { -+ // Spigot start - this is dynamic now -+ /*if (!sender.getServer().getPluginManager().useTimings()) { - sender.sendMessage("Please enable timings by setting \"settings.plugin-profiling\" to true in bukkit.yml"); - return true; -+ }*/ -+ if ("on".equals(args[0])) { -+ ((SimplePluginManager)Bukkit.getServer().getPluginManager()).useTimings(true); -+ sender.sendMessage("Enabled Timings"); -+ } else if ("off".equals(args[0])) { -+ ((SimplePluginManager)Bukkit.getServer().getPluginManager()).useTimings(false); -+ sender.sendMessage("Disabled Timings"); - } -+ // Spigot end - - boolean separate = "separate".equals(args[0]); -- if ("reset".equals(args[0])) { -+ boolean paste = "paste".equals(args[0]); // Spigot -+ if ("on".equals(args[0]) || "reset".equals(args[0])) { // Spigot -+ if (!"on".equals(args[0]) && !Bukkit.getServer().getPluginManager().useTimings()) {sender.sendMessage("Please enable timings by typing /timings on"); return true; } // Spigot - for (HandlerList handlerList : HandlerList.getHandlerLists()) { - for (RegisteredListener listener : handlerList.getRegisteredListeners()) { - if (listener instanceof TimedRegisteredListener) { -@@ -51,10 +70,11 @@ public class TimingsCommand extends BukkitCommand { - } - } - } -+ CustomTimingsHandler.reload(); // Spigot - timingStart = System.nanoTime(); // Spigot - sender.sendMessage("Timings reset"); -- } else if ("merged".equals(args[0]) || separate) { -- -+ } else if ("merged".equals(args[0]) || separate || paste) { // Spigot -+ if (!Bukkit.getServer().getPluginManager().useTimings()) {sender.sendMessage("Please enable timings by typing /timings on"); return true; } // Spigot - long sampleTime = System.nanoTime() - timingStart; // Spigot - int index = 0; - int pluginIdx = 0; -@@ -62,11 +82,12 @@ public class TimingsCommand extends BukkitCommand { - timingFolder.mkdirs(); - File timings = new File(timingFolder, "timings.txt"); - File names = null; -+ ByteArrayOutputStream bout = (paste) ? new ByteArrayOutputStream() : null; // Spigot - while (timings.exists()) timings = new File(timingFolder, "timings" + (++index) + ".txt"); - PrintStream fileTimings = null; - PrintStream fileNames = null; - try { -- fileTimings = new PrintStream(timings); -+ fileTimings = (paste) ? new PrintStream(bout) : new PrintStream(timings); - if (separate) { - names = new File(timingFolder, "names" + index + ".txt"); - fileNames = new PrintStream(names); -@@ -89,14 +110,23 @@ public class TimingsCommand extends BukkitCommand { - totalTime += time; - Event event = trl.getEvent(); - if (count > 0 && event != null) { -- fileTimings.println(" " + event.getClass().getSimpleName() + (trl.hasMultiple() ? " (and others)" : "") + " Time: " + time + " Count: " + count + " Avg: " + avg); -+ fileTimings.println(" " + event.getClass().getSimpleName() + (trl.hasMultiple() ? " (and others)" : "") + " Time: " + time + " Count: " + count + " Avg: " + avg + " Violations: " + trl.violations); // Spigot - } - } - } - fileTimings.println(" Total time " + totalTime + " (" + totalTime / 1000000000 + "s)"); - } -+ -+ // Spigot start -+ CustomTimingsHandler.printTimings(fileTimings); - fileTimings.println( "Sample time " + sampleTime + " (" + sampleTime / 1E9 + "s)" ); // Spigot -- sender.sendMessage("Timings written to " + timings.getPath()); -+ if (paste) { -+ new PasteThread(sender, bout).start(); -+ } else { -+ sender.sendMessage("Timings written to " + timings.getPath()); -+ sender.sendMessage("Paste contents of file into form at http://aikar.co/timings.php to read results."); -+ } -+ // Spigot end - if (separate) sender.sendMessage("Names written to " + names.getPath()); - } catch (IOException e) { - } finally { -@@ -122,4 +152,42 @@ public class TimingsCommand extends BukkitCommand { - } - return ImmutableList.of(); - } -+ -+ // Spigot start -+ private static class PasteThread extends Thread { -+ -+ private final CommandSender sender; -+ private final ByteArrayOutputStream bout; -+ -+ public PasteThread(CommandSender sender, ByteArrayOutputStream bout) { -+ super("Timings paste thread"); -+ this.sender = sender; -+ this.bout = bout; -+ } -+ -+ @Override -+ public void run() { -+ try { -+ HttpURLConnection con = (HttpURLConnection) new URL("http://paste.ubuntu.com/").openConnection(); -+ con.setDoOutput(true); -+ con.setRequestMethod("POST"); -+ con.setInstanceFollowRedirects(false); -+ -+ OutputStream out = con.getOutputStream(); -+ out.write("poster=Spigot&syntax=text&content=".getBytes("UTF-8")); -+ out.write(URLEncoder.encode(bout.toString("UTF-8"), "UTF-8").getBytes("UTF-8")); -+ out.close(); -+ con.getInputStream().close(); -+ -+ String location = con.getHeaderField("Location"); -+ String pasteID = location.substring("http://paste.ubuntu.com/".length(), location.length() - 1); -+ sender.sendMessage(ChatColor.GREEN + "Your timings have been pasted to " + location); -+ sender.sendMessage(ChatColor.GREEN + "You can view the results at http://aikar.co/timings.php?url=" + pasteID); -+ } catch (IOException ex) { -+ sender.sendMessage(ChatColor.RED + "Error pasting timings, check your console for more information"); -+ Bukkit.getServer().getLogger().log(Level.WARNING, "Could not paste timings", ex); -+ } -+ } -+ } -+ // Spigot end - } -diff --git a/src/main/java/org/bukkit/plugin/TimedRegisteredListener.java b/src/main/java/org/bukkit/plugin/TimedRegisteredListener.java -index ed25e17..47dab3e 100644 ---- a/src/main/java/org/bukkit/plugin/TimedRegisteredListener.java -+++ b/src/main/java/org/bukkit/plugin/TimedRegisteredListener.java -@@ -1,5 +1,6 @@ - package org.bukkit.plugin; - -+import org.bukkit.Bukkit; // Spigot - import org.bukkit.event.Event; - import org.bukkit.event.EventException; - import org.bukkit.event.EventPriority; -@@ -11,6 +12,8 @@ import org.bukkit.event.Listener; - public class TimedRegisteredListener extends RegisteredListener { - private int count; - private long totalTime; -+ public long curTickTotal = 0; // Spigot -+ public long violations = 0; // Spigot - private Event event; - private boolean multiple = false; - -@@ -20,6 +23,7 @@ public class TimedRegisteredListener extends RegisteredListener { - - @Override - public void callEvent(Event event) throws EventException { -+ if (!Bukkit.getServer().getPluginManager().useTimings()) { super.callEvent(event);return; } // Spigot - if (event.isAsynchronous()) { - super.callEvent(event); - return; -@@ -33,7 +37,11 @@ public class TimedRegisteredListener extends RegisteredListener { - } - long start = System.nanoTime(); - super.callEvent(event); -- totalTime += System.nanoTime() - start; -+ // Spigot start -+ long diff = System.nanoTime() - start; -+ curTickTotal += diff; -+ totalTime += diff; -+ // Spigot end - } - - /** -@@ -42,6 +50,8 @@ public class TimedRegisteredListener extends RegisteredListener { - public void reset() { - count = 0; - totalTime = 0; -+ curTickTotal = 0; // Spigot -+ violations = 0; // Spigot - } - - /** -diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -index ea30d83..d905435 100644 ---- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -@@ -430,7 +430,7 @@ public class JavaPluginLoader implements PluginLoader { - } - } - }; -- if (useTimings) { -+ if (true) { // Spigot - TRL handles useTimings check now - eventSet.add(new TimedRegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled())); - } else { - eventSet.add(new RegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled())); --- -1.8.1.2 - diff --git a/Bukkit-Patches/0003-Timings-Paste-Command.patch b/Bukkit-Patches/0003-Timings-Paste-Command.patch new file mode 100644 index 0000000..0a7ee45 --- /dev/null +++ b/Bukkit-Patches/0003-Timings-Paste-Command.patch @@ -0,0 +1,140 @@ +From e33b904f22116acd6b470ee03967b5ae8b7b5311 Mon Sep 17 00:00:00 2001 +From: md_5 +Date: Sun, 2 Jun 2013 10:55:20 +1000 +Subject: [PATCH] Timings Paste Command + + +diff --git a/src/main/java/org/bukkit/command/defaults/TimingsCommand.java b/src/main/java/org/bukkit/command/defaults/TimingsCommand.java +index 3c4ef89..e3777ea 100644 +--- a/src/main/java/org/bukkit/command/defaults/TimingsCommand.java ++++ b/src/main/java/org/bukkit/command/defaults/TimingsCommand.java +@@ -19,6 +19,15 @@ import org.bukkit.util.StringUtil; + + import com.google.common.collect.ImmutableList; + ++// Spigot start ++import java.io.ByteArrayOutputStream; ++import java.io.OutputStream; ++import java.net.HttpURLConnection; ++import java.net.URL; ++import java.net.URLEncoder; ++import java.util.logging.Level; ++// Spigot end ++ + public class TimingsCommand extends BukkitCommand { + private static final List TIMINGS_SUBCOMMANDS = ImmutableList.of("merged", "reset", "separate"); + public static long timingStart = 0; // Spigot +@@ -26,14 +35,14 @@ public class TimingsCommand extends BukkitCommand { + public TimingsCommand(String name) { + super(name); + this.description = "Records timings for all plugin events"; +- this.usageMessage = "/timings "; ++ this.usageMessage = "/timings [paste]"; // Spigot + this.setPermission("bukkit.command.timings"); + } + + @Override + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; +- if (args.length != 1) { ++ if (args.length < 1) { // Spigot + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } +@@ -43,6 +52,7 @@ public class TimingsCommand extends BukkitCommand { + } + + boolean separate = "separate".equals(args[0]); ++ boolean paste = "paste".equals( args[0] ); // Spigot + if ("reset".equals(args[0])) { + for (HandlerList handlerList : HandlerList.getHandlerLists()) { + for (RegisteredListener listener : handlerList.getRegisteredListeners()) { +@@ -53,8 +63,7 @@ public class TimingsCommand extends BukkitCommand { + } + timingStart = System.nanoTime(); // Spigot + sender.sendMessage("Timings reset"); +- } else if ("merged".equals(args[0]) || separate) { +- ++ } else if ("merged".equals(args[0]) || separate || paste) { // Spigot + long sampleTime = System.nanoTime() - timingStart; // Spigot + int index = 0; + int pluginIdx = 0; +@@ -62,11 +71,12 @@ public class TimingsCommand extends BukkitCommand { + timingFolder.mkdirs(); + File timings = new File(timingFolder, "timings.txt"); + File names = null; ++ ByteArrayOutputStream bout = ( paste ) ? new ByteArrayOutputStream() : null; // Spigot + while (timings.exists()) timings = new File(timingFolder, "timings" + (++index) + ".txt"); + PrintStream fileTimings = null; + PrintStream fileNames = null; + try { +- fileTimings = new PrintStream(timings); ++ fileTimings = ( paste ) ? new PrintStream( bout ) : new PrintStream( timings ); + if (separate) { + names = new File(timingFolder, "names" + index + ".txt"); + fileNames = new PrintStream(names); +@@ -96,6 +106,13 @@ public class TimingsCommand extends BukkitCommand { + fileTimings.println(" Total time " + totalTime + " (" + totalTime / 1000000000 + "s)"); + } + fileTimings.println( "Sample time " + sampleTime + " (" + sampleTime / 1E9 + "s)" ); // Spigot ++ // Spigot start ++ if ( paste ) ++ { ++ new PasteThread( sender, bout ).start(); ++ return true; ++ } ++ // Spigot end + sender.sendMessage("Timings written to " + timings.getPath()); + if (separate) sender.sendMessage("Names written to " + names.getPath()); + } catch (IOException e) { +@@ -122,4 +139,47 @@ public class TimingsCommand extends BukkitCommand { + } + return ImmutableList.of(); + } ++ ++ // Spigot start ++ private static class PasteThread extends Thread ++ { ++ ++ private final CommandSender sender; ++ private final ByteArrayOutputStream bout; ++ ++ public PasteThread(CommandSender sender, ByteArrayOutputStream bout) ++ { ++ super( "Timings paste thread" ); ++ this.sender = sender; ++ this.bout = bout; ++ } ++ ++ @Override ++ public void run() ++ { ++ try ++ { ++ HttpURLConnection con = (HttpURLConnection) new URL( "http://paste.ubuntu.com/" ).openConnection(); ++ con.setDoOutput( true ); ++ con.setRequestMethod( "POST" ); ++ con.setInstanceFollowRedirects( false ); ++ ++ OutputStream out = con.getOutputStream(); ++ out.write( "poster=Spigot&syntax=text&content=".getBytes( "UTF-8" ) ); ++ out.write( URLEncoder.encode( bout.toString( "UTF-8" ), "UTF-8" ).getBytes( "UTF-8" ) ); ++ out.close(); ++ con.getInputStream().close(); ++ ++ String location = con.getHeaderField( "Location" ); ++ String pasteID = location.substring( "http://paste.ubuntu.com/".length(), location.length() - 1 ); ++ sender.sendMessage( ChatColor.GREEN + "Your timings have been pasted to " + location ); ++ sender.sendMessage( ChatColor.GREEN + "You can view the results at http://aikar.co/timings.php?url=" + pasteID ); ++ } catch ( IOException ex ) ++ { ++ sender.sendMessage( ChatColor.RED + "Error pasting timings, check your console for more information" ); ++ Bukkit.getServer().getLogger().log( Level.WARNING, "Could not paste timings", ex ); ++ } ++ } ++ } ++ // Spigot end + } +-- +1.8.1.2 + diff --git a/Bukkit-Patches/0004-Add-nag-for-bad-plugins.patch b/Bukkit-Patches/0004-Add-nag-for-bad-plugins.patch deleted file mode 100644 index ba6eaed..0000000 --- a/Bukkit-Patches/0004-Add-nag-for-bad-plugins.patch +++ /dev/null @@ -1,27 +0,0 @@ -From ed59e1ea0da9d4136dffe6056056748bcef8bfc3 Mon Sep 17 00:00:00 2001 -From: md_5 -Date: Sat, 2 Feb 2013 16:40:42 +1100 -Subject: [PATCH] Add nag for bad plugins. - - -diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -index 29ec3fc..a31500c 100644 ---- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java -@@ -69,6 +69,13 @@ public class PluginClassLoader extends URLClassLoader { - if (name.startsWith("org.bukkit.") || name.startsWith("net.minecraft.")) { - throw new ClassNotFoundException(name); - } -+ -+ // Spigot start -+ if (checkGlobal && name.equals("org.mcstats.Metrics")) { -+ loader.server.getLogger().warning("Plugin from file: " + getURLs()[0] + " has embedded Metrics in the default package. This is not advisable, go nag them!"); -+ } -+ // Spigot end -+ - Class result = classes.get(name); - - if (result == null) { --- -1.8.2.1 - diff --git a/Bukkit-Patches/0004-Enchanced-Timings.patch b/Bukkit-Patches/0004-Enchanced-Timings.patch new file mode 100644 index 0000000..32f8002 --- /dev/null +++ b/Bukkit-Patches/0004-Enchanced-Timings.patch @@ -0,0 +1,363 @@ +From b6caa7eeba80ff9a7228c5b7e221561b6d182ad3 Mon Sep 17 00:00:00 2001 +From: md_5 +Date: Sun, 2 Jun 2013 11:17:05 +1000 +Subject: [PATCH] Enchanced Timings + + +diff --git a/src/main/java/org/bukkit/command/defaults/ReloadCommand.java b/src/main/java/org/bukkit/command/defaults/ReloadCommand.java +index fb3c90f..ffbcac1 100644 +--- a/src/main/java/org/bukkit/command/defaults/ReloadCommand.java ++++ b/src/main/java/org/bukkit/command/defaults/ReloadCommand.java +@@ -20,6 +20,7 @@ public class ReloadCommand extends BukkitCommand { + public boolean execute(CommandSender sender, String currentAlias, String[] args) { + if (!testPermission(sender)) return true; + ++ org.spigotmc.CustomTimingsHandler.reload(); // Spigot: TODO: Why is this here? + Bukkit.reload(); + Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Reload complete."); + +diff --git a/src/main/java/org/bukkit/command/defaults/TimingsCommand.java b/src/main/java/org/bukkit/command/defaults/TimingsCommand.java +index e3777ea..d2f5d29 100644 +--- a/src/main/java/org/bukkit/command/defaults/TimingsCommand.java ++++ b/src/main/java/org/bukkit/command/defaults/TimingsCommand.java +@@ -35,7 +35,7 @@ public class TimingsCommand extends BukkitCommand { + public TimingsCommand(String name) { + super(name); + this.description = "Records timings for all plugin events"; +- this.usageMessage = "/timings [paste]"; // Spigot ++ this.usageMessage = "/timings [paste]"; // Spigot + this.setPermission("bukkit.command.timings"); + } + +@@ -46,14 +46,33 @@ public class TimingsCommand extends BukkitCommand { + sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); + return false; + } +- if (!sender.getServer().getPluginManager().useTimings()) { ++ /*if (!sender.getServer().getPluginManager().useTimings()) { + sender.sendMessage("Please enable timings by setting \"settings.plugin-profiling\" to true in bukkit.yml"); + return true; ++ }*/ ++ ++ // Spigot start - dynamic enable ++ if ( "on".equals( args[0] ) ) ++ { ++ ( (org.bukkit.plugin.SimplePluginManager) Bukkit.getPluginManager() ).useTimings( true ); ++ sender.sendMessage( "Enabled Timings" ); ++ } else if ( "off".equals( args[0] ) ) ++ { ++ ( (org.bukkit.plugin.SimplePluginManager) Bukkit.getPluginManager() ).useTimings( false ); ++ sender.sendMessage( "Disabled Timings" ); + } ++ // Spigot end + + boolean separate = "separate".equals(args[0]); + boolean paste = "paste".equals( args[0] ); // Spigot +- if ("reset".equals(args[0])) { ++ if ("on".equals(args[0]) || "reset".equals(args[0])) { // Spigot ++ // Spigot start ++ if ( !"on".equals( args[0] ) && !Bukkit.getPluginManager().useTimings() ) ++ { ++ sender.sendMessage( "Please enable timings by typing /timings on" ); ++ return true; ++ } ++ // Spigot end + for (HandlerList handlerList : HandlerList.getHandlerLists()) { + for (RegisteredListener listener : handlerList.getRegisteredListeners()) { + if (listener instanceof TimedRegisteredListener) { +@@ -61,10 +80,18 @@ public class TimingsCommand extends BukkitCommand { + } + } + } +- timingStart = System.nanoTime(); // Spigot ++ // Spigot start ++ org.spigotmc.CustomTimingsHandler.reload(); ++ timingStart = System.nanoTime(); + sender.sendMessage("Timings reset"); +- } else if ("merged".equals(args[0]) || separate || paste) { // Spigot +- long sampleTime = System.nanoTime() - timingStart; // Spigot ++ } else if ("merged".equals(args[0]) || separate || paste) { ++ if ( !Bukkit.getPluginManager().useTimings() ) ++ { ++ sender.sendMessage( "Please enable timings by typing /timings on" ); ++ return true; ++ } ++ long sampleTime = System.nanoTime() - timingStart; ++ // Spigot end + int index = 0; + int pluginIdx = 0; + File timingFolder = new File("timings"); +@@ -99,12 +126,15 @@ public class TimingsCommand extends BukkitCommand { + totalTime += time; + Event event = trl.getEvent(); + if (count > 0 && event != null) { +- fileTimings.println(" " + event.getClass().getSimpleName() + (trl.hasMultiple() ? " (and others)" : "") + " Time: " + time + " Count: " + count + " Avg: " + avg); ++ fileTimings.println(" " + event.getClass().getSimpleName() + (trl.hasMultiple() ? " (and others)" : "") + " Time: " + time + " Count: " + count + " Avg: " + avg + " Violations: " + trl.violations); // Spigot + } + } + } + fileTimings.println(" Total time " + totalTime + " (" + totalTime / 1000000000 + "s)"); + } ++ ++ // Spigot start ++ org.spigotmc.CustomTimingsHandler.printTimings(fileTimings); + fileTimings.println( "Sample time " + sampleTime + " (" + sampleTime / 1E9 + "s)" ); // Spigot + // Spigot start + if ( paste ) +@@ -114,6 +144,7 @@ public class TimingsCommand extends BukkitCommand { + } + // Spigot end + sender.sendMessage("Timings written to " + timings.getPath()); ++ sender.sendMessage( "Paste contents of file into form at http://aikar.co/timings.php to read results." ); + if (separate) sender.sendMessage("Names written to " + names.getPath()); + } catch (IOException e) { + } finally { +diff --git a/src/main/java/org/bukkit/plugin/TimedRegisteredListener.java b/src/main/java/org/bukkit/plugin/TimedRegisteredListener.java +index ed25e17..064a320 100644 +--- a/src/main/java/org/bukkit/plugin/TimedRegisteredListener.java ++++ b/src/main/java/org/bukkit/plugin/TimedRegisteredListener.java +@@ -11,6 +11,10 @@ import org.bukkit.event.Listener; + public class TimedRegisteredListener extends RegisteredListener { + private int count; + private long totalTime; ++ // Spigot start ++ public long curTickTotal = 0; ++ public long violations = 0; ++ // Spigot end + private Event event; + private boolean multiple = false; + +@@ -20,6 +24,13 @@ public class TimedRegisteredListener extends RegisteredListener { + + @Override + public void callEvent(Event event) throws EventException { ++ // Spigot start ++ if ( !org.bukkit.Bukkit.getServer().getPluginManager().useTimings() ) ++ { ++ super.callEvent( event ); ++ return; ++ } ++ // Spigot end + if (event.isAsynchronous()) { + super.callEvent(event); + return; +@@ -33,7 +44,11 @@ public class TimedRegisteredListener extends RegisteredListener { + } + long start = System.nanoTime(); + super.callEvent(event); +- totalTime += System.nanoTime() - start; ++ // Spigot start ++ long diff = System.nanoTime() - start; ++ curTickTotal += diff; ++ totalTime += diff; ++ // Spigot end + } + + /** +@@ -42,6 +57,10 @@ public class TimedRegisteredListener extends RegisteredListener { + public void reset() { + count = 0; + totalTime = 0; ++ // Spigot start ++ curTickTotal = 0; ++ violations = 0; ++ // Spigot end + } + + /** +diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +index ea30d83..d905435 100644 +--- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java ++++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java +@@ -430,7 +430,7 @@ public class JavaPluginLoader implements PluginLoader { + } + } + }; +- if (useTimings) { ++ if (true) { // Spigot - TRL handles useTimings check now + eventSet.add(new TimedRegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled())); + } else { + eventSet.add(new RegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled())); +diff --git a/src/main/java/org/spigotmc/CustomTimingsHandler.java b/src/main/java/org/spigotmc/CustomTimingsHandler.java +new file mode 100644 +index 0000000..fe6cb42 +--- /dev/null ++++ b/src/main/java/org/spigotmc/CustomTimingsHandler.java +@@ -0,0 +1,174 @@ ++package org.spigotmc; ++ ++import org.bukkit.event.HandlerList; ++import org.bukkit.plugin.Plugin; ++import org.bukkit.plugin.RegisteredListener; ++import org.bukkit.plugin.TimedRegisteredListener; ++import java.io.PrintStream; ++import java.util.Collection; ++import java.util.HashSet; ++import org.bukkit.Bukkit; ++import org.bukkit.World; ++ ++/** ++ * Provides custom timing sections for /timings merged. ++ */ ++public class CustomTimingsHandler ++{ ++ ++ private static final Collection ALL_HANDLERS = new HashSet(); ++ private static CustomTimingsHandler[] BAKED_HANDLERS; ++ /*========================================================================*/ ++ private final String name; ++ private final CustomTimingsHandler parent; ++ private long count = 0; ++ private long start = 0; ++ private long timingDepth = 0; ++ private long totalTime = 0; ++ private long curTickTotal = 0; ++ private long violations = 0; ++ ++ public CustomTimingsHandler(String name) ++ { ++ this( name, null ); ++ } ++ ++ public CustomTimingsHandler(String name, CustomTimingsHandler parent) ++ { ++ this.name = name; ++ this.parent = parent; ++ ALL_HANDLERS.add( this ); ++ BAKED_HANDLERS = ALL_HANDLERS.toArray( new CustomTimingsHandler[ ALL_HANDLERS.size() ] ); ++ } ++ ++ /** ++ * Prints the timings and extra data to the given stream. ++ * ++ * @param printStream ++ */ ++ public static void printTimings(PrintStream printStream) ++ { ++ printStream.println( "Minecraft" ); ++ for ( CustomTimingsHandler timings : BAKED_HANDLERS ) ++ { ++ long time = timings.totalTime; ++ long count = timings.count; ++ if ( count == 0 ) ++ { ++ continue; ++ } ++ long avg = time / count; ++ ++ printStream.println( " " + timings.name + " Time: " + time + " Count: " + count + " Avg: " + avg + " Violations: " + timings.violations ); ++ } ++ printStream.println( "# Version " + Bukkit.getVersion() ); ++ int entities = 0; ++ int livingEntities = 0; ++ for ( World world : Bukkit.getWorlds() ) ++ { ++ entities += world.getEntities().size(); ++ livingEntities += world.getLivingEntities().size(); ++ } ++ printStream.println( "# Entities " + entities ); ++ printStream.println( "# LivingEntities " + livingEntities ); ++ } ++ ++ /** ++ * Resets all timings. ++ */ ++ public static void reload() ++ { ++ if ( Bukkit.getPluginManager().useTimings() ) ++ { ++ for ( CustomTimingsHandler timings : BAKED_HANDLERS ) ++ { ++ timings.reset(); ++ } ++ } ++ } ++ ++ /** ++ * Ticked every tick by CraftBukkit to count the number of times a timer ++ * caused TPS loss. ++ */ ++ public static void tick() ++ { ++ if ( Bukkit.getPluginManager().useTimings() ) ++ { ++ for ( CustomTimingsHandler timings : BAKED_HANDLERS ) ++ { ++ if ( timings.curTickTotal > 50000000 ) ++ { ++ timings.violations += Math.ceil( timings.curTickTotal / 50000000 ); ++ } ++ timings.curTickTotal = 0; ++ } ++ ++ for ( Plugin plugin : Bukkit.getPluginManager().getPlugins() ) ++ { ++ for ( RegisteredListener listener : HandlerList.getRegisteredListeners( plugin ) ) ++ { ++ if ( listener instanceof TimedRegisteredListener ) ++ { ++ TimedRegisteredListener timings = (TimedRegisteredListener) listener; ++ if ( timings.curTickTotal > 50000000 ) ++ { ++ timings.violations += Math.ceil( timings.curTickTotal / 50000000 ); ++ } ++ timings.curTickTotal = 0; ++ } ++ } ++ } ++ } ++ } ++ ++ /** ++ * Starts timing to track a section of code. ++ */ ++ public void startTiming() ++ { ++ // If second condtion fails we are already timing ++ if ( Bukkit.getPluginManager().useTimings() && ++timingDepth != 1 ) ++ { ++ start = System.nanoTime(); ++ if ( parent != null && ++parent.timingDepth == 1 ) ++ { ++ parent.start = start; ++ } ++ } ++ } ++ ++ /** ++ * Stops timing a section of code. ++ */ ++ public void stopTiming() ++ { ++ if ( Bukkit.getPluginManager().useTimings() ) ++ { ++ if ( --timingDepth != 0 || start == 0 ) ++ { ++ return; ++ } ++ long diff = System.nanoTime() - start; ++ totalTime += diff; ++ curTickTotal += diff; ++ count++; ++ start = 0; ++ if ( parent != null ) ++ { ++ parent.stopTiming(); ++ } ++ } ++ } ++ ++ /** ++ * Reset this timer, setting all values to zero. ++ */ ++ public void reset() ++ { ++ count = 0; ++ violations = 0; ++ curTickTotal = 0; ++ totalTime = 0; ++ } ++} +-- +1.8.1.2 +