001 package org.bukkit.command.defaults; 002 003 import java.io.File; 004 import java.io.IOException; 005 import java.io.PrintStream; 006 import java.util.ArrayList; 007 import java.util.List; 008 009 import org.apache.commons.lang.Validate; 010 import org.bukkit.Bukkit; 011 import org.bukkit.ChatColor; 012 import org.bukkit.command.CommandSender; 013 import org.bukkit.event.Event; 014 import org.bukkit.event.HandlerList; 015 import org.bukkit.plugin.Plugin; 016 import org.bukkit.plugin.RegisteredListener; 017 import org.bukkit.plugin.TimedRegisteredListener; 018 import org.bukkit.util.StringUtil; 019 020 import com.google.common.collect.ImmutableList; 021 022 public class TimingsCommand extends BukkitCommand { 023 private static final List<String> TIMINGS_SUBCOMMANDS = ImmutableList.of("merged", "reset", "separate"); 024 025 public TimingsCommand(String name) { 026 super(name); 027 this.description = "Records timings for all plugin events"; 028 this.usageMessage = "/timings <reset|merged|separate>"; 029 this.setPermission("bukkit.command.timings"); 030 } 031 032 @Override 033 public boolean execute(CommandSender sender, String currentAlias, String[] args) { 034 if (!testPermission(sender)) return true; 035 if (args.length != 1) { 036 sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); 037 return false; 038 } 039 if (!sender.getServer().getPluginManager().useTimings()) { 040 sender.sendMessage("Please enable timings by setting \"settings.plugin-profiling\" to true in bukkit.yml"); 041 return true; 042 } 043 044 boolean separate = "separate".equals(args[0]); 045 if ("reset".equals(args[0])) { 046 for (HandlerList handlerList : HandlerList.getHandlerLists()) { 047 for (RegisteredListener listener : handlerList.getRegisteredListeners()) { 048 if (listener instanceof TimedRegisteredListener) { 049 ((TimedRegisteredListener)listener).reset(); 050 } 051 } 052 } 053 sender.sendMessage("Timings reset"); 054 } else if ("merged".equals(args[0]) || separate) { 055 056 int index = 0; 057 int pluginIdx = 0; 058 File timingFolder = new File("timings"); 059 timingFolder.mkdirs(); 060 File timings = new File(timingFolder, "timings.txt"); 061 File names = null; 062 while (timings.exists()) timings = new File(timingFolder, "timings" + (++index) + ".txt"); 063 PrintStream fileTimings = null; 064 PrintStream fileNames = null; 065 try { 066 fileTimings = new PrintStream(timings); 067 if (separate) { 068 names = new File(timingFolder, "names" + index + ".txt"); 069 fileNames = new PrintStream(names); 070 } 071 for (Plugin plugin : Bukkit.getPluginManager().getPlugins()) { 072 pluginIdx++; 073 long totalTime = 0; 074 if (separate) { 075 fileNames.println(pluginIdx + " " + plugin.getDescription().getFullName()); 076 fileTimings.println("Plugin " + pluginIdx); 077 } 078 else fileTimings.println(plugin.getDescription().getFullName()); 079 for (RegisteredListener listener : HandlerList.getRegisteredListeners(plugin)) { 080 if (listener instanceof TimedRegisteredListener) { 081 TimedRegisteredListener trl = (TimedRegisteredListener) listener; 082 long time = trl.getTotalTime(); 083 int count = trl.getCount(); 084 if (count == 0) continue; 085 long avg = time / count; 086 totalTime += time; 087 Class<? extends Event> eventClass = trl.getEventClass(); 088 if (count > 0 && eventClass != null) { 089 fileTimings.println(" " + eventClass.getSimpleName() + (trl.hasMultiple() ? " (and sub-classes)" : "") + " Time: " + time + " Count: " + count + " Avg: " + avg); 090 } 091 } 092 } 093 fileTimings.println(" Total time " + totalTime + " (" + totalTime / 1000000000 + "s)"); 094 } 095 sender.sendMessage("Timings written to " + timings.getPath()); 096 if (separate) sender.sendMessage("Names written to " + names.getPath()); 097 } catch (IOException e) { 098 } finally { 099 if (fileTimings != null) { 100 fileTimings.close(); 101 } 102 if (fileNames != null) { 103 fileNames.close(); 104 } 105 } 106 } 107 return true; 108 } 109 110 @Override 111 public List<String> tabComplete(CommandSender sender, String alias, String[] args) { 112 Validate.notNull(sender, "Sender cannot be null"); 113 Validate.notNull(args, "Arguments cannot be null"); 114 Validate.notNull(alias, "Alias cannot be null"); 115 116 if (args.length == 1) { 117 return StringUtil.copyPartialMatches(args[0], TIMINGS_SUBCOMMANDS, new ArrayList<String>(TIMINGS_SUBCOMMANDS.size())); 118 } 119 return ImmutableList.of(); 120 } 121 }