RegTest: Log state and RAM hashes on exit
Useful for checking determinism.
This commit is contained in:
parent
1ed9e609a5
commit
82a843c121
|
@ -195,9 +195,6 @@ static void UpdatePerGameMemoryCards();
|
|||
static std::unique_ptr<MemoryCard> GetMemoryCardForSlot(u32 slot, MemoryCardType type);
|
||||
static void UpdateMultitaps();
|
||||
|
||||
/// Returns the maximum size of a save state, considering the current configuration.
|
||||
static size_t GetMaxSaveStateSize();
|
||||
|
||||
static std::string GetMediaPathFromSaveState(const char* path);
|
||||
static bool SaveUndoLoadState();
|
||||
static void UpdateMemorySaveStateSettings();
|
||||
|
@ -2929,7 +2926,18 @@ bool System::LoadStateFromBuffer(const SaveStateBuffer& buffer, Error* error, bo
|
|||
// Updating game/loading settings can turn on hardcore mode. Catch this.
|
||||
Achievements::DisableHardcoreMode();
|
||||
|
||||
StateWrapper sw(buffer.state_data.cspan(0, buffer.state_size), StateWrapper::Mode::Read, buffer.version);
|
||||
return LoadStateDataFromBuffer(buffer.state_data.cspan(0, buffer.state_size), buffer.version, error, update_display);
|
||||
}
|
||||
|
||||
bool System::LoadStateDataFromBuffer(std::span<const u8> data, u32 version, Error* error, bool update_display)
|
||||
{
|
||||
if (IsShutdown()) [[unlikely]]
|
||||
{
|
||||
Error::SetStringView(error, "System is invalid.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
StateWrapper sw(data, StateWrapper::Mode::Read, version);
|
||||
if (!DoState(sw, update_display))
|
||||
{
|
||||
Error::SetStringView(error, "Save state stream is corrupted.");
|
||||
|
@ -3197,12 +3205,6 @@ bool System::SaveState(std::string path, Error* error, bool backup_existing_save
|
|||
|
||||
bool System::SaveStateToBuffer(SaveStateBuffer* buffer, Error* error, u32 screenshot_size /* = 256 */)
|
||||
{
|
||||
if (IsShutdown()) [[unlikely]]
|
||||
{
|
||||
Error::SetStringView(error, "System is invalid.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
buffer->title = s_state.running_game_title;
|
||||
buffer->serial = s_state.running_game_serial;
|
||||
buffer->version = SAVE_STATE_VERSION;
|
||||
|
@ -3250,14 +3252,25 @@ bool System::SaveStateToBuffer(SaveStateBuffer* buffer, Error* error, u32 screen
|
|||
if (buffer->state_data.empty())
|
||||
buffer->state_data.resize(GetMaxSaveStateSize());
|
||||
|
||||
StateWrapper sw(buffer->state_data.span(), StateWrapper::Mode::Write, SAVE_STATE_VERSION);
|
||||
return SaveStateDataToBuffer(buffer->state_data, &buffer->state_size, error);
|
||||
}
|
||||
|
||||
bool System::SaveStateDataToBuffer(std::span<u8> data, size_t* data_size, Error* error)
|
||||
{
|
||||
if (IsShutdown()) [[unlikely]]
|
||||
{
|
||||
Error::SetStringView(error, "System is invalid.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
StateWrapper sw(data, StateWrapper::Mode::Write, SAVE_STATE_VERSION);
|
||||
if (!DoState(sw, false))
|
||||
{
|
||||
Error::SetStringView(error, "DoState() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
buffer->state_size = sw.GetPosition();
|
||||
*data_size = sw.GetPosition();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -260,11 +260,18 @@ bool BootSystem(SystemBootParameters parameters, Error* error);
|
|||
void PauseSystem(bool paused);
|
||||
void ResetSystem();
|
||||
|
||||
/// Returns the maximum size of a save state, considering the current configuration.
|
||||
size_t GetMaxSaveStateSize();
|
||||
|
||||
/// Loads state from the specified path.
|
||||
bool LoadState(const char* path, Error* error, bool save_undo_state);
|
||||
bool SaveState(std::string path, Error* error, bool backup_existing_save, bool ignore_memcard_busy);
|
||||
bool SaveResumeState(Error* error);
|
||||
|
||||
/// State data access, use with care as the media path is not updated.
|
||||
bool LoadStateDataFromBuffer(std::span<const u8> data, u32 version, Error* error, bool update_display);
|
||||
bool SaveStateDataToBuffer(std::span<u8> data, size_t* data_size, Error* error);
|
||||
|
||||
/// Runs the VM until the CPU execution is canceled.
|
||||
void Execute();
|
||||
|
||||
|
|
|
@ -2,12 +2,15 @@
|
|||
// SPDX-License-Identifier: CC-BY-NC-ND-4.0
|
||||
|
||||
#include "core/achievements.h"
|
||||
#include "core/bus.h"
|
||||
#include "core/controller.h"
|
||||
#include "core/fullscreen_ui.h"
|
||||
#include "core/game_list.h"
|
||||
#include "core/gpu.h"
|
||||
#include "core/gpu_backend.h"
|
||||
#include "core/gpu_thread.h"
|
||||
#include "core/host.h"
|
||||
#include "core/spu.h"
|
||||
#include "core/system.h"
|
||||
#include "core/system_private.h"
|
||||
|
||||
|
@ -27,6 +30,7 @@
|
|||
#include "common/log.h"
|
||||
#include "common/memory_settings_interface.h"
|
||||
#include "common/path.h"
|
||||
#include "common/sha256_digest.h"
|
||||
#include "common/string_util.h"
|
||||
#include "common/timer.h"
|
||||
|
||||
|
@ -38,6 +42,7 @@
|
|||
LOG_CHANNEL(Host);
|
||||
|
||||
namespace RegTestHost {
|
||||
|
||||
static bool ParseCommandLineParameters(int argc, char* argv[], std::optional<SystemBootParameters>& autoboot);
|
||||
static void PrintCommandLineVersion();
|
||||
static void PrintCommandLineHelp(const char* progname);
|
||||
|
@ -46,8 +51,10 @@ static void InitializeEarlyConsole();
|
|||
static void HookSignals();
|
||||
static bool SetFolders();
|
||||
static bool SetNewDataRoot(const std::string& filename);
|
||||
static void DumpSystemStateHashes();
|
||||
static std::string GetFrameDumpFilename(u32 frame);
|
||||
static void GPUThreadEntryPoint();
|
||||
|
||||
} // namespace RegTestHost
|
||||
|
||||
static std::unique_ptr<MemorySettingsInterface> s_base_settings_interface;
|
||||
|
@ -320,7 +327,10 @@ void Host::PumpMessagesOnCPUThread()
|
|||
{
|
||||
s_frames_remaining--;
|
||||
if (s_frames_remaining == 0)
|
||||
{
|
||||
RegTestHost::DumpSystemStateHashes();
|
||||
System::ShutdownSystem(false);
|
||||
}
|
||||
}
|
||||
|
||||
void Host::RunOnCPUThread(std::function<void()> function, bool block /* = false */)
|
||||
|
@ -528,6 +538,32 @@ void RegTestHost::GPUThreadEntryPoint()
|
|||
GPUThread::Internal::GPUThreadEntryPoint();
|
||||
}
|
||||
|
||||
void RegTestHost::DumpSystemStateHashes()
|
||||
{
|
||||
Error error;
|
||||
|
||||
// don't save full state on gpu dump, it's not going to be complete...
|
||||
if (!System::IsReplayingGPUDump())
|
||||
{
|
||||
DynamicHeapArray<u8> state_data(System::GetMaxSaveStateSize());
|
||||
size_t state_data_size;
|
||||
if (!System::SaveStateDataToBuffer(state_data, &state_data_size, &error))
|
||||
{
|
||||
ERROR_LOG("Failed to save system state: {}", error.GetDescription());
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG("Save State Hash: {}",
|
||||
SHA256Digest::DigestToString(SHA256Digest::GetDigest(state_data.cspan(0, state_data_size))));
|
||||
INFO_LOG("RAM Hash: {}",
|
||||
SHA256Digest::DigestToString(SHA256Digest::GetDigest(std::span<const u8>(Bus::g_ram, Bus::g_ram_size))));
|
||||
INFO_LOG("SPU RAM Hash: {}", SHA256Digest::DigestToString(SHA256Digest::GetDigest(SPU::GetRAM())));
|
||||
}
|
||||
|
||||
INFO_LOG("VRAM Hash: {}", SHA256Digest::DigestToString(SHA256Digest::GetDigest(
|
||||
std::span<const u8>(reinterpret_cast<const u8*>(g_vram), VRAM_SIZE))));
|
||||
}
|
||||
|
||||
void RegTestHost::InitializeEarlyConsole()
|
||||
{
|
||||
const bool was_console_enabled = Log::IsConsoleOutputEnabled();
|
||||
|
|
Loading…
Reference in New Issue