Browse Source

Optimize `DoCrawl`

Benchmark:

```
cmake -S. -Bbuild-reld -G Ninja -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTING=ON
cmake --build build-reld --target crawl_benchmark && build-reld/crawl_benchmark
```

Before:

```
------------------------------------------------------
Benchmark            Time             CPU   Iterations
------------------------------------------------------
BM_Crawl/1        3.53 ns         3.53 ns    198384032
BM_Crawl/4        54.3 ns         54.2 ns     12907171
BM_Crawl/16        733 ns          732 ns       955101
BM_Crawl/20       1142 ns         1141 ns       613766
```

After:

```
------------------------------------------------------
Benchmark            Time             CPU   Iterations
------------------------------------------------------
BM_Crawl/1        1.36 ns         1.36 ns    453018506
BM_Crawl/4        5.59 ns         5.59 ns    124244505
BM_Crawl/16        102 ns          101 ns      6577269
BM_Crawl/20        147 ns          147 ns      4684004
```
pull/7322/head
Gleb Mazovetskiy 2 years ago
parent
commit
112e113201
  1. 77
      Source/crawl.cpp
  2. 2
      test/crawl_benchmark.cpp

77
Source/crawl.cpp

@ -7,66 +7,39 @@
#include "engine/displacement.hpp"
namespace devilution {
namespace {
bool CrawlFlipsX(Displacement mirrored, tl::function_ref<bool(Displacement)> function)
{
for (const Displacement displacement : { mirrored.flipX(), mirrored }) {
if (!function(displacement))
return false;
}
return true;
}
bool CrawlFlipsY(Displacement mirrored, tl::function_ref<bool(Displacement)> function)
{
for (const Displacement displacement : { mirrored, mirrored.flipY() }) {
if (!function(displacement))
return false;
}
return true;
}
bool CrawlFlipsXY(Displacement mirrored, tl::function_ref<bool(Displacement)> function)
bool DoCrawl(unsigned radius, tl::function_ref<bool(Displacement)> function)
{
for (const Displacement displacement : { mirrored.flipX(), mirrored, mirrored.flipXY(), mirrored.flipY() }) {
if (!function(displacement))
return false;
}
return true;
return DoCrawl(radius, radius, function);
}
} // namespace
bool DoCrawl(unsigned radius, tl::function_ref<bool(Displacement)> function)
bool DoCrawl(unsigned minRadius, unsigned maxRadius, tl::function_ref<bool(Displacement)> function)
{
if (radius == 0)
return function(Displacement { 0, 0 });
if (!CrawlFlipsY({ 0, static_cast<int>(radius) }, function))
return false;
for (unsigned i = 1; i < radius; i++) {
if (!CrawlFlipsXY({ static_cast<int>(i), static_cast<int>(radius) }, function))
return false;
for (int r = static_cast<int>(minRadius); r <= static_cast<int>(maxRadius); ++r) {
if (!function(Displacement { 0, r })) return false;
if (r == 0) continue;
if (!function(Displacement { 0, -r })) return false;
for (int x = 1; x < r; ++x) {
if (!function(Displacement { -x, r })) return false;
if (!function(Displacement { x, r })) return false;
if (!function(Displacement { -x, -r })) return false;
if (!function(Displacement { x, -r })) return false;
}
if (radius > 1) {
if (!CrawlFlipsXY({ static_cast<int>(radius) - 1, static_cast<int>(radius) - 1 }, function))
return false;
if (r > 1) {
const int d = r - 1;
if (!function(Displacement { -d, d })) return false;
if (!function(Displacement { d, d })) return false;
if (!function(Displacement { -d, -d })) return false;
if (!function(Displacement { d, -d })) return false;
}
if (!CrawlFlipsX({ static_cast<int>(radius), 0 }, function))
return false;
for (unsigned i = 1; i < radius; i++) {
if (!CrawlFlipsXY({ static_cast<int>(radius), static_cast<int>(i) }, function))
return false;
if (!function(Displacement { -r, 0 })) return false;
if (!function(Displacement { r, 0 })) return false;
for (int y = 1; y < r; ++y) {
if (!function(Displacement { -r, y })) return false;
if (!function(Displacement { r, y })) return false;
if (!function(Displacement { -r, -y })) return false;
if (!function(Displacement { r, -y })) return false;
}
return true;
}
bool DoCrawl(unsigned minRadius, unsigned maxRadius, tl::function_ref<bool(Displacement)> function)
{
for (unsigned i = minRadius; i <= maxRadius; i++) {
if (!DoCrawl(i, function))
return false;
}
return true;
}

2
test/crawl_benchmark.cpp

@ -8,7 +8,7 @@ namespace {
void BM_Crawl(benchmark::State &state)
{
const int radius = state.range(0);
const int radius = static_cast<int>(state.range(0));
for (auto _ : state) {
int sum;
Crawl(0, radius, [&sum](Displacement d) {

Loading…
Cancel
Save