/** * Builds an XML report of the timings to be uploaded for parsing. * * @param sender Who to report to */ static void reportTimings(CommandSource sender) { Platform platform = SpongeImpl.getGame().getPlatform(); JsonObjectBuilder builder = JSONUtil.objectBuilder() // Get some basic system details about the server .add( "version", platform .getImplementation() .getVersion() .orElse(platform.getMinecraftVersion().getName() + "-DEV")) .add("maxplayers", SpongeImpl.getGame().getServer().getMaxPlayers()) .add("start", TimingsManager.timingStart / 1000) .add("end", System.currentTimeMillis() / 1000) .add("sampletime", (System.currentTimeMillis() - TimingsManager.timingStart) / 1000); if (!TimingsManager.privacy) { builder .add("server", getServerName()) .add("motd", SpongeImpl.getGame().getServer().getMotd().toPlain()) .add("online-mode", SpongeImpl.getGame().getServer().getOnlineMode()) .add("icon", MinecraftServer.getServer().getServerStatusResponse().getFavicon()); } final Runtime runtime = Runtime.getRuntime(); RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean(); builder.add( "system", JSONUtil.objectBuilder() .add("timingcost", getCost()) .add("name", System.getProperty("os.name")) .add("version", System.getProperty("os.version")) .add("jvmversion", System.getProperty("java.version")) .add("arch", System.getProperty("os.arch")) .add("maxmem", runtime.maxMemory()) .add("cpu", runtime.availableProcessors()) .add("runtime", ManagementFactory.getRuntimeMXBean().getUptime()) .add("flags", RUNTIME_FLAG_JOINER.join(runtimeBean.getInputArguments())) .add( "gc", JSONUtil.mapArrayToObject( ManagementFactory.getGarbageCollectorMXBeans(), (input) -> { return JSONUtil.singleObjectPair( input.getName(), JSONUtil.arrayOf(input.getCollectionCount(), input.getCollectionTime())); }))); Set<BlockType> blockTypeSet = Sets.newHashSet(); Set<EntityType> entityTypeSet = Sets.newHashSet(); int size = HISTORY.size(); TimingHistory[] history = new TimingHistory[size + 1]; int i = 0; for (TimingHistory timingHistory : HISTORY) { blockTypeSet.addAll(timingHistory.blockTypeSet); entityTypeSet.addAll(timingHistory.entityTypeSet); history[i++] = timingHistory; } history[i] = new TimingHistory(); // Current snapshot blockTypeSet.addAll(history[i].blockTypeSet); entityTypeSet.addAll(history[i].entityTypeSet); JsonObjectBuilder handlersBuilder = JSONUtil.objectBuilder(); for (TimingIdentifier.TimingGroup group : TimingIdentifier.GROUP_MAP.values()) { for (TimingHandler id : group.handlers) { if (!id.timed && !id.isSpecial()) { continue; } handlersBuilder.add(id.id, JSONUtil.arrayOf(group.id, id.name)); } } builder.add( "idmap", JSONUtil.objectBuilder() .add( "groups", JSONUtil.mapArrayToObject( TimingIdentifier.GROUP_MAP.values(), (group) -> { return JSONUtil.singleObjectPair(group.id, group.name); })) .add("handlers", handlersBuilder) .add( "worlds", JSONUtil.mapArrayToObject( TimingHistory.worldMap.entrySet(), (entry) -> { return JSONUtil.singleObjectPair(entry.getValue(), entry.getKey()); })) .add( "tileentity", JSONUtil.mapArrayToObject( blockTypeSet, (blockType) -> { return JSONUtil.singleObjectPair( Block.getIdFromBlock((Block) blockType), blockType.getId()); })) .add( "entity", JSONUtil.mapArrayToObject( entityTypeSet, (entityType) -> { return JSONUtil.singleObjectPair( ((SpongeEntityType) entityType).entityTypeId, entityType.getId()); }))); // Information about loaded plugins builder.add( "plugins", JSONUtil.mapArrayToObject( SpongeImpl.getGame().getPluginManager().getPlugins(), (plugin) -> { return JSONUtil.objectBuilder() .add( plugin.getId(), JSONUtil.objectBuilder() .add("version", plugin.getVersion().orElse("")) .add("description", plugin.getDescription().orElse("")) .add("website", plugin.getUrl().orElse("")) .add("authors", AUTHOR_LIST_JOINER.join(plugin.getAuthors()))) .build(); })); // Information on the users Config builder.add( "config", JSONUtil.objectBuilder() .add("sponge", serializeConfigNode(SpongeImpl.getGlobalConfig().getRootNode()))); new TimingsExport(sender, builder.build(), history).start(); }
TimingHistory() { this.endTime = System.currentTimeMillis() / 1000; this.startTime = TimingsManager.historyStart / 1000; if (timedTicks % 1200 != 0 || MINUTE_REPORTS.isEmpty()) { this.minuteReports = MINUTE_REPORTS.toArray(new MinuteReport[MINUTE_REPORTS.size() + 1]); this.minuteReports[this.minuteReports.length - 1] = new MinuteReport(); } else { this.minuteReports = MINUTE_REPORTS.toArray(new MinuteReport[MINUTE_REPORTS.size()]); } long ticks = 0; for (MinuteReport mp : this.minuteReports) { ticks += mp.ticksRecord.timed; } this.totalTicks = ticks; this.totalTime = FULL_SERVER_TICK.record.totalTime; this.entries = new TimingHistoryEntry[TimingsManager.HANDLERS.size()]; int i = 0; for (TimingHandler handler : TimingsManager.HANDLERS) { this.entries[i++] = new TimingHistoryEntry(handler); } final Map<EntityType, Counter> entityCounts = MRUMapCache.of(LoadingMap.of(Maps.newHashMap(), Counter.loader())); final Map<BlockType, Counter> tileEntityCounts = MRUMapCache.of(LoadingMap.of(Maps.newHashMap(), Counter.loader())); // Information about all loaded chunks/entities this.worlds = JSONUtil.mapArrayToObject( SpongeImpl.getGame().getServer().getWorlds(), (world) -> { return JSONUtil.singleObjectPair( String.valueOf(worldMap.get(world.getName())), JSONUtil.mapArray( world.getLoadedChunks(), (chunk) -> { entityCounts.clear(); tileEntityCounts.clear(); for (Entity entity : chunk.getEntities()) { if (entity.getType() == null) { SpongeImpl.getLogger().error("Entity is not registered {}", entity); continue; } entityCounts.get(entity.getType()).increment(); } for (TileEntity tileEntity : chunk.getTileEntities()) { tileEntityCounts.get(tileEntity.getBlock().getType()).increment(); } if (tileEntityCounts.isEmpty() && entityCounts.isEmpty()) { return null; } return JSONUtil.arrayOf( chunk.getPosition().getX(), chunk.getPosition().getZ(), JSONUtil.mapArrayToObject( entityCounts.entrySet(), (entry) -> { if (entry.getKey() == EntityTypes.UNKNOWN) { return null; } this.entityTypeSet.add(entry.getKey()); return JSONUtil.singleObjectPair( ((SpongeEntityType) entry.getKey()).entityTypeId, entry.getValue().count()); }), JSONUtil.mapArrayToObject( tileEntityCounts.entrySet(), (entry) -> { this.blockTypeSet.add(entry.getKey()); return JSONUtil.singleObjectPair( Block.getIdFromBlock((Block) entry.getKey()), entry.getValue().count()); })); })); }); }