diff --git a/src/Summary.cpp b/src/Summary.cpp index 36f59ba37..fec7c65cf 100644 --- a/src/Summary.cpp +++ b/src/Summary.cpp @@ -71,7 +71,7 @@ static void print_cpu(xmrig::Config *) Log::print(GREEN_BOLD(" * ") WHITE_BOLD("%-13s%s (%d)") " %sx64 %sAES %sAVX2", "CPU", Cpu::info()->brand(), - Cpu::info()->sockets(), + Cpu::info()->packages(), Cpu::info()->isX64() ? GREEN_BOLD_S : RED_BOLD_S "-", Cpu::info()->hasAES() ? GREEN_BOLD_S : RED_BOLD_S "-", Cpu::info()->hasAVX2() ? GREEN_BOLD_S : RED_BOLD_S "-" diff --git a/src/backend/cpu/interfaces/ICpuInfo.h b/src/backend/cpu/interfaces/ICpuInfo.h index 5848db89f..7faa7187f 100644 --- a/src/backend/cpu/interfaces/ICpuInfo.h +++ b/src/backend/cpu/interfaces/ICpuInfo.h @@ -48,14 +48,13 @@ public: virtual Assembly::Id assembly() const = 0; virtual bool hasAES() const = 0; virtual bool hasAVX2() const = 0; - virtual bool isSupported() const = 0; virtual const char *brand() const = 0; virtual CpuThreads threads(const Algorithm &algorithm) const = 0; virtual size_t cores() const = 0; virtual size_t L2() const = 0; virtual size_t L3() const = 0; virtual size_t nodes() const = 0; - virtual size_t sockets() const = 0; + virtual size_t packages() const = 0; virtual size_t threads() const = 0; }; diff --git a/src/backend/cpu/platform/AdvancedCpuInfo.cpp b/src/backend/cpu/platform/AdvancedCpuInfo.cpp index 45b0dd66e..cd44cc2e0 100644 --- a/src/backend/cpu/platform/AdvancedCpuInfo.cpp +++ b/src/backend/cpu/platform/AdvancedCpuInfo.cpp @@ -32,37 +32,61 @@ #include "backend/cpu/platform/AdvancedCpuInfo.h" +namespace xmrig { + + +static inline void cpu_brand_string(char out[64], const char *in) { + size_t pos = 0; + const size_t size = strlen(in); + + for (size_t i = 0; i < size; ++i) { + if (in[i] == ' ' && ((pos > 0 && out[pos - 1] == ' ') || pos == 0)) { + continue; + } + + out[pos++] = in[i]; + } + + if (pos > 0 && out[pos - 1] == ' ') { + out[pos - 1] = '\0'; + } +} + + +} // namespace xmrig + + xmrig::AdvancedCpuInfo::AdvancedCpuInfo() : m_brand() { struct cpu_raw_data_t raw = {}; - struct cpu_id_t data = {}; + struct cpu_id_t data = {}; cpuid_get_raw_data(&raw); cpu_identify(&raw, &data); - strncpy(m_brand, data.brand_str, sizeof(m_brand)); + cpu_brand_string(m_brand, data.brand_str); - m_threads = static_cast(data.total_logical_cpus); - m_sockets = std::max(threads() / static_cast(data.num_logical_cpus), 1); - m_cores = static_cast(data.num_cores) * m_sockets; - m_L3 = data.l3_cache > 0 ? static_cast(data.l3_cache) * m_sockets : 0; + m_threads = static_cast(data.total_logical_cpus); + m_packages = std::max(threads() / static_cast(data.num_logical_cpus), 1); + m_cores = static_cast(data.num_cores) * m_packages; + m_L3 = data.l3_cache > 0 ? static_cast(data.l3_cache) * m_packages : 0; const size_t l2 = static_cast(data.l2_cache); // Workaround for AMD CPUs https://github.com/anrieff/libcpuid/issues/97 if (data.vendor == VENDOR_AMD && data.ext_family >= 0x15 && data.ext_family < 0x17) { - m_L2 = l2 * (cores() / 2) * m_sockets; + m_L2 = l2 * (cores() / 2) * m_packages; m_L2_exclusive = true; } // Workaround for Intel Pentium Dual-Core, Core Duo, Core 2 Duo, Core 2 Quad and their Xeon homologue // These processors have L2 cache shared by 2 cores. else if (data.vendor == VENDOR_INTEL && data.ext_family == 0x06 && (data.ext_model == 0x0E || data.ext_model == 0x0F || data.ext_model == 0x17)) { size_t l2_count_per_socket = cores() > 1 ? cores() / 2 : 1; - m_L2 = data.l2_cache > 0 ? l2 * l2_count_per_socket * m_sockets : 0; + m_L2 = data.l2_cache > 0 ? l2 * l2_count_per_socket * m_packages : 0; } else{ - m_L2 = data.l2_cache > 0 ? l2 * cores() * m_sockets : 0; + m_L2 = data.l2_cache > 0 ? l2 * cores() * m_packages : 0; } if (data.flags[CPU_FEATURE_AES]) { diff --git a/src/backend/cpu/platform/AdvancedCpuInfo.h b/src/backend/cpu/platform/AdvancedCpuInfo.h index 889fba006..e82258443 100644 --- a/src/backend/cpu/platform/AdvancedCpuInfo.h +++ b/src/backend/cpu/platform/AdvancedCpuInfo.h @@ -43,13 +43,12 @@ protected: inline Assembly::Id assembly() const override { return m_assembly; } inline bool hasAES() const override { return m_aes; } inline bool hasAVX2() const override { return m_avx2; } - inline bool isSupported() const override { return true; } inline const char *brand() const override { return m_brand; } inline size_t cores() const override { return m_cores; } inline size_t L2() const override { return m_L2; } inline size_t L3() const override { return m_L3; } inline size_t nodes() const override { return 0; } - inline size_t sockets() const override { return m_sockets; } + inline size_t packages() const override { return m_packages; } inline size_t threads() const override { return m_threads; } private: @@ -61,7 +60,7 @@ private: size_t m_cores = 0; size_t m_L2 = 0; size_t m_L3 = 0; - size_t m_sockets = 1; + size_t m_packages = 1; size_t m_threads = 0; }; diff --git a/src/backend/cpu/platform/BasicCpuInfo.cpp b/src/backend/cpu/platform/BasicCpuInfo.cpp index f30466fe9..1ceefecc4 100644 --- a/src/backend/cpu/platform/BasicCpuInfo.cpp +++ b/src/backend/cpu/platform/BasicCpuInfo.cpp @@ -64,70 +64,88 @@ #define EDX_Reg (3) -#ifdef _MSC_VER -static inline void cpuid(int level, int output[4]) { - __cpuid(output, level); +namespace xmrig { + + +static inline void cpuid(uint32_t level, int32_t output[4]) +{ + memset(output, 0, sizeof(int32_t) * 4); + +# ifdef _MSC_VER + __cpuid(output, static_cast(level)); +# else + __cpuid_count(level, 0, output[0], output[1], output[2], output[3]); +# endif } -#else -static inline void cpuid(int level, int output[4]) { - int a, b, c, d; - __cpuid_count(level, 0, a, b, c, d); - - output[0] = a; - output[1] = b; - output[2] = c; - output[3] = d; -} -#endif -static inline void cpu_brand_string(char* s) { +static void cpu_brand_string(char out[64 + 6]) { int32_t cpu_info[4] = { 0 }; + char buf[64] = { 0 }; + cpuid(VENDOR_ID, cpu_info); if (cpu_info[EAX_Reg] >= 4) { - for (int i = 0; i < 4; i++) { + for (uint32_t i = 0; i < 4; i++) { cpuid(0x80000002 + i, cpu_info); - memcpy(s, cpu_info, sizeof(cpu_info)); - s += 16; + memcpy(buf + (i * 16), cpu_info, sizeof(cpu_info)); } } + + size_t pos = 0; + const size_t size = strlen(buf); + + for (size_t i = 0; i < size; ++i) { + if (buf[i] == ' ' && ((pos > 0 && out[pos - 1] == ' ') || pos == 0)) { + continue; + } + + out[pos++] = buf[i]; + } + + if (pos > 0 && out[pos - 1] == ' ') { + out[pos - 1] = '\0'; + } +} + + +static bool has_feature(uint32_t level, uint32_t reg, int32_t bit) +{ + int32_t cpu_info[4] = { 0 }; + cpuid(level, cpu_info); + + return (cpu_info[reg] & bit) != 0; +} + + +static inline int32_t get_masked(int32_t val, int32_t h, int32_t l) +{ + val &= (0x7FFFFFFF >> (31 - (h - l))) << l; + return val >> l; } static inline bool has_aes_ni() { - int32_t cpu_info[4] = { 0 }; - cpuid(PROCESSOR_INFO, cpu_info); - - return (cpu_info[ECX_Reg] & bit_AES) != 0; + return has_feature(PROCESSOR_INFO, ECX_Reg, bit_AES); } static inline bool has_avx2() { - int32_t cpu_info[4] = { 0 }; - cpuid(EXTENDED_FEATURES, cpu_info); - - return (cpu_info[EBX_Reg] & bit_AVX2) != 0; + return has_feature(EXTENDED_FEATURES, EBX_Reg, bit_AVX2) && has_feature(PROCESSOR_INFO, ECX_Reg, bit_OSXSAVE); } -static inline bool has_ossave() -{ - int32_t cpu_info[4] = { 0 }; - cpuid(PROCESSOR_INFO, cpu_info); - - return (cpu_info[ECX_Reg] & bit_OSXSAVE) != 0; -} +} // namespace xmrig xmrig::BasicCpuInfo::BasicCpuInfo() : + m_threads(std::thread::hardware_concurrency()), m_assembly(Assembly::NONE), m_aes(has_aes_ni()), m_brand(), - m_avx2(has_avx2() && has_ossave()), - m_threads(std::thread::hardware_concurrency()) + m_avx2(has_avx2()) { cpu_brand_string(m_brand); @@ -136,17 +154,20 @@ xmrig::BasicCpuInfo::BasicCpuInfo() : char vendor[13] = { 0 }; int32_t data[4] = { 0 }; - cpuid(0, data); + cpuid(VENDOR_ID, data); memcpy(vendor + 0, &data[1], 4); memcpy(vendor + 4, &data[3], 4); memcpy(vendor + 8, &data[2], 4); - if (memcmp(vendor, "GenuineIntel", 12) == 0) { - m_assembly = Assembly::INTEL; + if (memcmp(vendor, "AuthenticAMD", 12) == 0) { + cpuid(PROCESSOR_INFO, data); + const int32_t family = get_masked(data[EAX_Reg], 12, 8) + get_masked(data[EAX_Reg], 28, 20); + + m_assembly = family >= 23 ? Assembly::RYZEN : Assembly::BULLDOZER; } - else if (memcmp(vendor, "AuthenticAMD", 12) == 0) { - m_assembly = Assembly::RYZEN; + else { + m_assembly = Assembly::INTEL; } } # endif diff --git a/src/backend/cpu/platform/BasicCpuInfo.h b/src/backend/cpu/platform/BasicCpuInfo.h index 12d0e0379..b05ed9cc3 100644 --- a/src/backend/cpu/platform/BasicCpuInfo.h +++ b/src/backend/cpu/platform/BasicCpuInfo.h @@ -43,21 +43,22 @@ protected: inline Assembly::Id assembly() const override { return m_assembly; } inline bool hasAES() const override { return m_aes; } inline bool hasAVX2() const override { return m_avx2; } - inline bool isSupported() const override { return true; } inline const char *brand() const override { return m_brand; } inline size_t cores() const override { return 0; } inline size_t L2() const override { return 0; } inline size_t L3() const override { return 0; } inline size_t nodes() const override { return 0; } - inline size_t sockets() const override { return 1; } + inline size_t packages() const override { return 1; } inline size_t threads() const override { return m_threads; } +protected: + size_t m_threads; + private: Assembly m_assembly; bool m_aes; char m_brand[64 + 6]; const bool m_avx2; - const size_t m_threads; }; diff --git a/src/core/Miner.cpp b/src/core/Miner.cpp index df83c5e9a..d0bfa78fa 100644 --- a/src/core/Miner.cpp +++ b/src/core/Miner.cpp @@ -134,7 +134,7 @@ public: cpu.AddMember("brand", StringRef(Cpu::info()->brand()), allocator); cpu.AddMember("aes", Cpu::info()->hasAES(), allocator); cpu.AddMember("x64", Cpu::info()->isX64(), allocator); - cpu.AddMember("sockets", static_cast(Cpu::info()->sockets()), allocator); + cpu.AddMember("sockets", static_cast(Cpu::info()->packages()), allocator); reply.AddMember("version", APP_VERSION, allocator); reply.AddMember("kind", APP_KIND, allocator);