From ab31776658cda99d6d8a788f6e1a07b23bda325e Mon Sep 17 00:00:00 2001 From: amir Date: Thu, 23 Apr 2026 14:13:48 +0100 Subject: [PATCH] Reworking IO Ring pipeline to fully support multiple infilght files Reworking the filequeue, the buffer chaining logic and the error handling. Renaming functions. Fix bug in arena. --- .gitignore | 1 + arena.c | 6 +- base.h | 1 + binaries/changelog.txt | 2 +- file_hasher | Bin 245536 -> 0 bytes file_hasher.c | 22 +- platform.c | 716 ++++++++++++++++++++--------------------- 7 files changed, 365 insertions(+), 383 deletions(-) delete mode 100644 file_hasher diff --git a/.gitignore b/.gitignore index 19b273a..91ce0c9 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ temp_code.c /.cache/clangd/index /file_hasher /io_uring_test +/file_hasher diff --git a/arena.c b/arena.c index 8c03d99..61767d5 100644 --- a/arena.c +++ b/arena.c @@ -437,12 +437,14 @@ void *arena_push(mem_arena **arena_ptr, u64 size, bool zero) { // mk push Commit memory if needed ------------------------------------------------------------ */ - if (local_post > selected->commit_pos) { - u64 new_commit = ALIGN_UP_POW2(local_post, arena_pagesize()); + if (local_post > selected->commit_pos - + ALIGN_UP_POW2(sizeof(mem_arena), selected->align)) { + u64 new_commit = ALIGN_UP_POW2(local_post + ALIGN_UP_POW2(sizeof(mem_arena), selected->align), arena_pagesize()); new_commit = MIN(new_commit, selected->reserve_size); if (!plat_mem_commit((u8 *)selected + selected->commit_pos, new_commit - selected->commit_pos)) { + printf("ERROR: Could not commit memory!\n"); return NULL; } diff --git a/base.h b/base.h index 4439968..24b9e18 100644 --- a/base.h +++ b/base.h @@ -46,6 +46,7 @@ #include #include #include +#include /* ------------------------------------------------------------ Base types diff --git a/binaries/changelog.txt b/binaries/changelog.txt index e2b14d8..9062932 100644 --- a/binaries/changelog.txt +++ b/binaries/changelog.txt @@ -50,7 +50,7 @@ Fixing user prompt parsing Reorganising the code Improving the scan function -5.0: Implementing the IO Ring for windows and ui_uring for linux instead of buffered hashing, huge performance gains. The IO Ring is event driven, thread local, uses DMA and direct disk I/O, bypassing the OS cash completely, registred buffers, it supports bashing multiple submissions and can handle multiple files at the same time. +5.0: Implementing the IO Ring for windows and ui_uring for linux instead of buffered hashing, huge performance gains. The IO Ring is event driven, thread local, uses DMA and direct disk I/O, bypassing the OS cache completely, registred buffers, it supports bashing multiple submissions and can handle multiple files at the same time. Hashing small files using XXH3_128bits() instead of the streaming pipeline(XXH3_128bits_reset(), XXH3_128bits_update(), XXH3_128bits_digest()), this reduses the overhead of creating a state and digest, coupled with the IO Ring it improves the hashing of small files whose size is inferior to the size of IO Ring buffers fixing the xxh_x86dispatch warnings Updating the progress printing function diff --git a/file_hasher b/file_hasher deleted file mode 100644 index 8c12d074d16ec49d546cfa63db36d9f337926f66..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 245536 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 diff --git a/file_hasher.c b/file_hasher.c index 7948f12..52e2c9b 100644 --- a/file_hasher.c +++ b/file_hasher.c @@ -77,14 +77,19 @@ int main(int argc, char **argv) { // Detect hardware // ------------------------------- // --- Windows: detect PHYSICAL cores (not logical threads) --- - size_t hw_threads = platform_physical_cores(); + uint32_t cpu_cores = platform_physical_cores(); // Logical threads = CPU cores * 2 - size_t num_threads = hw_threads * 2; + uint32_t cpu_threads = cpu_cores * 2; - printf("Starting thread pool: %zu threads (CPU cores: %zu)\n", num_threads, - hw_threads); - printf(" Selected instruction set: %s\n", get_xxhash_instruction_set()); + uint32_t num_scan_threads = cpu_threads; + uint32_t num_hash_threads = cpu_threads; + // uint32_t num_hash_threads = 1; + + printf("%d cores %d threads CPU detected with %s instruction set\n" + "Starting thread pool: %d scanning and %d hashing threads\n", + cpu_cores, cpu_threads, get_xxhash_instruction_set(), num_scan_threads, + num_hash_threads); // Align IO Ring block size to the system page size g_ioring_buffer_size = ALIGN_UP_POW2(g_ioring_buffer_size, g_pagesize); @@ -119,9 +124,6 @@ int main(int argc, char **argv) { // } // Starting hash threads - size_t num_hash_threads = num_threads; - // size_t num_hash_threads = 1; - WorkerContext workers[num_hash_threads]; Thread *hash_threads = arena_push(&gp_arena, sizeof(Thread) * num_hash_threads, true); @@ -130,7 +132,7 @@ int main(int argc, char **argv) { workers[i].arena = arena_create(¶ms); workers[i].file_queue = &file_queue; - if (thread_create(&hash_threads[i], (ThreadFunc)hash_worker_io_ring, + if (thread_create(&hash_threads[i], (ThreadFunc)hash_worker_ioring, &workers[i]) != 0) { fprintf(stderr, "Failed to create hash thread %zu\n", i); exit(1); @@ -178,8 +180,6 @@ int main(int argc, char **argv) { } // Starting scan threads - size_t num_scan_threads = num_threads; - ScannerContext scanners[num_scan_threads]; Thread *scan_threads = arena_push(&gp_arena, sizeof(Thread) * num_scan_threads, true); diff --git a/platform.c b/platform.c index b277ea6..deb0e63 100644 --- a/platform.c +++ b/platform.c @@ -887,11 +887,11 @@ static THREAD_RETURN progress_thread(void *arg) { // ======================== Hash worker IO Ring ======================== // -------------------------- Configuration --------------------------- -// #define IORING_BUFFER_SIZE (KiB(32)) #define IORING_BUFFER_SIZE (KiB(256)) #define NUM_BUFFERS_PER_THREAD 32 -#define MAX_ACTIVE_FILES 1 +#define MAX_ACTIVE_FILES 32 #define SUBMIT_TIMEOUT_MS 30000 +// #define IORING_DEBUG // Uncomment to print some errors // Globals u64 g_ioring_buffer_size = 4096 * 64; @@ -901,108 +901,116 @@ static atomic_uint_fast64_t g_io_ring_fallbacks = 0; #if defined(_WIN32) || defined(_WIN64) // Windows I/O Ring types -typedef HIORING AsyncIoRing; -typedef HIORING AsyncIoHandle; -#define INVALID_ASYNC_IO_HANDLE NULL -#define SUBMIT_READ_RETURN_VALUE HRESULT +typedef HIORING IoRingHandle; +#define BUILD_READ_RETURN_VALUE HRESULT + +typedef struct { + HRESULT ResultCode; + uint32_t Information; + uintptr_t UserData; +} IoRingCQE; #elif defined(__linux__) // Linux io_uring types typedef struct { struct io_uring ring; - int event_fd; struct io_uring_cqe *cqe_cache; int cqe_cache_index; int cqe_cache_count; -} AsyncIoRingImpl; +} IoUring; -typedef AsyncIoRingImpl *AsyncIoRing; -typedef int AsyncIoHandle; +typedef IoUring *IoRingHandle; typedef struct iovec IORING_BUFFER_INFO; -#define INVALID_ASYNC_IO_HANDLE (-1) -#define SUBMIT_READ_RETURN_VALUE int +#define BUILD_READ_RETURN_VALUE int typedef struct { int ResultCode; uint32_t Information; uintptr_t UserData; -} AsyncIoCompletion; +} IoRingCQE; #endif typedef struct IoBuffer IoBuffer; typedef struct FileReadContext { - FileHandle hFile; - uint64_t file_size; - int use_incremental_hash; - union { - XXH3_state_t hash_state; // For incremental hash (large files) - XXH128_hash_t single_hash; // For single-shot hash (small files) - }; FileEntry *fe; - - // Completion tracking - int reads_submitted; - int reads_completed; - - int active_reads; - int failed_reads; - - int reads_hashed; - uint64_t bytes_hashed; + uint64_t file_size; // For in-order hashing - uint64_t next_hash_offset; uint64_t next_read_offset; IoBuffer *head; IoBuffer *tail; + // Completion tracking + uint64_t bytes_hashed; + uint32_t reads_hashed; + + uint32_t reads_submitted; + uint32_t reads_completed; + + uint32_t active_reads; + + union { + XXH3_state_t hash_state; // For incremental hash (large files) + XXH128_hash_t single_hash; // For single-shot hash (small files) + }; + + FileHandle file_handle; + + bool use_incremental_hash; + + bool completed; + } FileReadContext; // -------------------------- Buffer structure --------------------------- -typedef struct IoBuffer { - void *data; - uint64_t offset; - size_t size; - size_t bytes_read; - SUBMIT_READ_RETURN_VALUE result; +#define IO_PENDING INT_MIN - int buffer_id; +typedef struct IoBuffer { + FileReadContext *file; + void *data; + size_t size; + uint64_t offset; + size_t bytes_read; + + BUILD_READ_RETURN_VALUE result; int completed; - FileReadContext *file; - struct IoBuffer *next; + int buffer_id; } IoBuffer; // Thread-local I/O Ring context typedef struct ThreadIoContext { - AsyncIoRing ring; + IoRingHandle ring; void *completion_event; unsigned char *fallback_buffer; IoBuffer buffers[NUM_BUFFERS_PER_THREAD]; int buffer_pool[NUM_BUFFERS_PER_THREAD]; int free_count; - int submitting; int num_submissions; int active_files; + bool submitting; + +#if defined(__linux__) + bool use_registered_buffers; +#endif - int use_registered_buffers; } ThreadIoContext; typedef struct { uint32_t MaxSubmissionQueueSize; uint32_t MaxCompletionQueueSize; uint32_t MaxVersion; -} AsyncIoCapabilities; +} IoRingCapabilities; // ----------------------------- Async I/O Abstraction ------------------------- #if defined(_WIN32) || defined(_WIN64) // Windows I/O Ring functions -static void async_io_query_capabilities(AsyncIoCapabilities *caps) { +static void ioring_query_capabilities(IoRingCapabilities *caps) { IORING_CAPABILITIES win_caps; QueryIoRingCapabilities(&win_caps); caps->MaxSubmissionQueueSize = win_caps.MaxSubmissionQueueSize; @@ -1010,32 +1018,30 @@ static void async_io_query_capabilities(AsyncIoCapabilities *caps) { caps->MaxVersion = win_caps.MaxVersion; } -static void *async_io_create_completion_event(void) { +static void *ioring_create_completion_event(void) { return CreateEvent(NULL, FALSE, FALSE, NULL); } -static void async_io_set_completion_event(AsyncIoRing ring, void *event) { +static void ioring_set_completion_event(IoRingHandle ring, void *event) { SetIoRingCompletionEvent(ring, event); } -static void async_io_wait_for_completion(ThreadIoContext *ctx) { +static void ioring_wait_for_completion(ThreadIoContext *ctx) { if (ctx->num_submissions > 0) { WaitForSingleObject(ctx->completion_event, SUBMIT_TIMEOUT_MS); return; } } -static int async_io_create_ring(ThreadIoContext *thread_ctx, - uint32_t queue_size) { +static int create_ioring(ThreadIoContext *thread_ctx, uint32_t queue_size) { IORING_CREATE_FLAGS flags = {0}; HRESULT hr = CreateIoRing(IORING_VERSION_3, flags, queue_size, queue_size * 2, &thread_ctx->ring); // Create completion event - thread_ctx->completion_event = async_io_create_completion_event(); + thread_ctx->completion_event = ioring_create_completion_event(); if (thread_ctx->completion_event) { - async_io_set_completion_event(thread_ctx->ring, - thread_ctx->completion_event); + ioring_set_completion_event(thread_ctx->ring, thread_ctx->completion_event); } return SUCCEEDED(hr) ? 0 : -1; } @@ -1045,78 +1051,83 @@ static int async_io_create_ring(ThreadIoContext *thread_ctx, #define MAKE_BUF_INFO(a, l) \ (IORING_BUFFER_INFO) { .Address = (a), .Length = (uint32_t)(l) } -static int async_io_submit(ThreadIoContext *thread_ctx, uint32_t wait_count, - uint32_t timeout_ms, uint32_t *submitted) { +static int ioring_submit(ThreadIoContext *thread_ctx, uint32_t wait_count, + uint32_t timeout_ms, uint32_t *submitted) { HRESULT hr = SubmitIoRing(thread_ctx->ring, 0, timeout_ms, submitted); // HRESULT hr = SubmitIoRing(ring, wait_count, timeout_ms, submitted); // The wait_count in windows is not implemented yet, so we wait with a // completion event for a single completion - async_io_wait_for_completion(thread_ctx); + ioring_wait_for_completion(thread_ctx); return SUCCEEDED(hr) ? 0 : -1; } -static int async_io_register_buffers(ThreadIoContext *thread_ctx, - uint32_t num_buffers, - IORING_BUFFER_INFO *buf_info) { +static int ioring_register_buffers(ThreadIoContext *thread_ctx, + uint32_t num_buffers, + IORING_BUFFER_INFO *buf_info) { HRESULT hr = BuildIoRingRegisterBuffers( thread_ctx->ring, NUM_BUFFERS_PER_THREAD, buf_info, USERDATA_REGISTER); if (FAILED(hr)) { - LPSTR messageBuffer = NULL; + char error_msg[256]; size_t size = FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&messageBuffer, 0, NULL); + NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), error_msg, + sizeof(error_msg), NULL); if (size > 0) { - fprintf(stderr, "Error registering buffers: %s (0x%08X)\n", messageBuffer, + fprintf(stderr, "Error registering buffers: %s (0x%08X)\n", error_msg, (unsigned int)hr); - LocalFree(messageBuffer); // Free the memory allocated by FormatMessage } else { fprintf(stderr, "Error registering buffers: Unknown HRESULT (0x%08X)\n", (unsigned int)hr); } } // Submit registration - async_io_submit(thread_ctx, 0, 0, NULL); + ioring_submit(thread_ctx, 0, 0, NULL); return hr; } -static void async_io_close_event(void *event) { CloseHandle(event); } +static void ioring_close_event(void *event) { CloseHandle(event); } -static int async_io_close_ring(ThreadIoContext *thread_ctx) { +static int close_ioring(ThreadIoContext *thread_ctx) { if (thread_ctx->completion_event) - async_io_close_event(thread_ctx->completion_event); + ioring_close_event(thread_ctx->completion_event); CloseIoRing(thread_ctx->ring); return 0; } -static SUBMIT_READ_RETURN_VALUE -async_io_build_read(ThreadIoContext *thread_ctx, AsyncIoHandle file_handle, - uint32_t buffer_id, size_t size, uint64_t offset, - uintptr_t user_data) { - IORING_HANDLE_REF file_ref = IoRingHandleRefFromHandle(file_handle); +static BUILD_READ_RETURN_VALUE ioring_build_read(ThreadIoContext *thread_ctx, + FileReadContext *file_ctx, + uint32_t buffer_id, + size_t size, uint64_t offset, + uintptr_t user_data) { + IORING_HANDLE_REF file_ref = IoRingHandleRefFromHandle(file_ctx->file_handle); IORING_BUFFER_REF buffer_ref = IoRingBufferRefFromIndexAndOffset(buffer_id, 0); HRESULT hr = BuildIoRingReadFile(thread_ctx->ring, file_ref, buffer_ref, (uint32_t)size, offset, user_data, IOSQE_FLAGS_NONE); + if (FAILED(hr)) { + char error_msg[256]; + FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + error_msg, sizeof(error_msg), NULL); + + fprintf(stderr, + "ERROR: Building read error for file: %s - Code: %s (0x%08X)\n", + file_ctx->fe->path, error_msg, (unsigned int)hr); + } return hr; } -typedef struct { - HRESULT ResultCode; - uint32_t Information; - uintptr_t UserData; -} AsyncIoCompletion; - -static int async_io_pop_completion(AsyncIoRing ring, AsyncIoCompletion *cqe) { +static int ioring_pop_completion(IoRingHandle ring, IoRingCQE *cqe) { IORING_CQE win_cqe; while (1) { @@ -1128,10 +1139,10 @@ static int async_io_pop_completion(AsyncIoRing ring, AsyncIoCompletion *cqe) { if (FAILED(hr)) return -1; - // Unlike linux, in addition of IO operations, Windows IO Ring produces CQEs - // (completion queue entries) when doing operations like register buffer or - // submiting, we filter them here cqe.UserData == USERDATA_REGISTER - // cqe.ResultCode == S_OK (or error) + // Unlike linux, in addition of IO operations, Windows IO Ring produces + // CQEs (completion queue entries) when doing operations like register + // buffer or submiting, we filter them here cqe.UserData == + // USERDATA_REGISTER cqe.ResultCode == S_OK (or error) if (win_cqe.UserData == USERDATA_REGISTER) continue; @@ -1145,9 +1156,18 @@ static int async_io_pop_completion(AsyncIoRing ring, AsyncIoCompletion *cqe) { FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, win_cqe.ResultCode, 0, error_msg, sizeof(error_msg), NULL); + + // Try to get the file path from the buffer + IoBuffer *buf = (IoBuffer *)win_cqe.UserData; + const char *file_path = "unknown"; + if (buf && buf->file && buf->file->fe) { + file_path = buf->file->fe->path; + } + fprintf(stderr, - "WARNING: I/O completion error - Code: 0x%lx, Error: %s\n", - win_cqe.ResultCode, error_msg); + "WARNING: I/O completion error for file '%s' - Code: 0x%lx, " + "Error: %s\n", + file_path, win_cqe.ResultCode, error_msg); } return 1; @@ -1156,7 +1176,7 @@ static int async_io_pop_completion(AsyncIoRing ring, AsyncIoCompletion *cqe) { #elif defined(__linux__) // Linux io_uring functions implementation -static void async_io_query_capabilities(AsyncIoCapabilities *caps) { +static void ioring_query_capabilities(IoRingCapabilities *caps) { // Get system limits for io_uring long max_entries = sysconf(_SC_IOV_MAX); if (max_entries <= 0) @@ -1169,9 +1189,8 @@ static void async_io_query_capabilities(AsyncIoCapabilities *caps) { } // static int async_io_create_ring(uint32_t queue_size, AsyncIoRing *ring) { -static int async_io_create_ring(ThreadIoContext *thread_ctx, - uint32_t queue_size) { - AsyncIoRingImpl *impl = (AsyncIoRingImpl *)calloc(1, sizeof(AsyncIoRingImpl)); +static int create_ioring(ThreadIoContext *thread_ctx, uint32_t queue_size) { + IoUring *impl = (IoUring *)calloc(1, sizeof(IoUring)); if (!impl) return -1; @@ -1210,25 +1229,76 @@ static int async_io_create_ring(ThreadIoContext *thread_ctx, #define MAKE_BUF_INFO(a, l) \ (IORING_BUFFER_INFO) { .iov_base = (a), .iov_len = (size_t)(l) } -static int async_io_register_buffers(ThreadIoContext *thread_ctx, - uint32_t num_buffers, - IORING_BUFFER_INFO *buf_info) { - AsyncIoRingImpl *impl = (AsyncIoRingImpl *)thread_ctx->ring; +static int ioring_register_buffers(ThreadIoContext *thread_ctx, + uint32_t num_buffers, + IORING_BUFFER_INFO *buf_info) { + IoUring *impl = (IoUring *)thread_ctx->ring; int hr = io_uring_register_buffers(&impl->ring, buf_info, num_buffers); if (hr < 0) { - fprintf(stderr, "Error registering buffers: %s (code: %d)\n", strerror(-hr), - hr); - fprintf(stderr, "WARNING: Memlock limit too low buffer size! Fallback to " - "unregistred buffers\n"); + if (hr == -ENOMEM) { + struct rlimit limit; + getrlimit(RLIMIT_MEMLOCK, &limit); + + fprintf(stderr, + "WARNING: Buffer registration failed due to memlock limits " + "(ENOMEM).\n" + "Increase the limit to solve this warning.\n"); + + // The memlock limit in Linux restricts the amount of memory a process can + // "lock" into physical RAM using the mlock() family of system calls. This + // prevents the operating system from swapping that memory out to disk. + // And registering buffers will lock the buffers memory so the hardware + // can access it directly without kernel intervention. Increase the limit + // to be able to register the buffers. + // + // **Modifying the Limit: + // The method for changing the memlock limit depends on whether you are + // managing a user session or a system service. + // 1. For Users and Interactive Sessions + // To permanently increase the limit for a specific user or group, modify + // the /etc/security/limits.conf file. Add the following lines: + // # Example for a specific user (replace 'username') + // username soft memlock unlimited + // username hard memlock unlimited + // + // # Example for all users + // * soft memlock unlimited + // * hard memlock unlimited + // + // Soft Limit: The value the user starts with; can be raised up to the + // hard limit. + // + // Hard Limit: The absolute maximum; only a privileged user + // (root) can increase this. Values: Can be set in Kilobytes (KB) or as + // unlimited. + // + // 2. For Systemd Services + // Settings in limits.conf do not affect background services managed by + // systemd. To increase the limit for a service, edit its service file + // (e.g., /etc/systemd/system/myservice.service) and add: + // + // [Service] + // LimitMEMLOCK=infinity + + } else { + // For any other error (e.g., EFAULT, EBUSY, EINVAL) + fprintf(stderr, "Error registering buffers: %s (code: %d)\n", + strerror(-hr), hr); + } + + fprintf(stderr, "Falling back to unregistered buffers (performance may " + "be reduced).\n"); } + + thread_ctx->use_registered_buffers = (hr == 0); return hr == 0 ? 0 : -1; } -static int async_io_submit(ThreadIoContext *thread_ctx, uint32_t wait_count, - uint32_t timeout_ms, uint32_t *submitted) { - AsyncIoRingImpl *impl = (AsyncIoRingImpl *)thread_ctx->ring; +static int ioring_submit(ThreadIoContext *thread_ctx, uint32_t wait_count, + uint32_t timeout_ms, uint32_t *submitted) { + IoUring *impl = (IoUring *)thread_ctx->ring; if (!impl) return -1; @@ -1251,27 +1321,26 @@ static int async_io_submit(ThreadIoContext *thread_ctx, uint32_t wait_count, return 0; } -static int async_io_close_ring(ThreadIoContext *thread_ctx) { - AsyncIoRingImpl *impl = (AsyncIoRingImpl *)thread_ctx->ring; +static int close_ioring(ThreadIoContext *thread_ctx) { + IoUring *impl = (IoUring *)thread_ctx->ring; if (!impl) return -1; if (thread_ctx->use_registered_buffers) { io_uring_unregister_buffers(&impl->ring); } - close(impl->event_fd); io_uring_queue_exit(&impl->ring); free(impl); return 0; } -static int async_io_build_read(ThreadIoContext *thread_ctx, - AsyncIoHandle file_handle, uint32_t buffer_id, - size_t size, uint64_t offset, - uintptr_t user_data) { - AsyncIoRing ring = thread_ctx->ring; - AsyncIoRingImpl *impl = (AsyncIoRingImpl *)ring; +static int ioring_build_read(ThreadIoContext *thread_ctx, + FileReadContext *file_ctx, uint32_t buffer_id, + size_t size, uint64_t offset, + uintptr_t user_data) { + IoRingHandle ring = thread_ctx->ring; + IoUring *impl = (IoUring *)ring; if (!impl) return -1; @@ -1281,22 +1350,21 @@ static int async_io_build_read(ThreadIoContext *thread_ctx, return -1; } - ThreadIoContext *ctx = thread_ctx; // or pass it properly TODO : look here - - void *buf = ctx->buffers[buffer_id].data; + void *buf = thread_ctx->buffers[buffer_id].data; if (thread_ctx->use_registered_buffers) { - io_uring_prep_read_fixed(sqe, file_handle, buf, size, offset, buffer_id); + io_uring_prep_read_fixed(sqe, file_ctx->file_handle, buf, size, offset, + buffer_id); } else { - io_uring_prep_read(sqe, file_handle, buf, size, offset); + io_uring_prep_read(sqe, file_ctx->file_handle, buf, size, offset); } io_uring_sqe_set_data64(sqe, user_data); return 0; } -static int async_io_pop_completion(AsyncIoRing ring, AsyncIoCompletion *cqe) { - AsyncIoRingImpl *impl = (AsyncIoRingImpl *)ring; +static int ioring_pop_completion(IoRingHandle ring, IoRingCQE *cqe) { + IoUring *impl = (IoUring *)ring; struct io_uring_cqe *cqe_ptr = NULL; @@ -1333,8 +1401,17 @@ static int async_io_pop_completion(AsyncIoRing ring, AsyncIoCompletion *cqe) { // Check for error and print warning if (res < 0) { - fprintf(stderr, "WARNING: I/O completion error - Code: %d, Error: %s\n", - res, strerror(-res)); + // Try to get the file path from the buffer + IoBuffer *buf = (IoBuffer *)cqe->UserData; + const char *file_path = "unknown"; + if (buf && buf->file && buf->file->fe) { + file_path = buf->file->fe->path; + } + + fprintf( + stderr, + "WARNING: I/O completion error for file '%s' - Code: %d, Error: %s\n", + file_path, res, strerror(-res)); } return 1; @@ -1343,8 +1420,8 @@ static int async_io_pop_completion(AsyncIoRing ring, AsyncIoCompletion *cqe) { #endif // OS-agnostic helper macros -#define ASYNC_IO_SUCCEEDED(result) ((result) >= 0) -#define ASYNC_IO_FAILED(result) ((result) < 0) +#define IORING_SUCCEEDED(result) ((result) >= 0) +#define IORING_FAILED(result) ((result) < 0) // ---------------------- FIFO queue operations --------------------------- typedef struct FileQueue { @@ -1364,55 +1441,51 @@ static FileReadContext *fq_push(FileQueue *fq) { return f; } -static FileReadContext *fq_peek(FileQueue *fq) { +static FileReadContext *fq_peek_tail(FileQueue *fq) { if (fq->count == 0) return NULL; - return &fq->files[fq->head]; + + int idx = (fq->tail - 1 + MAX_ACTIVE_FILES) % MAX_ACTIVE_FILES; + return &fq->files[idx]; // return the newest file } -static void fq_pop(FileQueue *fq) { - fq->head = (fq->head + 1) % MAX_ACTIVE_FILES; - fq->count--; +static FileReadContext *fq_peek_at(FileQueue *fq, int index) { + if (index < 0 || index >= fq->count) + return NULL; + + int idx = (fq->head + index) % MAX_ACTIVE_FILES; + return &fq->files[idx]; } -static void fq_remove_at(FileQueue *fq, int index) { - if (fq->count == 0) - return; +static void fq_trim(FileQueue *fq) { + while (fq->count > 0) { + FileReadContext *f = &fq->files[fq->head]; - int remove_idx = (fq->head + index) % MAX_ACTIVE_FILES; + if (!f->completed) + break; - int last_logical = fq->count - 1; - int last_idx = (fq->head + last_logical) % MAX_ACTIVE_FILES; - - // Swap with last logical element if needed - if (index != last_logical) { - fq->files[remove_idx] = fq->files[last_idx]; + fq->head = (fq->head + 1) % MAX_ACTIVE_FILES; + fq->count--; } - - // Just decrease count - fq->count--; - - // Recompute tail properly - fq->tail = (fq->head + fq->count) % MAX_ACTIVE_FILES; } -// ---------------------- Initialize thread context --------------------------- -static ThreadIoContext *io_ring_init_thread(void) { +// ----------------- Initialize thread context ----------------------- +static ThreadIoContext *ioring_init_thread(void) { ThreadIoContext *thread_ctx = (ThreadIoContext *)calloc(1, sizeof(ThreadIoContext)); if (!thread_ctx) return NULL; // Query I/O Ring capabilities - AsyncIoCapabilities caps; - async_io_query_capabilities(&caps); + IoRingCapabilities caps; + ioring_query_capabilities(&caps); uint32_t queue_size = caps.MaxSubmissionQueueSize; if (queue_size > 4096) queue_size = 4096; // Cap at 4096 for reasonable memory usage // Create I/O Ring - if (async_io_create_ring(thread_ctx, queue_size) != 0) { + if (create_ioring(thread_ctx, queue_size) != 0) { free(thread_ctx); thread_ctx = NULL; return NULL; @@ -1430,14 +1503,14 @@ static ThreadIoContext *io_ring_init_thread(void) { if (base_ptr) { if (!plat_mem_commit(base_ptr, buf_pool_size)) { plat_mem_release(base_ptr, 0); - async_io_close_ring(thread_ctx); + close_ioring(thread_ctx); free(thread_ctx); thread_ctx = NULL; return NULL; } } else { - async_io_close_ring(thread_ctx); + close_ioring(thread_ctx); free(thread_ctx); thread_ctx = NULL; return NULL; @@ -1456,22 +1529,21 @@ static ThreadIoContext *io_ring_init_thread(void) { // Register buffers int hr = - async_io_register_buffers(thread_ctx, NUM_BUFFERS_PER_THREAD, buf_info); + ioring_register_buffers(thread_ctx, NUM_BUFFERS_PER_THREAD, buf_info); - thread_ctx->use_registered_buffers = (hr == 0); - thread_ctx->submitting = 1; + thread_ctx->submitting = true; thread_ctx->num_submissions = 0; thread_ctx->active_files = 0; return thread_ctx; } -static void io_ring_cleanup_thread(ThreadIoContext *thread_ctx) { +static void ioring_cleanup_thread(ThreadIoContext *thread_ctx) { if (!thread_ctx) return; if (thread_ctx->ring) - async_io_close_ring(thread_ctx); + close_ioring(thread_ctx); // Free the buffer pool memory if (thread_ctx->buffers[0].data) { @@ -1494,7 +1566,8 @@ static IoBuffer *get_free_buffer(ThreadIoContext *ctx) { IoBuffer *buf = &ctx->buffers[idx]; buf->completed = 0; buf->bytes_read = 0; - buf->result = 0; + buf->result = IO_PENDING; + buf->next = NULL; return buf; } @@ -1513,104 +1586,63 @@ static int build_read(ThreadIoContext *thread_ctx, FileReadContext *file_ctx, buf->size = size; buf->file = file_ctx; - SUBMIT_READ_RETURN_VALUE result = - async_io_build_read(thread_ctx, file_ctx->hFile, buf->buffer_id, size, - offset, (uintptr_t)buf); + BUILD_READ_RETURN_VALUE result = ioring_build_read( + thread_ctx, file_ctx, buf->buffer_id, size, offset, (uintptr_t)buf); - if (ASYNC_IO_SUCCEEDED(result)) { + if (IORING_SUCCEEDED(result)) { file_ctx->active_reads++; file_ctx->reads_submitted++; thread_ctx->num_submissions++; } else { - buf->completed = 1; + buf->completed = true; buf->result = result; // Store the error code return_buffer(thread_ctx, buf); } return result; } -// ------------ Link completed buffers in an ordered list ------------- -static void insert_buffer_ordered(FileReadContext *file, IoBuffer *buf) { - buf->next = NULL; - - // empty list - if (!file->head) { - file->head = file->tail = buf; - return; - } - - // insert at head - if (buf->offset < file->head->offset) { - buf->next = file->head; - file->head = buf; - return; - } - - // find position - IoBuffer *cur = file->head; - - while (cur->next && cur->next->offset < buf->offset) { - cur = cur->next; - } - - buf->next = cur->next; - cur->next = buf; - - if (!buf->next) - file->tail = buf; -} - // -------------------------- Process completions --------------------------- static void process_completions(ThreadIoContext *thread_ctx, FileQueue *fq) { - AsyncIoCompletion cqe; + IoRingCQE cqe; - // Keep processing as long as there are completions available - while (async_io_pop_completion(thread_ctx->ring, &cqe) == 1) { + while (ioring_pop_completion(thread_ctx->ring, &cqe) == 1) { IoBuffer *buf = (IoBuffer *)cqe.UserData; FileReadContext *file = buf->file; buf->result = cqe.ResultCode; buf->bytes_read = cqe.Information; - buf->completed = 1; file->active_reads--; file->reads_completed++; thread_ctx->num_submissions--; - - if (ASYNC_IO_SUCCEEDED(cqe.ResultCode) && cqe.Information > 0) { - - buf->next = NULL; - - insert_buffer_ordered(file, buf); - - } else { - file->failed_reads++; - return_buffer(thread_ctx, buf); - } } } // -------------------- File operations ----------------------- -static int init_file(FileReadContext *f, FileEntry *fe) { - memset(f, 0, sizeof(*f)); +static int init_file(FileReadContext *file, FileEntry *fe) { + memset(file, 0, sizeof(*file)); - f->fe = fe; - f->file_size = fe->size_bytes; + file->fe = fe; + file->file_size = fe->size_bytes; + file->head = file->tail = NULL; - // Use the abstracted os_file_open_async for async I/O with no buffering - f->hFile = os_file_open(fe->path, FLAG_ASYNC_DIRECT_READ); + file->file_handle = os_file_open(fe->path, FLAG_ASYNC_DIRECT_READ); - if (f->hFile == INVALID_ASYNC_IO_HANDLE) { + if (file->file_handle == INVALID_FILE_HANDLE) { + +#ifdef IORING_DEBUG + printf("ERROR: Could not open file %s\n", fe->path); +#endif return 0; } // Determine hash method based on file size - if (f->file_size > g_ioring_buffer_size) { - f->use_incremental_hash = true; - XXH3_128bits_reset(&f->hash_state); + if (file->file_size > g_ioring_buffer_size) { + file->use_incremental_hash = true; + XXH3_128bits_reset(&file->hash_state); } else { - f->use_incremental_hash = false; + file->use_incremental_hash = false; } return 1; } @@ -1620,9 +1652,11 @@ static void finalize_file(FileReadContext *file, ThreadIoContext *thread_ctx, FileEntry *fe = file->fe; + os_file_close(file->file_handle); + char hash[HASH_STRLEN]; - if (file->failed_reads == 0 && file->bytes_hashed == file->file_size) { + if (file->bytes_hashed == file->file_size) { if (file->use_incremental_hash) { // Large file: digest the accumulated hash state XXH128_hash_t h = XXH3_128bits_digest(&file->hash_state); @@ -1635,10 +1669,12 @@ static void finalize_file(FileReadContext *file, ThreadIoContext *thread_ctx, (unsigned long long)file->single_hash.low64); } } else { +#ifdef IORING_DEBUG + printf("WARNING: Fallback for path: %s\n", fe->path); +#endif + atomic_fetch_add(&g_io_ring_fallbacks, 1); xxh3_hash_file_stream(fe->path, hash, thread_ctx->fallback_buffer); - // DEBUG - // printf("Fallback for path: %s\n", fe->path); } char created[32], modified[32]; @@ -1657,219 +1693,164 @@ static void finalize_file(FileReadContext *file, ThreadIoContext *thread_ctx, atomic_fetch_add(&g_files_hashed, 1); } -// -------------------- Hash head file ----------------------- -static void hash_head_file(ThreadIoContext *thread_ctx, FileQueue *fq, - WorkerContext *worker_ctx) { - - FileReadContext *file = fq_peek(fq); - if (!file) - return; - - // Keep hashing while the next buffer in sequence is ready at head - while (file->head && file->head->offset == file->next_hash_offset) { - - IoBuffer *buf = file->head; - - // Consume from head - file->head = buf->next; - if (!file->head) - file->tail = NULL; - - // Process the buffer - if (ASYNC_IO_SUCCEEDED(buf->result) && buf->bytes_read > 0) { - // Calculate actual bytes to hash (handle last partial sector) - size_t bytes_to_hash = buf->bytes_read; - - // If this is the last buffer and we read beyond file size, trim it - if (buf->offset + buf->bytes_read > file->file_size) { - bytes_to_hash = file->file_size - buf->offset; - } - - if (bytes_to_hash > 0) { - if (file->use_incremental_hash) { - // Large file: update incremental hash state - XXH3_128bits_update(&file->hash_state, buf->data, bytes_to_hash); - } else { - // Small file: single-shot hash - file->single_hash = XXH3_128bits(buf->data, bytes_to_hash); - } - - file->bytes_hashed += bytes_to_hash; - atomic_fetch_add(&g_bytes_processed, bytes_to_hash); - } - - file->reads_hashed++; - } else if (buf->bytes_read == 0 && ASYNC_IO_SUCCEEDED(buf->result)) { - // Read operation completed with 0 bytes (EOF) - file->reads_hashed++; - } else { - // Read failed - file->failed_reads++; - file->reads_hashed++; - } - - // Move to next offset - file->next_hash_offset += buf->size; - - // Return buffer to pool - return_buffer(thread_ctx, buf); - } - - // Finalize file when all reads are complete - if (file->active_reads == 0 && file->bytes_hashed >= file->file_size) { - finalize_file(file, thread_ctx, worker_ctx); - os_file_close(file->hFile); - fq_pop(fq); - thread_ctx->active_files--; - } -} - +// -------------------- Hash files ----------------------- static void hash_ready_files(ThreadIoContext *thread_ctx, FileQueue *fq, WorkerContext *worker_ctx) { - for (int i = 0; i < fq->count;) { - int idx = (fq->head + i) % MAX_ACTIVE_FILES; - FileReadContext *file = &fq->files[idx]; + for (int i = 0; i < fq->count; i++) { - bool progressed = false; + FileReadContext *file = fq_peek_at(fq, i); + if (!file || file->completed) + continue; - // ---- HASH READY BUFFERS ---- + // ---- HASH READY BUFFERS IN ORDER ---- while (file->head) { IoBuffer *buf = file->head; - if (buf->offset != file->bytes_hashed) + // CQE not received yet + if (buf->result == IO_PENDING) break; - progressed = true; - + // Consume buffer file->head = buf->next; - if (!file->head) - file->tail = NULL; - size_t bytes_to_hash = buf->bytes_read; + if (IORING_SUCCEEDED(buf->result) && buf->bytes_read > 0) { - if (buf->offset + buf->bytes_read > file->file_size) { - bytes_to_hash = file->file_size - buf->offset; - } + size_t bytes_to_hash = buf->bytes_read; - if (bytes_to_hash > 0) { - if (file->use_incremental_hash) { - XXH3_128bits_update(&file->hash_state, buf->data, bytes_to_hash); - } else { - file->single_hash = XXH3_128bits(buf->data, bytes_to_hash); + if (buf->offset + buf->bytes_read > file->file_size) { + bytes_to_hash = file->file_size - buf->offset; } - file->bytes_hashed += bytes_to_hash; - atomic_fetch_add(&g_bytes_processed, bytes_to_hash); + if (bytes_to_hash > 0) { + if (file->use_incremental_hash) { + XXH3_128bits_update(&file->hash_state, buf->data, bytes_to_hash); + } else { + file->single_hash = XXH3_128bits(buf->data, bytes_to_hash); + } + + file->bytes_hashed += bytes_to_hash; + atomic_fetch_add(&g_bytes_processed, bytes_to_hash); + } + + file->reads_hashed++; + + } else if (buf->bytes_read == 0 && IORING_SUCCEEDED(buf->result)) { + file->reads_hashed++; // EOF + } else { + finalize_file(file, thread_ctx, worker_ctx); + file->completed = true; } return_buffer(thread_ctx, buf); } // ---- FINALIZE ---- - if (file->active_reads == 0 && file->bytes_hashed >= file->file_size) { + if (!file->completed && file->active_reads == 0 && + file->bytes_hashed >= file->file_size) { finalize_file(file, thread_ctx, worker_ctx); - os_file_close(file->hFile); - - fq_remove_at(fq, i); + file->completed = true; thread_ctx->active_files--; - - continue; } - i++; } + + // Clean up completed files from the head + fq_trim(fq); } -// ------------- Submit pending reads - fill all free buffers ----------------- +// ------------------ Build pending reads ---------------------- static void build_pending_reads(ThreadIoContext *thread_ctx, FileQueue *fq, WorkerContext *worker_ctx) { MPMCQueue *file_queue = worker_ctx->file_queue; - // Try to submit reads for the current head file - FileReadContext *f = fq_peek(fq); + FileReadContext *file = fq_peek_tail(fq); for (;;) { - if (f) { - while (f->next_read_offset < f->file_size) { + // ---------------- BUILD READS FOR CURRENT FILE ---------------- + if (file) { + while (file->next_read_offset < file->file_size) { IoBuffer *buf = get_free_buffer(thread_ctx); if (!buf) return; - size_t remaining = f->file_size - f->next_read_offset; - size_t size; - - // Check if this is the last read and the file size is not - // sector-aligned - int is_last_read = (remaining <= g_ioring_buffer_size); + size_t remaining = file->file_size - file->next_read_offset; + size_t bytes_to_read; if (remaining >= g_ioring_buffer_size) { - // Normal full read - size = g_ioring_buffer_size; + bytes_to_read = g_ioring_buffer_size; } else { - // Last read - handle partial sector - if (remaining % g_pagesize != 0) { - size = ALIGN_UP_POW2(remaining, g_pagesize); - - } else { - size = remaining; - } + bytes_to_read = ALIGN_UP_POW2(remaining, g_pagesize); } - SUBMIT_READ_RETURN_VALUE hr = - build_read(thread_ctx, f, buf, f->next_read_offset, size); + // Initialize buffer + buf->file = file; + buf->offset = file->next_read_offset; + buf->size = bytes_to_read; - if (ASYNC_IO_FAILED(hr)) { + // Chain buffer + if (!file->head) { + file->head = buf; + } else { + file->tail->next = buf; + } + file->tail = buf; + + BUILD_READ_RETURN_VALUE hr = + ioring_build_read(thread_ctx, file, buf->buffer_id, bytes_to_read, + buf->offset, (uintptr_t)buf); + + if (IORING_FAILED(hr)) { + // mark failure and stop this file return_buffer(thread_ctx, buf); - f->failed_reads++; - f->active_reads = 0; - f->reads_submitted = 0; - f->next_read_offset = f->file_size; + finalize_file(file, thread_ctx, worker_ctx); + file->completed = true; break; } - f->next_read_offset += size; + file->active_reads++; + file->reads_submitted++; + thread_ctx->num_submissions++; + + file->next_read_offset += bytes_to_read; } } - // Add new file if possible + // ---------------- ADD NEW FILE ---------------- if (!thread_ctx->submitting) return; - if (thread_ctx->active_files >= MAX_ACTIVE_FILES) + if (fq->count >= MAX_ACTIVE_FILES) return; FileEntry *fe = mpmc_pop(file_queue); if (!fe) { - thread_ctx->submitting = 0; + thread_ctx->submitting = false; return; } - FileReadContext *newf = fq_push(fq); + FileReadContext *newfile = fq_push(fq); - if (!init_file(newf, fe)) { - // File can't be opened with NO_BUFFERING, process with fallback - char hash[HASH_STRLEN]; - finalize_file(newf, thread_ctx, worker_ctx); - fq_pop(fq); + if (!init_file(newfile, fe)) { + finalize_file(newfile, thread_ctx, worker_ctx); + newfile->completed = true; continue; } - f = newf; + file = newfile; thread_ctx->active_files++; } } - // -------------------------- Hash worker I/O Ring --------------------------- -static THREAD_RETURN hash_worker_io_ring(void *arg) { - WorkerContext *ctx = (WorkerContext *)arg; +static THREAD_RETURN hash_worker_ioring(void *arg) { + WorkerContext *worker_ctx = (WorkerContext *)arg; // Init IO ring - ThreadIoContext *thread_ctx = io_ring_init_thread(); + ThreadIoContext *thread_ctx = ioring_init_thread(); if (!thread_ctx || !thread_ctx->ring) { printf("I/O Ring unavailable, using buffered I/O\n"); return hash_worker(arg); @@ -1886,28 +1867,25 @@ static THREAD_RETURN hash_worker_io_ring(void *arg) { for (;;) { // Submit new reads - build_pending_reads(thread_ctx, &fq, ctx); + build_pending_reads(thread_ctx, &fq, worker_ctx); - wait_count = MIN(thread_ctx->num_submissions, NUM_BUFFERS_PER_THREAD - 2); + wait_count = MIN(thread_ctx->num_submissions, NUM_BUFFERS_PER_THREAD - 6); submitted = 0; - // async_io_submit(ring_ctx->ring, 0, 0, &submitted); - async_io_submit(thread_ctx, wait_count, 0, &submitted); + ioring_submit(thread_ctx, wait_count, 0, &submitted); // Process completions process_completions(thread_ctx, &fq); // debug - // printf("Free buffers: %d, Submissions: %d, Active files: %d\n", - // ring_ctx->free_count, ring_ctx->num_submissions, - // ring_ctx->active_files); + // printf( + // "Free buffers: %d, Submissions: %d, Active files: %d, fq count: + // %d\n", thread_ctx->free_count, thread_ctx->num_submissions, + // thread_ctx->active_files, fq.count); // debug end // Hash files - for (int i = 0; i < fq.count; i++) { - hash_head_file(thread_ctx, &fq, ctx); - } - // hash_ready_files(ring_ctx, &fq, ctx); + hash_ready_files(thread_ctx, &fq, worker_ctx); // Exit condition if (!thread_ctx->submitting && thread_ctx->active_files == 0 && @@ -1916,6 +1894,6 @@ static THREAD_RETURN hash_worker_io_ring(void *arg) { } } - io_ring_cleanup_thread(thread_ctx); + ioring_cleanup_thread(thread_ctx); return THREAD_RETURN_VALUE; }