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 }