From 14d330fabaff7c24218377601056b79ddef144cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kleines=20Filmr=C3=B6llchen?= Date: Sun, 3 Oct 2021 11:39:17 +0200 Subject: [PATCH] LibAudio: Avoid frequent read() calls in FLAC residual decode Decoding the residual in FLAC subframes is by far the most I/O-heavy operation in FLAC decoding, as the residual data makes up the majority of subframe data in LPC subframes. As the residual consists of many Rice-encoded numbers with different bit sizes for differently large numbers, the residual decoder frequently reads only one or two bytes at a time. As we use a normal FileInputStream, that directly translates to many calls to the read() syscall. We can see that the I/O overhead while FLAC decoding is quite large, and much time is spent in the read() syscall's kernel code. This is optimized by using a Buffered instead, leading to 4K blocks being read at once and a large reduction in I/O overhead. Benchmarking with the new abench utility gives a 15-20% speedup on identical files, usually pushing FLAC decoding to 10-15x realtime speed on common sample rates. --- Userland/Libraries/LibAudio/FlacLoader.cpp | 11 ++++++++--- Userland/Libraries/LibAudio/FlacLoader.h | 12 ++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Userland/Libraries/LibAudio/FlacLoader.cpp b/Userland/Libraries/LibAudio/FlacLoader.cpp index 90b6f0ad1c..c38a3b2c5d 100644 --- a/Userland/Libraries/LibAudio/FlacLoader.cpp +++ b/Userland/Libraries/LibAudio/FlacLoader.cpp @@ -28,9 +28,14 @@ FlacLoaderPlugin::FlacLoaderPlugin(StringView path) return; } - m_stream = make(Core::InputFileStream(*m_file)); + auto maybe_stream = Core::InputFileStream::open_buffered(path); + if (maybe_stream.is_error()) { + m_error_string = "Can't open file stream"; + return; + } + m_stream = make(maybe_stream.release_value()); if (!m_stream) { - m_error_string = String::formatted("Can't open memory stream"); + m_error_string = "Can't open file stream"; return; } @@ -69,7 +74,7 @@ bool FlacLoaderPlugin::parse_header() InputBitStream bit_input = [&]() -> InputBitStream { if (m_file) { - return InputBitStream(m_stream->get()); + return InputBitStream(m_stream->get>()); } return InputBitStream(m_stream->get()); }(); diff --git a/Userland/Libraries/LibAudio/FlacLoader.h b/Userland/Libraries/LibAudio/FlacLoader.h index dd7da0e423..8152d48827 100644 --- a/Userland/Libraries/LibAudio/FlacLoader.h +++ b/Userland/Libraries/LibAudio/FlacLoader.h @@ -10,6 +10,7 @@ #include "FlacTypes.h" #include "Loader.h" #include +#include #include #include #include @@ -17,16 +18,19 @@ namespace Audio { -class FlacInputStream : public Variant { +class FlacInputStream : public Variant, InputMemoryStream> { public: - using Variant::Variant; + using Variant, InputMemoryStream>::Variant; bool seek(size_t pos) { return this->visit( - [&](Core::InputFileStream& stream) { - return stream.seek(pos); + [&](Buffered& buffered) { + // Discard the buffer, then seek normally. + if (!buffered.discard_or_error(buffered.buffered())) + return false; + return buffered.underlying_stream().seek(pos); }, [&](InputMemoryStream& stream) { if (pos >= stream.bytes().size()) {