
Sepals
一个用于Minecraft服务器性能的极其激进和实验性的优化方案。
Sepals
一个极度激进且实验性的 Minecraft 服务器性能优化模组。
我们建议将 Sepals 与 Lithium 和 Async 配合使用,以获得最佳性能。
前言
首先,Sepals 是一系列高度实验性的服务端优化集合,针对 Minecraft 的 AI、实体处理以及任务系统中的特定性能瓶颈。与 Lithium 提供的广泛“通用”优化不同,Sepals 专注于对少数几个极其昂贵的原版机制进行深度重写——尤其是村民大脑(villager brains)、青蛙行为(frog behavior)、实体挤压(entity cramming)、目标过滤(target filtering)和附近实体感知(nearby-entity sensing)。
那么它在实际使用中表现如何?
如果你运行大型刷怪塔、村民大厅、密集的生物围栏, 或任何在小范围内存在成百上千实体的场景, Sepals 通过避开原版最昂贵的 AI 操作,大幅降低每次游戏刻(tick)的耗时。
如果你运行的是农场较小的普通 SMP 服务器,你可能感觉不到太大差异。
它是实验性的,并非每项优化都保证与原版行为完全一致, 但在性能压力测试中,其提升效果可能非常显著。
兼容性
目前,Sepals 与几乎所有模组兼容。
以下为已与最新 Sepals 版本验证兼容的模组列表:
| 目标模组 | 所需目标版本 |
|---|---|
| Sodium | 全部 |
| Iris | 全部 |
| FerriteCore | 全部 |
| Krypton | 全部 |
| Lithium | >=0.18.0 |
| C2ME | >=0.3.4.0.0 |
| Moonrise | >=0.6.0-beta.1+45edfd7 |
| Async | >=0.1.7+alpha.7-1.21.8 |
如果你不确定该选择哪个版本,请使用优化模组的最新版本,因为 Sepals 会确保与它们的兼容性。
重要提示
Sepals 不支持任何 Minecraft 的旧版本和快照版本;所有错误修复和功能仅在最新版本中可用。
当与 Async 一起使用时, 请在启用 Sepals 和 Async 的情况下手动对比性能,并调整它们的配置,以找出哪些优化是值得的, 因为不同机器的结果会有差异。
Sepals 相关设置项:enableSepalsEntitiesCramming。
配置
| 配置名称 | 允许值 | 默认值 |
|---|---|---|
| forceEnableSepalsPoi | 布尔值 | false |
| enableSepalsVillager | 布尔值 | true |
| enableSepalsFrogLookAt | 布尔值 | true |
| enableSepalsFrogAttackableSensor | 布尔值 | true |
| enableSepalsLivingTargetCache | 布尔值 | true |
| nearestLivingEntitiesSensorUseQuickSort | 布尔值 | true |
| enableSepalsBiasedLongJumpTask | 布尔值 | true |
| enableSepalsEntitiesCramming | 布尔值 | true |
| enableSepalsItemMerge | 布尔值 | true |
| enableSepalsQuickCanBePushByEntityPredicate | 布尔值 | true |
性能
测试在由 feimia 提供的 Mars 服务器上进行,CPU:Intel i7-14700K;游戏内存:4G;操作系统:Ubuntu 24.04.1 LTS; Minecraft 版本:1.21。
实体挤压(Entities cramming)
使用箱体缓存来防止过多的 'getOtherEntities' 调用
-- 注意 --
此功能会忽略每个实体的记分板/队伍(scoreboard/team)判定条件,
可能导致意外行为。
此问题在原版中不会影响任何内容,除非使用
命令方块时。
-- 状态 --
默认启用
1390 个村民挤压在 7x7 的空间中:
| 环境 | tickCramming | 百分比(平均) |
|---|---|---|
| 原版 | 53.6 ms | 100 % |
| Lithium | 54.4 ms | 101 % |
| Sepals | 10.2 ms | 19 % |
| Sepals + Lithium | 8.5 ms | 15 % |
加权随机(Weighted random)
使用二分查找替代原版的权重随机
-- 警告 --
此功能可能不值得启用,
因为 Spark 证明在构建范围表时它比原版更慢,
尽管二分查找本身接近 0 ms。
-- 状态 --
默认禁用
-- 警告 --
未经过测试。
偏向长跳跃任务(Biased long jump task)
使用 Sepals 的长跳跃任务实现替代原版
如上所述,二分查找的成本几乎为零,
Sepals 的实现会在生成目标的同时构建范围表,
并使用 Catheter 替代 Java Stream。
同时,重新调整了青蛙大脑中的跳跃条件,以获得更好的性能。
-- 注意 --
此功能无法在游戏运行时更改,
需要重启服务器以应用更改。
-- 状态 --
默认启用
800 只青蛙挤压在 7x7 的空间中:
| 环境 | keepRunning | 百分比(平均) |
|---|---|---|
| 原版 (LongJumpTask) |
43.1 ms | 100 % |
| Lithium (LongJumpTask) |
7.5 ms | 17 % |
| Sepals (SepalsLongJumpTask) |
0.2 ms | 0.4 % |
| Sepals + Lithium (SepalsLongJumpTask) |
0.05 ms | 0.1 % |
| 环境 | getTarget | 百分比(平均) | 百分比(在 keepRunning 内) |
|---|---|---|---|
| 原版 (LongJumpTask) |
43.1 ms | 100 % | 100 % |
| Lithium (LongJumpTask) |
3.6 ms | 9 % | 48 % |
| Sepals (SepalsLongJumpTask) |
N/A ms | 0 % | 0 % |
| Sepals + Lithium (SepalsLongJumpTask) |
N/A ms | 0 % | 0 % |
NearestLivingEntitiesSensor 中的快速排序
使用来自 FastUtil 的快速排序替代 Java 的 TimSort
-- 状态 --
默认启用
800 只青蛙挤压在 7x7 的空间中:
| 环境 | 排序 (NearestLivingEntitiesSensor#sense) | 百分比(平均) |
|---|---|---|
| 原版 | 3.8 ms | 100 % |
| Lithium | 3.6 ms | 94 % |
| Sepals | 2.2 ms | 57 % |
| Sepals + Lithium | 2.2 ms | 57 % |
青蛙可攻击目标过滤器
重新排列可攻击条件,
将成本最低的条件放在最前面,
从而降低高成本计算的触发概率。
-- 反馈 --
Mojang 的可攻击判定是:
!entity.getBrain().hasMemoryModule(MemoryModuleType.HAS_HUNTING_COOLDOWN)
&& Sensor.testAttackableTargetPredicate(entity, target)
&& FrogEntity.isValidFrogFood(target)
&& !this.isTargetUnreachable(entity, target)
&& target.isInRange(entity, 10.0)
在这种情况下,'Sensor#testAttackableTargetPredicate' 调用了 'TargetPredicate#test',
当区域内实体过多时会导致大量射线检测(raycast)计算,
考虑到 Minecraft 的射线检测慢得令人痛苦,这使情况变得更糟。
在这种情况下,'TargetPredicate#test' (800 只青蛙) 每个游戏刻花费了 9.8ms,
其中 'BlockView.raycast' 贡献了 7.3ms。
因此,我将其修改为:
FrogEntity.isValidFrogFood(target) &&
entity.getBrain().hasMemoryModule(MemoryModuleType.HAS_HUNTING_COOLDOWN) &&
target.isInRange(entity, 10.0) &&
Sensor.testAttackableTargetPredicate(entity, target) &&
isTargetUnreachable(entity, target);
'isValidFrogFood' 是一个简单的条件,它检查实体的 'frog_food' 标签
并在实体是史莱姆且其尺寸不为 1 时提供一个额外的跳过检查。
'isInRange' 和 'hasMemoryModule' 也很好,因为它们只计算一些简单的操作。
-- 状态 --
默认启用
800 只青蛙挤压在 7x7 的空间中:
| 环境 | 时间 | 百分比(平均) |
|---|---|---|
| 原版 (FrogAttackablesSensor#matches) | 10 ms | 100 % |
| Lithium (FrogAttackablesSensor#matches) | 5.7 ms | 57 % |
| Sepals (SepalsFrogBrain#attackable) | 0.1 ms | 1 % |
| Sepals + Lithium (SepalsFrogBrain#attackable) | 0.1 ms | 1 % |
青蛙注视目标过滤器
使用 'SepalsLivingTargetCache' 提高目标搜索性能
你必须启用该选项,否则此功能与原版相同。
-- 注意 --
射线检测在 TargetPredicate 测试中,
在 LivingTargetCache 的 'findFirst' 中当输入判定成功时执行。
但是如果后续条件失败,那么进一步计算是无用的,
因为即使 findFirst 已经找到(射线检测成功),
我们也不会在后续环境中使用这个结果。
-- 状态 --
默认启用
800 只青蛙挤压在 7x7 的空间中:
| 环境 | findFirst | 百分比 |
|---|---|---|
| 原版 (LookAtMobWithIntervalTask$$Lambda#findFirst) |
2.7 ms | 100 % |
| Lithium (LookAtMobWithIntervalTask$$Lambda#findFirst) |
2.5 ms | 92 % |
| Sepals (SepalsLookAtMobWithIntervalTask$$Lambda#findFirstPlayer) |
0.1 ms | 3 % |
| Sepals + Lithium (SepalsLookAtMobWithIntervalTask$$Lambda#findFirstPlayer) |
0.1 ms | 3 % |
村民杂项优化
以下是 Sepals 所做的:
1. 使用 Catheter 替代 Java 的 Stream,因为与 Stream 相比,它具有更好的性能和可扩展性。
2. 缓存任务(tasks)、活动(activities)、运行中的任务(running tasks)和记忆(memory),以改善任务启动和更新的时间。
3. 使用 Sepals 复合任务替代原版复合任务。
4. 在可能的情况下,寻找机会跳过更多的射线检测和无用的判定。
5. 使用 'SepalsLivingTargetCache' 替代原版缓存。在传感器 tick 期间多花费一些成本,以减少寻找交互目标或注视生物任务期间的成本。
6. 重新排列判定条件并添加低成本判定,目的是将高成本判定延后或最好不执行,以提前跳过剩余的高成本判定。
7. 从 Lithium 复制并修改了 'SerializingRegionBasedStorage' 的优化。
8. 针对特定任务,不使用泛型以减少无用操作。
9. 使用二分查找列表替代哈希集查找。
-- 注意 --
建议与 Lithium 和 C2ME 一起使用以获得最佳性能。
-- 警告 --
尚未进行长期稳定性测试,仅一个月的运行表明目前没有问题。
此功能尚未被证明与原版行为完全一致,
但也没有显示出统计学上的显著差异。
-- 状态 --
默认启用
800 个村民在正午挤压在 7x7 的空间中:
| 环境 | Brain#tick (总) | 百分比 | Brain#startTasks | 百分比(startTasks) | Brain#tickSensors | 百分比(tickSensors) | Brain#updateTasks | 百分比(updateTasks) | Brain#tickMemories | 百分比(tickMemories) |
|---|---|---|---|---|---|---|---|---|---|---|
| 原版 | 18 ms | 100 % | 9.3 ms | 100 % | 5.2 ms | 100 % | 3 ms | 100 % | 0.5 ms | 100 % |
| Lithium | 12.4 ms | 68 % | 4.8 ms | 51 % | 5.9 ms | 113 % | 1.2 ms | 40 % | 0.5 ms | 100 % |
| Sepals | 9.7 ms | 53 % | 3.6 ms | 38 % | 3.7 ms | 71 % | 2 ms | 66 % | 0.4 ms | 80 % |
| Sepals + Lithium | 10 ms | 55 % | 3.4 ms | 36 % | 3.7 ms | 71 % | 2.5 ms | 83 % | 0.4 ms | 80 % |
800 个村民在夜晚挤压在 7x7 的空间中:
| 环境 | Brain#tick (总) | 百分比 | Brain#startTasks | 百分比(startTasks) | Brain#tickSensors | 百分比(tickSensors) | Brain#updateTasks | 百分比(updateTasks) | Brain#tickMemories | 百分比(tickMemories) |
|---|---|---|---|---|---|---|---|---|---|---|
| 原版 | 16.7 ms | 100 % | 8.2 ms | 100 % | 6 ms | 100 % | 2 ms | 100 % | 0.5 ms | 100 % |
| Lithium | 10.2 ms | 61 % | 3.2 ms | 24 % | 6 ms | 113 % | 0.5 ms | 25 % | 0.5 ms | 100 % |
| Sepals | 9 ms | 53 % | 3.3 ms | 16 % | 4.7 ms | 78 % | 0.7 ms | 35 % | 0.3 ms | 60 % |
| Sepals + Lithium | 8.7 ms | 52 % | 2.9 ms | 11 % | 4.6 ms | 76 % | 0.7 ms | 35 % | 0.5 ms | 100 % |
判定条件优化
1172 只青蛙挤压在 3x3 的空间中:
| 环境 | 时间 | 百分比(平均) |
|---|---|---|
| 原版 (java.util.function.Predicate.lambda$and$0()) | 49.01 ms | 100 % |
| Sepals (com.github.cao.awa.sepals.entity.predicate.SepalsEntityPredicates$$Lambda/0x000002d8f116e000.test()) | 22.6 ms | 46 % |
正在加载版本记录…
正在加载评论…
评论在新手盒子客户端中发表,这里同步展示。