mirror of
https://github.com/minetest/minetest.git
synced 2024-11-27 10:03:45 +01:00
Try to benchmark common MapBlock usage
This commit is contained in:
parent
e5a6048eec
commit
2c2bc4a427
@ -2,6 +2,7 @@ set (BENCHMARK_SRCS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/benchmark.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/benchmark_lighting.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/benchmark_serialize.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/benchmark_mapblock.cpp
|
||||
PARENT_SCOPE)
|
||||
|
||||
set (BENCHMARK_CLIENT_SRCS
|
||||
|
185
src/benchmark/benchmark_mapblock.cpp
Normal file
185
src/benchmark/benchmark_mapblock.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
/*
|
||||
Minetest
|
||||
Copyright (C) 2023 Minetest Authors
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "benchmark_setup.h"
|
||||
#include "mapblock.h"
|
||||
#include <vector>
|
||||
|
||||
typedef std::vector<MapBlock*> MBContainer;
|
||||
|
||||
static void allocateSome(MBContainer &vec, u32 n)
|
||||
{
|
||||
vec.reserve(vec.size() + n);
|
||||
Map *map = reinterpret_cast<Map*>(0x1234);
|
||||
for (u32 i = 0; i < n; i++) {
|
||||
auto *mb = new MapBlock(map, {i & 0xff, 0, i >> 8}, nullptr);
|
||||
vec.push_back(mb);
|
||||
}
|
||||
}
|
||||
|
||||
static void freeSome(MBContainer &vec, u32 n)
|
||||
{
|
||||
// deallocate from end since that has no cost moving data inside the vector
|
||||
u32 start_i = 0;
|
||||
if (vec.size() > n)
|
||||
start_i = vec.size() - n;
|
||||
for (u32 i = start_i; i < vec.size(); i++)
|
||||
delete vec[i];
|
||||
vec.resize(start_i);
|
||||
}
|
||||
|
||||
static inline void freeAll(MBContainer &vec) { freeSome(vec, vec.size()); }
|
||||
|
||||
// usage patterns inspired by ClientMap::updateDrawList()
|
||||
static void workOnMetadata(const MBContainer &vec)
|
||||
{
|
||||
for (MapBlock *block : vec) {
|
||||
#ifndef SERVER
|
||||
bool foo = !!block->mesh;
|
||||
#else
|
||||
bool foo = true;
|
||||
#endif
|
||||
|
||||
if (block->refGet() > 2)
|
||||
block->refDrop();
|
||||
|
||||
v3s16 pos = block->getPos() * MAP_BLOCKSIZE;
|
||||
if (foo)
|
||||
pos += v3s16(MAP_BLOCKSIZE / 2);
|
||||
|
||||
if (pos.getDistanceFrom(v3s16(0)) > 30000)
|
||||
continue;
|
||||
|
||||
block->resetUsageTimer();
|
||||
block->refGrab();
|
||||
}
|
||||
}
|
||||
|
||||
// usage patterns inspired by LBMManager::applyLBMs()
|
||||
static u32 workOnNodes(const MBContainer &vec)
|
||||
{
|
||||
u32 foo = 0;
|
||||
for (MapBlock *block : vec) {
|
||||
block->resetUsageTimer();
|
||||
|
||||
if (block->isOrphan())
|
||||
continue;
|
||||
|
||||
v3s16 pos_of_block = block->getPosRelative();
|
||||
v3s16 pos;
|
||||
MapNode n;
|
||||
for (pos.X = 0; pos.X < MAP_BLOCKSIZE; pos.X++) {
|
||||
for (pos.Y = 0; pos.Y < MAP_BLOCKSIZE; pos.Y++) {
|
||||
for (pos.Z = 0; pos.Z < MAP_BLOCKSIZE; pos.Z++) {
|
||||
n = block->getNodeNoCheck(pos);
|
||||
|
||||
if (n.getContent() == CONTENT_AIR) {
|
||||
auto p = pos + pos_of_block;
|
||||
foo ^= p.X + p.Y + p.Z;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return foo;
|
||||
}
|
||||
|
||||
// usage patterns inspired by ABMHandler::apply()
|
||||
// touches both metadata and node data at the same time
|
||||
static u32 workOnBoth(const MBContainer &vec)
|
||||
{
|
||||
int foo = 0;
|
||||
for (MapBlock *block : vec) {
|
||||
block->contents.clear();
|
||||
block->contents_cached = false;
|
||||
|
||||
v3s16 p0;
|
||||
for(p0.X=0; p0.X<MAP_BLOCKSIZE; p0.X++)
|
||||
for(p0.Y=0; p0.Y<MAP_BLOCKSIZE; p0.Y++)
|
||||
for(p0.Z=0; p0.Z<MAP_BLOCKSIZE; p0.Z++)
|
||||
{
|
||||
MapNode n = block->getNodeNoCheck(p0);
|
||||
content_t c = n.getContent();
|
||||
|
||||
if (!block->contents_cached && !block->do_not_cache_contents) {
|
||||
block->contents.insert(c);
|
||||
if (block->contents.size() > 10) {
|
||||
// Too many different nodes... don't try to cache
|
||||
block->do_not_cache_contents = true;
|
||||
block->contents.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
block->contents_cached = !block->do_not_cache_contents;
|
||||
foo += block->contents.size();
|
||||
}
|
||||
return foo;
|
||||
}
|
||||
|
||||
#define BENCH1(_count) \
|
||||
BENCHMARK_ADVANCED("allocate_" #_count)(Catch::Benchmark::Chronometer meter) { \
|
||||
MBContainer vec; \
|
||||
const u32 pcount = _count / meter.runs(); \
|
||||
meter.measure([&] { \
|
||||
allocateSome(vec, pcount); \
|
||||
return vec.size(); \
|
||||
}); \
|
||||
freeAll(vec); \
|
||||
}; \
|
||||
BENCHMARK_ADVANCED("testCase1_" #_count)(Catch::Benchmark::Chronometer meter) { \
|
||||
MBContainer vec; \
|
||||
allocateSome(vec, _count); \
|
||||
meter.measure([&] { \
|
||||
workOnMetadata(vec); \
|
||||
}); \
|
||||
freeAll(vec); \
|
||||
}; \
|
||||
BENCHMARK_ADVANCED("testCase2_" #_count)(Catch::Benchmark::Chronometer meter) { \
|
||||
MBContainer vec; \
|
||||
allocateSome(vec, _count); \
|
||||
meter.measure([&] { \
|
||||
return workOnNodes(vec); \
|
||||
}); \
|
||||
freeAll(vec); \
|
||||
}; \
|
||||
BENCHMARK_ADVANCED("testCase3_" #_count)(Catch::Benchmark::Chronometer meter) { \
|
||||
MBContainer vec; \
|
||||
allocateSome(vec, _count); \
|
||||
meter.measure([&] { \
|
||||
return workOnBoth(vec); \
|
||||
}); \
|
||||
freeAll(vec); \
|
||||
}; \
|
||||
BENCHMARK_ADVANCED("free_" #_count)(Catch::Benchmark::Chronometer meter) { \
|
||||
MBContainer vec; \
|
||||
allocateSome(vec, _count); \
|
||||
/* catch2 does multiple runs so we have to be careful to not dealloc too many */ \
|
||||
const u32 pcount = _count / meter.runs(); \
|
||||
meter.measure([&] { \
|
||||
freeSome(vec, pcount); \
|
||||
return vec.size(); \
|
||||
}); \
|
||||
freeAll(vec); \
|
||||
};
|
||||
|
||||
TEST_CASE("benchmark_mapblock") {
|
||||
BENCH1(900)
|
||||
BENCH1(2200)
|
||||
BENCH1(7500) // <- default client_mapblock_limit
|
||||
}
|
Loading…
Reference in New Issue
Block a user