feat(client): show profiler handler details

This commit is contained in:
MoePus committed 2026-08-18 13:50:46 +09:00
1 parent 03bf028855
commit f8932a0ba4
6 files changed
+81 -27

No files matched your search

@@ -108,8 +108,9 @@ final class PerfReportRows {
String label = tickableLabel(entry);
String coordinate = tickablePosition(entry);
String prefix = coordinate.isEmpty() ? label : label.substring(0, label.length() - coordinate.length());
String tooltip = entry.type() == TickType.HANDLER ? entry.eventLoop() : null;
return Row.leaf(tickableKey(entry), prefix, coordinate, typeLabel(entry.type()),
0, 0, 0, entry.metric(), 0, teleportCommand(entry));
0, 0, 0, entry.metric(), 0, teleportCommand(entry), tooltip);
}
private static Row ownerSourceRow(String ownerKey, PerfReportData.OwnerSourceEntry entry) {
@@ -119,12 +120,18 @@ final class PerfReportRows {
}
private static String tickableLabel(PerfReportData.TickableEntry entry) {
if (entry.type() == TickType.HANDLER) {
return entry.className();
}
String name = PerfDisplayText.objectName(
entry.detailKind(), entry.className(), entry.detailId());
if (entry.type() == TickType.ENTITY) {
name += "#" + entry.entityId();
}
if (entry.type() == TickType.TASK) {
if (entry.eventLoop().isEmpty()) {
return PerfDisplayText.translated("screen.serverwarashi.profiler.tickable.unknown");
}
return name + " @ " + entry.eventLoop();
}
if (!entry.positioned()) {
@@ -148,6 +155,7 @@ final class PerfReportRows {
case ENTITY -> PerfDisplayText.translated("screen.serverwarashi.profiler.type.entity");
case BLOCK_ENTITY -> PerfDisplayText.translated("screen.serverwarashi.profiler.type.block_entity");
case TASK -> PerfDisplayText.translated("screen.serverwarashi.profiler.type.task");
case HANDLER -> PerfDisplayText.translated("screen.serverwarashi.profiler.type.handler");
};
}
@@ -208,6 +216,7 @@ final class PerfReportRows {
+ entry.z() + ":" + entry.className();
case CHUNK -> chunkKey(entry.dimension(), entry.x(), entry.z());
case TASK -> "task:" + entry.eventLoop() + ":" + entry.className();
case HANDLER -> "handler:" + entry.eventLoop();
};
}
@@ -266,25 +275,33 @@ final class PerfReportRows {
boolean expanded,
String expansionKey,
String teleportCommand,
boolean summary) {
boolean summary,
String tooltip) {
static Row leaf(String key, String labelPrefix, String coordinate, String type,
int entityCount, int blockEntityCount, int chunkCount,
PerfReportData.Metric metric, int depth, String teleportCommand) {
return leaf(key, labelPrefix, coordinate, type, entityCount, blockEntityCount,
chunkCount, metric, depth, teleportCommand, null);
}
static Row leaf(String key, String labelPrefix, String coordinate, String type,
int entityCount, int blockEntityCount, int chunkCount,
PerfReportData.Metric metric, int depth, String teleportCommand, String tooltip) {
return new Row(key, labelPrefix, coordinate, type, entityCount, blockEntityCount, chunkCount,
false, false, 0L, metric, depth, false, false, null, teleportCommand, false);
false, false, 0L, metric, depth, false, false, null, teleportCommand, false, tooltip);
}
static Row chunk(String key, String labelPrefix, String coordinate,
int entityCount, int blockEntityCount, PerfReportData.Metric metric,
String teleportCommand, boolean expandable, boolean expanded) {
return new Row(key, labelPrefix, coordinate, "", entityCount, blockEntityCount,
0, false, false, 0L, metric, 0, expandable, expanded, key, teleportCommand, false);
0, false, false, 0L, metric, 0, expandable, expanded, key, teleportCommand, false, null);
}
static Row summary(String key, String label, int entityCount, int blockEntityCount,
String coordinate, String teleportCommand) {
return new Row(key, label, coordinate, "", entityCount, blockEntityCount,
0, false, false, 0L, EMPTY_METRIC, 1, false, false, null, teleportCommand, true);
0, false, false, 0L, EMPTY_METRIC, 1, false, false, null, teleportCommand, true, null);
}
static Row owner(String key, String label, PerfReportData.OwnerEntry owner,
@@ -292,7 +309,7 @@ final class PerfReportRows {
boolean player = owner.kind() == PerfReportData.AttributionKind.PLAYER;
return new Row(key, label, positionText(owner.position()), "", 0, 0, owner.chunkCount(),
player, owner.online(), owner.lastLoginEpochMillis(), owner.metric(), 0,
expandable, expanded, key, PerfReportRows.teleportCommand(owner.position()), false);
expandable, expanded, key, PerfReportRows.teleportCommand(owner.position()), false, null);
}
String label() {
@@ -52,8 +52,9 @@ public final class PerfReportScreen extends Screen {
renderControls(graphics, geometry, mouseX, mouseY);
renderSummary(graphics, geometry);
renderTableHeader(graphics, geometry, mouseX, mouseY);
renderRows(graphics, geometry, rows, mouseX, mouseY);
String tooltip = renderRows(graphics, geometry, rows, mouseX, mouseY);
renderScrollbar(graphics, geometry);
renderTooltip(graphics, tooltip, mouseX, mouseY);
}
@Override
@@ -193,20 +194,24 @@ public final class PerfReportScreen extends Screen {
}
private void renderSummary(GuiGraphics graphics, PerfReportGeometry geometry) {
String text = PerfDisplayText.translated("screen.serverwarashi.profiler.summary",
String key = selectedTab == Tab.TICKABLES
? "screen.serverwarashi.profiler.summary.tickables"
: "screen.serverwarashi.profiler.summary";
String text = PerfDisplayText.translated(key,
String.format(Locale.ROOT, "%.2f", report.serverMspt()),
String.format(Locale.ROOT, "%.1f", report.elapsedMillis() / 1000.0),
String.format(Locale.ROOT, "%,d", report.tickCount()), report.intervalMicros(),
String.format(Locale.ROOT, "%,d", omittedForTab()));
String.format(Locale.ROOT, "%,d", omittedForTab()), report.lastTickGcMillis());
int y = geometry.panelY() + TITLE_HEIGHT + CONTROLS_HEIGHT + 3;
graphics.drawString(font, fit(font, text, geometry.contentWidth()), geometry.contentX(), y, MUTED, true);
}
private void renderRows(GuiGraphics graphics,
PerfReportGeometry geometry,
List<PerfReportRows.Row> rows,
int mouseX,
int mouseY) {
private String renderRows(GuiGraphics graphics,
PerfReportGeometry geometry,
List<PerfReportRows.Row> rows,
int mouseX,
int mouseY) {
String tooltip = null;
graphics.enableScissor(geometry.contentX(), geometry.rowsY(), geometry.contentRight(), geometry.rowsBottom());
int y = geometry.rowsY() - state().scroll;
if (rows.isEmpty()) {
@@ -214,31 +219,46 @@ public final class PerfReportScreen extends Screen {
geometry.contentX() + 2, y + 3, MUTED, true);
}
for (int index = 0; index < rows.size(); index++) {
renderRow(graphics, geometry, rows.get(index), index, y, mouseX, mouseY);
String rowTooltip = renderRow(graphics, geometry, rows.get(index), index, y, mouseX, mouseY);
if (rowTooltip != null) {
tooltip = rowTooltip;
}
y += ROW_HEIGHT;
}
graphics.disableScissor();
return tooltip;
}
private void renderRow(GuiGraphics graphics,
PerfReportGeometry geometry,
PerfReportRows.Row row,
int index,
int y,
int mouseX,
int mouseY) {
private String renderRow(GuiGraphics graphics,
PerfReportGeometry geometry,
PerfReportRows.Row row,
int index,
int y,
int mouseX,
int mouseY) {
if (y + ROW_HEIGHT <= geometry.rowsY() || y >= geometry.rowsBottom()) {
return;
return null;
}
var context = new PerfReportTableRenderer.RowContext(tableContext(geometry), row, y);
List<Hit> rowHits = rowHits(row, geometry, y);
boolean hovered = rowHits.stream().anyMatch(hit -> hit.contains(mouseX, mouseY));
boolean tooltipHovered = row.tooltip() != null
&& PerfReportTableRenderer.labelBounds(font, context).contains(mouseX, mouseY);
boolean hovered = tooltipHovered || rowHits.stream().anyMatch(hit -> hit.contains(mouseX, mouseY));
if (hovered || index % 2 == 0) {
graphics.fill(geometry.contentX(), y, geometry.contentRight(), y + ROW_HEIGHT,
hovered ? HOVER : ROW_ALT);
}
PerfReportTableRenderer.renderRow(graphics, font,
new PerfReportTableRenderer.RowContext(tableContext(geometry), row, y));
PerfReportTableRenderer.renderRow(graphics, font, context);
hits.addAll(rowHits);
return tooltipHovered ? row.tooltip() : null;
}
private void renderTooltip(GuiGraphics graphics, String tooltip, int mouseX, int mouseY) {
if (tooltip == null) {
return;
}
int tooltipWidth = Math.max(1, Math.min(TOOLTIP_MAX_WIDTH, width - TOOLTIP_MARGIN));
graphics.renderTooltip(font, font.split(Component.literal(tooltip), tooltipWidth), mouseX, mouseY);
}
private List<Hit> rowHits(PerfReportRows.Row row, PerfReportGeometry geometry, int y) {
@@ -14,10 +14,12 @@ final class PerfReportStyle {
static final int SCROLLBAR_WIDTH = 4;
static final int TAB_WIDTH = 72;
static final int PAGE_BUTTON_WIDTH = 20;
static final int SESSION_BUTTON_WIDTH = 48;
static final int SESSION_BUTTON_WIDTH = 64;
static final int CONTROL_HEIGHT = 16;
static final int GAP = 3;
static final int INDENT = 12;
static final int TOOLTIP_MAX_WIDTH = 320;
static final int TOOLTIP_MARGIN = 24;
static final int BACKDROP = 0xC0101012;
static final int PANEL = 0xFF161719;
@@ -90,6 +90,15 @@ final class PerfReportTableRenderer {
return new PerfReportBounds(x, context.y, font.width(coordinate), ROW_HEIGHT);
}
static PerfReportBounds labelBounds(Font font, RowContext context) {
int labelWidth = labelWidth(context.table);
int x = context.table.geometry.contentX() + context.row.depth() * INDENT;
int width = Math.max(1, labelWidth - context.row.depth() * INDENT);
String marker = context.row.expandable() ? (context.row.expanded() ? "[-] " : "[+] ") : "";
String label = fit(font, marker + context.row.labelPrefix(), width);
return new PerfReportBounds(x, context.y, font.width(label), ROW_HEIGHT);
}
private static void renderLabel(GuiGraphics graphics, Font font, RowContext context, int labelWidth) {
int x = context.table.geometry.contentX() + context.row.depth() * INDENT;
int width = labelWidth - context.row.depth() * INDENT;
@@ -9,6 +9,7 @@
"screen.serverwarashi.profiler.game_paused_tooltip": "The current map screen pauses singleplayer, so performance data cannot be collected while it is open. Close the map to start collecting.",
"screen.serverwarashi.profiler.page": "Page %1$s/%2$s",
"screen.serverwarashi.profiler.summary": "Server %1$s MSPT | %2$ss | %3$s ticks | %4$sus | omitted %5$s",
"screen.serverwarashi.profiler.summary.tickables": "Server %1$s MSPT | Previous tick GC %6$s ms | %2$ss | %3$s ticks | %4$sus | omitted %5$s",
"screen.serverwarashi.profiler.no_data": "No data",
"screen.serverwarashi.profiler.tab.chunks": "Chunks",
"screen.serverwarashi.profiler.tab.tickables": "Tickables",
@@ -24,6 +25,8 @@
"screen.serverwarashi.profiler.type.entity": "Entity",
"screen.serverwarashi.profiler.type.block_entity": "Block Entity",
"screen.serverwarashi.profiler.type.task": "Task",
"screen.serverwarashi.profiler.type.handler": "Handler",
"screen.serverwarashi.profiler.tickable.unknown": "Unknown",
"screen.serverwarashi.profiler.owner.system": "System (system)",
"screen.serverwarashi.profiler.owner.unknown": "Unknown (unknown)",
"screen.serverwarashi.profiler.source.self": "Self",
@@ -9,6 +9,7 @@
"screen.serverwarashi.profiler.game_paused_tooltip": "当前地图界面会暂停单人游戏,无法在地图打开时采集性能数据。你需要关闭地图才能正常采集。",
"screen.serverwarashi.profiler.page": "第 %1$s/%2$s 页",
"screen.serverwarashi.profiler.summary": "服务器 %1$s MSPT | %2$s 秒 | %3$s tick | %4$s 微秒 | 省略 %5$s",
"screen.serverwarashi.profiler.summary.tickables": "服务器 %1$s MSPT | 上一 tick GC %6$s 毫秒 | %2$s 秒 | %3$s tick | %4$s 微秒 | 省略 %5$s",
"screen.serverwarashi.profiler.no_data": "暂无数据",
"screen.serverwarashi.profiler.tab.chunks": "区块",
"screen.serverwarashi.profiler.tab.tickables": "Tick 对象",
@@ -24,6 +25,8 @@
"screen.serverwarashi.profiler.type.entity": "实体",
"screen.serverwarashi.profiler.type.block_entity": "方块实体",
"screen.serverwarashi.profiler.type.task": "任务",
"screen.serverwarashi.profiler.type.handler": "处理器",
"screen.serverwarashi.profiler.tickable.unknown": "未知",
"screen.serverwarashi.profiler.owner.system": "系统",
"screen.serverwarashi.profiler.owner.unknown": "未知",
"screen.serverwarashi.profiler.source.self": "自身",