MetaCore/tests/MetaCoreSceneBenchmark.cpp
2026-07-27 17:02:26 +08:00

82 lines
3.5 KiB
C++

#include "MetaCoreScene/MetaCorePrefab.h"
#include "MetaCoreScene/MetaCoreSceneWorld.h"
#include <algorithm>
#include <chrono>
#include <cstdlib>
#include <iostream>
#include <vector>
namespace {
double MillisecondsSince(std::chrono::steady_clock::time_point begin) {
return std::chrono::duration<double, std::milli>(std::chrono::steady_clock::now() - begin).count();
}
} // namespace
int main() {
using namespace MetaCore;
MetaCoreSceneDocument largeScene;
largeScene.SceneGuid = MetaCoreAssetGuid::Generate();
largeScene.Name = "SceneBenchmark";
constexpr std::size_t objectCount = 10000;
largeScene.GameObjects.reserve(objectCount);
for (std::size_t index = 0; index < objectCount; ++index) {
MetaCoreGameObjectData object;
object.Id = index + 1;
object.ParentId = index == 0 ? 0 : (index / 10) + 1;
if (object.ParentId == object.Id) object.ParentId = 0;
object.SceneGuid = largeScene.SceneGuid;
object.StableObjectGuid = MetaCoreBuildDeterministicGuid(largeScene.SceneGuid, object.Id);
object.Name = "Object_" + std::to_string(index);
largeScene.GameObjects.push_back(std::move(object));
}
MetaCoreSceneWorld world;
const auto loadBegin = std::chrono::steady_clock::now();
if (!world.LoadDocumentNow(largeScene, MetaCoreSceneLoadMode::Replace)) return EXIT_FAILURE;
const double loadMilliseconds = MillisecondsSince(loadBegin);
std::vector<double> captureSamples;
captureSamples.reserve(40);
for (int sample = 0; sample < 40; ++sample) {
const auto begin = std::chrono::steady_clock::now();
if (!world.CaptureSceneDocument(largeScene.SceneGuid)) return EXIT_FAILURE;
captureSamples.push_back(MillisecondsSince(begin));
}
std::sort(captureSamples.begin(), captureSamples.end());
const double captureP95 = captureSamples[static_cast<std::size_t>(captureSamples.size() * 0.95)];
MetaCorePrefabDocument prefab;
prefab.PrefabGuid = MetaCoreAssetGuid::Generate();
prefab.Name = "BenchmarkPrefab";
prefab.GameObjects.assign(largeScene.GameObjects.begin(), largeScene.GameObjects.begin() + 100);
MetaCorePrefabResolver resolver([&](const MetaCoreAssetGuid& guid) -> std::optional<MetaCorePrefabDocument> {
return guid == prefab.PrefabGuid ? std::optional(prefab) : std::nullopt;
});
std::vector<double> prefabSamples;
prefabSamples.reserve(100);
for (int sample = 0; sample < 100; ++sample) {
const auto begin = std::chrono::steady_clock::now();
if (!resolver.Instantiate(prefab.PrefabGuid, MetaCoreAssetGuid::Generate())) return EXIT_FAILURE;
prefabSamples.push_back(MillisecondsSince(begin));
}
std::sort(prefabSamples.begin(), prefabSamples.end());
const double prefabP95 = prefabSamples[static_cast<std::size_t>(prefabSamples.size() * 0.95)];
std::cout << "SceneBenchmark objects=" << objectCount
<< " load_ms=" << loadMilliseconds
<< " capture_p95_ms=" << captureP95
<< " prefab100_p95_ms=" << prefabP95 << '\n';
// Linux x86_64 signed baseline (2026-07-27): load 37.10 ms,
// capture p95 12.17 ms, prefab(100 nodes) p95 0.031 ms. Gates are
// rounded up from 120% to avoid sub-microsecond timer noise.
if (loadMilliseconds > 45.0 || captureP95 > 15.0 || prefabP95 > 0.04) {
std::cerr << "Scene/Prefab benchmark exceeded Linux x86_64 regression gate\n";
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}