Skip to content

Commit db40940

Browse files
authored
Add direct I/O tests
1 parent 03704d8 commit db40940

File tree

1 file changed

+157
-0
lines changed

1 file changed

+157
-0
lines changed

src/coro_io/tests/test_corofile.cpp

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@
1414
#include <ylt/coro_io/coro_io.hpp>
1515
#include <ylt/coro_io/io_context_pool.hpp>
1616

17+
#if !defined(ASIO_WINDOWS)
18+
#include <fcntl.h>
19+
#include <unistd.h>
20+
#include <cstdlib>
21+
#include <cstring>
22+
#endif
23+
1724
namespace fs = std::filesystem;
1825
using namespace coro_io;
1926

@@ -923,3 +930,153 @@ TEST_CASE("large_file_write_with_pool_test") {
923930
file.close();
924931
fs::remove(fs::path(filename));
925932
}
933+
934+
#if !defined(ASIO_WINDOWS)
935+
constexpr size_t DIRECT_IO_ALIGNMENT = 512;
936+
937+
inline void* aligned_alloc_direct_io(size_t size) {
938+
void* ptr = nullptr;
939+
if (posix_memalign(&ptr, DIRECT_IO_ALIGNMENT, size) != 0) {
940+
return nullptr;
941+
}
942+
return ptr;
943+
}
944+
945+
inline void aligned_free_direct_io(void* ptr) {
946+
free(ptr);
947+
}
948+
949+
inline size_t align_offset_for_direct_io(size_t offset) {
950+
return (offset / DIRECT_IO_ALIGNMENT) * DIRECT_IO_ALIGNMENT;
951+
}
952+
953+
inline size_t align_size_for_direct_io(size_t size) {
954+
return ((size + DIRECT_IO_ALIGNMENT - 1) / DIRECT_IO_ALIGNMENT) * DIRECT_IO_ALIGNMENT;
955+
}
956+
957+
template <coro_io::execution_type execute_type>
958+
void test_direct_io_read_write(std::string_view filename) {
959+
size_t file_size = 8 * KB;
960+
create_files({std::string(filename)}, file_size);
961+
962+
auto executor = coro_io::get_global_block_executor();
963+
coro_io::basic_random_coro_file<execute_type> file(executor);
964+
965+
bool opened = file.open(filename, std::ios::in | std::ios::out, true);
966+
if (!opened) {
967+
WARN("Direct I/O not supported on this filesystem, skipping test");
968+
return;
969+
}
970+
971+
CHECK(file.is_open());
972+
973+
size_t aligned_size = align_size_for_direct_io(block_size);
974+
void* aligned_buf = aligned_alloc_direct_io(aligned_size);
975+
REQUIRE(aligned_buf != nullptr);
976+
977+
struct BufferGuard {
978+
void* ptr;
979+
~BufferGuard() {
980+
if (ptr) {
981+
aligned_free_direct_io(ptr);
982+
}
983+
}
984+
} guard{aligned_buf};
985+
986+
char* buf = static_cast<char*>(aligned_buf);
987+
988+
size_t aligned_offset = align_offset_for_direct_io(0);
989+
size_t aligned_read_size = align_size_for_direct_io(block_size);
990+
991+
auto [ec, bytes_read] = async_simple::coro::syncAwait(
992+
file.async_read_at(aligned_offset, buf, aligned_read_size));
993+
994+
CHECK(!ec);
995+
CHECK(bytes_read == aligned_read_size);
996+
CHECK(!file.eof());
997+
998+
std::memset(buf, 'X', aligned_read_size);
999+
1000+
auto [write_ec, bytes_written] = async_simple::coro::syncAwait(
1001+
file.async_write_at(aligned_offset, std::string_view(buf, aligned_read_size)));
1002+
1003+
CHECK(!write_ec);
1004+
CHECK(bytes_written == aligned_read_size);
1005+
1006+
std::memset(buf, 0, aligned_read_size);
1007+
auto [read_ec, read_bytes] = async_simple::coro::syncAwait(
1008+
file.async_read_at(aligned_offset, buf, aligned_read_size));
1009+
1010+
CHECK(!read_ec);
1011+
CHECK(read_bytes == aligned_read_size);
1012+
1013+
for (size_t i = 0; i < aligned_read_size; ++i) {
1014+
CHECK(buf[i] == 'X');
1015+
}
1016+
1017+
for (size_t offset = 0; offset < file_size - aligned_read_size; offset += aligned_read_size) {
1018+
size_t aligned_off = align_offset_for_direct_io(offset);
1019+
1020+
std::memset(buf, 'A' + (offset / aligned_read_size) % 26, aligned_read_size);
1021+
auto [w_ec, w_bytes] = async_simple::coro::syncAwait(
1022+
file.async_write_at(aligned_off, std::string_view(buf, aligned_read_size)));
1023+
CHECK(!w_ec);
1024+
CHECK(w_bytes == aligned_read_size);
1025+
1026+
std::memset(buf, 0, aligned_read_size);
1027+
auto [r_ec, r_bytes] = async_simple::coro::syncAwait(
1028+
file.async_read_at(aligned_off, buf, aligned_read_size));
1029+
CHECK(!r_ec);
1030+
CHECK(r_bytes == aligned_read_size);
1031+
1032+
char expected = 'A' + (offset / aligned_read_size) % 26;
1033+
for (size_t i = 0; i < aligned_read_size; ++i) {
1034+
CHECK(buf[i] == expected);
1035+
}
1036+
}
1037+
1038+
file.close();
1039+
}
1040+
#endif
1041+
1042+
#if !defined(ASIO_WINDOWS)
1043+
TEST_CASE("direct io read write test - thread_pool") {
1044+
std::string filename = "direct_io_test_thread_pool.tmp";
1045+
test_direct_io_read_write<coro_io::execution_type::thread_pool>(filename);
1046+
fs::remove(fs::path(filename));
1047+
}
1048+
#endif
1049+
1050+
#if defined(ASIO_HAS_FILE) && !defined(ASIO_WINDOWS)
1051+
TEST_CASE("direct io read write test - native_async") {
1052+
std::string filename = "direct_io_test_native_async.tmp";
1053+
test_direct_io_read_write<coro_io::execution_type::native_async>(filename);
1054+
fs::remove(fs::path(filename));
1055+
}
1056+
#endif
1057+
1058+
TEST_CASE("direct io alignment test") {
1059+
#if !defined(ASIO_WINDOWS)
1060+
CHECK(align_offset_for_direct_io(0) == 0);
1061+
CHECK(align_offset_for_direct_io(100) == 0);
1062+
CHECK(align_offset_for_direct_io(512) == 512);
1063+
CHECK(align_offset_for_direct_io(1000) == 512);
1064+
CHECK(align_offset_for_direct_io(1024) == 1024);
1065+
1066+
CHECK(align_size_for_direct_io(0) == 0);
1067+
CHECK(align_size_for_direct_io(100) == 512);
1068+
CHECK(align_size_for_direct_io(512) == 512);
1069+
CHECK(align_size_for_direct_io(1000) == 1024);
1070+
CHECK(align_size_for_direct_io(1024) == 1024);
1071+
1072+
void* ptr1 = aligned_alloc_direct_io(1024);
1073+
REQUIRE(ptr1 != nullptr);
1074+
CHECK(reinterpret_cast<uintptr_t>(ptr1) % DIRECT_IO_ALIGNMENT == 0);
1075+
aligned_free_direct_io(ptr1);
1076+
1077+
void* ptr2 = aligned_alloc_direct_io(4096);
1078+
REQUIRE(ptr2 != nullptr);
1079+
CHECK(reinterpret_cast<uintptr_t>(ptr2) % DIRECT_IO_ALIGNMENT == 0);
1080+
aligned_free_direct_io(ptr2);
1081+
#endif
1082+
}

0 commit comments

Comments
 (0)