From df8b9863f93da24e25d25f32e548605743ed8f66 Mon Sep 17 00:00:00 2001
From: bunnei <bunneidev@gmail.com>
Date: Wed, 12 Jul 2017 22:19:34 -0400
Subject: [PATCH] telemetry: Log performance, configuration, and system data.

---
 src/core/core.cpp                             | 10 +++
 src/core/loader/ncch.cpp                      |  6 +-
 src/core/telemetry_session.cpp                | 76 ++++++++++++++++---
 src/video_core/renderer_opengl/pica_to_gl.h   |  7 +-
 .../renderer_opengl/renderer_opengl.cpp       | 15 +++-
 5 files changed, 96 insertions(+), 18 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 5429bcb268..d08f18623f 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -168,6 +168,16 @@ System::ResultStatus System::Init(EmuWindow* emu_window, u32 system_mode) {
 }
 
 void System::Shutdown() {
+    // Log last frame performance stats
+    auto perf_results = GetAndResetPerfStats();
+    Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_EmulationSpeed",
+                         perf_results.emulation_speed * 100.0);
+    Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate",
+                         perf_results.game_fps);
+    Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
+                         perf_results.frametime * 1000.0);
+
+    // Shutdown emulation session
     GDBStub::Shutdown();
     AudioCore::Shutdown();
     VideoCore::Shutdown();
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index ffc019560c..fc4d14a595 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -342,9 +342,11 @@ ResultStatus AppLoader_NCCH::Load() {
     if (result != ResultStatus::Success)
         return result;
 
-    LOG_INFO(Loader, "Program ID: %016" PRIX64, ncch_header.program_id);
+    std::string program_id{Common::StringFromFormat("%016" PRIX64, ncch_header.program_id)};
 
-    Core::Telemetry().AddField(Telemetry::FieldType::Session, "ProgramId", ncch_header.program_id);
+    LOG_INFO(Loader, "Program ID: %s", program_id.c_str());
+
+    Core::Telemetry().AddField(Telemetry::FieldType::Session, "ProgramId", program_id);
 
     is_loaded = true; // Set state to loaded
 
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 70eff4340a..841d6cfa1b 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -4,7 +4,10 @@
 
 #include <cstring>
 
+#include "common/assert.h"
 #include "common/scm_rev.h"
+#include "common/x64/cpu_detect.h"
+#include "core/settings.h"
 #include "core/telemetry_session.h"
 
 #ifdef ENABLE_WEB_SERVICE
@@ -13,6 +16,18 @@
 
 namespace Core {
 
+static const char* CpuVendorToStr(Common::CPUVendor vendor) {
+    switch (vendor) {
+    case Common::CPUVendor::INTEL:
+        return "Intel";
+    case Common::CPUVendor::AMD:
+        return "Amd";
+    case Common::CPUVendor::OTHER:
+        return "Other";
+    }
+    UNREACHABLE();
+}
+
 TelemetrySession::TelemetrySession() {
 #ifdef ENABLE_WEB_SERVICE
     backend = std::make_unique<WebService::TelemetryJson>();
@@ -20,22 +35,63 @@ TelemetrySession::TelemetrySession() {
     backend = std::make_unique<Telemetry::NullVisitor>();
 #endif
     // Log one-time session start information
-    const auto duration{std::chrono::steady_clock::now().time_since_epoch()};
-    const auto start_time{std::chrono::duration_cast<std::chrono::microseconds>(duration).count()};
-    AddField(Telemetry::FieldType::Session, "StartTime", start_time);
+    const s64 init_time{std::chrono::duration_cast<std::chrono::milliseconds>(
+                            std::chrono::system_clock::now().time_since_epoch())
+                            .count()};
+    AddField(Telemetry::FieldType::Session, "Init_Time", init_time);
 
-    // Log one-time application information
+    // Log application information
     const bool is_git_dirty{std::strstr(Common::g_scm_desc, "dirty") != nullptr};
-    AddField(Telemetry::FieldType::App, "GitIsDirty", is_git_dirty);
-    AddField(Telemetry::FieldType::App, "GitBranch", Common::g_scm_branch);
-    AddField(Telemetry::FieldType::App, "GitRevision", Common::g_scm_rev);
+    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);
+
+    // Log user system information
+    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_Vendor",
+             CpuVendorToStr(Common::GetCPUCaps().vendor));
+    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);
+
+    // Log user configuration information
+    AddField(Telemetry::FieldType::UserConfig, "Audio_EnableAudioStretching",
+             Settings::values.enable_audio_stretching);
+    AddField(Telemetry::FieldType::UserConfig, "Core_UseCpuJit", Settings::values.use_cpu_jit);
+    AddField(Telemetry::FieldType::UserConfig, "Renderer_ResolutionFactor",
+             Settings::values.resolution_factor);
+    AddField(Telemetry::FieldType::UserConfig, "Renderer_ToggleFramelimit",
+             Settings::values.toggle_framelimit);
+    AddField(Telemetry::FieldType::UserConfig, "Renderer_UseHwRenderer",
+             Settings::values.use_hw_renderer);
+    AddField(Telemetry::FieldType::UserConfig, "Renderer_UseShaderJit",
+             Settings::values.use_shader_jit);
+    AddField(Telemetry::FieldType::UserConfig, "Renderer_UseVsync", Settings::values.use_vsync);
+    AddField(Telemetry::FieldType::UserConfig, "System_IsNew3ds", Settings::values.is_new_3ds);
+    AddField(Telemetry::FieldType::UserConfig, "System_RegionValue", Settings::values.region_value);
 }
 
 TelemetrySession::~TelemetrySession() {
     // Log one-time session end information
-    const auto duration{std::chrono::steady_clock::now().time_since_epoch()};
-    const auto end_time{std::chrono::duration_cast<std::chrono::microseconds>(duration).count()};
-    AddField(Telemetry::FieldType::Session, "EndTime", end_time);
+    const s64 shutdown_time{std::chrono::duration_cast<std::chrono::milliseconds>(
+                                std::chrono::system_clock::now().time_since_epoch())
+                                .count()};
+    AddField(Telemetry::FieldType::Session, "Shutdown_Time", shutdown_time);
 
     // Complete the session, submitting to web service if necessary
     // This is just a placeholder to wrap up the session once the core completes and this is
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index 70298e211c..c7fa1f873a 100644
--- a/src/video_core/renderer_opengl/pica_to_gl.h
+++ b/src/video_core/renderer_opengl/pica_to_gl.h
@@ -12,6 +12,7 @@
 #include "common/common_funcs.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
+#include "core/core.h"
 #include "video_core/regs_framebuffer.h"
 #include "video_core/regs_lighting.h"
 #include "video_core/regs_texturing.h"
@@ -72,9 +73,9 @@ inline GLenum WrapMode(Pica::TexturingRegs::TextureConfig::WrapMode mode) {
     }
 
     if (static_cast<u32>(mode) > 3) {
-        // It is still unclear whether mode 4-7 are valid, so log it if a game uses them.
-        // TODO(wwylele): telemetry should be added here so we can collect more info about which
-        // game uses this.
+        Core::Telemetry().AddField(Telemetry::FieldType::Session,
+                                   "VideoCore_Pica_UnsupportedTextureWrapMode",
+                                   static_cast<u32>(mode));
         LOG_WARNING(Render_OpenGL, "Using texture wrap mode %u", static_cast<u32>(mode));
     }
 
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index d90c776f93..65c18aecc2 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -481,9 +481,18 @@ bool RendererOpenGL::Init() {
         glDebugMessageCallback(DebugHandler, nullptr);
     }
 
-    LOG_INFO(Render_OpenGL, "GL_VERSION: %s", glGetString(GL_VERSION));
-    LOG_INFO(Render_OpenGL, "GL_VENDOR: %s", glGetString(GL_VENDOR));
-    LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", glGetString(GL_RENDERER));
+    const char* gl_version{reinterpret_cast<char const*>(glGetString(GL_VERSION))};
+    const char* gpu_vendor{reinterpret_cast<char const*>(glGetString(GL_VENDOR))};
+    const char* gpu_model{reinterpret_cast<char const*>(glGetString(GL_RENDERER))};
+
+    LOG_INFO(Render_OpenGL, "GL_VERSION: %s", gl_version);
+    LOG_INFO(Render_OpenGL, "GL_VENDOR: %s", gpu_vendor);
+    LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", gpu_model);
+
+    Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Vendor", gpu_vendor);
+    Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model);
+    Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_OpenGL_Version", gl_version);
+
     if (!GLAD_GL_VERSION_3_3) {
         return false;
     }