调研编号:
污染作物的 updateEntity 每 tick 的常态路径(生长分支)里,getBlock(x, y-1, z) 在一条 && 条件中被求值 3 次(短路也至少 1 次、通常 3 次),getBlockMetadata(x, y, z) 被求值 2 次,另外每 tick 查一次 biome——而 biome 只用于把生长阈值从 4000 改成 3550,同一方块的 biome 在 tick 之间根本不变。整个过程没有任何局部变量承接,也没有节流门。
updateEntity
getBlock(x, y-1, z)
&&
getBlockMetadata(x, y, z)
PERF
type/perf
p3
getChunkFromBlockCoords
getBlock
TDLM/thaumicadditions
origin/main
cded7cd3ee59
src/main/java/com/pengu/thaumcraft/additions/tileentity/TileTaintedCrops.java:21
:33
:37-38
// :21 同一个坐标 (x, y-1, z) 在一条短路口径里被 getBlock 三次 if(!this.worldObj.getBlock(this.xCoord, this.yCoord - 1, this.zCoord).canSustainPlant(this.worldObj, this.xCoord, this.yCoord - 1, this.zCoord, ForgeDirection.UP, (IPlantable)All.B_taint_crops) && this.worldObj.getBlock(this.xCoord, this.yCoord - 1, this.zCoord) != Blocks.grass && this.worldObj.getBlock(this.xCoord, this.yCoord - 1, this.zCoord) != Blocks.dirt) { // :33 / :38 同一 tick 内 getBlockMetadata(x,y,z) 两次 if(this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord) < 4) { ++this.tick; } // :37 每 tick 只为一个常量阈值查一次 biome if(this.tick >= 4000 - (this.worldObj.getBiomeGenForCoords(this.xCoord, this.zCoord).biomeID == Config.biomeTaintID?450:0)) { Util.setBlockMetadata(this.worldObj, this.xCoord, this.yCoord, this.zCoord, this.worldObj.getBlockMetadata(this.xCoord, this.yCoord, this.zCoord) + 1);
getBlock(y-1)
getBlockMetadata(y)
getBiomeGenForCoords(x,z)
Block below = worldObj.getBlock(x, y-1, z); int meta = worldObj.getBlockMetadata(x,y,z);
taintBiome
markDirty
onNeighborChange
getBlockMetadata
thaumicadditions
client,server
:33/:38
:37
F4 帧内不变量重复求值
T1 tick 重扫无 memo
src/main/java/com/pengu/thaumcraft/additions/tileentity/TileTaintedCrops.java:21,33,37-38
关闭,不改:TileTaintedCrops(:21-38)每个作物 tile 每 tick 三次 getBlock 和一次群系查询,开销微小且不在 profile 里。
TileTaintedCrops
No dependencies set.
The note is not visible to the blocked user.
调研编号:
现象
污染作物的
updateEntity每 tick 的常态路径(生长分支)里,getBlock(x, y-1, z)在一条&&条件中被求值 3 次(短路也至少 1 次、通常 3 次),getBlockMetadata(x, y, z)被求值 2 次,另外每 tick 查一次 biome——而 biome 只用于把生长阈值从 4000 改成 3550,同一方块的 biome 在 tick 之间根本不变。整个过程没有任何局部变量承接,也没有节流门。危害类与优先级
PERF(每 tick 同参数重复求值 + 每 tick 重算 tick 不变的不变量)→ 标签type/perfp3单次开销小,但乘数是「每 tick × 每株作物」;污染作物是成片种植的(一片 10×10 就是 100 株),且 biome 查询走getChunkFromBlockCoords+ chunk biome 数组,比getBlock更重证据(生效源码)
TDLM/thaumicadditions+ 分支origin/main+ pincded7cd3ee59(source 类仓,无 patch 层,代码可点开)src/main/java/com/pengu/thaumcraft/additions/tileentity/TileTaintedCrops.java:21、:33、:37-38getBlock(y-1)3 次、getBlockMetadata(y)2 次、getBiomeGenForCoords(x,z)1 次 ⇒ 6 次查询里 4 次是同一目标的重复;把Block below = worldObj.getBlock(x, y-1, z); int meta = worldObj.getBlockMetadata(x,y,z);提到前面复用,biome 换成缓存的taintBiome布尔(或在markDirty/onNeighborChange时重算),可压到 2 次且结果逐 tick 相同触发与复现
getBlock+ 200 次getBlockMetadata+ 100 次 biome 查询 = 600 次/片/tick;20 tps ⇒ 12,000 次/秒,其中 8,000 次是同一目标的重复查询。等价改法(局部变量承接 + biome 结果缓存)后降到 2×100 = 200 次/tick,生长判定逐 tick 相同。thaumicadditions/sidesclient,server/默认配置可达 是落点
TDLM/thaumicadditions→src/main/java/com/pengu/thaumcraft/additions/tileentity/TileTaintedCrops.java:21(重复取块)、:33/:38(重复取元数据)、:37(每 tick biome)范式
F4 帧内不变量重复求值(同参查询无局部承接;:37属 tick 级不变量)T1 tick 重扫无 memo(biome 结果未缓存)引证
来源
src/main/java/com/pengu/thaumcraft/additions/tileentity/TileTaintedCrops.java:21,33,37-38关闭,不改:
TileTaintedCrops(:21-38)每个作物 tile 每 tick 三次getBlock和一次群系查询,开销微小且不在 profile 里。