1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-26 05:07:35 +00:00

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<FileInputStream> 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.
This commit is contained in:
kleines Filmröllchen 2021-10-03 11:39:17 +02:00 committed by Brian Gianforcaro
parent cbb2b4fe71
commit 14d330faba
2 changed files with 16 additions and 7 deletions

View file

@ -28,9 +28,14 @@ FlacLoaderPlugin::FlacLoaderPlugin(StringView path)
return;
}
m_stream = make<FlacInputStream>(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<FlacInputStream>(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<Core::InputFileStream>());
return InputBitStream(m_stream->get<Buffered<Core::InputFileStream>>());
}
return InputBitStream(m_stream->get<InputMemoryStream>());
}();

View file

@ -10,6 +10,7 @@
#include "FlacTypes.h"
#include "Loader.h"
#include <AK/BitStream.h>
#include <AK/Buffered.h>
#include <AK/Stream.h>
#include <AK/Types.h>
#include <AK/Variant.h>
@ -17,16 +18,19 @@
namespace Audio {
class FlacInputStream : public Variant<Core::InputFileStream, InputMemoryStream> {
class FlacInputStream : public Variant<Buffered<Core::InputFileStream>, InputMemoryStream> {
public:
using Variant<Core::InputFileStream, InputMemoryStream>::Variant;
using Variant<Buffered<Core::InputFileStream>, InputMemoryStream>::Variant;
bool seek(size_t pos)
{
return this->visit(
[&](Core::InputFileStream& stream) {
return stream.seek(pos);
[&](Buffered<Core::InputFileStream>& 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()) {