Spark API

基本信息

属性 值
公共 API 模块 spark-api(8 个 .java 文件)
入口 me.lucko.spark.api.SparkProvider.get()
接口 me.lucko.spark.api.Spark
实现 me.lucko.spark.common.api.SparkApi(在 spark-common 中,spark-common shade 进 1710 jar)
注册时机 平台 enable() 中 SparkApi.register(api)
注销时机 平台 disable() 中 SparkApi.unregister()

spark 提供一个单例门面,让其他模组以编程方式读取性能统计,而不必解析聊天输出。

获取实例

Spark spark = SparkProvider.get();

SparkProvider.get() 在实例未注册时抛 IllegalStateException("spark has not loaded yet!") —— 不是返回 null。因此依赖方必须自己处理「spark 尚未加载」的情况(典型做法是包一层 try/catch 或延迟初始化)。

在 1.7.10 上,SparkPlatform.enable() 由 Forge1710ServerSparkPlugin.register()(FMLServerStartingEvent 阶段)与 Forge1710ClientSparkPlugin.register()(FMLInitializationEvent 客户端阶段)触发,因此:

  • 服务端可在 FMLServerStartingEvent 之后安全获取
  • 服务端在 FMLPreInitializationEvent 阶段尚不可用

反射式单例注入

SparkApi 与 SparkProvider 分属不同模块,SparkProvider.set 是包级私有方法,因此通过反射调用(SparkApi.java:50-57):

private static final Method SINGLETON_SET_METHOD;

static {
    try {
        SINGLETON_SET_METHOD = SparkProvider.class.getDeclaredMethod("set", Spark.class);
        SINGLETON_SET_METHOD.setAccessible(true);
    } catch (ReflectiveOperationException e) {
        throw new RuntimeException(e);
    }
}

register(Spark) 调用 SINGLETON_SET_METHOD.invoke(null, spark),unregister() 调用 invoke(null, new Object[]{null})(把单位置空)。两者都只 catch (ReflectiveOperationException e) { e.printStackTrace(); }。

SparkPlugin 另有 registerApi(Spark) 钩子(SparkPlugin.java:206),1.7.10 未覆写,保持接口默认的空实现;实际生效的是上面的静态 SparkApi.register。

5 个统计方法

方法 返回类型 可为 null 说明
cpuProcess() DoubleStatistic<CpuUsage> 否 进程 CPU 占用
cpuSystem() DoubleStatistic<CpuUsage> 否 系统 CPU 占用
tps() DoubleStatistic<TicksPerSecond> 是 平台不支持 tick 统计时返回 null
mspt() GenericStatistic<DoubleAverageInfo, MillisPerTick> 是 stats == null 或 !stats.isDurationSupported() 时返回 null
gc() Map<String, GarbageCollector> 否 收集器名 → 统计(@Unmodifiable)

tps() 与 mspt() 是可空的,调用方必须判空。在 1.7.10 上二者均可用(Forge1710TickHook 与 Forge1710TickReporter 都已注册),但 API 层面仍按可空设计。

统计窗口

StatisticWindow 的三个枚举定义了各指标的滚动平均窗口,与 /spark tps 的命令行输出窗口一致:

枚举 窗口
CpuUsage SECONDS_10 / MINUTES_1 / MINUTES_15
TicksPerSecond SECONDS_5 / SECONDS_10 / MINUTES_1 / MINUTES_5 / MINUTES_15
MillisPerTick SECONDS_10 / MINUTES_1 / MINUTES_5

每个窗口实现 length() 返回 java.time.Duration。

Statistic<W> 接口只有两个方法:name()(统计名,如 "CPU Process Usage")与 getWindows()(可用窗口数组)。

GarbageCollector

gc() 返回的每个条目提供:

方法 返回
name() 收集器名
totalCollections() 累计回收次数
totalTime() 累计回收耗时
avgTime() 平均单次耗时
avgFrequency() 平均回收间隔

1.7.10 上的语义差异

与 /spark ping 的情况不同,API 本身在 1.7.10 上是完整可用的 —— TPS / MSPT / CPU / GC 四类统计都来自已接线的 Forge1710TickHook、Forge1710TickReporter 与 CpuMonitor。

但要注意 gc() 的时间基准:其内部用 platform.getServerNormalOperationStartTime() 计算 serverUptime,与 /spark gc 命令一样,是相对「服务器正常运营时刻」而非 JVM 启动时刻。

另外 ping 没有对应的 API 方法 —— Spark 接口不提供玩家延迟查询,1.7.10 上该数据源也未接线(详见 ping 条目的死代码分析)。

数值

数值名 值 来源
API 方法数 5 Spark 接口
公共 API 文件数 8 spark-api 模块 .java 计数
可为 null 的方法数 2(tps()、mspt()) Spark 接口的 @Nullable 标注
CpuUsage 窗口数 3 StatisticWindow.CpuUsage
TicksPerSecond 窗口数 5 StatisticWindow.TicksPerSecond
MillisPerTick 窗口数 3 StatisticWindow.MillisPerTick
未注册时的行为 抛 IllegalStateException SparkProvider.get

相关条目