Merge pull request #5501 from FearlessTobi/port-1064-3948

Port yuzu-emu/yuzu#1064 and yuzu-emu/yuzu#3948: Changes to Telemetry and CPU feature detection
This commit is contained in:
bunnei 2021-04-23 22:58:08 -07:00 committed by GitHub
commit 9ff97270cf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
17 changed files with 137 additions and 89 deletions

View file

@ -382,7 +382,7 @@ int main(int argc, char** argv) {
break; // Expected case break; // Expected case
} }
system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "SDL"); system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "SDL");
if (use_multiplayer) { if (use_multiplayer) {
if (auto member = Network::GetRoomMember().lock()) { if (auto member = Network::GetRoomMember().lock()) {

View file

@ -52,7 +52,8 @@ void CompatDB::Submit() {
back(); back();
LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId()); LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId());
Core::System::GetInstance().TelemetrySession().AddField( Core::System::GetInstance().TelemetrySession().AddField(
Telemetry::FieldType::UserFeedback, "Compatibility", compatibility->checkedId()); Common::Telemetry::FieldType::UserFeedback, "Compatibility",
compatibility->checkedId());
button(NextButton)->setEnabled(false); button(NextButton)->setEnabled(false);
button(NextButton)->setText(tr("Submitting")); button(NextButton)->setText(tr("Submitting"));

View file

@ -190,7 +190,20 @@ GMainWindow::GMainWindow()
LOG_INFO(Frontend, "Citra Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch, LOG_INFO(Frontend, "Citra Version: {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch,
Common::g_scm_desc); Common::g_scm_desc);
#ifdef ARCHITECTURE_x86_64 #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 #endif
LOG_INFO(Frontend, "Host OS: {}", QSysInfo::prettyProductName().toStdString()); LOG_INFO(Frontend, "Host OS: {}", QSysInfo::prettyProductName().toStdString());
UpdateWindowTitle(); UpdateWindowTitle();
@ -989,7 +1002,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
game_path = filename; game_path = filename;
system.TelemetrySession().AddField(Telemetry::FieldType::App, "Frontend", "Qt"); system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "Qt");
return true; return true;
} }

View file

@ -3,9 +3,16 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <algorithm> #include <algorithm>
#include <cstring>
#include "common/assert.h"
#include "common/scm_rev.h"
#include "common/telemetry.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 { void FieldCollection::Accept(VisitorInterface& visitor) const {
for (const auto& field : fields) { for (const auto& field : fields) {
@ -37,4 +44,48 @@ template class Field<std::string>;
template class Field<const char*>; template class Field<const char*>;
template class Field<std::chrono::microseconds>; template class Field<std::chrono::microseconds>;
} // 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

View file

@ -10,7 +10,7 @@
#include <string> #include <string>
#include "common/common_types.h" #include "common/common_types.h"
namespace Telemetry { namespace Common::Telemetry {
/// Field type, used for grouping fields together in the final submitted telemetry log /// Field type, used for grouping fields together in the final submitted telemetry log
enum class FieldType : u8 { enum class FieldType : u8 {
@ -55,8 +55,8 @@ public:
Field(FieldType type, std::string name, T value) Field(FieldType type, std::string name, T value)
: name(std::move(name)), type(type), value(std::move(value)) {} : name(std::move(name)), type(type), value(std::move(value)) {}
Field(const Field& other) = default; Field(const Field&) = default;
Field& operator=(const Field& other) = default; Field& operator=(const Field&) = default;
Field(Field&&) = default; Field(Field&&) = default;
Field& operator=(Field&& other) = 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

View file

@ -110,6 +110,11 @@ static CPUCaps Detect() {
caps.bmi1 = true; caps.bmi1 = true;
if ((cpu_id[1] >> 8) & 1) if ((cpu_id[1] >> 8) & 1)
caps.bmi2 = true; 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;
}
} }
} }

View file

@ -18,6 +18,7 @@ struct CPUCaps {
bool sse4_2; bool sse4_2;
bool avx; bool avx;
bool avx2; bool avx2;
bool avx512;
bool bmi1; bool bmi1;
bool bmi2; bool bmi2;
bool fma; bool fma;

View file

@ -519,14 +519,13 @@ void System::RegisterImageInterface(std::shared_ptr<Frontend::ImageInterface> im
void System::Shutdown(bool is_deserializing) { void System::Shutdown(bool is_deserializing) {
// Log last frame performance stats // Log last frame performance stats
const auto perf_results = GetAndResetPerfStats(); 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); perf_results.emulation_speed * 100.0);
telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate", telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps);
perf_results.game_fps); telemetry_session->AddField(performance, "Shutdown_Frametime", perf_results.frametime * 1000.0);
telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime", telemetry_session->AddField(performance, "Mean_Frametime_MS", perf_stats->GetMeanFrametime());
perf_results.frametime * 1000.0);
telemetry_session->AddField(Telemetry::FieldType::Performance, "Mean_Frametime_MS",
perf_stats->GetMeanFrametime());
// Shutdown emulation session // Shutdown emulation session
VideoCore::Shutdown(); VideoCore::Shutdown();

View file

@ -230,8 +230,8 @@ void Module::APTInterface::GetSharedFont(Kernel::HLERequestContext& ctx) {
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
// Log in telemetry if the game uses the shared font // Log in telemetry if the game uses the shared font
apt->system.TelemetrySession().AddField(Telemetry::FieldType::Session, "RequiresSharedFont", apt->system.TelemetrySession().AddField(Common::Telemetry::FieldType::Session,
true); "RequiresSharedFont", true);
if (!apt->shared_font_loaded) { if (!apt->shared_font_loaded) {
// On real 3DS, font loading happens on booting. However, we load it on demand to coordinate // On real 3DS, font loading happens on booting. However, we load it on demand to coordinate

View file

@ -199,7 +199,8 @@ ResultStatus AppLoader_NCCH::Load(std::shared_ptr<Kernel::Process>& process) {
} }
auto& system = Core::System::GetInstance(); 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()) { if (auto room_member = Network::GetRoomMember().lock()) {
Network::GameInfo game_info; Network::GameInfo game_info;

View file

@ -2,16 +2,13 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <cstring>
#include <cryptopp/osrng.h> #include <cryptopp/osrng.h>
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/scm_rev.h" #include "common/scm_rev.h"
#ifdef ARCHITECTURE_x86_64
#include "common/x64/cpu_detect.h"
#endif
#include "core/core.h" #include "core/core.h"
#include "core/settings.h" #include "core/settings.h"
#include "core/telemetry_session.h" #include "core/telemetry_session.h"
@ -23,6 +20,8 @@
namespace Core { namespace Core {
namespace Telemetry = Common::Telemetry;
static u64 GenerateTelemetryId() { static u64 GenerateTelemetryId() {
u64 telemetry_id{}; u64 telemetry_id{};
CryptoPP::AutoSeededRandomPool rng; CryptoPP::AutoSeededRandomPool rng;
@ -117,46 +116,11 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
} }
// Log application information // Log application information
const bool is_git_dirty{std::strstr(Common::g_scm_desc, "dirty") != nullptr}; Telemetry::AppendBuildInfo(field_collection);
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);
// Log user system information // Log user system information
#ifdef ARCHITECTURE_x86_64 Telemetry::AppendCPUInfo(field_collection);
AddField(Telemetry::FieldType::UserSystem, "CPU_Model", Common::GetCPUCaps().cpu_string); Telemetry::AppendOSInfo(field_collection);
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 configuration information // Log user configuration information
AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", Settings::values.sink_id); AddField(Telemetry::FieldType::UserConfig, "Audio_SinkId", Settings::values.sink_id);

View file

@ -53,7 +53,7 @@ public:
* @param value Value for the field to add. * @param value Value for the field to add.
*/ */
template <typename T> template <typename T>
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)); field_collection.AddField(type, name, std::move(value));
} }
@ -64,7 +64,8 @@ public:
bool SubmitTestcase(); bool SubmitTestcase();
private: private:
Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session /// Tracks all added fields for the session
Common::Telemetry::FieldCollection field_collection;
}; };
/** /**

View file

@ -1527,8 +1527,8 @@ vec4 secondary_fragment_color = vec4(0.0);
// Blend the fog // Blend the fog
out += "last_tex_env_out.rgb = mix(fog_color.rgb, last_tex_env_out.rgb, fog_factor);\n"; 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) { } else if (state.fog_mode == TexturingRegs::FogMode::Gas) {
Core::System::GetInstance().TelemetrySession().AddField(Telemetry::FieldType::Session, Core::System::GetInstance().TelemetrySession().AddField(
"VideoCore_Pica_UseGasMode", true); Common::Telemetry::FieldType::Session, "VideoCore_Pica_UseGasMode", true);
LOG_CRITICAL(Render_OpenGL, "Unimplemented gas mode"); LOG_CRITICAL(Render_OpenGL, "Unimplemented gas mode");
out += "discard; }"; out += "discard; }";
return {std::move(out)}; return {std::move(out)};

View file

@ -90,7 +90,7 @@ inline GLenum WrapMode(Pica::TexturingRegs::TextureConfig::WrapMode mode) {
if (index > 3) { if (index > 3) {
Core::System::GetInstance().TelemetrySession().AddField( Core::System::GetInstance().TelemetrySession().AddField(
Telemetry::FieldType::Session, "VideoCore_Pica_UnsupportedTextureWrapMode", Common::Telemetry::FieldType::Session, "VideoCore_Pica_UnsupportedTextureWrapMode",
static_cast<u32>(index)); static_cast<u32>(index));
LOG_WARNING(Render_OpenGL, "Using texture wrap mode {}", index); LOG_WARNING(Render_OpenGL, "Using texture wrap mode {}", index);
} }

View file

@ -1215,12 +1215,10 @@ VideoCore::ResultStatus RendererOpenGL::Init() {
LOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model); LOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model);
auto& telemetry_session = Core::System::GetInstance().TelemetrySession(); auto& telemetry_session = Core::System::GetInstance().TelemetrySession();
telemetry_session.AddField(Telemetry::FieldType::UserSystem, "GPU_Vendor", constexpr auto user_system = Common::Telemetry::FieldType::UserSystem;
std::string(gpu_vendor)); telemetry_session.AddField(user_system, "GPU_Vendor", std::string(gpu_vendor));
telemetry_session.AddField(Telemetry::FieldType::UserSystem, "GPU_Model", telemetry_session.AddField(user_system, "GPU_Model", std::string(gpu_model));
std::string(gpu_model)); telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version));
telemetry_session.AddField(Telemetry::FieldType::UserSystem, "GPU_OpenGL_Version",
std::string(gl_version));
if (!strcmp(gpu_vendor, "GDI Generic")) { if (!strcmp(gpu_vendor, "GDI Generic")) {
return VideoCore::ResultStatus::ErrorGenericDrivers; return VideoCore::ResultStatus::ErrorGenericDrivers;

View file

@ -10,6 +10,8 @@
namespace WebService { namespace WebService {
namespace Telemetry = Common::Telemetry;
struct TelemetryJson::Impl { struct TelemetryJson::Impl {
Impl(std::string host, std::string username, std::string token) Impl(std::string host, std::string username, std::string token)
: host{std::move(host)}, username{std::move(username)}, token{std::move(token)} {} : host{std::move(host)}, username{std::move(username)}, token{std::move(token)} {}

View file

@ -15,25 +15,25 @@ namespace WebService {
* Implementation of VisitorInterface that serialized telemetry into JSON, and submits it to the * Implementation of VisitorInterface that serialized telemetry into JSON, and submits it to the
* Citra web service * Citra web service
*/ */
class TelemetryJson : public Telemetry::VisitorInterface { class TelemetryJson : public Common::Telemetry::VisitorInterface {
public: public:
TelemetryJson(std::string host, std::string username, std::string token); TelemetryJson(std::string host, std::string username, std::string token);
~TelemetryJson() override; ~TelemetryJson() override;
void Visit(const Telemetry::Field<bool>& field) override; void Visit(const Common::Telemetry::Field<bool>& field) override;
void Visit(const Telemetry::Field<double>& field) override; void Visit(const Common::Telemetry::Field<double>& field) override;
void Visit(const Telemetry::Field<float>& field) override; void Visit(const Common::Telemetry::Field<float>& field) override;
void Visit(const Telemetry::Field<u8>& field) override; void Visit(const Common::Telemetry::Field<u8>& field) override;
void Visit(const Telemetry::Field<u16>& field) override; void Visit(const Common::Telemetry::Field<u16>& field) override;
void Visit(const Telemetry::Field<u32>& field) override; void Visit(const Common::Telemetry::Field<u32>& field) override;
void Visit(const Telemetry::Field<u64>& field) override; void Visit(const Common::Telemetry::Field<u64>& field) override;
void Visit(const Telemetry::Field<s8>& field) override; void Visit(const Common::Telemetry::Field<s8>& field) override;
void Visit(const Telemetry::Field<s16>& field) override; void Visit(const Common::Telemetry::Field<s16>& field) override;
void Visit(const Telemetry::Field<s32>& field) override; void Visit(const Common::Telemetry::Field<s32>& field) override;
void Visit(const Telemetry::Field<s64>& field) override; void Visit(const Common::Telemetry::Field<s64>& field) override;
void Visit(const Telemetry::Field<std::string>& field) override; void Visit(const Common::Telemetry::Field<std::string>& field) override;
void Visit(const Telemetry::Field<const char*>& field) override; void Visit(const Common::Telemetry::Field<const char*>& field) override;
void Visit(const Telemetry::Field<std::chrono::microseconds>& field) override; void Visit(const Common::Telemetry::Field<std::chrono::microseconds>& field) override;
void Complete() override; void Complete() override;
bool SubmitTestcase() override; bool SubmitTestcase() override;