-
Notifications
You must be signed in to change notification settings - Fork 376
Support for io_uring #670
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: cpp_main
Are you sure you want to change the base?
Support for io_uring #670
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,16 +44,16 @@ target_link_libraries(gen_random_slice ${PROJECT_NAME} ${DISKANN_TOOLS_TCMALLOC_ | |
| add_executable(simulate_aggregate_recall simulate_aggregate_recall.cpp) | ||
|
|
||
| add_executable(calculate_recall calculate_recall.cpp) | ||
| target_link_libraries(calculate_recall ${PROJECT_NAME} ${DISKANN_ASYNC_LIB} ${DISKANN_TOOLS_TCMALLOC_LINK_OPTIONS}) | ||
| target_link_libraries(calculate_recall ${PROJECT_NAME} ${DISKANN_ASYNC_LIB} ${DISKANN_ASYNC_LIB_URING} ${DISKANN_TOOLS_TCMALLOC_LINK_OPTIONS}) | ||
|
|
||
| # Compute ground truth thing outside of DiskANN main source that depends on MKL. | ||
| add_executable(compute_groundtruth compute_groundtruth.cpp) | ||
| target_include_directories(compute_groundtruth PRIVATE ${DISKANN_MKL_INCLUDE_DIRECTORIES}) | ||
| target_link_libraries(compute_groundtruth ${PROJECT_NAME} ${DISKANN_MKL_LINK_LIBRARIES} ${DISKANN_ASYNC_LIB} Boost::program_options) | ||
| target_link_libraries(compute_groundtruth ${PROJECT_NAME} ${DISKANN_MKL_LINK_LIBRARIES} ${DISKANN_ASYNC_LIB} ${DISKANN_ASYNC_LIB_URING} Boost::program_options) | ||
|
|
||
| add_executable(compute_groundtruth_for_filters compute_groundtruth_for_filters.cpp) | ||
| target_include_directories(compute_groundtruth_for_filters PRIVATE ${DISKANN_MKL_INCLUDE_DIRECTORIES}) | ||
| target_link_libraries(compute_groundtruth_for_filters ${PROJECT_NAME} ${DISKANN_MKL_LINK_LIBRARIES} ${DISKANN_ASYNC_LIB} Boost::program_options) | ||
| target_link_libraries(compute_groundtruth_for_filters ${PROJECT_NAME} ${DISKANN_MKL_LINK_LIBRARIES} ${DISKANN_ASYNC_LIB} ${DISKANN_ASYNC_LIB_URING} Boost::program_options) | ||
|
|
||
|
|
||
| add_executable(generate_pq generate_pq.cpp) | ||
|
|
@@ -67,10 +67,10 @@ add_executable(partition_with_ram_budget partition_with_ram_budget.cpp) | |
| target_link_libraries(partition_with_ram_budget ${PROJECT_NAME} ${DISKANN_TOOLS_TCMALLOC_LINK_OPTIONS}) | ||
|
|
||
| add_executable(merge_shards merge_shards.cpp) | ||
| target_link_libraries(merge_shards ${PROJECT_NAME} ${DISKANN_TOOLS_TCMALLOC_LINK_OPTIONS} ${DISKANN_ASYNC_LIB}) | ||
| target_link_libraries(merge_shards ${PROJECT_NAME} ${DISKANN_TOOLS_TCMALLOC_LINK_OPTIONS} ${DISKANN_ASYNC_LIB} ${DISKANN_ASYNC_LIB_URING}) | ||
|
|
||
| add_executable(create_disk_layout create_disk_layout.cpp) | ||
| target_link_libraries(create_disk_layout ${PROJECT_NAME} ${DISKANN_ASYNC_LIB} ${DISKANN_TOOLS_TCMALLOC_LINK_OPTIONS}) | ||
| target_link_libraries(create_disk_layout ${PROJECT_NAME} ${DISKANN_ASYNC_LIB} ${DISKANN_ASYNC_LIB_URING} ${DISKANN_TOOLS_TCMALLOC_LINK_OPTIONS}) | ||
|
Comment on lines
47
to
73
|
||
|
|
||
| add_executable(generate_synthetic_labels generate_synthetic_labels.cpp) | ||
| target_link_libraries(generate_synthetic_labels ${PROJECT_NAME} Boost::program_options) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| // Copyright (c) KIOXIA Corporation. All rights reserved. | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT license. | ||
|
|
||
| #pragma once | ||
| #ifndef _WINDOWS | ||
|
|
||
| #include "aligned_file_reader.h" | ||
|
|
||
| class LinuxAlignedFileReader : public AlignedFileReader | ||
| { | ||
| private: | ||
| uint64_t file_sz; | ||
| FileHandle file_desc; | ||
| IOContext bad_ctx = (IOContext)-1; | ||
|
|
||
| public: | ||
| LinuxAlignedFileReader(); | ||
| ~LinuxAlignedFileReader(); | ||
|
|
||
| IOContext &get_ctx(); | ||
|
|
||
| // register thread-id for a context | ||
| void register_thread(); | ||
|
|
||
| // de-register thread-id for a context | ||
| void deregister_thread(); | ||
| void deregister_all_threads(); | ||
|
|
||
| // Open & close ops | ||
| // Blocking calls | ||
| void open(const std::string &fname); | ||
| void close(); | ||
|
|
||
| // process batch of aligned requests in parallel | ||
| // NOTE :: blocking call | ||
| void read(std::vector<AlignedRead> &read_reqs, IOContext &ctx, bool async = false); | ||
| }; | ||
|
|
||
| #endif |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -49,6 +49,7 @@ target_link_libraries( | |||||||||||||||||||||||
| ${PROJECT_NAME} | ||||||||||||||||||||||||
| ${DISKANN_TOOLS_TCMALLOC_LINK_OPTIONS} | ||||||||||||||||||||||||
| ${DISKANN_ASYNC_LIB} | ||||||||||||||||||||||||
| ${DISKANN_ASYNC_LIB_URING} | ||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
|
Comment on lines
+52
to
54
|
||||||||||||||||||||||||
| ${DISKANN_ASYNC_LIB_URING} | |
| ) | |
| ) | |
| if (IOURING) | |
| target_link_libraries( | |
| _diskannpy | |
| PRIVATE | |
| ${DISKANN_ASYNC_LIB_URING} | |
| ) | |
| endif() |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -10,13 +10,19 @@ else() | |||||
| #file(GLOB CPP_SOURCES *.cpp) | ||||||
| set(CPP_SOURCES abstract_data_store.cpp ann_exception.cpp disk_utils.cpp | ||||||
| distance.cpp index.cpp in_mem_graph_store.cpp in_mem_data_store.cpp | ||||||
| linux_aligned_file_reader.cpp math_utils.cpp natural_number_map.cpp | ||||||
| math_utils.cpp natural_number_map.cpp | ||||||
| in_mem_data_store.cpp in_mem_graph_store.cpp | ||||||
| natural_number_set.cpp memory_mapper.cpp partition.cpp pq.cpp | ||||||
| pq_flash_index.cpp scratch.cpp logger.cpp utils.cpp filter_utils.cpp index_factory.cpp abstract_index.cpp pq_l2_distance.cpp pq_data_store.cpp) | ||||||
| if (RESTAPI) | ||||||
| list(APPEND CPP_SOURCES restapi/search_wrapper.cpp restapi/server.cpp) | ||||||
| endif() | ||||||
| if (NOT IOURING) | ||||||
| list(APPEND CPP_SOURCES linux_aligned_file_reader.cpp) | ||||||
| else() | ||||||
|
||||||
| else() | |
| else() |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,218 @@ | ||||||||||||||||||||||
| // Copyright (c) KIOXIA Corporation. All rights reserved. | ||||||||||||||||||||||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||||||||||||||||||||||
| // Licensed under the MIT license. | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| #include "linux_aligned_file_reader_uring.h" | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| #include <cassert> | ||||||||||||||||||||||
| #include <cstdio> | ||||||||||||||||||||||
| #include <iostream> | ||||||||||||||||||||||
| #include "tsl/robin_map.h" | ||||||||||||||||||||||
| #include "utils.h" | ||||||||||||||||||||||
| #define QUEUE_DEPTH 1024 | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| void execute_io(IOContext ctx, int fd, std::vector<AlignedRead> &read_reqs, uint64_t n_retries = 0) | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| #ifdef DEBUG | ||||||||||||||||||||||
| for (auto &req : read_reqs) | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| assert(IS_ALIGNED(req.len, 512)); | ||||||||||||||||||||||
| // std::cout << "request:"<<req.offset<<":"<<req.len << std::endl; | ||||||||||||||||||||||
| assert(IS_ALIGNED(req.offset, 512)); | ||||||||||||||||||||||
| assert(IS_ALIGNED(req.buf, 512)); | ||||||||||||||||||||||
| // assert(malloc_usable_size(req.buf) >= req.len); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| #endif | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // break-up requests into chunks of size QUEUE_DEPTH each | ||||||||||||||||||||||
|
||||||||||||||||||||||
| uint64_t n_iters = ROUND_UP(read_reqs.size(), QUEUE_DEPTH) / QUEUE_DEPTH; | ||||||||||||||||||||||
| for (uint64_t iter = 0; iter < n_iters; iter++) | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| uint64_t n_ops = std::min((uint64_t)read_reqs.size() - (iter * QUEUE_DEPTH), (uint64_t)QUEUE_DEPTH); | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| // create n_ops io requests | ||||||||||||||||||||||
| for (uint64_t j = 0; j < n_ops; j++) | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| struct io_uring_sqe *sqe = io_uring_get_sqe(ctx); | ||||||||||||||||||||||
| if (!sqe){ | ||||||||||||||||||||||
| std::cerr << "io_uring_get_sqe() failed; ernno=" << errno; | ||||||||||||||||||||||
|
||||||||||||||||||||||
| std::cout << "ctx: " << ctx << "\n"; | ||||||||||||||||||||||
| exit(-1); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| io_uring_prep_read(sqe, fd, read_reqs[j + iter * QUEUE_DEPTH].buf, read_reqs[j + iter * QUEUE_DEPTH].len, | ||||||||||||||||||||||
| read_reqs[j + iter * QUEUE_DEPTH].offset); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| uint64_t n_tries = 0; | ||||||||||||||||||||||
| while (n_tries <= n_retries) | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| // send io requests here | ||||||||||||||||||||||
| int64_t ret = io_uring_submit(ctx); | ||||||||||||||||||||||
| // if requests didn't get accepted | ||||||||||||||||||||||
| if (ret != (int64_t)n_ops) | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| std::cerr << "io_uring_submit() failed; returned " << ret << ", expected=" << n_ops << ", ernno=" << errno | ||||||||||||||||||||||
|
||||||||||||||||||||||
| << "=" << ::strerror(-ret) << ", try #" << n_tries + 1; | ||||||||||||||||||||||
| std::cout << "ctx: " << ctx << "\n"; | ||||||||||||||||||||||
| exit(-1); | ||||||||||||||||||||||
| } | ||||||||||||||||||||||
| else | ||||||||||||||||||||||
| { | ||||||||||||||||||||||
| struct io_uring_cqe *cqes[QUEUE_DEPTH]; | ||||||||||||||||||||||
| unsigned int count = 0; | ||||||||||||||||||||||
|
||||||||||||||||||||||
| unsigned int count = 0; |
Copilot
AI
Feb 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in error message: "ernno" should be "errno"
Copilot
AI
Feb 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo in error message: "io_uring_waite_cqes" should be "io_uring_wait_cqes" (missing 't' in 'wait')
| std::cerr << "io_uring_waite_cqes() failed; returned " << ret << ", expected=" << n_ops | |
| std::cerr << "io_uring_wait_cqes() failed; returned " << ret << ", expected=" << n_ops |
Copilot
AI
Feb 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The retry logic appears broken. When io_uring_submit or io_uring_wait_cqes fails, the function calls exit(-1), so the increment of n_tries on line 79 is never reached. This means the n_retries parameter is effectively unused. Consider restructuring the error handling to allow retries before exiting, similar to the pattern in linux_aligned_file_reader.cpp where retries actually happen.
Copilot
AI
Feb 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The execute_io function is in the global namespace, but in linux_aligned_file_reader.cpp (the libaio equivalent), it's declared within an anonymous namespace to avoid potential symbol collisions. Consider wrapping execute_io in an anonymous namespace for consistency with the existing code and to prevent potential linker issues.
Copilot
AI
Feb 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error message refers to "io_setup()" which is the libaio function name. This should be updated to "io_uring_queue_init()" since this is the io_uring implementation. This appears to be a copy-paste error from the libaio version.
| std::cerr << "io_setup() failed with EAGAIN" << std::endl; | |
| } | |
| else | |
| { | |
| std::cerr << "io_setup() failed; returned " << ret << ": " << ::strerror(-ret) << std::endl; | |
| std::cerr << "io_uring_queue_init() failed with EAGAIN" << std::endl; | |
| } | |
| else | |
| { | |
| std::cerr << "io_uring_queue_init() failed; returned " << ret << ": " << ::strerror(-ret) << std::endl; |
Copilot
AI
Feb 5, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If io_uring_queue_init fails, the allocated memory at ctx is never freed, causing a memory leak. Add free(ctx) in the error path before returning or exiting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The DISKANN_ASYNC_LIB_URING library is unconditionally linked even when IOURING is not enabled. This will cause a linking error when building without -DIOURING=True, as the uring library won't be needed and may not be installed. The linking should be conditional on IOURING being enabled. Consider wrapping these link statements with: if(IOURING) target_link_libraries(...${DISKANN_ASYNC_LIB_URING}...) endif()