diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index bc4a53c797..b7aeb7696e 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -106,6 +106,13 @@ elseif(WIN32) # add an executable that also has the icon itself and the configured rc file as resources add_executable(${TARGET_NAME} WIN32 ${INTERFACE_SRCS} ${QM} ${CONFIGURE_ICON_RC_OUTPUT}) + + add_custom_command( + TARGET ${TARGET_NAME} + POST_BUILD + COMMAND "mt.exe" -manifest "${CMAKE_CURRENT_SOURCE_DIR}/interface.exe.manifest" -inputresource:"$"\;\#1 -outputresource:"$"\;\#1 + COMMENT "Adding OS version support manifest to exe" + ) else() add_executable(${TARGET_NAME} ${INTERFACE_SRCS} ${QM}) endif() diff --git a/interface/interface.exe.manifest b/interface/interface.exe.manifest new file mode 100644 index 0000000000..4806951c9d --- /dev/null +++ b/interface/interface.exe.manifest @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/interface/src/main.cpp b/interface/src/main.cpp index e67f95e2e3..9c07912b99 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -31,6 +31,7 @@ #include #endif + int main(int argc, const char* argv[]) { disableQtBearerPoll(); // Fixes wifi ping spikes @@ -180,6 +181,8 @@ int main(int argc, const char* argv[]) { mpSender.sendAdditionalFile(qPrintable(logPath)); #endif + printSystemInformation(); + QTranslator translator; translator.load("i18n/interface_en"); app.installTranslator(&translator); diff --git a/libraries/shared/src/CPUID.cpp b/libraries/shared/src/CPUID.cpp new file mode 100644 index 0000000000..e0eae248f3 --- /dev/null +++ b/libraries/shared/src/CPUID.cpp @@ -0,0 +1,75 @@ +// +// CPUID.cpp +// +// Created by Ryan Huffman on 3/25/16. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "CPUID.h" + +#ifdef Q_OS_WIN + +const CPUID::CPUID_Internal CPUID::CPU_Rep; + +std::vector CPUID::getAllFeatures() { + std::vector features; + + features.push_back({ "3DNOW", CPUID::_3DNOW() }); + features.push_back({ "3DNOWEXT", CPUID::_3DNOWEXT() }); + features.push_back({ "ABM", CPUID::ABM() }); + features.push_back({ "ADX", CPUID::ADX() }); + features.push_back({ "AES", CPUID::AES() }); + features.push_back({ "AVX", CPUID::AVX() }); + features.push_back({ "AVX2", CPUID::AVX2() }); + features.push_back({ "AVX512CD", CPUID::AVX512CD() }); + features.push_back({ "AVX512ER", CPUID::AVX512ER() }); + features.push_back({ "AVX512F", CPUID::AVX512F() }); + features.push_back({ "AVX512PF", CPUID::AVX512PF() }); + features.push_back({ "BMI1", CPUID::BMI1() }); + features.push_back({ "BMI2", CPUID::BMI2() }); + features.push_back({ "CLFSH", CPUID::CLFSH() }); + features.push_back({ "CMPXCHG16B", CPUID::CMPXCHG16B() }); + features.push_back({ "CX8", CPUID::CX8() }); + features.push_back({ "ERMS", CPUID::ERMS() }); + features.push_back({ "F16C", CPUID::F16C() }); + features.push_back({ "FMA", CPUID::FMA() }); + features.push_back({ "FSGSBASE", CPUID::FSGSBASE() }); + features.push_back({ "FXSR", CPUID::FXSR() }); + features.push_back({ "HLE", CPUID::HLE() }); + features.push_back({ "INVPCID", CPUID::INVPCID() }); + features.push_back({ "LAHF", CPUID::LAHF() }); + features.push_back({ "LZCNT", CPUID::LZCNT() }); + features.push_back({ "MMX", CPUID::MMX() }); + features.push_back({ "MMXEXT", CPUID::MMXEXT() }); + features.push_back({ "MONITOR", CPUID::MONITOR() }); + features.push_back({ "MOVBE", CPUID::MOVBE() }); + features.push_back({ "MSR", CPUID::MSR() }); + features.push_back({ "OSXSAVE", CPUID::OSXSAVE() }); + features.push_back({ "PCLMULQDQ", CPUID::PCLMULQDQ() }); + features.push_back({ "POPCNT", CPUID::POPCNT() }); + features.push_back({ "PREFETCHWT1", CPUID::PREFETCHWT1() }); + features.push_back({ "RDRAND", CPUID::RDRAND() }); + features.push_back({ "RDSEED", CPUID::RDSEED() }); + features.push_back({ "RDTSCP", CPUID::RDTSCP() }); + features.push_back({ "RTM", CPUID::RTM() }); + features.push_back({ "SEP", CPUID::SEP() }); + features.push_back({ "SHA", CPUID::SHA() }); + features.push_back({ "SSE", CPUID::SSE() }); + features.push_back({ "SSE2", CPUID::SSE2() }); + features.push_back({ "SSE3", CPUID::SSE3() }); + features.push_back({ "SSE4.1", CPUID::SSE41() }); + features.push_back({ "SSE4.2", CPUID::SSE42() }); + features.push_back({ "SSE4a", CPUID::SSE4a() }); + features.push_back({ "SSSE3", CPUID::SSSE3() }); + features.push_back({ "SYSCALL", CPUID::SYSCALL() }); + features.push_back({ "TBM", CPUID::TBM() }); + features.push_back({ "XOP", CPUID::XOP() }); + features.push_back({ "XSAVE", CPUID::XSAVE() }); + + return features; +}; + +#endif \ No newline at end of file diff --git a/libraries/shared/src/CPUID.h b/libraries/shared/src/CPUID.h new file mode 100644 index 0000000000..a8b8921d19 --- /dev/null +++ b/libraries/shared/src/CPUID.h @@ -0,0 +1,212 @@ +// +// CPUID.h +// +// Adapted from Microsoft's example for using the cpuid intrinsic, +// found at https://msdn.microsoft.com/en-us/library/hskdteyh.aspx +// +// Provides acccess to information provided by the CPUID opcode +// +// TODO: Generalize to work outside of Windows. +// +// Created by Ryan Huffman on 3/25/16. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_CPUID_h +#define hifi_CPUID_h + +#include + +#include +#include +#include +#include + +#ifdef Q_OS_WIN + +#include + +class CPUID +{ + // forward declarations + class CPUID_Internal; + +public: + struct Feature { + std::string name; + bool supported; + }; + + static std::vector getAllFeatures(); + + static std::string Vendor(void) { return CPU_Rep.vendor_; } + static std::string Brand(void) { return CPU_Rep.brand_; } + + static bool SSE3(void) { return CPU_Rep.f_1_ECX_[0]; } + static bool PCLMULQDQ(void) { return CPU_Rep.f_1_ECX_[1]; } + static bool MONITOR(void) { return CPU_Rep.f_1_ECX_[3]; } + static bool SSSE3(void) { return CPU_Rep.f_1_ECX_[9]; } + static bool FMA(void) { return CPU_Rep.f_1_ECX_[12]; } + static bool CMPXCHG16B(void) { return CPU_Rep.f_1_ECX_[13]; } + static bool SSE41(void) { return CPU_Rep.f_1_ECX_[19]; } + static bool SSE42(void) { return CPU_Rep.f_1_ECX_[20]; } + static bool MOVBE(void) { return CPU_Rep.f_1_ECX_[22]; } + static bool POPCNT(void) { return CPU_Rep.f_1_ECX_[23]; } + static bool AES(void) { return CPU_Rep.f_1_ECX_[25]; } + static bool XSAVE(void) { return CPU_Rep.f_1_ECX_[26]; } + static bool OSXSAVE(void) { return CPU_Rep.f_1_ECX_[27]; } + static bool AVX(void) { return CPU_Rep.f_1_ECX_[28]; } + static bool F16C(void) { return CPU_Rep.f_1_ECX_[29]; } + static bool RDRAND(void) { return CPU_Rep.f_1_ECX_[30]; } + + static bool MSR(void) { return CPU_Rep.f_1_EDX_[5]; } + static bool CX8(void) { return CPU_Rep.f_1_EDX_[8]; } + static bool SEP(void) { return CPU_Rep.f_1_EDX_[11]; } + static bool CMOV(void) { return CPU_Rep.f_1_EDX_[15]; } + static bool CLFSH(void) { return CPU_Rep.f_1_EDX_[19]; } + static bool MMX(void) { return CPU_Rep.f_1_EDX_[23]; } + static bool FXSR(void) { return CPU_Rep.f_1_EDX_[24]; } + static bool SSE(void) { return CPU_Rep.f_1_EDX_[25]; } + static bool SSE2(void) { return CPU_Rep.f_1_EDX_[26]; } + + static bool FSGSBASE(void) { return CPU_Rep.f_7_EBX_[0]; } + static bool BMI1(void) { return CPU_Rep.f_7_EBX_[3]; } + static bool HLE(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_7_EBX_[4]; } + static bool AVX2(void) { return CPU_Rep.f_7_EBX_[5]; } + static bool BMI2(void) { return CPU_Rep.f_7_EBX_[8]; } + static bool ERMS(void) { return CPU_Rep.f_7_EBX_[9]; } + static bool INVPCID(void) { return CPU_Rep.f_7_EBX_[10]; } + static bool RTM(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_7_EBX_[11]; } + static bool AVX512F(void) { return CPU_Rep.f_7_EBX_[16]; } + static bool RDSEED(void) { return CPU_Rep.f_7_EBX_[18]; } + static bool ADX(void) { return CPU_Rep.f_7_EBX_[19]; } + static bool AVX512PF(void) { return CPU_Rep.f_7_EBX_[26]; } + static bool AVX512ER(void) { return CPU_Rep.f_7_EBX_[27]; } + static bool AVX512CD(void) { return CPU_Rep.f_7_EBX_[28]; } + static bool SHA(void) { return CPU_Rep.f_7_EBX_[29]; } + + static bool PREFETCHWT1(void) { return CPU_Rep.f_7_ECX_[0]; } + + static bool LAHF(void) { return CPU_Rep.f_81_ECX_[0]; } + static bool LZCNT(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_ECX_[5]; } + static bool ABM(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[5]; } + static bool SSE4a(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[6]; } + static bool XOP(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[11]; } + static bool TBM(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_ECX_[21]; } + + static bool SYSCALL(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_EDX_[11]; } + static bool MMXEXT(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[22]; } + static bool RDTSCP(void) { return CPU_Rep.isIntel_ && CPU_Rep.f_81_EDX_[27]; } + static bool _3DNOWEXT(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[30]; } + static bool _3DNOW(void) { return CPU_Rep.isAMD_ && CPU_Rep.f_81_EDX_[31]; } + +private: + static const CPUID_Internal CPU_Rep; + + class CPUID_Internal + { + public: + CPUID_Internal() + : nIds_ { 0 }, + nExIds_ { 0 }, + isIntel_ { false }, + isAMD_ { false }, + f_1_ECX_ { 0 }, + f_1_EDX_ { 0 }, + f_7_EBX_ { 0 }, + f_7_ECX_ { 0 }, + f_81_ECX_ { 0 }, + f_81_EDX_ { 0 }, + data_ {}, + extdata_ {} + { + //int cpuInfo[4] = {-1}; + std::array cpui; + + // Calling __cpuid with 0x0 as the function_id argument + // gets the number of the highest valid function ID. + __cpuid(cpui.data(), 0); + nIds_ = cpui[0]; + + for (int i = 0; i <= nIds_; ++i) { + __cpuidex(cpui.data(), i, 0); + data_.push_back(cpui); + } + + // Capture vendor string + char vendor[0x20]; + memset(vendor, 0, sizeof(vendor)); + *reinterpret_cast(vendor) = data_[0][1]; + *reinterpret_cast(vendor + 4) = data_[0][3]; + *reinterpret_cast(vendor + 8) = data_[0][2]; + vendor_ = vendor; + if (vendor_ == "GenuineIntel") { + isIntel_ = true; + } else if (vendor_ == "AuthenticAMD") { + isAMD_ = true; + } + + // load bitset with flags for function 0x00000001 + if (nIds_ >= 1) { + f_1_ECX_ = data_[1][2]; + f_1_EDX_ = data_[1][3]; + } + + // load bitset with flags for function 0x00000007 + if (nIds_ >= 7) { + f_7_EBX_ = data_[7][1]; + f_7_ECX_ = data_[7][2]; + } + + // Calling __cpuid with 0x80000000 as the function_id argument + // gets the number of the highest valid extended ID. + __cpuid(cpui.data(), 0x80000000); + nExIds_ = cpui[0]; + + char brand[0x40]; + memset(brand, 0, sizeof(brand)); + + for (int i = 0x80000000; i <= nExIds_; ++i) { + __cpuidex(cpui.data(), i, 0); + extdata_.push_back(cpui); + } + + // load bitset with flags for function 0x80000001 + if (nExIds_ >= 0x80000001) { + f_81_ECX_ = extdata_[1][2]; + f_81_EDX_ = extdata_[1][3]; + } + + // Interpret CPU brand string if reported + if (nExIds_ >= 0x80000004) { + memcpy(brand, extdata_[2].data(), sizeof(cpui)); + memcpy(brand + 16, extdata_[3].data(), sizeof(cpui)); + memcpy(brand + 32, extdata_[4].data(), sizeof(cpui)); + brand_ = brand; + } + }; + + int nIds_; + int nExIds_; + std::string vendor_; + std::string brand_; + bool isIntel_; + bool isAMD_; + std::bitset<32> f_1_ECX_; + std::bitset<32> f_1_EDX_; + std::bitset<32> f_7_EBX_; + std::bitset<32> f_7_ECX_; + std::bitset<32> f_81_ECX_; + std::bitset<32> f_81_EDX_; + std::vector> data_; + std::vector> extdata_; + }; + +}; + +#endif + +#endif // hifi_CPUID_h diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index c979d8f4b6..30d4726bcc 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -23,6 +23,11 @@ #include #endif +#ifdef Q_OS_WIN +#include "CPUID.h" +#endif + + #ifdef __APPLE__ #include #endif @@ -30,6 +35,8 @@ #include #include #include +#include +#include #include #include "NumericalConstants.h" @@ -692,3 +699,82 @@ void disableQtBearerPoll() { qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT); } +void printSystemInformation() { + // Write system information to log + qDebug() << "Build Information"; + qDebug().noquote() << "\tBuild ABI: " << QSysInfo::buildAbi(); + qDebug().noquote() << "\tBuild CPU Architecture: " << QSysInfo::buildCpuArchitecture(); + + qDebug().noquote() << "System Information"; + qDebug().noquote() << "\tProduct Name: " << QSysInfo::prettyProductName(); + qDebug().noquote() << "\tCPU Architecture: " << QSysInfo::currentCpuArchitecture(); + qDebug().noquote() << "\tKernel Type: " << QSysInfo::kernelType(); + qDebug().noquote() << "\tKernel Version: " << QSysInfo::kernelVersion(); + + auto macVersion = QSysInfo::macVersion(); + if (macVersion != QSysInfo::MV_None) { + qDebug() << "\tMac Version: " << macVersion; + } + + auto windowsVersion = QSysInfo::windowsVersion(); + if (windowsVersion != QSysInfo::WV_None) { + qDebug() << "\tWindows Version: " << windowsVersion; + } + +#ifdef Q_OS_WIN + SYSTEM_INFO si; + GetNativeSystemInfo(&si); + + qDebug() << "SYSTEM_INFO"; + qDebug().noquote() << "\tOEM ID: " << si.dwOemId; + qDebug().noquote() << "\tProcessor Architecture: " << si.wProcessorArchitecture; + qDebug().noquote() << "\tProcessor Type: " << si.dwProcessorType; + qDebug().noquote() << "\tProcessor Level: " << si.wProcessorLevel; + qDebug().noquote() << "\tProcessor Revision: " + << QString("0x%1").arg(si.wProcessorRevision, 4, 16, QChar('0')); + qDebug().noquote() << "\tNumber of Processors: " << si.dwNumberOfProcessors; + qDebug().noquote() << "\tPage size: " << si.dwPageSize << " Bytes"; + qDebug().noquote() << "\tMin Application Address: " + << QString("0x%1").arg(qulonglong(si.lpMinimumApplicationAddress), 16, 16, QChar('0')); + qDebug().noquote() << "\tMax Application Address: " + << QString("0x%1").arg(qulonglong(si.lpMaximumApplicationAddress), 16, 16, QChar('0')); + + const double BYTES_TO_MEGABYTE = 1.0 / (1024 * 1024); + + qDebug() << "MEMORYSTATUSEX"; + MEMORYSTATUSEX ms; + ms.dwLength = sizeof(ms); + if (GlobalMemoryStatusEx(&ms)) { + qDebug().noquote() << QString("\tCurrent System Memory Usage: %1%").arg(ms.dwMemoryLoad); + qDebug().noquote() << QString("\tAvail Physical Memory: %1 MB").arg(ms.ullAvailPhys * BYTES_TO_MEGABYTE, 20, 'f', 2); + qDebug().noquote() << QString("\tTotal Physical Memory: %1 MB").arg(ms.ullTotalPhys * BYTES_TO_MEGABYTE, 20, 'f', 2); + qDebug().noquote() << QString("\tAvail in Page File: %1 MB").arg(ms.ullAvailPageFile * BYTES_TO_MEGABYTE, 20, 'f', 2); + qDebug().noquote() << QString("\tTotal in Page File: %1 MB").arg(ms.ullTotalPageFile * BYTES_TO_MEGABYTE, 20, 'f', 2); + qDebug().noquote() << QString("\tAvail Virtual Memory: %1 MB").arg(ms.ullAvailVirtual * BYTES_TO_MEGABYTE, 20, 'f', 2); + qDebug().noquote() << QString("\tTotal Virtual Memory: %1 MB").arg(ms.ullTotalVirtual * BYTES_TO_MEGABYTE, 20, 'f', 2); + } else { + qDebug() << "\tFailed to retrieve memory status: " << GetLastError(); + } + + qDebug() << "CPUID"; + + qDebug() << "\tCPU Vendor: " << CPUID::Vendor().c_str(); + qDebug() << "\tCPU Brand: " << CPUID::Brand().c_str(); + + for (auto& feature : CPUID::getAllFeatures()) { + qDebug().nospace().noquote() << "\t[" << (feature.supported ? "x" : " ") << "] " << feature.name.c_str(); + } +#endif + + qDebug() << "Environment Variables"; + // List of env variables to include in the log. For privacy reasons we don't send all env variables. + const QStringList envWhitelist = { + "QTWEBENGINE_REMOTE_DEBUGGING" + }; + auto envVariables = QProcessEnvironment::systemEnvironment(); + for (auto& env : envWhitelist) + { + qDebug().noquote().nospace() << "\t" << + (envVariables.contains(env) ? " = " + envVariables.value(env) : " NOT FOUND"); + } +} \ No newline at end of file diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 01c5a74bb4..8fb65a5247 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -198,4 +198,6 @@ uint qHash(const std::shared_ptr& ptr, uint seed = 0) void disableQtBearerPoll(); +void printSystemInformation(); + #endif // hifi_SharedUtil_h