1 // Copyright 2016 Dolphin Emulator Project 2 // Licensed under GPLv2+ 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <array> 8 #include <memory> 9 #include <mutex> 10 #include <string> 11 #include <string_view> 12 #include <vector> 13 14 #include "Common/Analytics.h" 15 #include "Common/CommonTypes.h" 16 17 #if defined(ANDROID) 18 #include <functional> 19 #endif 20 // Non generic part of the Dolphin Analytics framework. See Common/Analytics.h 21 // for the main documentation. 22 23 enum class GameQuirk 24 { 25 // Sometimes code run from ICache is different from its mirror in RAM. 26 ICACHE_MATTERS = 0, 27 28 // The Wii remote hardware makes it possible to bypass normal data reporting and directly 29 // "read" extension or IR data. This would break our current TAS/NetPlay implementation. 30 DIRECTLY_READS_WIIMOTE_INPUT, 31 32 // Several Wii DI commands that are rarely/never used and not implemented by Dolphin 33 USES_DVD_LOW_STOP_LASER, 34 USES_DVD_LOW_OFFSET, 35 USES_DVD_LOW_READ_DISK_BCA, // NSMBW known to use this 36 USES_DVD_LOW_REQUEST_DISC_STATUS, 37 USES_DVD_LOW_REQUEST_RETRY_NUMBER, 38 USES_DVD_LOW_SER_MEAS_CONTROL, 39 40 // Dolphin only implements the simple DVDLowOpenPartition, not any of the variants where some 41 // already-read data is provided 42 USES_DIFFERENT_PARTITION_COMMAND, 43 44 // IOS has implementations for ioctls 0x85 and 0x89 and a stub for 0x87, but 45 // DVDLowMaskCoverInterrupt/DVDLowUnmaskCoverInterrupt/DVDLowUnmaskStatusInterrupts 46 // are all stubbed on the PPC side so they presumably will never be used. 47 // (DVDLowClearCoverInterrupt is used, though) 48 USES_DI_INTERRUPT_MASK_COMMAND, 49 50 // Some games configure a mismatched number of texture coordinates or colors between the transform 51 // and TEV/BP stages of the rendering pipeline. Currently, Dolphin just skips over these objects 52 // as the hardware renderers are not equipped to handle the case where the registers between 53 // stages are mismatched. 54 MISMATCHED_GPU_TEXGENS_BETWEEN_XF_AND_BP, 55 MISMATCHED_GPU_COLORS_BETWEEN_XF_AND_BP, 56 57 COUNT, 58 }; 59 60 class DolphinAnalytics 61 { 62 public: 63 // Performs lazy-initialization of a singleton and returns the instance. 64 static DolphinAnalytics& Instance(); 65 66 #if defined(ANDROID) 67 // Get value from java. 68 static void AndroidSetGetValFunc(std::function<std::string(std::string)> function); 69 #endif 70 // Resets and recreates the analytics system in order to reload 71 // configuration. 72 void ReloadConfig(); 73 // Rotates the unique identifier used for this instance of Dolphin and saves 74 // it into the configuration. 75 void GenerateNewIdentity(); 76 77 // Reports a Dolphin start event. 78 void ReportDolphinStart(std::string_view ui_type); 79 80 // Generates a base report for a "Game start" event. Also preseeds the 81 // per-game base data. 82 void ReportGameStart(); 83 84 // Generates a report for a special condition being hit by a game. This is automatically throttled 85 // to once per game run. 86 void ReportGameQuirk(GameQuirk quirk); 87 88 struct PerformanceSample 89 { 90 double speed_ratio; // See SystemTimers::GetEstimatedEmulationPerformance(). 91 int num_prims; 92 int num_draw_calls; 93 }; 94 // Reports performance information. This method performs its own throttling / aggregation -- 95 // calling it does not guarantee when a report will actually be sent. 96 // 97 // This method is NOT thread-safe. 98 void ReportPerformanceInfo(PerformanceSample&& sample); 99 100 // Forward Send method calls to the reporter. 101 template <typename T> Send(T report)102 void Send(T report) 103 { 104 std::lock_guard lk{m_reporter_mutex}; 105 m_reporter.Send(report); 106 } 107 108 private: 109 DolphinAnalytics(); 110 111 void MakeBaseBuilder(); 112 void MakePerGameBuilder(); 113 114 // Returns a unique ID derived on the global unique ID, hashed with some 115 // report-specific data. This avoid correlation between different types of 116 // events. 117 std::string MakeUniqueId(std::string_view data) const; 118 119 // Unique ID. This should never leave the application. Only used derived 120 // values created by MakeUniqueId. 121 std::string m_unique_id; 122 123 // Performance sampling configuration constants. 124 // 125 // 5min after startup + rand(0, 3min) jitter time, collect performance for 100 frames in a row. 126 // Repeat collection after 30min + rand(0, 3min). 127 static constexpr int NUM_PERFORMANCE_SAMPLES_PER_REPORT = 100; 128 static constexpr int PERFORMANCE_SAMPLING_INITIAL_WAIT_TIME_SECS = 300; 129 static constexpr int PERFORMANCE_SAMPLING_WAIT_TIME_JITTER_SECS = 180; 130 static constexpr int PERFORMANCE_SAMPLING_INTERVAL_SECS = 1800; 131 132 // Performance sampling state & internal helpers. 133 void InitializePerformanceSampling(); // Called on game start / title switch. 134 bool ShouldStartPerformanceSampling(); 135 u64 m_sampling_next_start_us; // Next timestamp (in us) at which to trigger sampling. 136 bool m_sampling_performance_info = false; // Whether we are currently collecting samples. 137 std::vector<PerformanceSample> m_performance_samples; 138 139 // What quirks have already been reported about the current game. 140 std::array<bool, static_cast<size_t>(GameQuirk::COUNT)> m_reported_quirks; 141 142 // Builder that contains all non variable data that should be sent with all 143 // reports. 144 Common::AnalyticsReportBuilder m_base_builder; 145 146 // Builder that contains per game data and is initialized when a game start 147 // report is sent. 148 Common::AnalyticsReportBuilder m_per_game_builder; 149 150 std::mutex m_reporter_mutex; 151 Common::AnalyticsReporter m_reporter; 152 }; 153