mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2025-12-24 00:03:11 +01:00
Merge pull request #10700 from janisozaur/benchsimulate
Add benchsimulate command
This commit is contained in:
@@ -238,6 +238,7 @@
|
||||
9308DA04209908090079EE96 /* TileElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 9308D9FC209908080079EE96 /* TileElement.h */; };
|
||||
9308DA05209908090079EE96 /* Surface.h in Headers */ = {isa = PBXBuildFile; fileRef = 9308D9FD209908090079EE96 /* Surface.h */; };
|
||||
930EEA6A24FC00950070314E /* ScenarioSelect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 930EEA6924FC00940070314E /* ScenarioSelect.cpp */; };
|
||||
9329D520240C17C60054301C /* BenchUpdate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9329D51F240C17C60054301C /* BenchUpdate.cpp */; };
|
||||
932A211E22D73CFA00C57EDB /* GameActionCompat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 932A20CF22D73CEE00C57EDB /* GameActionCompat.cpp */; };
|
||||
932A211F22D73CFA00C57EDB /* GameActionRegistration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 932A20D322D73CEF00C57EDB /* GameActionRegistration.cpp */; };
|
||||
932A212022D73CFA00C57EDB /* GameAction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 932A211C22D73CFA00C57EDB /* GameAction.cpp */; };
|
||||
@@ -1325,6 +1326,9 @@
|
||||
9308D9FC209908080079EE96 /* TileElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TileElement.h; sourceTree = "<group>"; };
|
||||
9308D9FD209908090079EE96 /* Surface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Surface.h; sourceTree = "<group>"; };
|
||||
930EEA6924FC00940070314E /* ScenarioSelect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScenarioSelect.cpp; sourceTree = "<group>"; };
|
||||
9329D51F240C17C60054301C /* BenchUpdate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BenchUpdate.cpp; sourceTree = "<group>"; };
|
||||
932A20CD22D73CEE00C57EDB /* GuestSetNameAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = GuestSetNameAction.hpp; sourceTree = "<group>"; };
|
||||
932A20CE22D73CEE00C57EDB /* RideSetVehiclesAction.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RideSetVehiclesAction.hpp; sourceTree = "<group>"; };
|
||||
932A20CF22D73CEE00C57EDB /* GameActionCompat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GameActionCompat.cpp; sourceTree = "<group>"; };
|
||||
932A20D322D73CEF00C57EDB /* GameActionRegistration.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GameActionRegistration.cpp; sourceTree = "<group>"; };
|
||||
932A20F522D73CF300C57EDB /* GameAction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GameAction.h; sourceTree = "<group>"; };
|
||||
@@ -3122,6 +3126,7 @@
|
||||
children = (
|
||||
D48AFDB61EF78DBF0081C644 /* BenchGfxCommmands.cpp */,
|
||||
4C724B2121F0AD790012ADD0 /* BenchSpriteSort.cpp */,
|
||||
9329D51F240C17C60054301C /* BenchUpdate.cpp */,
|
||||
F76C83631EC4E7CC00FA49E2 /* CommandLine.cpp */,
|
||||
F76C83641EC4E7CC00FA49E2 /* CommandLine.hpp */,
|
||||
F76C83651EC4E7CC00FA49E2 /* ConvertCommand.cpp */,
|
||||
@@ -4659,6 +4664,7 @@
|
||||
C688785820289A0A0084B384 /* Balloon.cpp in Sources */,
|
||||
C688788820289ADE0084B384 /* X8DrawingEngine.cpp in Sources */,
|
||||
66A10F6A257F1E1800DD651A /* LargeScenerySetColourAction.cpp in Sources */,
|
||||
9329D520240C17C60054301C /* BenchUpdate.cpp in Sources */,
|
||||
F775F5381EE3725C001F00E7 /* DummyAudioContext.cpp in Sources */,
|
||||
F775F5351EE35A89001F00E7 /* DummyUiContext.cpp in Sources */,
|
||||
2A1F4FE1221FF4B0003CA045 /* Audio.cpp in Sources */,
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "Context.h"
|
||||
#include "Editor.h"
|
||||
#include "Game.h"
|
||||
#include "GameState.h"
|
||||
#include "GameStateSnapshots.h"
|
||||
#include "Input.h"
|
||||
#include "OpenRCT2.h"
|
||||
@@ -37,6 +38,7 @@
|
||||
#include "world/Scenery.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
|
||||
using namespace OpenRCT2;
|
||||
using namespace OpenRCT2::Scripting;
|
||||
@@ -225,8 +227,17 @@ void GameState::Update()
|
||||
gInUpdateCode = false;
|
||||
}
|
||||
|
||||
void GameState::UpdateLogic()
|
||||
void GameState::UpdateLogic(LogicTimings* timings)
|
||||
{
|
||||
auto start_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
auto report_time = [timings, start_time](LogicTimePart part) {
|
||||
if (timings != nullptr)
|
||||
{
|
||||
timings->TimingInfo[part][timings->CurrentIdx] = std::chrono::high_resolution_clock::now() - start_time;
|
||||
}
|
||||
};
|
||||
|
||||
gScreenAge++;
|
||||
if (gScreenAge == 0)
|
||||
gScreenAge--;
|
||||
@@ -234,6 +245,7 @@ void GameState::UpdateLogic()
|
||||
GetContext()->GetReplayManager()->Update();
|
||||
|
||||
network_update();
|
||||
report_time(LogicTimePart::NetworkUpdate);
|
||||
|
||||
if (network_get_mode() == NETWORK_MODE_SERVER)
|
||||
{
|
||||
@@ -277,33 +289,51 @@ void GameState::UpdateLogic()
|
||||
|
||||
date_update();
|
||||
_date = Date(static_cast<uint32_t>(gDateMonthsElapsed), gDateMonthTicks);
|
||||
report_time(LogicTimePart::Date);
|
||||
|
||||
scenario_update();
|
||||
report_time(LogicTimePart::Scenario);
|
||||
climate_update();
|
||||
report_time(LogicTimePart::Climate);
|
||||
map_update_tiles();
|
||||
report_time(LogicTimePart::MapTiles);
|
||||
// Temporarily remove provisional paths to prevent peep from interacting with them
|
||||
map_remove_provisional_elements();
|
||||
report_time(LogicTimePart::MapStashProvisionalElements);
|
||||
map_update_path_wide_flags();
|
||||
report_time(LogicTimePart::MapPathWideFlags);
|
||||
peep_update_all();
|
||||
report_time(LogicTimePart::Peep);
|
||||
map_restore_provisional_elements();
|
||||
report_time(LogicTimePart::MapRestoreProvisionalElements);
|
||||
vehicle_update_all();
|
||||
report_time(LogicTimePart::Vehicle);
|
||||
sprite_misc_update_all();
|
||||
report_time(LogicTimePart::Misc);
|
||||
Ride::UpdateAll();
|
||||
report_time(LogicTimePart::Ride);
|
||||
|
||||
if (!(gScreenFlags & SCREEN_FLAGS_EDITOR))
|
||||
{
|
||||
_park->Update(_date);
|
||||
}
|
||||
report_time(LogicTimePart::Park);
|
||||
|
||||
research_update();
|
||||
report_time(LogicTimePart::Research);
|
||||
ride_ratings_update_all();
|
||||
report_time(LogicTimePart::RideRatings);
|
||||
ride_measurements_update();
|
||||
report_time(LogicTimePart::RideMeasurments);
|
||||
News::UpdateCurrentItem();
|
||||
report_time(LogicTimePart::News);
|
||||
|
||||
map_animation_invalidate_all();
|
||||
report_time(LogicTimePart::MapAnimation);
|
||||
vehicle_sounds_update();
|
||||
peep_update_crowd_noise();
|
||||
climate_update_sound();
|
||||
report_time(LogicTimePart::Sounds);
|
||||
editor_open_windows_for_current_step();
|
||||
|
||||
// Update windows
|
||||
@@ -316,9 +346,11 @@ void GameState::UpdateLogic()
|
||||
}
|
||||
|
||||
GameActions::ProcessQueue();
|
||||
report_time(LogicTimePart::GameActions);
|
||||
|
||||
network_process_pending();
|
||||
network_flush();
|
||||
report_time(LogicTimePart::NetworkFlush);
|
||||
|
||||
gCurrentTicks++;
|
||||
gScenarioTicks++;
|
||||
@@ -332,7 +364,13 @@ void GameState::UpdateLogic()
|
||||
{
|
||||
hookEngine.Call(HOOK_TYPE::INTERVAL_DAY, true);
|
||||
}
|
||||
report_time(LogicTimePart::Scripts);
|
||||
#endif
|
||||
|
||||
if (timings != nullptr)
|
||||
{
|
||||
timings->CurrentIdx = (timings->CurrentIdx + 1) % LOGIC_UPDATE_MEASUREMENTS_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
void GameState::CreateStateSnapshot()
|
||||
|
||||
@@ -11,12 +11,55 @@
|
||||
|
||||
#include "Date.h"
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace OpenRCT2
|
||||
{
|
||||
class Park;
|
||||
|
||||
// Information regarding various pieces of logic update
|
||||
enum class LogicTimePart
|
||||
{
|
||||
NetworkUpdate,
|
||||
Date,
|
||||
Scenario,
|
||||
Climate,
|
||||
MapTiles,
|
||||
MapStashProvisionalElements,
|
||||
MapPathWideFlags,
|
||||
Peep,
|
||||
MapRestoreProvisionalElements,
|
||||
Vehicle,
|
||||
Misc,
|
||||
Ride,
|
||||
Park,
|
||||
Research,
|
||||
RideRatings,
|
||||
RideMeasurments,
|
||||
News,
|
||||
MapAnimation,
|
||||
Sounds,
|
||||
GameActions,
|
||||
NetworkFlush,
|
||||
Scripts,
|
||||
};
|
||||
|
||||
// ~6.5s at 40Hz
|
||||
constexpr size_t LOGIC_UPDATE_MEASUREMENTS_COUNT = 256;
|
||||
|
||||
// In order not to cause allocations, collect multiple samples into single pre-allocated struct
|
||||
using LogicTimingInfo = std::unordered_map<
|
||||
LogicTimePart, std::array<std::chrono::duration<double>, LOGIC_UPDATE_MEASUREMENTS_COUNT>>;
|
||||
|
||||
struct LogicTimings
|
||||
{
|
||||
LogicTimingInfo TimingInfo;
|
||||
size_t CurrentIdx{};
|
||||
};
|
||||
|
||||
/**
|
||||
* Class to update the state of the map and park.
|
||||
*/
|
||||
@@ -41,7 +84,7 @@ namespace OpenRCT2
|
||||
|
||||
void InitAll(int32_t mapSize);
|
||||
void Update();
|
||||
void UpdateLogic();
|
||||
void UpdateLogic(LogicTimings* timings = nullptr);
|
||||
|
||||
private:
|
||||
void CreateStateSnapshot();
|
||||
|
||||
161
src/openrct2/cmdline/BenchUpdate.cpp
Normal file
161
src/openrct2/cmdline/BenchUpdate.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
/*****************************************************************************
|
||||
* Copyright (c) 2014-2020 OpenRCT2 developers
|
||||
*
|
||||
* For a complete list of all authors, please refer to contributors.md
|
||||
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||
*
|
||||
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "CommandLine.hpp"
|
||||
|
||||
#ifdef USE_BENCHMARK
|
||||
|
||||
# include "../Context.h"
|
||||
# include "../GameState.h"
|
||||
# include "../OpenRCT2.h"
|
||||
# include "../platform/Platform2.h"
|
||||
# include "../platform/platform.h"
|
||||
|
||||
# include <benchmark/benchmark.h>
|
||||
# include <cstdint>
|
||||
# include <iterator>
|
||||
# include <numeric>
|
||||
# include <vector>
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
static void BM_update(benchmark::State& state, const std::string& filename)
|
||||
{
|
||||
std::unique_ptr<IContext> context(CreateContext());
|
||||
if (context->Initialise())
|
||||
{
|
||||
if (!filename.empty() && !context->LoadParkFromFile(filename))
|
||||
{
|
||||
state.SkipWithError("Failed to load file!");
|
||||
}
|
||||
|
||||
std::vector<LogicTimings> timings(1);
|
||||
timings.reserve(100);
|
||||
int currentTimingIdx = 0;
|
||||
for (auto _ : state)
|
||||
{
|
||||
if (timings[currentTimingIdx].CurrentIdx == (LOGIC_UPDATE_MEASUREMENTS_COUNT - 1))
|
||||
{
|
||||
timings.resize(timings.size() + 1);
|
||||
currentTimingIdx++;
|
||||
}
|
||||
LogicTimings* timingToUse = &timings[currentTimingIdx];
|
||||
context->GetGameState()->UpdateLogic(timingToUse);
|
||||
}
|
||||
state.SetItemsProcessed(state.iterations());
|
||||
auto accumulator = [timings](LogicTimePart part) -> double {
|
||||
std::chrono::duration<double> timesum;
|
||||
for (const auto& timing : timings)
|
||||
{
|
||||
timesum = std::accumulate(
|
||||
timing.TimingInfo.at(part).begin(), timing.TimingInfo.at(part).end(), std::chrono::duration<double>());
|
||||
}
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(timesum).count();
|
||||
};
|
||||
state.counters["NetworkUpdateAcc_ms"] = accumulator(LogicTimePart::NetworkUpdate);
|
||||
state.counters["DateAcc_ms"] = accumulator(LogicTimePart::Date);
|
||||
state.counters["ScenarioAcc_ms"] = accumulator(LogicTimePart::Scenario);
|
||||
state.counters["ClimateAcc_ms"] = accumulator(LogicTimePart::Climate);
|
||||
state.counters["MapTilesAcc_ms"] = accumulator(LogicTimePart::MapTiles);
|
||||
state.counters["MapStashProvisionalElementsAcc_ms"] = accumulator(LogicTimePart::MapStashProvisionalElements);
|
||||
state.counters["MapPathWideFlagsAcc_ms"] = accumulator(LogicTimePart::MapPathWideFlags);
|
||||
state.counters["PeepAcc_ms"] = accumulator(LogicTimePart::Peep);
|
||||
state.counters["MapRestoreProvisionalElementsAcc_ms"] = accumulator(LogicTimePart::MapRestoreProvisionalElements);
|
||||
state.counters["VehicleAcc_ms"] = accumulator(LogicTimePart::Vehicle);
|
||||
state.counters["MiscAcc_ms"] = accumulator(LogicTimePart::Misc);
|
||||
state.counters["RideAcc_ms"] = accumulator(LogicTimePart::Ride);
|
||||
state.counters["ParkAcc_ms"] = accumulator(LogicTimePart::Park);
|
||||
state.counters["ResearchAcc_ms"] = accumulator(LogicTimePart::Research);
|
||||
state.counters["RideRatingsAcc_ms"] = accumulator(LogicTimePart::RideRatings);
|
||||
state.counters["RideMeasurmentsAcc_ms"] = accumulator(LogicTimePart::RideMeasurments);
|
||||
state.counters["NewsAcc_ms"] = accumulator(LogicTimePart::News);
|
||||
state.counters["MapAnimationAcc_ms"] = accumulator(LogicTimePart::MapAnimation);
|
||||
state.counters["SoundsAcc_ms"] = accumulator(LogicTimePart::Sounds);
|
||||
state.counters["GameActionsAcc_ms"] = accumulator(LogicTimePart::GameActions);
|
||||
state.counters["NetworkFlushAcc_ms"] = accumulator(LogicTimePart::NetworkFlush);
|
||||
state.counters["ScriptsAcc_ms"] = accumulator(LogicTimePart::Scripts);
|
||||
}
|
||||
else
|
||||
{
|
||||
state.SkipWithError("Context initialization failed.");
|
||||
}
|
||||
}
|
||||
|
||||
static int CmdlineForBenchSpriteSort(int argc, const char* const* argv)
|
||||
{
|
||||
// Add a baseline test on an empty park
|
||||
benchmark::RegisterBenchmark("baseline", BM_update, std::string{});
|
||||
|
||||
// Google benchmark does stuff to argv. It doesn't modify the pointees,
|
||||
// but it wants to reorder the pointers, so present a copy of them.
|
||||
std::vector<char*> argv_for_benchmark;
|
||||
|
||||
// argv[0] is expected to contain the binary name. It's only for logging purposes, don't bother.
|
||||
argv_for_benchmark.push_back(nullptr);
|
||||
|
||||
// Extract file names from argument list. If there is no such file, consider it benchmark option.
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
if (Platform::FileExists(argv[i]))
|
||||
{
|
||||
// Register benchmark for sv6 if valid
|
||||
benchmark::RegisterBenchmark(argv[i], BM_update, argv[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
argv_for_benchmark.push_back(const_cast<char*>(argv[i]));
|
||||
}
|
||||
}
|
||||
// Update argc with all the changes made
|
||||
argc = static_cast<int>(argv_for_benchmark.size());
|
||||
::benchmark::Initialize(&argc, &argv_for_benchmark[0]);
|
||||
if (::benchmark::ReportUnrecognizedArguments(argc, &argv_for_benchmark[0]))
|
||||
return -1;
|
||||
|
||||
core_init();
|
||||
gOpenRCT2Headless = true;
|
||||
|
||||
::benchmark::RunSpecifiedBenchmarks();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static exitcode_t HandleBenchUpdate(CommandLineArgEnumerator* argEnumerator)
|
||||
{
|
||||
const char* const* argv = static_cast<const char* const*>(argEnumerator->GetArguments()) + argEnumerator->GetIndex();
|
||||
int32_t argc = argEnumerator->GetCount() - argEnumerator->GetIndex();
|
||||
int32_t result = CmdlineForBenchSpriteSort(argc, argv);
|
||||
if (result < 0)
|
||||
{
|
||||
return EXITCODE_FAIL;
|
||||
}
|
||||
return EXITCODE_OK;
|
||||
}
|
||||
|
||||
#else
|
||||
static exitcode_t HandleBenchUpdate(CommandLineArgEnumerator* argEnumerator)
|
||||
{
|
||||
log_error("Sorry, Google benchmark not enabled in this build");
|
||||
return EXITCODE_FAIL;
|
||||
}
|
||||
#endif // USE_BENCHMARK
|
||||
|
||||
const CommandLineCommand CommandLine::BenchUpdateCommands[]{
|
||||
#ifdef USE_BENCHMARK
|
||||
DefineCommand(
|
||||
"",
|
||||
"<file>... [--benchmark_list_tests={true|false}] [--benchmark_filter=<regex>] [--benchmark_min_time=<min_time>] "
|
||||
"[--benchmark_repetitions=<num_repetitions>] [--benchmark_report_aggregates_only={true|false}] "
|
||||
"[--benchmark_format=<console|json|csv>] [--benchmark_out=<filename>] [--benchmark_out_format=<json|console|csv>] "
|
||||
"[--benchmark_color={auto|true|false}] [--benchmark_counters_tabular={true|false}] [--v=<verbosity>]",
|
||||
nullptr, HandleBenchUpdate),
|
||||
CommandTableEnd
|
||||
#else
|
||||
DefineCommand("", "*** SORRY NOT ENABLED IN THIS BUILD ***", nullptr, HandleBenchUpdate), CommandTableEnd
|
||||
#endif // USE_BENCHMARK
|
||||
};
|
||||
@@ -118,6 +118,7 @@ namespace CommandLine
|
||||
extern const CommandLineCommand SpriteCommands[];
|
||||
extern const CommandLineCommand BenchGfxCommands[];
|
||||
extern const CommandLineCommand BenchSpriteSortCommands[];
|
||||
extern const CommandLineCommand BenchUpdateCommands[];
|
||||
extern const CommandLineCommand SimulateCommands[];
|
||||
|
||||
extern const CommandLineExample RootExamples[];
|
||||
|
||||
@@ -140,6 +140,7 @@ const CommandLineCommand CommandLine::RootCommands[]
|
||||
DefineSubCommand("sprite", CommandLine::SpriteCommands ),
|
||||
DefineSubCommand("benchgfx", CommandLine::BenchGfxCommands ),
|
||||
DefineSubCommand("benchspritesort", CommandLine::BenchSpriteSortCommands ),
|
||||
DefineSubCommand("benchsimulate", CommandLine::BenchUpdateCommands ),
|
||||
DefineSubCommand("simulate", CommandLine::SimulateCommands ),
|
||||
CommandTableEnd
|
||||
};
|
||||
|
||||
@@ -553,6 +553,7 @@
|
||||
<ClCompile Include="CmdlineSprite.cpp" />
|
||||
<ClCompile Include="cmdline\BenchGfxCommmands.cpp" />
|
||||
<ClCompile Include="cmdline\BenchSpriteSort.cpp" />
|
||||
<ClCompile Include="cmdline/BenchUpdate.cpp" />
|
||||
<ClCompile Include="cmdline\CommandLine.cpp" />
|
||||
<ClCompile Include="cmdline\ConvertCommand.cpp" />
|
||||
<ClCompile Include="cmdline\RootCommands.cpp" />
|
||||
|
||||
Reference in New Issue
Block a user