Function "Within" is slower than iterating with "At"
Xkonti opened this issue · 0 comments
Xkonti commented
I noticed that when using the Within
on the grid to iterate through values of all tiles it's slower than when iterating by simply using At
. Here are benchmarks I quickly wrote:
Benchmark testing the performance of the built-in Within
:
func BenchmarkGridWithin(b *testing.B) {
// Generate map
theMap := tile.NewGridOf[tileData](900, 900)
theMap.Each(func(pos point, currentTile tile.Tile[tileData]) {
currentTile.Write(getRandomSliceIndex(tileImages))
})
// Benchmark
chunkSize := 9
for i := 0; i < b.N; i++ {
pos := point{X: int16((i * 9) % 900), Y: int16((i * 45) % 900)}
theMap.Within(pos, pos.Add(point{X: chunkSize * 3, Y: chunkSize * 3}), func(tilePos point, currentTile tile.Tile[tileData]) {
value := currentTile.Value()
_ = tileImages[int(value)]
})
}
}
Benchmark using At
where whole chunk is scanned with a simple double for loop:
func BenchmarkGridAtScan(b *testing.B) {
// Generate map
theMap := tile.NewGridOf[tileData](900, 900)
theMap.Each(func(pos point, currentTile tile.Tile[tileData]) {
currentTile.Write(getRandomSliceIndex(tileImages))
})
// Benchmark
chunkSize := 9
for i := 0; i < b.N; i++ {
pos := point{X: int16((i * 9) % 900), Y: int16((i * 45) % 900)}
for x := pos.X; x < pos.X+chunkSize*3; x++ {
for y := pos.Y; y < pos.Y+chunkSize*3; y++ {
currentTile, ok := theMap.At(x, y)
if !ok {
continue
}
value := currentTile.Value()
_ = tileImages[int(value)]
}
}
}
}
A benchmark that tries to get values using At
but working on a page at a time:
func BenchmarkGridAtPage(b *testing.B) {
// Generate map
theMap := tile.NewGridOf[tileData](900, 900)
theMap.Each(func(pos point, currentTile tile.Tile[tileData]) {
currentTile.Write(getRandomSliceIndex(tileImages))
})
// Benchmark
chunkSize := 9
for i := 0; i < b.N; i++ {
pos := point{X: int16((i * 9) % 900), Y: int16((i * 45) % 900)}
// Iterate through pages
for x := pos.X; x < pos.X+chunkSize*3; x += 3 {
for y := pos.Y; y < pos.Y+chunkSize*3; y += 3 {
// Get all tiles in a page
for tileX := x; tileX < x+3; tileX++ {
for tileY := y; tileY < y+3; tileY++ {
currentTile, ok := theMap.At(tileX, tileY)
if !ok {
continue
}
value := currentTile.Value()
_ = tileImages[int(value)]
}
}
}
}
}
}
Results show that At
is significantly faster than Within
. Also accessing tile's values page-at-a-time increases performance by only ≈0.82%:
goos: windows
goarch: amd64
pkg: tile-game
cpu: 12th Gen Intel(R) Core(TM) i9-12900KF
BenchmarkGridWithin-24 531561 2251 ns/op
BenchmarkGridAtScan-24 656180 1826 ns/op
BenchmarkGridAtPage-24 661200 1811 ns/op
I'm not sure if that's intended behavior but something tells me there's an opportunity for adding an optimized values getter.