mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 16:07:46 +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:
parent
cbb2b4fe71
commit
14d330faba
2 changed files with 16 additions and 7 deletions
|
@ -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()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue