线程分组与导出

基本信息

属性 值
分组器 me.lucko.spark.common.sampler.ThreadGrouper
导出器 me.lucko.spark.common.sampler.ThreadDumper
相关配置 backgroundProfilerThreadGrouper、backgroundProfilerThreadDumper

采样器采集到的是「一堆线程各自的时间」,需要两步加工才有意义:ThreadDumper 决定采哪些线程,ThreadGrouper 决定采到的线程怎么合并成报告里的几行。

ThreadGrouper(线程归并)

ThreadGrouper.parseConfigSetting(String setting)(ThreadGrouper.java:67-76):

switch (setting) {
    case "as-one":   return AS_ONE;
    case "by-name":  return BY_NAME;
    default:         return BY_POOL;
}
配置值 常量 归并规则
as-one AS_ONE 所有线程合并为单一分组
by-name BY_NAME 按线程名归并(getGroup 返回 threadName)
by-pool(默认) BY_POOL 按线程池归并 —— 未匹配任何已知池名时落到此分支

注意 switch 的 default 落到 BY_POOL —— 任何拼错的配置值都会静默变成 by-pool,不报错。

在多线程服务器上这直接决定报告可读性:默认 by-pool 会把 Acceptor #0/Worker #0 这类 Netty/pool 线程合并成几行,而不是几十行独立条目;改成 by-name 则每个线程单列。

ThreadDumper(线程筛选)

ThreadDumper.parseConfigSetting(String setting)(ThreadDumper.java:71-81):

switch (setting) {
    case "default":  return null;
    case "all":      return ALL;
    default:
        Set<String> threadNames = Arrays.stream(setting.split(",")).collect(Collectors.toSet());
        return new ThreadDumper.Specific(threadNames);
}
配置值 结果
default 返回 null,由调用方回退到平台默认线程
all ThreadDumper.ALL —— threadBean.dumpAllThreads(false, false),导出全部线程
其他任意字符串 按 , 拆分为线程名集合,构造 ThreadDumper.Specific

default 返回 null 是有意设计:调用方 BackgroundSamplerManager.startSampler() 判空后回退到 platform.getPlugin().getDefaultThreadDumper(),由平台决定「默认线程」是什么。

逗号分隔的多线程名是本配置的主要用法 —— 例如 "Server thread,Netty Server IO#0"。注意解析不 trim 空白,且分隔符固定为英文逗号。

1.7.10 的平台默认线程

SparkPlugin.getDefaultThreadDumper() 的接口默认实现返回 ThreadDumper.ALL(SparkPlugin.java:105-107),但 1.7.10 两个插件都覆写了它:

平台 默认线程导出器 捕获时机
服务端 ThreadDumper.GameThread,在 Forge1710ServerSparkPlugin 构造时 setThread(Thread.currentThread()) Forge1710ServerSparkPlugin.java:83-84
客户端 ThreadDumper.Specific(minecraft.mcThread) Forge1710ClientSparkPlugin.java:56

即 1.7.10 上默认只采主线程(服务端)或 Minecraft 客户端线程,与其他平台默认导出全部线程的行为不同。要在服务端采全部线程需显式设 backgroundProfilerThreadDumper: "all"。

服务端之所以要在构造时捕获当前线程:插件在 FMLServerStartingEvent 中注册,此时 Thread.currentThread() 即服务端主线程。

客户端主线程的访问变换器

客户端访问 minecraft.mcThread 需要 FMLAT。spark-forge1710/src/main/resources/META-INF/spark_at.cfg 内容仅一行:

public net.minecraft.client.Minecraft field_152352_aC # mcThread

由 spark-forge1710/build.gradle 的 jar { manifest { attributes 'FMLAT': 'spark_at.cfg' } } 挂载。详见 访问变换器。

数值

数值名 值 来源
ThreadGrouper 合法值 as-one / by-name / 其他(含 by-pool) ThreadGrouper.parseConfigSetting
ThreadDumper 特殊值 default / all / 其他=逗号分隔线程名 ThreadDumper.parseConfigSetting
线程名分隔符 ,(不 trim) ThreadDumper.parseConfigSetting
1.7.10 服务端默认线程 主线程(构造时捕获) Forge1710ServerSparkPlugin
1.7.10 客户端默认线程 minecraft.mcThread Forge1710ClientSparkPlugin

相关条目