From 38dac6473d3ade3ed380fe8626426ef97352f44b Mon Sep 17 00:00:00 2001 From: Chris Blume Date: Mon, 6 Oct 2025 21:47:34 -0400 Subject: [PATCH] Report core performance/efficiency This commit reports the different efficiency levels of the various CPU cores. It also changes the worker threads count to match the highest performance core count. This contributes to (and possibly closes) #3 --- Code/EntryPoint.cpp | 26 +++-- Code/GetProcessorCoreInformation.cpp | 68 +++++++++++++ Code/GetProcessorCoreInformation.hpp | 28 ++++++ Code/GetProcessorInformation.cpp | 98 ------------------- Code/GetProcessorInformation.hpp | 22 ----- .../VisualStudio/FileReadSpeedTest.vcxproj | 4 +- 6 files changed, 116 insertions(+), 130 deletions(-) create mode 100644 Code/GetProcessorCoreInformation.cpp create mode 100644 Code/GetProcessorCoreInformation.hpp delete mode 100644 Code/GetProcessorInformation.cpp delete mode 100644 Code/GetProcessorInformation.hpp diff --git a/Code/EntryPoint.cpp b/Code/EntryPoint.cpp index fdf5063..77201d7 100644 --- a/Code/EntryPoint.cpp +++ b/Code/EntryPoint.cpp @@ -2,9 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include #include -#include "GetProcessorInformation.hpp" +#include "GetProcessorCoreInformation.hpp" #include "OverlappedIOFileRead.hpp" int main(int argc, const char * argv[]) { @@ -14,19 +15,28 @@ int main(int argc, const char * argv[]) { return -1; } - auto processor_information = FileReadSpeedTest::GetProcessorInformation(); - if (!processor_information.has_value()) { + auto processor_core_information = FileReadSpeedTest::GetProcessorCoreInformation(); + if (!processor_core_information.has_value()) { std::cerr << "Error: Could not find processor information." << std::endl; return -1; } - std::cout << "CPU cores: " << processor_information->actual_cores_; - if (processor_information->hyperthreading_cores_ != 0) { - std::cout << " (and " << processor_information->hyperthreading_cores_ << " hyperthreading cores)"; + int16_t max_efficiency = -1; + uint16_t max_efficiency_core_count = 0; + for (auto& core_information : *processor_core_information) { + std::cout << "CPU cores: " << core_information.count_ << " @ performance class: " << core_information.efficiency_class_; + if (core_information.has_hyperthreading_ != 0) { + std::cout << " (with hyperthreading)"; + } + + if (core_information.efficiency_class_ > max_efficiency) { + max_efficiency = core_information.efficiency_class_; + max_efficiency_core_count = core_information.count_; + } + std::cout << std::endl; } - std::cout << std::endl; - auto overlapped_io_file_read = FileReadSpeedTest::PrepareToReadFile(argv[1], processor_information->actual_cores_); + auto overlapped_io_file_read = FileReadSpeedTest::PrepareToReadFile(argv[1], max_efficiency_core_count); if (!overlapped_io_file_read.has_value()) { std::cerr << "Error"; return -1; diff --git a/Code/GetProcessorCoreInformation.cpp b/Code/GetProcessorCoreInformation.cpp new file mode 100644 index 0000000..b09b910 --- /dev/null +++ b/Code/GetProcessorCoreInformation.cpp @@ -0,0 +1,68 @@ +// Copyright 2025, The FileReadSpeedTest Contributors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "GetProcessorCoreInformation.hpp" + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include + +#include +#include + +namespace FileReadSpeedTest { + + ProcessorCoreInformation::ProcessorCoreInformation(uint16_t efficiency_class, uint16_t count, bool has_hyperthreading) noexcept + : efficiency_class_(std::move(efficiency_class)) + , count_(std::move(count)) + , has_hyperthreading_(std::move(has_hyperthreading)) + {} + + std::optional> GetProcessorCoreInformation() noexcept { + DWORD required_buffer_size = 0; + BOOL result = GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, &required_buffer_size); + if (result == FALSE) { + DWORD error_code = GetLastError(); + if (error_code != ERROR_INSUFFICIENT_BUFFER) { + return std::nullopt; + } + } + + const size_t element_size = sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX); + // char[] because chars enable aliasing + auto buffer = std::make_unique(required_buffer_size); + auto buffer_end = buffer.get() + required_buffer_size; + auto* current_pointer = buffer.get(); + auto* processor_information = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)current_pointer; + result = GetLogicalProcessorInformationEx(RelationProcessorCore, processor_information, &required_buffer_size); + if (result == FALSE) { + return std::nullopt; + } + + std::vector core_informations; + for (size_t i = 0; (char*)current_pointer < buffer_end; i++) { + uint32_t efficiency = processor_information->Processor.EfficiencyClass; + bool hyperthreading = processor_information->Processor.Flags == LTP_PC_SMT; + + bool match_found = false; + for (auto& core_information : core_informations) { + if (core_information.efficiency_class_ == efficiency && + core_information.has_hyperthreading_ == hyperthreading) { + match_found = true; + core_information.count_++; + } + } + if (!match_found) { + core_informations.emplace_back(efficiency, 1, hyperthreading); + } + + current_pointer += processor_information->Size; + processor_information = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)current_pointer; + } + + return core_informations; + } + +} // namespace FileReadSpeedTest \ No newline at end of file diff --git a/Code/GetProcessorCoreInformation.hpp b/Code/GetProcessorCoreInformation.hpp new file mode 100644 index 0000000..dbe5eb1 --- /dev/null +++ b/Code/GetProcessorCoreInformation.hpp @@ -0,0 +1,28 @@ +// Copyright 2025, The FileReadSpeedTest Contributors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef FILEREADSPEEDTEST_GETPROCESSORCOREINFORMATION_HPP +#define FILEREADSPEEDTEST_GETPROCESSORCOREINFORMATION_HPP + +#include +#include +#include + +namespace FileReadSpeedTest { + + struct ProcessorCoreInformation { + public: + + explicit ProcessorCoreInformation(uint16_t efficiency_class, uint16_t count, bool has_hyperthreading) noexcept; + + uint16_t efficiency_class_; + uint16_t count_; + bool has_hyperthreading_; + }; + + std::optional> GetProcessorCoreInformation() noexcept; + +} // namespace FileReadSpeedTest + +#endif // #ifndef FILEREADSPEEDTEST_GETPROCESSORCOREINFORMATION_HPP \ No newline at end of file diff --git a/Code/GetProcessorInformation.cpp b/Code/GetProcessorInformation.cpp deleted file mode 100644 index 6f9fc04..0000000 --- a/Code/GetProcessorInformation.cpp +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2025, The FileReadSpeedTest Contributors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "GetProcessorInformation.hpp" - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif -#include - -#include - -//#include - -namespace FileReadSpeedTest { - - /*struct ProcessorInformation { - int actual_cores_; - int hyperthreading_cores_; - };*/ - - std::optional GetProcessorInformation() noexcept { - DWORD required_buffer_size = 0; - BOOL result = GetLogicalProcessorInformation(nullptr, &required_buffer_size); - if (result == FALSE) { - DWORD error_code = GetLastError(); - if (error_code != ERROR_INSUFFICIENT_BUFFER) { - return std::nullopt; - } - } - size_t processor_information_count = required_buffer_size / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); - auto processor_information = std::make_unique(processor_information_count); - result = GetLogicalProcessorInformation(processor_information.get(), &required_buffer_size); - if (result == FALSE) { - return std::nullopt; - } - - ProcessorCoreInformation processor_core_information = {}; - - for(DWORD i = 0; i < processor_information_count; i++) { - //std::cout << "Core " << i << ": " << processor_information[i].ProcessorMask << std::endl; - switch (processor_information[i].Relationship) { - /* - case RelationProcessorPackage: - std::cout << "\tPhysical package" << std::endl; - break; - case RelationNumaNode: - std::cout << "\tNUMA node: " << processor_information[i].NumaNode.NodeNumber << std::endl; - break; - */ - case RelationProcessorCore: - { - processor_core_information.actual_cores_++; - if (processor_information[i].ProcessorCore.Flags == 1) { - processor_core_information.hyperthreading_cores_++; - } - } - break; - /* - case RelationCache: - std::cout << "\tL"; - switch (processor_information[i].Cache.Level) { - case 1: - std::cout << "1 "; - break; - case 2: - std::cout << "2 "; - break; - case 3: - std::cout << "3 "; - break; - } - switch (processor_information[i].Cache.Type) { - case CacheUnified: - std::cout << "unified"; - break; - case CacheInstruction: - std::cout << "instuction"; - break; - case CacheData: - std::cout << "data"; - break; - case CacheTrace: - std::cout << "trace"; - break; - } - std::cout << " cache, " << processor_information[i].Cache.Size << " KiB" << std::endl; - std::cout << "\tCache line size: " << processor_information[i].Cache.LineSize << " KiB" << std::endl; - break; - */ - } - } - - return processor_core_information; - } - -} // namespace FileReadSpeedTest \ No newline at end of file diff --git a/Code/GetProcessorInformation.hpp b/Code/GetProcessorInformation.hpp deleted file mode 100644 index 05dac23..0000000 --- a/Code/GetProcessorInformation.hpp +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright 2025, The FileReadSpeedTest Contributors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef FILEREADSPEEDTEST_GETPROCESSORINFORMATION_HPP -#define FILEREADSPEEDTEST_GETPROCESSORINFORMATION_HPP - -#include - -namespace FileReadSpeedTest { - - class ProcessorCoreInformation { - public: - int actual_cores_; - int hyperthreading_cores_; - }; - - std::optional GetProcessorInformation() noexcept; - -} // namespace FileReadSpeedTest - -#endif // #ifndef FILEREADSPEEDTEST_GETPROCESSORINFORMATION_HPP \ No newline at end of file diff --git a/Projects/VisualStudio/FileReadSpeedTest.vcxproj b/Projects/VisualStudio/FileReadSpeedTest.vcxproj index 63dd2b8..7ecf7cb 100644 --- a/Projects/VisualStudio/FileReadSpeedTest.vcxproj +++ b/Projects/VisualStudio/FileReadSpeedTest.vcxproj @@ -20,13 +20,13 @@ - + - +