2023-12-13 21:43:11 +01:00
|
|
|
/*
|
|
|
|
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);
|
|
|
|
for (u32 i = 0; i < n; i++) {
|
2023-12-12 15:43:39 +01:00
|
|
|
auto *mb = new MapBlock({i & 0xff, 0, i >> 8}, nullptr);
|
2023-12-13 21:43:11 +01:00
|
|
|
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();
|
2023-12-12 16:08:41 +01:00
|
|
|
|
|
|
|
bool want_contents_cached = block->contents.empty() && !block->do_not_cache_contents;
|
2023-12-13 21:43:11 +01:00
|
|
|
|
|
|
|
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();
|
|
|
|
|
2023-12-12 16:08:41 +01:00
|
|
|
if (want_contents_cached && !CONTAINS(block->contents, c)) {
|
|
|
|
if (block->contents.size() >= 10) {
|
|
|
|
want_contents_cached = false;
|
2023-12-13 21:43:11 +01:00
|
|
|
block->do_not_cache_contents = true;
|
|
|
|
block->contents.clear();
|
2023-12-12 15:30:26 +01:00
|
|
|
block->contents.shrink_to_fit();
|
2023-12-12 16:08:41 +01:00
|
|
|
} else {
|
|
|
|
block->contents.push_back(c);
|
2023-12-13 21:43:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-12-12 16:08:41 +01:00
|
|
|
|
2023-12-13 21:43:11 +01:00
|
|
|
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
|
|
|
|
}
|