diff --git a/Code/EntryPoint.cpp b/Code/EntryPoint.cpp index 4ffbb46..d1b398a 100644 --- a/Code/EntryPoint.cpp +++ b/Code/EntryPoint.cpp @@ -1,5 +1,6 @@ #include +#include "GetProcessorInformation.hpp" #include "OverlappedIOFileRead.hpp" int main(int argc, const char * argv[]) { @@ -9,9 +10,19 @@ int main(int argc, const char * argv[]) { return -1; } - const DWORD worker_thread_count = 6; - // TODO: Take the file as part of the command line parameters. - auto overlapped_io_file_read = PrepareToReadFile(argv[1], worker_thread_count); + auto processor_information = GetProcessorInformation(); + if (!processor_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)"; + } + std::cout << std::endl; + + auto overlapped_io_file_read = PrepareToReadFile(argv[1], processor_information->actual_cores_); if (!overlapped_io_file_read.has_value()) { std::cerr << "Error"; return -1; diff --git a/Code/GetProcessorInformation.cpp b/Code/GetProcessorInformation.cpp new file mode 100644 index 0000000..e2169d7 --- /dev/null +++ b/Code/GetProcessorInformation.cpp @@ -0,0 +1,90 @@ +#include "GetProcessorInformation.hpp" + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include + +#include + +//#include + +/*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; +} \ No newline at end of file diff --git a/Code/GetProcessorInformation.hpp b/Code/GetProcessorInformation.hpp new file mode 100644 index 0000000..c42f35e --- /dev/null +++ b/Code/GetProcessorInformation.hpp @@ -0,0 +1,14 @@ +#ifndef GETPROCESSORINFORMATION_HPP +#define GETPROCESSORINFORMATION_HPP + +#include + +class ProcessorCoreInformation { +public: + int actual_cores_; + int hyperthreading_cores_; +}; + +std::optional GetProcessorInformation() noexcept; + +#endif // #ifndef GETPROCESSORINFORMATION_HPP \ No newline at end of file diff --git a/Code/OverlappedIOFileRead.cpp b/Code/OverlappedIOFileRead.cpp index 092f598..ed67675 100644 --- a/Code/OverlappedIOFileRead.cpp +++ b/Code/OverlappedIOFileRead.cpp @@ -79,7 +79,8 @@ namespace { if (!allocation.has_value()) { return std::nullopt; } - //buffer = std::make_unique(BUFFER_SIZE); + // TODO: Confirm the allocation is aligned to volume sector size + // TODO: Confirm buffer_size is a multiple of volume sector size auto io_context = IOContext{std::move(overlapped), overlapped_io_file.handle_, std::move(*allocation), buffer_size, file_offset}; @@ -227,12 +228,30 @@ std::expected PrepareToReadFile(LP return std::unexpected{PrepareToReadFileError::CouldNotGetFileSize}; } + std::cout << "File size: " << file_size.QuadPart << std::endl; + FILE_STORAGE_INFO file_storage_info; result = GetFileInformationByHandleEx(file->handle_, FileStorageInfo, &file_storage_info, sizeof(file_storage_info)); if (result == FALSE) { return std::unexpected{PrepareToReadFileError::CouldNotGetFileSize}; } - unsigned long partition_block_size = file_storage_info.PhysicalBytesPerSectorForPerformance; + unsigned long partition_block_size = file_storage_info.LogicalBytesPerSector; + // When doing writes instead of reads, prefer file_storage_info.PhysicalBytesPerSectorForPerformance; + + // Get the page size + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + /*if (compiling for x86 or arm64) { + SYSTEM_INFO native_system_info; + GetNativeSystemInfo(&native_system_info); + }*/ + partition_block_size = system_info.dwPageSize; + // TODO: Confirm the page size is a multiple of the logical bytes per sector + + // On Windows, VirtualAlloc has 64 KiB granularity: + // https://devblogs.microsoft.com/oldnewthing/20031008-00/?p=42223 + // TODO: Should we push the buffer size to 64 KiB? + std::cout << "Buffer size: " << partition_block_size << std::endl; auto completion_port = CreateCompletionPort(*file, worker_thread_count); diff --git a/Projects/VisualStudio/FileReadSpeedTest.vcxproj b/Projects/VisualStudio/FileReadSpeedTest.vcxproj index a25c850..63dd2b8 100644 --- a/Projects/VisualStudio/FileReadSpeedTest.vcxproj +++ b/Projects/VisualStudio/FileReadSpeedTest.vcxproj @@ -20,11 +20,13 @@ + + diff --git a/Projects/VisualStudio/FileReadSpeedTest.vcxproj.filters b/Projects/VisualStudio/FileReadSpeedTest.vcxproj.filters index 90c1572..164f3b5 100644 --- a/Projects/VisualStudio/FileReadSpeedTest.vcxproj.filters +++ b/Projects/VisualStudio/FileReadSpeedTest.vcxproj.filters @@ -5,10 +5,12 @@ + + \ No newline at end of file