瀏覽代碼

LibCore: Keep track of file offset to avoid system call for tell()

This optimization makes the new test run 2x faster.
kleines Filmröllchen 2 年之前
父節點
當前提交
10edd38543
共有 3 個文件被更改,包括 33 次插入1 次删除
  1. 19 0
      Tests/LibCore/TestLibCoreStream.cpp
  2. 11 1
      Userland/Libraries/LibCore/File.cpp
  3. 3 0
      Userland/Libraries/LibCore/File.h

+ 19 - 0
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);

+ 11 - 1
Userland/Libraries/LibCore/File.cpp

@@ -117,6 +117,7 @@ ErrorOr<Bytes> 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<size_t> 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<size_t> 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<size_t> File::tell() const
+{
+    return m_file_offset;
+}
+
 ErrorOr<void> File::truncate(size_t length)
 {
     if (length > static_cast<size_t>(NumericLimits<off_t>::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);
 }
 

+ 3 - 0
Userland/Libraries/LibCore/File.h

@@ -67,6 +67,7 @@ public:
     virtual bool is_open() const override;
     virtual void close() override;
     virtual ErrorOr<size_t> seek(i64 offset, SeekMode) override;
+    virtual ErrorOr<size_t> tell() const override;
     virtual ErrorOr<void> 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)