From 10edd385435ceb4dff9a87988712b25ca6793bb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kleines=20Filmr=C3=B6llchen?= Date: Thu, 6 Jul 2023 13:41:38 +0200 Subject: [PATCH] LibCore: Keep track of file offset to avoid system call for tell() This optimization makes the new test run 2x faster. --- Tests/LibCore/TestLibCoreStream.cpp | 19 +++++++++++++++++++ Userland/Libraries/LibCore/File.cpp | 12 +++++++++++- Userland/Libraries/LibCore/File.h | 3 +++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Tests/LibCore/TestLibCoreStream.cpp b/Tests/LibCore/TestLibCoreStream.cpp index fff9054823..daff490119 100644 --- a/Tests/LibCore/TestLibCoreStream.cpp +++ b/Tests/LibCore/TestLibCoreStream.cpp @@ -92,6 +92,25 @@ TEST_CASE(file_seeking_around) EXPECT_EQ(buffer_contents, expected_seek_contents3); } +BENCHMARK_CASE(file_tell) +{ + auto file = TRY_OR_FAIL(Core::File::open("/usr/Tests/LibCore/10kb.txt"sv, Core::File::OpenMode::Read)); + auto expected_file_offset = 0u; + auto ten_byte_buffer = TRY_OR_FAIL(ByteBuffer::create_uninitialized(1)); + for (auto i = 0u; i < 4000; ++i) { + TRY_OR_FAIL(file->read_until_filled(ten_byte_buffer)); + expected_file_offset += 1u; + EXPECT_EQ(expected_file_offset, TRY_OR_FAIL(file->tell())); + } + + for (auto i = 0u; i < 4000; ++i) { + auto seek_file_offset = TRY_OR_FAIL(file->seek(-1, SeekMode::FromCurrentPosition)); + expected_file_offset -= 1; + EXPECT_EQ(seek_file_offset, TRY_OR_FAIL(file->tell())); + EXPECT_EQ(expected_file_offset, TRY_OR_FAIL(file->tell())); + } +} + TEST_CASE(file_adopt_fd) { int rc = ::open("/usr/Tests/LibCore/long_lines.txt", O_RDONLY); diff --git a/Userland/Libraries/LibCore/File.cpp b/Userland/Libraries/LibCore/File.cpp index be65e1ddc1..bcfb18a78e 100644 --- a/Userland/Libraries/LibCore/File.cpp +++ b/Userland/Libraries/LibCore/File.cpp @@ -117,6 +117,7 @@ ErrorOr File::read_some(Bytes buffer) ssize_t nread = TRY(System::read(m_fd, buffer)); m_last_read_was_eof = nread == 0; + m_file_offset += nread; return buffer.trim(nread); } @@ -135,7 +136,9 @@ ErrorOr File::write_some(ReadonlyBytes buffer) return Error::from_errno(EBADF); } - return TRY(System::write(m_fd, buffer)); + auto nwritten = TRY(System::write(m_fd, buffer)); + m_file_offset += nwritten; + return nwritten; } bool File::is_eof() const { return m_last_read_was_eof; } @@ -177,15 +180,22 @@ ErrorOr File::seek(i64 offset, SeekMode mode) } size_t seek_result = TRY(System::lseek(m_fd, offset, syscall_mode)); + m_file_offset = seek_result; m_last_read_was_eof = false; return seek_result; } +ErrorOr File::tell() const +{ + return m_file_offset; +} + ErrorOr File::truncate(size_t length) { if (length > static_cast(NumericLimits::max())) return Error::from_string_literal("Length is larger than the maximum supported length"); + m_file_offset = min(length, m_file_offset); return System::ftruncate(m_fd, length); } diff --git a/Userland/Libraries/LibCore/File.h b/Userland/Libraries/LibCore/File.h index c6de26d9c4..dc5e91fe30 100644 --- a/Userland/Libraries/LibCore/File.h +++ b/Userland/Libraries/LibCore/File.h @@ -67,6 +67,7 @@ public: virtual bool is_open() const override; virtual void close() override; virtual ErrorOr seek(i64 offset, SeekMode) override; + virtual ErrorOr tell() const override; virtual ErrorOr truncate(size_t length) override; // Sets the blocking mode of the file. If blocking mode is disabled, reads @@ -109,6 +110,8 @@ private: int m_fd { -1 }; bool m_last_read_was_eof { false }; ShouldCloseFileDescriptor m_should_close_file_descriptor { ShouldCloseFileDescriptor::Yes }; + + size_t m_file_offset { 0 }; }; AK_ENUM_BITWISE_OPERATORS(File::OpenMode)