Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions Code/EntryPoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@

#include "OverlappedIOFileRead.hpp"

int main() {
int main(int argc, const char * argv[]) {
if (argc != 2) {
std::cerr << "Error: No file provided.\n";
std::cerr << "Use the form: FileReadSpeedTest.exe C:\\my\\file.txt" << std::endl;
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(R"(../../Test Data/crystaldiskmark nvme ssd.png)", worker_thread_count);
auto overlapped_io_file_read = PrepareToReadFile(argv[1], worker_thread_count);
if (!overlapped_io_file_read.has_value()) {
std::cerr << "Error";
return -1;
Expand Down
19 changes: 16 additions & 3 deletions Code/OverlappedIOFileRead.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@

namespace {

std::chrono::time_point<std::chrono::high_resolution_clock> pre_open_time_;


std::optional<OverlappedIOFile> CreateOverlappedIOFile(LPCSTR file_name) noexcept {
// TODO: Add FILE_FLAG_NO_BUFFERING flag
// and FILE_FLAG_RANDOM_ACCESS or FILE_FLAG_SEQUENTIAL_SCAN
HANDLE file_handle = CreateFileA(file_name, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
pre_open_time_ = std::chrono::high_resolution_clock::now();
// Use FILE_FLAG_RANDOM_ACCESS instead of FILE_FLAG_SEQUENTIAL_SCAN for file formats where that is a better fit
// FILE_FLAG_NO_BUFFERING
HANDLE file_handle = CreateFileA(file_name, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | FILE_FLAG_SEQUENTIAL_SCAN | FILE_FLAG_NO_BUFFERING, NULL);
if (file_handle == INVALID_HANDLE_VALUE) {
// GetLastError
return std::nullopt;
Expand Down Expand Up @@ -183,6 +187,11 @@ void OverlappedIOFileRead::WaitForThreadsToFinish() noexcept {
// Wait for worker threads to finish
WaitForMultipleObjects(static_cast<DWORD>(thread_pool_.threads_.size()), (const HANDLE*)thread_pool_.threads_.data(), TRUE, INFINITE);

auto open_delay = std::chrono::duration_cast<std::chrono::nanoseconds>(overlapped_io_file_.file_open_time_ - pre_open_time_);
auto open_to_read_delay = std::chrono::duration_cast<std::chrono::nanoseconds>(read_issue_time_ - overlapped_io_file_.file_open_time_);
std::cout << "Open delay: " << open_delay << std::endl;
std::cout << "Open to read delay: " << open_to_read_delay << std::endl;

size_t i = 0;
for (auto& context : contexts_) {
auto read_issue_delay = std::chrono::duration_cast<std::chrono::nanoseconds>(context.request_start_time_ - read_issue_time_);
Expand Down Expand Up @@ -231,6 +240,10 @@ std::expected<OverlappedIOFileRead, PrepareToReadFileError> PrepareToReadFile(LP
return std::unexpected{PrepareToReadFileError::CouldNotCreateCompletionPort};
}

// TODO: Creating the threads takes a significant amount of time.
// This happens after the file is opened and the completion port is created.
// The OS *could* begin prefetching the data. I don't know if it does or not.
// But if it does, this gives it ample opportunity to impact the measurements.
auto thread_pool = CreateThreadPool(WorkerThread, completion_port->handle_, worker_thread_count);
if (!thread_pool.has_value()) {
return std::unexpected{PrepareToReadFileError::CouldNotCreateThread};
Expand Down
14 changes: 12 additions & 2 deletions Code/OverlappedIOFileRead.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,21 @@
#define NOMINMAX
#include <Windows.h>

using OverlappedIOFile = SpecificHandleObject;
//using OverlappedIOFile = SpecificHandleObject;
using CompletionPort = SpecificHandleObject;
using Thread = SpecificHandleObject;

struct OverlappedIOFile : public SpecificHandleObject {

explicit OverlappedIOFile(HANDLE handle) noexcept
: SpecificHandleObject(std::move(handle))
, file_open_time_(std::chrono::high_resolution_clock::now())
{}

std::chrono::time_point<std::chrono::high_resolution_clock> file_open_time_;

};

class ThreadPool {
public:

Expand All @@ -40,7 +51,6 @@ struct IOContext {
std::chrono::time_point<std::chrono::high_resolution_clock> request_start_time_;
std::chrono::time_point<std::chrono::high_resolution_clock> request_complete_time_;


};

class OverlappedIOFileRead {
Expand Down
Loading