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 @@ - + - +