JfrProfiler.java

net.minecraft.util.profiling.jfr.JfrProfiler

信息

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

    TODO

字段/常量

  • LOGGER

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

      TODO

  • ROOT_CATEGORY

    • 类型: String
    • 修饰符: public static final
    • 源码定位: L57
    • 说明:

      TODO

  • WORLD_GEN_CATEGORY

    • 类型: String
    • 修饰符: public static final
    • 源码定位: L58
    • 说明:

      TODO

  • TICK_CATEGORY

    • 类型: String
    • 修饰符: public static final
    • 源码定位: L59
    • 说明:

      TODO

  • NETWORK_CATEGORY

    • 类型: String
    • 修饰符: public static final
    • 源码定位: L60
    • 说明:

      TODO

  • STORAGE_CATEGORY

    • 类型: String
    • 修饰符: public static final
    • 源码定位: L61
    • 说明:

      TODO

  • CUSTOM_EVENTS

    • 类型: List<Class<?extends Event>>
    • 修饰符: private static final
    • 源码定位: L62
    • 说明:

      TODO

  • FLIGHT_RECORDER_CONFIG

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

      TODO

  • DATE_TIME_FORMATTER

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

      TODO

  • INSTANCE

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

      TODO

  • recording

    • 类型: Recording
    • 修饰符: private
    • 源码定位: L80
    • 说明:

      TODO

  • currentFPS

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

      TODO

  • currentAverageTickTimeServer

    • 类型: float
    • 修饰符: private
    • 源码定位: L82
    • 说明:

      TODO

  • networkTrafficByAddress

    • 类型: Map<String,NetworkSummaryEvent.SumAggregation>
    • 修饰符: private final
    • 源码定位: L83
    • 说明:

      TODO

  • periodicClientFps

    • 类型: Runnable
    • 修饰符: private final
    • 源码定位: L84
    • 说明:

      TODO

  • periodicServerTickTime

    • 类型: Runnable
    • 修饰符: private final
    • 源码定位: L85
    • 说明:

      TODO

  • periodicNetworkSummary

    • 类型: Runnable
    • 修饰符: private final
    • 源码定位: L86
    • 说明:

      TODO

内部类/嵌套类型

构造器

private JfrProfiler() @ L95

  • 构造器名:JfrProfiler
  • 源码定位:L95
  • 修饰符:private

参数:

说明:

TODO

方法

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

private void registerPeriodicEvents() @ L117

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

参数:

说明:

TODO

private static void addPeriodicEvent(Class<?extends Event> eventClass, Runnable runnable) @ L123

  • 方法名:addPeriodicEvent
  • 源码定位:L123
  • 返回类型:void
  • 修饰符:private static

参数:

  • eventClass: Class<?extends Event>
  • runnable: Runnable

说明:

TODO

public static JfrProfiler getInstance() @ L128

  • 方法名:getInstance
  • 源码定位:L128
  • 返回类型:JfrProfiler
  • 修饰符:public static

参数:

说明:

TODO

public boolean start(Environment environment) @ L132

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

参数:

  • environment: Environment

说明:

TODO

public Path stop() @ L153

  • 方法名:stop
  • 源码定位:L153
  • 返回类型:Path
  • 修饰符:public

参数:

说明:

TODO

public boolean isRunning() @ L165

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

参数:

说明:

TODO

public boolean isAvailable() @ L170

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

参数:

说明:

TODO

private boolean start(Reader configurationFile, Environment environment) @ L175

  • 方法名:start
  • 源码定位:L175
  • 返回类型:boolean
  • 修饰符:private

参数:

  • configurationFile: Reader
  • environment: Environment

说明:

TODO

private void setupSummaryListener() @ L214

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

参数:

说明:

TODO

public void onClientTick(int fps) @ L240

  • 方法名:onClientTick
  • 源码定位:L240
  • 返回类型:void
  • 修饰符:public

参数:

  • fps: int

说明:

TODO

public void onServerTick(float currentAverageTickTime) @ L247

  • 方法名:onServerTick
  • 源码定位:L247
  • 返回类型:void
  • 修饰符:public

参数:

  • currentAverageTickTime: float

说明:

TODO

public void onPacketReceived(ConnectionProtocol protocol, PacketType<?> packetId, SocketAddress remoteAddress, int readableBytes) @ L254

  • 方法名:onPacketReceived
  • 源码定位:L254
  • 返回类型:void
  • 修饰符:public

参数:

  • protocol: ConnectionProtocol
  • packetId: PacketType<?>
  • remoteAddress: SocketAddress
  • readableBytes: int

说明:

TODO

public void onPacketSent(ConnectionProtocol protocol, PacketType<?> packetId, SocketAddress remoteAddress, int writtenBytes) @ L265

  • 方法名:onPacketSent
  • 源码定位:L265
  • 返回类型:void
  • 修饰符:public

参数:

  • protocol: ConnectionProtocol
  • packetId: PacketType<?>
  • remoteAddress: SocketAddress
  • writtenBytes: int

说明:

TODO

private NetworkSummaryEvent.SumAggregation networkStatFor(SocketAddress remoteAddress) @ L276

  • 方法名:networkStatFor
  • 源码定位:L276
  • 返回类型:NetworkSummaryEvent.SumAggregation
  • 修饰符:private

参数:

  • remoteAddress: SocketAddress

说明:

TODO

public void onRegionFileRead(RegionStorageInfo info, ChunkPos pos, RegionFileVersion version, int readBytes) @ L280

  • 方法名:onRegionFileRead
  • 源码定位:L280
  • 返回类型:void
  • 修饰符:public

参数:

  • info: RegionStorageInfo
  • pos: ChunkPos
  • version: RegionFileVersion
  • readBytes: int

说明:

TODO

public void onRegionFileWrite(RegionStorageInfo info, ChunkPos pos, RegionFileVersion version, int writtenBytes) @ L287

  • 方法名:onRegionFileWrite
  • 源码定位:L287
  • 返回类型:void
  • 修饰符:public

参数:

  • info: RegionStorageInfo
  • pos: ChunkPos
  • version: RegionFileVersion
  • writtenBytes: int

说明:

TODO

public ProfiledDuration onWorldLoadedStarted() @ L294

  • 方法名:onWorldLoadedStarted
  • 源码定位:L294
  • 返回类型:ProfiledDuration
  • 修饰符:public

参数:

说明:

TODO

public ProfiledDuration onChunkGenerate(ChunkPos pos, ResourceKey<Level> dimension, String name) @ L305

  • 方法名:onChunkGenerate
  • 源码定位:L305
  • 返回类型:ProfiledDuration
  • 修饰符:public

参数:

  • pos: ChunkPos
  • dimension: ResourceKey
  • name: String

说明:

TODO

public ProfiledDuration onStructureGenerate(ChunkPos sourceChunkPos, ResourceKey<Level> dimension, Holder<Structure> structure) @ L316

  • 方法名:onStructureGenerate
  • 源码定位:L316
  • 返回类型:ProfiledDuration
  • 修饰符:public

参数:

  • sourceChunkPos: ChunkPos
  • dimension: ResourceKey
  • structure: Holder

说明:

TODO

代码

public class JfrProfiler implements JvmProfiler {
    private static final Logger LOGGER = LogUtils.getLogger();
    public static final String ROOT_CATEGORY = "Minecraft";
    public static final String WORLD_GEN_CATEGORY = "World Generation";
    public static final String TICK_CATEGORY = "Ticking";
    public static final String NETWORK_CATEGORY = "Network";
    public static final String STORAGE_CATEGORY = "Storage";
    private static final List<Class<? extends Event>> CUSTOM_EVENTS = List.of(
        ChunkGenerationEvent.class,
        ChunkRegionReadEvent.class,
        ChunkRegionWriteEvent.class,
        PacketReceivedEvent.class,
        PacketSentEvent.class,
        NetworkSummaryEvent.class,
        ServerTickTimeEvent.class,
        ClientFpsEvent.class,
        StructureGenerationEvent.class,
        WorldLoadFinishedEvent.class
    );
    private static final String FLIGHT_RECORDER_CONFIG = "/flightrecorder-config.jfc";
    private static final DateTimeFormatter DATE_TIME_FORMATTER = new DateTimeFormatterBuilder()
        .appendPattern("yyyy-MM-dd-HHmmss")
        .toFormatter(Locale.ROOT)
        .withZone(ZoneId.systemDefault());
    private static final JfrProfiler INSTANCE = new JfrProfiler();
    private @Nullable Recording recording;
    private int currentFPS;
    private float currentAverageTickTimeServer;
    private final Map<String, NetworkSummaryEvent.SumAggregation> networkTrafficByAddress = new ConcurrentHashMap<>();
    private final Runnable periodicClientFps = () -> new ClientFpsEvent(this.currentFPS).commit();
    private final Runnable periodicServerTickTime = () -> new ServerTickTimeEvent(this.currentAverageTickTimeServer).commit();
    private final Runnable periodicNetworkSummary = () -> {
        Iterator<NetworkSummaryEvent.SumAggregation> iterator = this.networkTrafficByAddress.values().iterator();
 
        while (iterator.hasNext()) {
            iterator.next().commitEvent();
            iterator.remove();
        }
    };
 
    private JfrProfiler() {
        CUSTOM_EVENTS.forEach(FlightRecorder::register);
        this.registerPeriodicEvents();
        FlightRecorder.addListener(new FlightRecorderListener() {
            {
                Objects.requireNonNull(JfrProfiler.this);
            }
 
            @Override
            public void recordingStateChanged(Recording rec) {
                switch (rec.getState()) {
                    case STOPPED:
                        JfrProfiler.this.registerPeriodicEvents();
                    case NEW:
                    case DELAYED:
                    case RUNNING:
                    case CLOSED:
                }
            }
        });
    }
 
    private void registerPeriodicEvents() {
        addPeriodicEvent(ClientFpsEvent.class, this.periodicClientFps);
        addPeriodicEvent(ServerTickTimeEvent.class, this.periodicServerTickTime);
        addPeriodicEvent(NetworkSummaryEvent.class, this.periodicNetworkSummary);
    }
 
    private static void addPeriodicEvent(Class<? extends Event> eventClass, Runnable runnable) {
        FlightRecorder.removePeriodicEvent(runnable);
        FlightRecorder.addPeriodicEvent(eventClass, runnable);
    }
 
    public static JfrProfiler getInstance() {
        return INSTANCE;
    }
 
    @Override
    public boolean start(Environment environment) {
        URL resource = JfrProfiler.class.getResource("/flightrecorder-config.jfc");
        if (resource == null) {
            LOGGER.warn("Could not find default flight recorder config at {}", "/flightrecorder-config.jfc");
            return false;
        } else {
            try {
                boolean var4;
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.openStream(), StandardCharsets.UTF_8))) {
                    var4 = this.start(reader, environment);
                }
 
                return var4;
            } catch (IOException var8) {
                LOGGER.warn("Failed to start flight recorder using configuration at {}", resource, var8);
                return false;
            }
        }
    }
 
    @Override
    public Path stop() {
        if (this.recording == null) {
            throw new IllegalStateException("Not currently profiling");
        } else {
            this.networkTrafficByAddress.clear();
            Path report = this.recording.getDestination();
            this.recording.stop();
            return report;
        }
    }
 
    @Override
    public boolean isRunning() {
        return this.recording != null;
    }
 
    @Override
    public boolean isAvailable() {
        return FlightRecorder.isAvailable();
    }
 
    private boolean start(Reader configurationFile, Environment environment) {
        if (this.isRunning()) {
            LOGGER.warn("Profiling already in progress");
            return false;
        } else {
            try {
                Configuration jfrConfig = Configuration.create(configurationFile);
                String startTimestamp = DATE_TIME_FORMATTER.format(Instant.now());
                this.recording = Util.make(
                    new Recording(jfrConfig),
                    self -> {
                        CUSTOM_EVENTS.forEach(self::enable);
                        self.setDumpOnExit(true);
                        self.setToDisk(true);
                        self.setName(
                            String.format(Locale.ROOT, "%s-%s-%s", environment.getDescription(), SharedConstants.getCurrentVersion().name(), startTimestamp)
                        );
                    }
                );
                Path destination = Paths.get(String.format(Locale.ROOT, "debug/%s-%s.jfr", environment.getDescription(), startTimestamp));
                FileUtil.createDirectoriesSafe(destination.getParent());
                this.recording.setDestination(destination);
                this.recording.start();
                this.setupSummaryListener();
            } catch (ParseException | IOException var6) {
                LOGGER.warn("Failed to start jfr profiling", (Throwable)var6);
                return false;
            }
 
            LOGGER.info(
                "Started flight recorder profiling id({}):name({}) - will dump to {} on exit or stop command",
                this.recording.getId(),
                this.recording.getName(),
                this.recording.getDestination()
            );
            return true;
        }
    }
 
    private void setupSummaryListener() {
        FlightRecorder.addListener(new FlightRecorderListener() {
            final SummaryReporter summaryReporter;
 
            {
                Objects.requireNonNull(JfrProfiler.this);
                this.summaryReporter = new SummaryReporter(() -> JfrProfiler.this.recording = null);
            }
 
            @Override
            public void recordingStateChanged(Recording rec) {
                if (rec == JfrProfiler.this.recording) {
                    switch (rec.getState()) {
                        case STOPPED:
                            this.summaryReporter.recordingStopped(rec.getDestination());
                            FlightRecorder.removeListener(this);
                        case NEW:
                        case DELAYED:
                        case RUNNING:
                        case CLOSED:
                    }
                }
            }
        });
    }
 
    @Override
    public void onClientTick(int fps) {
        if (ClientFpsEvent.TYPE.isEnabled()) {
            this.currentFPS = fps;
        }
    }
 
    @Override
    public void onServerTick(float currentAverageTickTime) {
        if (ServerTickTimeEvent.TYPE.isEnabled()) {
            this.currentAverageTickTimeServer = currentAverageTickTime;
        }
    }
 
    @Override
    public void onPacketReceived(ConnectionProtocol protocol, PacketType<?> packetId, SocketAddress remoteAddress, int readableBytes) {
        if (PacketReceivedEvent.TYPE.isEnabled()) {
            new PacketReceivedEvent(protocol.id(), packetId.flow().id(), packetId.id().toString(), remoteAddress, readableBytes).commit();
        }
 
        if (NetworkSummaryEvent.TYPE.isEnabled()) {
            this.networkStatFor(remoteAddress).trackReceivedPacket(readableBytes);
        }
    }
 
    @Override
    public void onPacketSent(ConnectionProtocol protocol, PacketType<?> packetId, SocketAddress remoteAddress, int writtenBytes) {
        if (PacketSentEvent.TYPE.isEnabled()) {
            new PacketSentEvent(protocol.id(), packetId.flow().id(), packetId.id().toString(), remoteAddress, writtenBytes).commit();
        }
 
        if (NetworkSummaryEvent.TYPE.isEnabled()) {
            this.networkStatFor(remoteAddress).trackSentPacket(writtenBytes);
        }
    }
 
    private NetworkSummaryEvent.SumAggregation networkStatFor(SocketAddress remoteAddress) {
        return this.networkTrafficByAddress.computeIfAbsent(remoteAddress.toString(), NetworkSummaryEvent.SumAggregation::new);
    }
 
    @Override
    public void onRegionFileRead(RegionStorageInfo info, ChunkPos pos, RegionFileVersion version, int readBytes) {
        if (ChunkRegionReadEvent.TYPE.isEnabled()) {
            new ChunkRegionReadEvent(info, pos, version, readBytes).commit();
        }
    }
 
    @Override
    public void onRegionFileWrite(RegionStorageInfo info, ChunkPos pos, RegionFileVersion version, int writtenBytes) {
        if (ChunkRegionWriteEvent.TYPE.isEnabled()) {
            new ChunkRegionWriteEvent(info, pos, version, writtenBytes).commit();
        }
    }
 
    @Override
    public @Nullable ProfiledDuration onWorldLoadedStarted() {
        if (!WorldLoadFinishedEvent.TYPE.isEnabled()) {
            return null;
        } else {
            WorldLoadFinishedEvent event = new WorldLoadFinishedEvent();
            event.begin();
            return ignored -> event.commit();
        }
    }
 
    @Override
    public @Nullable ProfiledDuration onChunkGenerate(ChunkPos pos, ResourceKey<Level> dimension, String name) {
        if (!ChunkGenerationEvent.TYPE.isEnabled()) {
            return null;
        } else {
            ChunkGenerationEvent event = new ChunkGenerationEvent(pos, dimension, name);
            event.begin();
            return ignored -> event.commit();
        }
    }
 
    @Override
    public @Nullable ProfiledDuration onStructureGenerate(ChunkPos sourceChunkPos, ResourceKey<Level> dimension, Holder<Structure> structure) {
        if (!StructureGenerationEvent.TYPE.isEnabled()) {
            return null;
        } else {
            StructureGenerationEvent event = new StructureGenerationEvent(sourceChunkPos, structure, dimension);
            event.begin();
            return success -> {
                event.success = success;
                event.commit();
            };
        }
    }
}

引用的其他类