test: cover testChunkCache

This commit is contained in:
dualfroz committed 2026-09-11 13:14:24 +02:00
1 parent 6e6a878a9b
commit fe22ed9085
1 file changed
+187
+187
View File
@@ -156,3 +156,190 @@ VF_TEST(distanceWeightedPolicyDropsFarChunksFirst) {
cache.setPolicy(CachePolicy::DistanceWeighted); cache.setPolicy(CachePolicy::DistanceWeighted);
CHECK(cache.evictionOrder().front() == distant); CHECK(cache.evictionOrder().front() == distant);
std::uint64_t entry = sizeOfEntry(4);
ChunkCache tight(entry, CachePolicy::DistanceWeighted);
tight.setObserver({0, 0, 0});
storeMarked(tight, nearby, 4);
storeMarked(tight, distant, 4);
CHECK(tight.contains(nearby));
CHECK(!tight.contains(distant));
ChunkCache recencyOnly(entry, CachePolicy::Lru);
recencyOnly.setObserver({0, 0, 0});
storeMarked(recencyOnly, nearby, 4);
storeMarked(recencyOnly, distant, 4);
CHECK(!recencyOnly.contains(nearby));
CHECK(recencyOnly.contains(distant));
}
VF_TEST(observerMoveRescoresResidentEntries) {
ChunkCache cache(1ull << 30, CachePolicy::DistanceWeighted);
cache.setObserver({0, 0, 0});
storeMarked(cache, {0, 0, 0}, 4);
storeMarked(cache, {8, 0, 0}, 4);
CHECK(cache.evictionOrder().front() == (Vec3i{8, 0, 0}));
cache.setObserver({8, 0, 0});
CHECK(cache.observer() == (Vec3i{8, 0, 0}));
CHECK(cache.evictionOrder().front() == (Vec3i{0, 0, 0}));
}
VF_TEST(blockEditDropsTheOwnerAndTheMeshesAcrossThatBorder) {
ChunkCache cache(1ull << 30, CachePolicy::Lru);
const Vec3i neighbours[] = {{1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
storeMarked(cache, {0, 0, 0}, 8);
for (const Vec3i& coord : neighbours) storeMarked(cache, coord, 8);
std::uint64_t before = cache.bytesUsed();
std::size_t dropped = cache.invalidateBlock(chunkSize - 1, 5, 5);
CHECK_EQ(dropped, static_cast<std::size_t>(1));
CHECK(!cache.contains({0, 0, 0}));
CHECK(cache.contains({1, 0, 0}));
CHECK(!cache.hasMesh({1, 0, 0})); // its ambient occlusion read the edit
CHECK(cache.hasMesh({-1, 0, 0}));
CHECK(cache.hasMesh({0, 1, 0}));
CHECK(cache.hasMesh({0, 0, 1}));
CHECK_EQ(cache.bytesUsed(), before - sizeOfEntry(8) - (sizeOfEntry(8) - sizeOfEntry(0)));
CacheStats counted = cache.stats();
CHECK_EQ(counted.invalidations, static_cast<std::uint64_t>(1));
CHECK_EQ(counted.meshInvalidations, static_cast<std::uint64_t>(1));
}
VF_TEST(cornerBlockEditCascadesToEverySharingNeighbour) {
ChunkCache cache(1ull << 30, CachePolicy::Lru);
storeMarked(cache, {0, 0, 0}, 3);
for (int dx = 0; dx <= 1; ++dx)
for (int dy = 0; dy <= 1; ++dy)
for (int dz = 0; dz <= 1; ++dz)
if (dx || dy || dz) storeMarked(cache, {dx, dy, dz}, 3);
storeMarked(cache, {-1, 0, 0}, 3);
std::size_t dropped = cache.invalidateBlock(chunkSize - 1, chunkSize - 1, chunkSize - 1);
CHECK_EQ(dropped, static_cast<std::size_t>(7));
CHECK(cache.hasMesh({-1, 0, 0})); // opposite side, untouched
CHECK(!cache.hasMesh({1, 1, 1}));
CHECK(!cache.hasMesh({0, 0, 1}));
CHECK_EQ(cache.stats().meshInvalidations, static_cast<std::uint64_t>(7));
}
VF_TEST(interiorBlockEditLeavesNeighbourMeshesAlone) {
ChunkCache cache(1ull << 30, CachePolicy::Lru);
storeMarked(cache, {0, 0, 0}, 5);
storeMarked(cache, {1, 0, 0}, 5);
storeMarked(cache, {0, 0, 1}, 5);
std::size_t dropped = cache.invalidateBlock(5, 5, 5);
CHECK_EQ(dropped, static_cast<std::size_t>(0));
CHECK(!cache.contains({0, 0, 0}));
CHECK(cache.hasMesh({1, 0, 0}));
CHECK(cache.hasMesh({0, 0, 1}));
CHECK_EQ(cache.stats().meshInvalidations, static_cast<std::uint64_t>(0));
}
VF_TEST(statsTrackHitsMissesAndHitRate) {
ChunkCache cache(1ull << 30, CachePolicy::Lru);
storeMarked(cache, {0, 0, 0}, 2);
Chunk chunk;
ChunkMesh mesh;
CHECK(cache.fetchChunk({0, 0, 0}, chunk));
CHECK(cache.fetchMesh({0, 0, 0}, mesh));
CHECK(cache.fetchChunk({0, 0, 0}, chunk));
CHECK(!cache.fetchChunk({7, 0, 0}, chunk));
CacheStats counted = cache.stats();
CHECK_EQ(counted.hits, static_cast<std::uint64_t>(3));
CHECK_EQ(counted.misses, static_cast<std::uint64_t>(1));
CHECK_NEAR(counted.hitRate(), 0.75, 1e-9);
CHECK_EQ(counted.entries, static_cast<std::size_t>(1));
CHECK_EQ(counted.bytesUsed, sizeOfEntry(2));
CHECK_EQ(mesh.opaque.quadCount(), static_cast<std::size_t>(2));
cache.resetStats();
CHECK_EQ(cache.stats().hits, static_cast<std::uint64_t>(0));
CHECK_NEAR(cache.stats().hitRate(), 0.0, 1e-9);
}
VF_TEST(peekDoesNotDisturbRecencyOrStatistics) {
ChunkCache cache(1ull << 30, CachePolicy::Lru);
storeMarked(cache, {0, 0, 0}, 2);
storeMarked(cache, {1, 0, 0}, 2);
Chunk chunk;
CHECK(cache.peekChunk({0, 0, 0}, chunk));
CHECK(!cache.peekChunk({5, 0, 0}, chunk));
CacheStats counted = cache.stats();
CHECK_EQ(counted.hits, static_cast<std::uint64_t>(0));
CHECK_EQ(counted.misses, static_cast<std::uint64_t>(0));
CHECK(cache.evictionOrder().front() == (Vec3i{0, 0, 0}));
}
VF_TEST(storingOverAnEntryKeepsByteAccountingAndPinning) {
ChunkCache cache(1ull << 30, CachePolicy::Lru);
storeMarked(cache, {0, 0, 0}, 12);
cache.pin({0, 0, 0});
CHECK_EQ(cache.bytesUsed(), sizeOfEntry(12));
storeMarked(cache, {0, 0, 0}, 3);
CHECK_EQ(cache.size(), static_cast<std::size_t>(1));
CHECK_EQ(cache.bytesUsed(), sizeOfEntry(3));
CHECK(cache.isPinned({0, 0, 0}));
CacheEntry entry;
CHECK(cache.entryFor({0, 0, 0}, entry));
CHECK_EQ(entry.mesh.opaque.quadCount(), static_cast<std::size_t>(3));
CHECK(entry.hasMesh);
CHECK(entry.pinned);
}
VF_TEST(clearEmptiesTheCache) {
ChunkCache cache(1ull << 30, CachePolicy::Lru);
for (int i = 0; i < 5; ++i) storeMarked(cache, {i, 0, 0}, 4);
CHECK_EQ(cache.size(), static_cast<std::size_t>(5));
cache.clear();
CHECK_EQ(cache.size(), static_cast<std::size_t>(0));
CHECK_EQ(cache.bytesUsed(), static_cast<std::uint64_t>(0));
CHECK(cache.residentCoords().empty());
CHECK(!cache.contains({0, 0, 0}));
}
VF_TEST(concurrentReadersNeverSeeAHalfWrittenEntry) {
ChunkCache cache(1ull << 30, CachePolicy::Lru);
const int coordCount = 8;
for (int i = 0; i < coordCount; ++i) storeMarked(cache, {i, 0, 0}, 4 + i);
std::atomic<int> mismatches{0};
std::atomic<long long> observed{0};
std::atomic<bool> stop{false};
std::vector<std::thread> readers;
for (int reader = 0; reader < 4; ++reader) {
readers.emplace_back([&] {
while (!stop.load(std::memory_order_acquire)) {
for (int i = 0; i < coordCount; ++i) {
ChunkMesh mesh;
if (!cache.peekMesh({i, 0, 0}, mesh)) continue;
observed.fetch_add(1);
if (mesh.opaque.quadCount() != static_cast<std::size_t>(4 + i))
mismatches.fetch_add(1);
else if (mesh.opaque.vertices[0].px != static_cast<float>(i))
mismatches.fetch_add(1);
if (mesh.opaque.indices.size() != mesh.opaque.quadCount() * 6)
mismatches.fetch_add(1);
}
}
});
}
for (int round = 0; round < 150; ++round)
for (int i = 0; i < coordCount; ++i) storeMarked(cache, {i, 0, 0}, 4 + i);
stop.store(true, std::memory_order_release);
for (std::thread& reader : readers) reader.join();
CHECK_EQ(mismatches.load(), 0);
CHECK(observed.load() > 0);
CHECK_EQ(cache.size(), static_cast<std::size_t>(coordCount));
}