diff --git a/Source/Core/Core/Analytics.cpp b/Source/Core/Core/Analytics.cpp index b76f3b09f4..e6f9db25c2 100644 --- a/Source/Core/Core/Analytics.cpp +++ b/Source/Core/Core/Analytics.cpp @@ -131,9 +131,34 @@ void DolphinAnalytics::ReportGameStart() builder.AddData("type", "game-start"); Send(builder); + // Reset per-game state. + m_reported_quirks.fill(false); InitializePerformanceSampling(); } +// Keep in sync with enum class GameQuirk definition. +const char* GAME_QUIRKS_NAMES[] = { + "icache-matters", // ICACHE_MATTERS +}; +static_assert(sizeof(GAME_QUIRKS_NAMES) / sizeof(GAME_QUIRKS_NAMES[0]) == + static_cast(GameQuirk::COUNT), + "Game quirks names and enum definition are out of sync."); + +void DolphinAnalytics::ReportGameQuirk(GameQuirk quirk) +{ + u32 quirk_idx = static_cast(quirk); + + // Only report once per run. + if (m_reported_quirks[quirk_idx]) + return; + m_reported_quirks[quirk_idx] = true; + + Common::AnalyticsReportBuilder builder(m_per_game_builder); + builder.AddData("type", "quirk"); + builder.AddData("quirk", GAME_QUIRKS_NAMES[quirk_idx]); + Send(builder); +} + void DolphinAnalytics::ReportPerformanceInfo(PerformanceSample&& sample) { if (ShouldStartPerformanceSampling()) diff --git a/Source/Core/Core/Analytics.h b/Source/Core/Core/Analytics.h index c0725efd51..0de0f839f8 100644 --- a/Source/Core/Core/Analytics.h +++ b/Source/Core/Core/Analytics.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include #include @@ -18,6 +19,14 @@ // Non generic part of the Dolphin Analytics framework. See Common/Analytics.h // for the main documentation. +enum class GameQuirk +{ + // Sometimes code run from ICache is different from its mirror in RAM. + ICACHE_MATTERS = 0, + + COUNT, +}; + class DolphinAnalytics { public: @@ -42,6 +51,10 @@ public: // per-game base data. void ReportGameStart(); + // Generates a report for a special condition being hit by a game. This is automatically throttled + // to once per game run. + void ReportGameQuirk(GameQuirk quirk); + struct PerformanceSample { double speed_ratio; // See SystemTimers::GetEstimatedEmulationPerformance(). @@ -93,6 +106,9 @@ private: bool m_sampling_performance_info = false; // Whether we are currently collecting samples. std::vector m_performance_samples; + // What quirks have already been reported about the current game. + std::array(GameQuirk::COUNT)> m_reported_quirks; + // Builder that contains all non variable data that should be sent with all // reports. Common::AnalyticsReportBuilder m_base_builder; diff --git a/Source/Core/Core/PowerPC/PPCCache.cpp b/Source/Core/Core/PowerPC/PPCCache.cpp index 1b8e41b5b1..f3cdefb0c3 100644 --- a/Source/Core/Core/PowerPC/PPCCache.cpp +++ b/Source/Core/Core/PowerPC/PPCCache.cpp @@ -8,6 +8,7 @@ #include "Common/ChunkFile.h" #include "Common/Swap.h" +#include "Core/Analytics.h" #include "Core/HW/Memmap.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/PowerPC.h" @@ -148,6 +149,13 @@ u32 InstructionCache::ReadInstruction(u32 addr) // update plru plru[set] = (plru[set] & ~s_plru_mask[t]) | s_plru_value[t]; u32 res = Common::swap32(data[set][t][(addr >> 2) & 7]); + u32 inmem = Memory::Read_U32(addr); + if (res != inmem) + { + INFO_LOG(POWERPC, "ICache read at %08x returned stale data: CACHED: %08x vs. RAM: %08x", addr, + res, inmem); + DolphinAnalytics::Instance()->ReportGameQuirk(GameQuirk::ICACHE_MATTERS); + } return res; }