FilledProfileResults.java

net.minecraft.util.profiling.FilledProfileResults

信息

  • 全限定名:net.minecraft.util.profiling.FilledProfileResults
  • 类型:public class
  • 包:net.minecraft.util.profiling
  • 源码路径:src/main/java/net/minecraft/util/profiling/FilledProfileResults.java
  • 起始行号:L26
  • 实现:ProfileResults
  • 职责:

    TODO

字段/常量

  • LOGGER

    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L27
    • 说明:

      TODO

  • EMPTY

    • 类型: ProfilerPathEntry
    • 修饰符: private static final public public public public
    • 源码定位: L28
    • 说明:

      TODO

  • SPLITTER

    • 类型: Splitter
    • 修饰符: private static final
    • 源码定位: L49
    • 说明:

      TODO

  • COUNTER_ENTRY_COMPARATOR

    • 类型: Comparator<Entry<String,FilledProfileResults.CounterCollector>>
    • 修饰符: private static final
    • 源码定位: L50
    • 说明:

      TODO

  • entries

    • 类型: Map<String,?extends ProfilerPathEntry>
    • 修饰符: private final
    • 源码定位: L54
    • 说明:

      TODO

  • startTimeNano

    • 类型: long
    • 修饰符: private final
    • 源码定位: L55
    • 说明:

      TODO

  • startTimeTicks

    • 类型: int
    • 修饰符: private final
    • 源码定位: L56
    • 说明:

      TODO

  • endTimeNano

    • 类型: long
    • 修饰符: private final
    • 源码定位: L57
    • 说明:

      TODO

  • endTimeTicks

    • 类型: int
    • 修饰符: private final
    • 源码定位: L58
    • 说明:

      TODO

  • tickDuration

    • 类型: int
    • 修饰符: private final
    • 源码定位: L59
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.util.profiling.FilledProfileResults.CounterCollector
    • 类型: class
    • 修饰符: private static
    • 源码定位: L301
    • 说明:

      TODO

构造器

public FilledProfileResults(Map<String,?extends ProfilerPathEntry> entries, long startTimeNano, int startTimeTicks, long endTimeNano, int endTimeTicks) @ L61

  • 构造器名:FilledProfileResults
  • 源码定位:L61
  • 修饰符:public

参数:

  • entries: Map<String,?extends ProfilerPathEntry>
  • startTimeNano: long
  • startTimeTicks: int
  • endTimeNano: long
  • endTimeTicks: int

说明:

TODO

方法

下面的方法块按源码顺序生成。

private ProfilerPathEntry getEntry(String path) @ L70

  • 方法名:getEntry
  • 源码定位:L70
  • 返回类型:ProfilerPathEntry
  • 修饰符:private

参数:

  • path: String

说明:

TODO

public List<ResultField> getTimes(String path) @ L75

  • 方法名:getTimes
  • 源码定位:L75
  • 返回类型:List
  • 修饰符:public

参数:

  • path: String

说明:

TODO

private static boolean isDirectChild(String path, String test) @ L127

  • 方法名:isDirectChild
  • 源码定位:L127
  • 返回类型:boolean
  • 修饰符:private static

参数:

  • path: String
  • test: String

说明:

TODO

private Map<String,FilledProfileResults.CounterCollector> getCounterValues() @ L131

  • 方法名:getCounterValues
  • 源码定位:L131
  • 返回类型:Map<String,FilledProfileResults.CounterCollector>
  • 修饰符:private

参数:

说明:

TODO

public long getStartTimeNano() @ L149

  • 方法名:getStartTimeNano
  • 源码定位:L149
  • 返回类型:long
  • 修饰符:public

参数:

说明:

TODO

public int getStartTimeTicks() @ L154

  • 方法名:getStartTimeTicks
  • 源码定位:L154
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public long getEndTimeNano() @ L159

  • 方法名:getEndTimeNano
  • 源码定位:L159
  • 返回类型:long
  • 修饰符:public

参数:

说明:

TODO

public int getEndTimeTicks() @ L164

  • 方法名:getEndTimeTicks
  • 源码定位:L164
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

public boolean saveResults(Path file) @ L169

  • 方法名:saveResults
  • 源码定位:L169
  • 返回类型:boolean
  • 修饰符:public

参数:

  • file: Path

说明:

TODO

protected String getProfilerResults(long timespan, int tickspan) @ L189

  • 方法名:getProfilerResults
  • 源码定位:L189
  • 返回类型:String
  • 修饰符:protected

参数:

  • timespan: long
  • tickspan: int

说明:

TODO

public String getProfilerResults() @ L213

  • 方法名:getProfilerResults
  • 源码定位:L213
  • 返回类型:String
  • 修饰符:public

参数:

说明:

TODO

private static StringBuilder indentLine(StringBuilder builder, int depth) @ L220

  • 方法名:indentLine
  • 源码定位:L220
  • 返回类型:StringBuilder
  • 修饰符:private static

参数:

  • builder: StringBuilder
  • depth: int

说明:

TODO

private void appendProfilerResults(int depth, String path, StringBuilder builder) @ L230

  • 方法名:appendProfilerResults
  • 源码定位:L230
  • 返回类型:void
  • 修饰符:private

参数:

  • depth: int
  • path: String
  • builder: StringBuilder

说明:

TODO

private void appendCounterResults(int depth, String name, FilledProfileResults.CounterCollector result, int tickspan, StringBuilder builder) @ L269

  • 方法名:appendCounterResults
  • 源码定位:L269
  • 返回类型:void
  • 修饰符:private

参数:

  • depth: int
  • name: String
  • result: FilledProfileResults.CounterCollector
  • tickspan: int
  • builder: StringBuilder

说明:

TODO

private void appendCounters(Map<String,FilledProfileResults.CounterCollector> counters, StringBuilder builder, int tickspan) @ L288

  • 方法名:appendCounters
  • 源码定位:L288
  • 返回类型:void
  • 修饰符:private

参数:

  • counters: Map<String,FilledProfileResults.CounterCollector>
  • builder: StringBuilder
  • tickspan: int

说明:

TODO

public int getTickDuration() @ L296

  • 方法名:getTickDuration
  • 源码定位:L296
  • 返回类型:int
  • 修饰符:public

参数:

说明:

TODO

代码

public class FilledProfileResults implements ProfileResults {
    private static final Logger LOGGER = LogUtils.getLogger();
    private static final ProfilerPathEntry EMPTY = new ProfilerPathEntry() {
        @Override
        public long getDuration() {
            return 0L;
        }
 
        @Override
        public long getMaxDuration() {
            return 0L;
        }
 
        @Override
        public long getCount() {
            return 0L;
        }
 
        @Override
        public Object2LongMap<String> getCounters() {
            return Object2LongMaps.emptyMap();
        }
    };
    private static final Splitter SPLITTER = Splitter.on('\u001e');
    private static final Comparator<Entry<String, FilledProfileResults.CounterCollector>> COUNTER_ENTRY_COMPARATOR = Entry.<String, FilledProfileResults.CounterCollector>comparingByValue(
            Comparator.comparingLong(c -> c.totalValue)
        )
        .reversed();
    private final Map<String, ? extends ProfilerPathEntry> entries;
    private final long startTimeNano;
    private final int startTimeTicks;
    private final long endTimeNano;
    private final int endTimeTicks;
    private final int tickDuration;
 
    public FilledProfileResults(Map<String, ? extends ProfilerPathEntry> entries, long startTimeNano, int startTimeTicks, long endTimeNano, int endTimeTicks) {
        this.entries = entries;
        this.startTimeNano = startTimeNano;
        this.startTimeTicks = startTimeTicks;
        this.endTimeNano = endTimeNano;
        this.endTimeTicks = endTimeTicks;
        this.tickDuration = endTimeTicks - startTimeTicks;
    }
 
    private ProfilerPathEntry getEntry(String path) {
        ProfilerPathEntry result = this.entries.get(path);
        return result != null ? result : EMPTY;
    }
 
    @Override
    public List<ResultField> getTimes(String path) {
        String rawPath = path;
        ProfilerPathEntry rootEntry = this.getEntry("root");
        long globalTime = rootEntry.getDuration();
        ProfilerPathEntry currentEntry = this.getEntry(path);
        long selfTime = currentEntry.getDuration();
        long selfCount = currentEntry.getCount();
        List<ResultField> result = Lists.newArrayList();
        if (!path.isEmpty()) {
            path = path + "\u001e";
        }
 
        long totalTime = 0L;
 
        for (String key : this.entries.keySet()) {
            if (isDirectChild(path, key)) {
                totalTime += this.getEntry(key).getDuration();
            }
        }
 
        float oldTime = (float)totalTime;
        if (totalTime < selfTime) {
            totalTime = selfTime;
        }
 
        if (globalTime < totalTime) {
            globalTime = totalTime;
        }
 
        for (String keyx : this.entries.keySet()) {
            if (isDirectChild(path, keyx)) {
                ProfilerPathEntry entry = this.getEntry(keyx);
                long time = entry.getDuration();
                double timePercentage = time * 100.0 / totalTime;
                double globalPercentage = time * 100.0 / globalTime;
                String name = keyx.substring(path.length());
                result.add(new ResultField(name, timePercentage, globalPercentage, entry.getCount()));
            }
        }
 
        if ((float)totalTime > oldTime) {
            result.add(
                new ResultField("unspecified", ((float)totalTime - oldTime) * 100.0 / totalTime, ((float)totalTime - oldTime) * 100.0 / globalTime, selfCount)
            );
        }
 
        Collections.sort(result);
        result.add(0, new ResultField(rawPath, 100.0, totalTime * 100.0 / globalTime, selfCount));
        return result;
    }
 
    private static boolean isDirectChild(String path, String test) {
        return test.length() > path.length() && test.startsWith(path) && test.indexOf(30, path.length() + 1) < 0;
    }
 
    private Map<String, FilledProfileResults.CounterCollector> getCounterValues() {
        Map<String, FilledProfileResults.CounterCollector> result = Maps.newTreeMap();
        this.entries
            .forEach(
                (path, entry) -> {
                    Object2LongMap<String> counters = entry.getCounters();
                    if (!counters.isEmpty()) {
                        List<String> pathSegments = SPLITTER.splitToList(path);
                        counters.forEach(
                            (counter, value) -> result.computeIfAbsent(counter, k -> new FilledProfileResults.CounterCollector())
                                .addValue(pathSegments.iterator(), value)
                        );
                    }
                }
            );
        return result;
    }
 
    @Override
    public long getStartTimeNano() {
        return this.startTimeNano;
    }
 
    @Override
    public int getStartTimeTicks() {
        return this.startTimeTicks;
    }
 
    @Override
    public long getEndTimeNano() {
        return this.endTimeNano;
    }
 
    @Override
    public int getEndTimeTicks() {
        return this.endTimeTicks;
    }
 
    @Override
    public boolean saveResults(Path file) {
        Writer writer = null;
 
        boolean var4;
        try {
            Files.createDirectories(file.getParent());
            writer = Files.newBufferedWriter(file, StandardCharsets.UTF_8);
            writer.write(this.getProfilerResults(this.getNanoDuration(), this.getTickDuration()));
            return true;
        } catch (Throwable var8) {
            LOGGER.error("Could not save profiler results to {}", file, var8);
            var4 = false;
        } finally {
            IOUtils.closeQuietly(writer);
        }
 
        return var4;
    }
 
    protected String getProfilerResults(long timespan, int tickspan) {
        StringBuilder builder = new StringBuilder();
        ReportType.PROFILE.appendHeader(builder, List.of());
        builder.append("Version: ").append(SharedConstants.getCurrentVersion().id()).append('\n');
        builder.append("Time span: ").append(timespan / 1000000L).append(" ms\n");
        builder.append("Tick span: ").append(tickspan).append(" ticks\n");
        builder.append("// This is approximately ")
            .append(String.format(Locale.ROOT, "%.2f", tickspan / ((float)timespan / 1.0E9F)))
            .append(" ticks per second. It should be ")
            .append(20)
            .append(" ticks per second\n\n");
        builder.append("--- BEGIN PROFILE DUMP ---\n\n");
        this.appendProfilerResults(0, "root", builder);
        builder.append("--- END PROFILE DUMP ---\n\n");
        Map<String, FilledProfileResults.CounterCollector> counters = this.getCounterValues();
        if (!counters.isEmpty()) {
            builder.append("--- BEGIN COUNTER DUMP ---\n\n");
            this.appendCounters(counters, builder, tickspan);
            builder.append("--- END COUNTER DUMP ---\n\n");
        }
 
        return builder.toString();
    }
 
    @Override
    public String getProfilerResults() {
        StringBuilder builder = new StringBuilder();
        this.appendProfilerResults(0, "root", builder);
        return builder.toString();
    }
 
    private static StringBuilder indentLine(StringBuilder builder, int depth) {
        builder.append(String.format(Locale.ROOT, "[%02d] ", depth));
 
        for (int j = 0; j < depth; j++) {
            builder.append("|   ");
        }
 
        return builder;
    }
 
    private void appendProfilerResults(int depth, String path, StringBuilder builder) {
        List<ResultField> results = this.getTimes(path);
        Object2LongMap<String> counters = ObjectUtils.firstNonNull(this.entries.get(path), EMPTY).getCounters();
        counters.forEach(
            (id, value) -> indentLine(builder, depth)
                .append('#')
                .append(id)
                .append(' ')
                .append(value)
                .append('/')
                .append(value / this.tickDuration)
                .append('\n')
        );
        if (results.size() >= 3) {
            for (int i = 1; i < results.size(); i++) {
                ResultField result = results.get(i);
                indentLine(builder, depth)
                    .append(result.name)
                    .append('(')
                    .append(result.count)
                    .append('/')
                    .append(String.format(Locale.ROOT, "%.0f", (float)result.count / this.tickDuration))
                    .append(')')
                    .append(" - ")
                    .append(String.format(Locale.ROOT, "%.2f", result.percentage))
                    .append("%/")
                    .append(String.format(Locale.ROOT, "%.2f", result.globalPercentage))
                    .append("%\n");
                if (!"unspecified".equals(result.name)) {
                    try {
                        this.appendProfilerResults(depth + 1, path + "\u001e" + result.name, builder);
                    } catch (Exception var9) {
                        builder.append("[[ EXCEPTION ").append(var9).append(" ]]");
                    }
                }
            }
        }
    }
 
    private void appendCounterResults(int depth, String name, FilledProfileResults.CounterCollector result, int tickspan, StringBuilder builder) {
        indentLine(builder, depth)
            .append(name)
            .append(" total:")
            .append(result.selfValue)
            .append('/')
            .append(result.totalValue)
            .append(" average: ")
            .append(result.selfValue / tickspan)
            .append('/')
            .append(result.totalValue / tickspan)
            .append('\n');
        result.children
            .entrySet()
            .stream()
            .sorted(COUNTER_ENTRY_COMPARATOR)
            .forEach(e -> this.appendCounterResults(depth + 1, e.getKey(), e.getValue(), tickspan, builder));
    }
 
    private void appendCounters(Map<String, FilledProfileResults.CounterCollector> counters, StringBuilder builder, int tickspan) {
        counters.forEach((counter, counterRoot) -> {
            builder.append("-- Counter: ").append(counter).append(" --\n");
            this.appendCounterResults(0, "root", counterRoot.children.get("root"), tickspan, builder);
            builder.append("\n\n");
        });
    }
 
    @Override
    public int getTickDuration() {
        return this.tickDuration;
    }
 
    private static class CounterCollector {
        private long selfValue;
        private long totalValue;
        private final Map<String, FilledProfileResults.CounterCollector> children = Maps.newHashMap();
 
        public void addValue(Iterator<String> path, long value) {
            this.totalValue += value;
            if (!path.hasNext()) {
                this.selfValue += value;
            } else {
                this.children.computeIfAbsent(path.next(), k -> new FilledProfileResults.CounterCollector()).addValue(path, value);
            }
        }
    }
}

引用的其他类

  • SharedConstants

    • 引用位置: 方法调用
    • 关联成员: SharedConstants.getCurrentVersion()
  • ProfileResults

    • 引用位置: 实现
  • ProfilerPathEntry

    • 引用位置: 参数/字段/构造调用/返回值
    • 关联成员: ProfilerPathEntry()
  • ResultField

    • 引用位置: 构造调用/返回值
    • 关联成员: ResultField()