diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp index a1455d373..024980a91 100644 --- a/src/citra/citra.cpp +++ b/src/citra/citra.cpp @@ -382,7 +382,7 @@ int main(int argc, char** argv) { break; // Expected case } - system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "SDL"); + system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "SDL"); if (use_multiplayer) { if (auto member = Network::GetRoomMember().lock()) { diff --git a/src/citra_qt/compatdb.cpp b/src/citra_qt/compatdb.cpp index 948d1b8a2..28f5438f2 100644 --- a/src/citra_qt/compatdb.cpp +++ b/src/citra_qt/compatdb.cpp @@ -52,7 +52,8 @@ void CompatDB::Submit() { back(); LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId()); Core::System::GetInstance().TelemetrySession().AddField( - Telemetry::FieldType::UserFeedback, "Compatibility", compatibility->checkedId()); + Common::Telemetry::FieldType::UserFeedback, "Compatibility", + compatibility->checkedId()); button(NextButton)->setEnabled(false); button(NextButton)->setText(tr("Submitting")); diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index b93df716e..f4ae1cb98 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -190,7 +190,20 @@ GMainWindow::GMainWindow() LOG_INFO(Frontend, "Citra Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc); #ifdef ARCHITECTURE_x86_64 - LOG_INFO(Frontend, "Host CPU: {}", Common::GetCPUCaps().cpu_string); + const auto& caps = Common::GetCPUCaps(); + std::string cpu_string = caps.cpu_string; + if (caps.avx || caps.avx2 || caps.avx512) { + cpu_string += " | AVX"; + if (caps.avx512) { + cpu_string += "512"; + } else if (caps.avx2) { + cpu_string += '2'; + } + if (caps.fma || caps.fma4) { + cpu_string += " | FMA"; + } + } + LOG_INFO(Frontend, "Host CPU: {}", cpu_string); #endif LOG_INFO(Frontend, "Host OS: {}", QSysInfo::prettyProductName().toStdString()); UpdateWindowTitle(); @@ -989,7 +1002,7 @@ bool GMainWindow::LoadROM(const QString& filename) { game_path = filename; - system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "Qt"); + system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "Qt"); return true; } diff --git a/src/common/telemetry.cpp b/src/common/telemetry.cpp index bf1f54886..6241d08b3 100644 --- a/src/common/telemetry.cpp +++ b/src/common/telemetry.cpp @@ -3,9 +3,16 @@ // Refer to the license.txt file included. #include +#include +#include "common/assert.h" +#include "common/scm_rev.h" #include "common/telemetry.h" -namespace Telemetry { +#ifdef ARCHITECTURE_x86_64 +#include "common/x64/cpu_detect.h" +#endif + +namespace Common::Telemetry { void FieldCollection::Accept(VisitorInterface& visitor) const { for (const auto& field : fields) { @@ -37,4 +44,48 @@ template class Field; template class Field; template class Field; -} // namespace Telemetry +void AppendBuildInfo(FieldCollection& fc) { + const bool is_git_dirty{std::strstr(Common::g_scm_desc, "dirty") != nullptr}; + fc.AddField(FieldType::App, "Git_IsDirty", is_git_dirty); + fc.AddField(FieldType::App, "Git_Branch", Common::g_scm_branch); + fc.AddField(FieldType::App, "Git_Revision", Common::g_scm_rev); + fc.AddField(FieldType::App, "BuildDate", Common::g_build_date); + fc.AddField(FieldType::App, "BuildName", Common::g_build_name); +} + +void AppendCPUInfo(FieldCollection& fc) { +#ifdef ARCHITECTURE_x86_64 + fc.AddField(FieldType::UserSystem, "CPU_Model", Common::GetCPUCaps().cpu_string); + fc.AddField(FieldType::UserSystem, "CPU_BrandString", Common::GetCPUCaps().brand_string); + fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AES", Common::GetCPUCaps().aes); + fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX", Common::GetCPUCaps().avx); + fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX2", Common::GetCPUCaps().avx2); + fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_AVX512", Common::GetCPUCaps().avx512); + fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_BMI1", Common::GetCPUCaps().bmi1); + fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_BMI2", Common::GetCPUCaps().bmi2); + fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_FMA", Common::GetCPUCaps().fma); + fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_FMA4", Common::GetCPUCaps().fma4); + fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_SSE", Common::GetCPUCaps().sse); + fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_SSE2", Common::GetCPUCaps().sse2); + fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_SSE3", Common::GetCPUCaps().sse3); + fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_SSSE3", Common::GetCPUCaps().ssse3); + fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_SSE41", Common::GetCPUCaps().sse4_1); + fc.AddField(FieldType::UserSystem, "CPU_Extension_x64_SSE42", Common::GetCPUCaps().sse4_2); +#else + fc.AddField(FieldType::UserSystem, "CPU_Model", "Other"); +#endif +} + +void AppendOSInfo(FieldCollection& fc) { +#ifdef __APPLE__ + fc.AddField(FieldType::UserSystem, "OsPlatform", "Apple"); +#elif defined(_WIN32) + fc.AddField(FieldType::UserSystem, "OsPlatform", "Windows"); +#elif defined(__linux__) || defined(linux) || defined(__linux) + fc.AddField(FieldType::UserSystem, "OsPlatform", "Linux"); +#else + fc.AddField(FieldType::UserSystem, "OsPlatform", "Unknown"); +#endif +} + +} // namespace Common::Telemetry diff --git a/src/common/telemetry.h b/src/common/telemetry.h index 3bf18cfda..ba5f0c87d 100644 --- a/src/common/telemetry.h +++ b/src/common/telemetry.h @@ -10,7 +10,7 @@ #include #include "common/common_types.h" -namespace Telemetry { +namespace Common::Telemetry { /// Field type, used for grouping fields together in the final submitted telemetry log enum class FieldType : u8 { @@ -55,8 +55,8 @@ public: Field(FieldType type, std::string name, T value) : name(std::move(name)), type(type), value(std::move(value)) {} - Field(const Field& other) = default; - Field& operator=(const Field& other) = default; + Field(const Field&) = default; + Field& operator=(const Field&) = default; Field(Field&&) = default; Field& operator=(Field&& other) = default; @@ -184,4 +184,16 @@ struct NullVisitor : public VisitorInterface { } }; -} // namespace Telemetry +/// Appends build-specific information to the given FieldCollection, +/// such as branch name, revision hash, etc. +void AppendBuildInfo(FieldCollection& fc); + +/// Appends CPU-specific information to the given FieldCollection, +/// such as instruction set extensions, etc. +void AppendCPUInfo(FieldCollection& fc); + +/// Appends OS-specific information to the given FieldCollection, +/// such as platform name, etc. +void AppendOSInfo(FieldCollection& fc); + +} // namespace Common::Telemetry diff --git a/src/common/x64/cpu_detect.cpp b/src/common/x64/cpu_detect.cpp index 3a36c3f68..f6677d5a0 100644 --- a/src/common/x64/cpu_detect.cpp +++ b/src/common/x64/cpu_detect.cpp @@ -110,6 +110,11 @@ static CPUCaps Detect() { caps.bmi1 = true; if ((cpu_id[1] >> 8) & 1) caps.bmi2 = true; + // Checks for AVX512F, AVX512CD, AVX512VL, AVX512DQ, AVX512BW (Intel Skylake-X/SP) + if ((cpu_id[1] >> 16) & 1 && (cpu_id[1] >> 28) & 1 && (cpu_id[1] >> 31) & 1 && + (cpu_id[1] >> 17) & 1 && (cpu_id[1] >> 30) & 1) { + caps.avx512 = caps.avx2; + } } } diff --git a/src/common/x64/cpu_detect.h b/src/common/x64/cpu_detect.h index c34f44474..92c85c2ec 100644 --- a/src/common/x64/cpu_detect.h +++ b/src/common/x64/cpu_detect.h @@ -18,6 +18,7 @@ struct CPUCaps { bool sse4_2; bool avx; bool avx2; + bool avx512; bool bmi1; bool bmi2; bool fma; diff --git a/src/core/core.cpp b/src/core/core.cpp index 0d7b58e2c..901151eec 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -519,14 +519,13 @@ void System::RegisterImageInterface(std::shared_ptr im void System::Shutdown(bool is_deserializing) { // Log last frame performance stats const auto perf_results = GetAndResetPerfStats(); - telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_EmulationSpeed", + constexpr auto performance = Common::Telemetry::FieldType::Performance; + + telemetry_session->AddField(performance, "Shutdown_EmulationSpeed", perf_results.emulation_speed * 100.0); - telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate", - perf_results.game_fps); - telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime", - perf_results.frametime * 1000.0); - telemetry_session->AddField(Telemetry::FieldType::Performance, "Mean_Frametime_MS", - perf_stats->GetMeanFrametime()); + telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps); + telemetry_session->AddField(performance, "Shutdown_Frametime", perf_results.frametime * 1000.0); + telemetry_session->AddField(performance, "Mean_Frametime_MS", perf_stats->GetMeanFrametime()); // Shutdown emulation session VideoCore::Shutdown(); diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp index c38666b62..52e5150e3 100644 --- a/src/core/hle/service/apt/apt.cpp +++ b/src/core/hle/service/apt/apt.cpp @@ -230,8 +230,8 @@ void Module::APTInterface::GetSharedFont(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); // Log in telemetry if the game uses the shared font - apt->system.TelemetrySession().AddField(Telemetry::FieldType::Session, "RequiresSharedFont", - true); + apt->system.TelemetrySession().AddField(Common::Telemetry::FieldType::Session, + "RequiresSharedFont", true); if (!apt->shared_font_loaded) { // On real 3DS, font loading happens on booting. However, we load it on demand to coordinate diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 6f32cc2eb..3fade83a9 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -199,7 +199,8 @@ ResultStatus AppLoader_NCCH::Load(std::shared_ptr& process) { } auto& system = Core::System::GetInstance(); - system.TelemetrySession().AddField(Telemetry::FieldType::Session, "ProgramId", program_id); + system.TelemetrySession().AddField(Common::Telemetry::FieldType::Session, "ProgramId", + program_id); if (auto room_member = Network::GetRoomMember().lock()) { Network::GameInfo game_info; diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 6189e84ee..13c58e2f7 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -2,16 +2,13 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include #include #include "common/assert.h" +#include "common/common_types.h" #include "common/file_util.h" #include "common/logging/log.h" #include "common/scm_rev.h" -#ifdef ARCHITECTURE_x86_64 -#include "common/x64/cpu_detect.h" -#endif #include "core/core.h" #include "core/settings.h" #include "core/telemetry_session.h" @@ -23,6 +20,8 @@ namespace Core { +namespace Telemetry = Common::Telemetry; + static u64 GenerateTelemetryId() { u64 telemetry_id{}; CryptoPP::AutoSeededRandomPool rng; @@ -117,46 +116,11 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) { } // Log application information - const bool is_git_dirty{std::strstr(Common::g_scm_desc, "dirty") != nullptr}; - AddField(Telemetry::FieldType::App, "Git_IsDirty", is_git_dirty); - AddField(Telemetry::FieldType::App, "Git_Branch", Common::g_scm_branch); - AddField(Telemetry::FieldType::App, "Git_Revision", Common::g_scm_rev); - AddField(Telemetry::FieldType::App, "BuildDate", Common::g_build_date); - AddField(Telemetry::FieldType::App, "BuildName", Common::g_build_name); + Telemetry::AppendBuildInfo(field_collection); -// Log user system information -#ifdef ARCHITECTURE_x86_64 - AddField(Telemetry::FieldType::UserSystem, "CPU_Model", Common::GetCPUCaps().cpu_string); - AddField(Telemetry::FieldType::UserSystem, "CPU_BrandString", - Common::GetCPUCaps().brand_string); - AddField(Telemetry::FieldType::UserSystem, "CPU_Extension_x64_AES", Common::GetCPUCaps().aes); - AddField(Telemetry::FieldType::UserSystem, "CPU_Extension_x64_AVX", Common::GetCPUCaps().avx); - AddField(Telemetry::FieldType::UserSystem, "CPU_Extension_x64_AVX2", Common::GetCPUCaps().avx2); - AddField(Telemetry::FieldType::UserSystem, "CPU_Extension_x64_BMI1", Common::GetCPUCaps().bmi1); - AddField(Telemetry::FieldType::UserSystem, "CPU_Extension_x64_BMI2", Common::GetCPUCaps().bmi2); - AddField(Telemetry::FieldType::UserSystem, "CPU_Extension_x64_FMA", Common::GetCPUCaps().fma); - AddField(Telemetry::FieldType::UserSystem, "CPU_Extension_x64_FMA4", Common::GetCPUCaps().fma4); - AddField(Telemetry::FieldType::UserSystem, "CPU_Extension_x64_SSE", Common::GetCPUCaps().sse); - AddField(Telemetry::FieldType::UserSystem, "CPU_Extension_x64_SSE2", Common::GetCPUCaps().sse2); - AddField(Telemetry::FieldType::UserSystem, "CPU_Extension_x64_SSE3", Common::GetCPUCaps().sse3); - AddField(Telemetry::FieldType::UserSystem, "CPU_Extension_x64_SSSE3", - Common::GetCPUCaps().ssse3); - AddField(Telemetry::FieldType::UserSystem, "CPU_Extension_x64_SSE41", - Common::GetCPUCaps().sse4_1); - AddField(Telemetry::FieldType::UserSystem, "CPU_Extension_x64_SSE42", - Common::GetCPUCaps().sse4_2); -#else - AddField(Telemetry::FieldType::UserSystem, "CPU_Model", "Other"); -#endif -#ifdef __APPLE__ - AddField(Telemetry::FieldType::UserSystem, "OsPlatform", "Apple"); -#elif defined(_WIN32) - AddField(Telemetry::FieldType::UserSystem, "OsPlatform", "Windows"); -#elif defined(__linux__) || defined(linux) || defined(__linux) - AddField(Telemetry::FieldType::UserSystem, "OsPlatform", "Linux"); -#else - AddField(Telemetry::FieldType::UserSystem, "OsPlatform", "Unknown"); -#endif + // Log user system information + Telemetry::AppendCPUInfo(field_collection); + Telemetry::AppendOSInfo(field_collection); // Log user configuration information AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", Settings::values.sink_id); diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h index a5dd57ab1..f64dd2a64 100644 --- a/src/core/telemetry_session.h +++ b/src/core/telemetry_session.h @@ -53,7 +53,7 @@ public: * @param value Value for the field to add. */ template - void AddField(Telemetry::FieldType type, const char* name, T value) { + void AddField(Common::Telemetry::FieldType type, const char* name, T value) { field_collection.AddField(type, name, std::move(value)); } @@ -64,7 +64,8 @@ public: bool SubmitTestcase(); private: - Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session + /// Tracks all added fields for the session + Common::Telemetry::FieldCollection field_collection; }; /** diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index 8850e6b56..ee4cea9f2 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp @@ -1527,8 +1527,8 @@ vec4 secondary_fragment_color = vec4(0.0); // Blend the fog out += "last_tex_env_out.rgb = mix(fog_color.rgb, last_tex_env_out.rgb, fog_factor);\n"; } else if (state.fog_mode == TexturingRegs::FogMode::Gas) { - Core::System::GetInstance().TelemetrySession().AddField(Telemetry::FieldType::Session, - "VideoCore_Pica_UseGasMode", true); + Core::System::GetInstance().TelemetrySession().AddField( + Common::Telemetry::FieldType::Session, "VideoCore_Pica_UseGasMode", true); LOG_CRITICAL(Render_OpenGL, "Unimplemented gas mode"); out += "discard; }"; return {std::move(out)}; diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h index 6ce1144d3..7f854fc48 100644 --- a/src/video_core/renderer_opengl/pica_to_gl.h +++ b/src/video_core/renderer_opengl/pica_to_gl.h @@ -90,7 +90,7 @@ inline GLenum WrapMode(Pica::TexturingRegs::TextureConfig::WrapMode mode) { if (index > 3) { Core::System::GetInstance().TelemetrySession().AddField( - Telemetry::FieldType::Session, "VideoCore_Pica_UnsupportedTextureWrapMode", + Common::Telemetry::FieldType::Session, "VideoCore_Pica_UnsupportedTextureWrapMode", static_cast(index)); LOG_WARNING(Render_OpenGL, "Using texture wrap mode {}", index); } diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 3058ef879..113c9aa0a 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -1215,12 +1215,10 @@ VideoCore::ResultStatus RendererOpenGL::Init() { LOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model); auto& telemetry_session = Core::System::GetInstance().TelemetrySession(); - telemetry_session.AddField(Telemetry::FieldType::UserSystem, "GPU_Vendor", - std::string(gpu_vendor)); - telemetry_session.AddField(Telemetry::FieldType::UserSystem, "GPU_Model", - std::string(gpu_model)); - telemetry_session.AddField(Telemetry::FieldType::UserSystem, "GPU_OpenGL_Version", - std::string(gl_version)); + constexpr auto user_system = Common::Telemetry::FieldType::UserSystem; + telemetry_session.AddField(user_system, "GPU_Vendor", std::string(gpu_vendor)); + telemetry_session.AddField(user_system, "GPU_Model", std::string(gpu_model)); + telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version)); if (!strcmp(gpu_vendor, "GDI Generic")) { return VideoCore::ResultStatus::ErrorGenericDrivers; diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp index 9156ce802..97d19f696 100644 --- a/src/web_service/telemetry_json.cpp +++ b/src/web_service/telemetry_json.cpp @@ -10,6 +10,8 @@ namespace WebService { +namespace Telemetry = Common::Telemetry; + struct TelemetryJson::Impl { Impl(std::string host, std::string username, std::string token) : host{std::move(host)}, username{std::move(username)}, token{std::move(token)} {} diff --git a/src/web_service/telemetry_json.h b/src/web_service/telemetry_json.h index 5b6d3cfb5..f2cb19840 100644 --- a/src/web_service/telemetry_json.h +++ b/src/web_service/telemetry_json.h @@ -15,25 +15,25 @@ namespace WebService { * Implementation of VisitorInterface that serialized telemetry into JSON, and submits it to the * Citra web service */ -class TelemetryJson : public Telemetry::VisitorInterface { +class TelemetryJson : public Common::Telemetry::VisitorInterface { public: TelemetryJson(std::string host, std::string username, std::string token); ~TelemetryJson() override; - void Visit(const Telemetry::Field& field) override; - void Visit(const Telemetry::Field& field) override; - void Visit(const Telemetry::Field& field) override; - void Visit(const Telemetry::Field& field) override; - void Visit(const Telemetry::Field& field) override; - void Visit(const Telemetry::Field& field) override; - void Visit(const Telemetry::Field& field) override; - void Visit(const Telemetry::Field& field) override; - void Visit(const Telemetry::Field& field) override; - void Visit(const Telemetry::Field& field) override; - void Visit(const Telemetry::Field& field) override; - void Visit(const Telemetry::Field& field) override; - void Visit(const Telemetry::Field& field) override; - void Visit(const Telemetry::Field& field) override; + void Visit(const Common::Telemetry::Field& field) override; + void Visit(const Common::Telemetry::Field& field) override; + void Visit(const Common::Telemetry::Field& field) override; + void Visit(const Common::Telemetry::Field& field) override; + void Visit(const Common::Telemetry::Field& field) override; + void Visit(const Common::Telemetry::Field& field) override; + void Visit(const Common::Telemetry::Field& field) override; + void Visit(const Common::Telemetry::Field& field) override; + void Visit(const Common::Telemetry::Field& field) override; + void Visit(const Common::Telemetry::Field& field) override; + void Visit(const Common::Telemetry::Field& field) override; + void Visit(const Common::Telemetry::Field& field) override; + void Visit(const Common::Telemetry::Field& field) override; + void Visit(const Common::Telemetry::Field& field) override; void Complete() override; bool SubmitTestcase() override;