Audio reader benchmark in real conditions

This commit is contained in:
Jean Pierre Cimalando 2020-10-05 19:04:25 +02:00
parent dc422d07d9
commit 942f93fc8d
3 changed files with 84 additions and 102 deletions

View file

@ -13,6 +13,7 @@
#include <system_error> #include <system_error>
#include <stdexcept> #include <stdexcept>
#include <cstdio> #include <cstdio>
#include <cstdlib>
#include <cmath> #include <cmath>
#ifndef _WIN32 #ifndef _WIN32
#include <sys/types.h> #include <sys/types.h>
@ -22,43 +23,61 @@
#endif #endif
/// ///
struct AutoFD { struct TemporaryFile {
AutoFD() {} TemporaryFile();
~AutoFD() { reset(); } ~TemporaryFile();
AutoFD(const AutoFD&) = delete; TemporaryFile(const TemporaryFile&) = delete;
AutoFD &operator=(const AutoFD&) = delete; TemporaryFile& operator=(const TemporaryFile&) = delete;
AutoFD(AutoFD&& other) : fd_(other.fd_) { other.fd_ = -1; } TemporaryFile(TemporaryFile&&) = default;
AutoFD &operator=(AutoFD&& other) TemporaryFile& operator=(TemporaryFile&&) = default;
{
if (this == &other) return *this;
reset(other.fd_);
other.fd_ = -1;
return *this;
}
explicit operator bool() const noexcept { return fd_ != -1; } const fs::path& path() const { return path_; }
int get() const noexcept { return fd_; }
int release()
{
int fd = fd_;
fd_ = -1;
return fd;
}
void reset(int fd = -1) noexcept
{
if (fd_ == fd) return;
if (fd_ != -1) close(fd_);
fd_ = fd;
}
private: private:
int fd_ = -1; fs::path path_;
static fs::path createTemporaryFile();
}; };
TemporaryFile::TemporaryFile()
: path_(createTemporaryFile())
{
}
TemporaryFile::~TemporaryFile()
{
std::error_code ec;
fs::remove(path_, ec);
}
#if !defined(_WIN32)
fs::path TemporaryFile::createTemporaryFile()
{
char path[] = P_tmpdir "/sndXXXXXX";
int fd = mkstemp(path);
if (fd == -1)
throw std::runtime_error("Cannot create temporary file.");
close(fd);
return path;
}
#else
fs::path TemporaryFile::createTemporaryFile()
{
DWORD ret = GetTempPathW(0, buffer);
std::unique_ptr<WCHAR[]> path;
if (ret != 0) {
path.reset(new WCHAR[ret + 8]{});
ret = GetTempPathW(0, buffer);
if (ret != 0)
wcscat(path.get(), L"\\XXXXXX");
}
if (ret == 0 || !_wmktemp(path.get()))
throw std::runtime_error("Cannot create temporary file.");
return path.get();
}
#endif
/// ///
class AudioReaderFixture : public benchmark::Fixture { class AudioReaderFixture : public benchmark::Fixture {
public: public:
@ -71,20 +90,20 @@ public:
{ {
} }
static AutoFD createAudioFile(int format); static TemporaryFile createAudioFile(int format);
static AutoFD fileWav; static TemporaryFile fileWav;
static AutoFD fileFlac; static TemporaryFile fileFlac;
static AutoFD fileOgg; static TemporaryFile fileOgg;
std::vector<float> workBuffer; std::vector<float> workBuffer;
}; };
AutoFD AudioReaderFixture::fileWav = createAudioFile(SF_FORMAT_WAV|SF_FORMAT_PCM_16); TemporaryFile AudioReaderFixture::fileWav = createAudioFile(SF_FORMAT_WAV|SF_FORMAT_PCM_16);
AutoFD AudioReaderFixture::fileFlac = createAudioFile(SF_FORMAT_FLAC|SF_FORMAT_PCM_16); TemporaryFile AudioReaderFixture::fileFlac = createAudioFile(SF_FORMAT_FLAC|SF_FORMAT_PCM_16);
AutoFD AudioReaderFixture::fileOgg = createAudioFile(SF_FORMAT_OGG|SF_FORMAT_VORBIS); TemporaryFile AudioReaderFixture::fileOgg = createAudioFile(SF_FORMAT_OGG|SF_FORMAT_VORBIS);
AutoFD AudioReaderFixture::createAudioFile(int format) TemporaryFile AudioReaderFixture::createAudioFile(int format)
{ {
constexpr unsigned sampleRate = 44100; constexpr unsigned sampleRate = 44100;
constexpr unsigned fileDuration = 10; constexpr unsigned fileDuration = 10;
@ -100,53 +119,38 @@ AutoFD AudioReaderFixture::createAudioFile(int format)
phase -= static_cast<long>(phase); phase -= static_cast<long>(phase);
} }
// create anonymous temp file // create temp file
FILE* file = tmpfile(); TemporaryFile temp;
if (!file) fprintf(stderr, "* Temporary file: %s\n", temp.path().u8string().c_str());
throw std::system_error(errno, std::generic_category());
// convert FILE to fd, for sndfile // write to file
AutoFD fd; #if !defined(_WIN32)
fd.reset(dup(fileno(file))); SndfileHandle snd(temp.path().c_str(), SFM_WRITE, format, 2, sampleRate);
if (!fd) { #else
fclose(file); SndfileHandle snd(temp.path().wstring().c_str(), SFM_WRITE, format, 2, sampleRate);
throw std::system_error(errno, std::generic_category()); #endif
}
fclose(file);
// write to fd
SndfileHandle snd(fd.get(), false, SFM_WRITE, format, 2, sampleRate);
if (snd.error()) if (snd.error())
throw std::runtime_error("cannot open sound file for writing"); throw std::runtime_error("cannot open sound file for writing");
snd.writef(sndData.get(), fileFrames); snd.writef(sndData.get(), fileFrames);
snd = SndfileHandle(); snd = SndfileHandle();
return fd; return temp;
} }
static void rewindFd(int fd) static void doReaderBenchmark(const fs::path& path, std::vector<float> &buffer, sfz::AudioReaderType type)
{ {
#ifndef _WIN32 sfz::AudioReaderPtr reader = sfz::createExplicitAudioReader(path, type);
off_t off = lseek(fd, 0, SEEK_SET);
#else
off_t off = _lseek(fd, 0, SEEK_SET);
#endif
if (off == -1)
throw std::system_error(errno, std::generic_category());
}
static void doReaderBenchmark(int fd, std::vector<float> &buffer, sfz::AudioReaderType type)
{
rewindFd(fd);
sfz::AudioReaderPtr reader = sfz::createExplicitAudioReaderWithFd(fd, type);
while (reader->readNextBlock(buffer.data(), buffer.size() / 2) > 0); while (reader->readNextBlock(buffer.data(), buffer.size() / 2) > 0);
} }
static void doEntireRead(int fd) static void doEntireRead(const fs::path& path)
{ {
rewindFd(fd); #if !defined(_WIN32)
SndfileHandle handle(path.c_str());
SndfileHandle handle(fd, false); #else
SndfileHandle handle(path.wstring().c_str());
#endif
if (handle.error()) if (handle.error())
throw std::runtime_error("cannot open sound file for reading"); throw std::runtime_error("cannot open sound file for reading");
@ -157,63 +161,63 @@ static void doEntireRead(int fd)
BENCHMARK_DEFINE_F(AudioReaderFixture, EntireWav)(benchmark::State& state) BENCHMARK_DEFINE_F(AudioReaderFixture, EntireWav)(benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
doEntireRead(fileWav.get()); doEntireRead(fileWav.path());
} }
} }
BENCHMARK_DEFINE_F(AudioReaderFixture, ForwardWav)(benchmark::State& state) BENCHMARK_DEFINE_F(AudioReaderFixture, ForwardWav)(benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
doReaderBenchmark(fileWav.get(), workBuffer, sfz::AudioReaderType::Forward); doReaderBenchmark(fileWav.path(), workBuffer, sfz::AudioReaderType::Forward);
} }
} }
BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseWav)(benchmark::State& state) BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseWav)(benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
doReaderBenchmark(fileWav.get(), workBuffer, sfz::AudioReaderType::Reverse); doReaderBenchmark(fileWav.path(), workBuffer, sfz::AudioReaderType::Reverse);
} }
} }
BENCHMARK_DEFINE_F(AudioReaderFixture, EntireFlac)(benchmark::State& state) BENCHMARK_DEFINE_F(AudioReaderFixture, EntireFlac)(benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
doEntireRead(fileFlac.get()); doEntireRead(fileFlac.path());
} }
} }
BENCHMARK_DEFINE_F(AudioReaderFixture, ForwardFlac)(benchmark::State& state) BENCHMARK_DEFINE_F(AudioReaderFixture, ForwardFlac)(benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
doReaderBenchmark(fileFlac.get(), workBuffer, sfz::AudioReaderType::Forward); doReaderBenchmark(fileFlac.path(), workBuffer, sfz::AudioReaderType::Forward);
} }
} }
BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseFlac)(benchmark::State& state) BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseFlac)(benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
doReaderBenchmark(fileFlac.get(), workBuffer, sfz::AudioReaderType::Reverse); doReaderBenchmark(fileFlac.path(), workBuffer, sfz::AudioReaderType::Reverse);
} }
} }
BENCHMARK_DEFINE_F(AudioReaderFixture, EntireOgg)(benchmark::State& state) BENCHMARK_DEFINE_F(AudioReaderFixture, EntireOgg)(benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
doEntireRead(fileOgg.get()); doEntireRead(fileOgg.path());
} }
} }
BENCHMARK_DEFINE_F(AudioReaderFixture, ForwardOgg)(benchmark::State& state) BENCHMARK_DEFINE_F(AudioReaderFixture, ForwardOgg)(benchmark::State& state)
{ {
for (auto _ : state) { for (auto _ : state) {
doReaderBenchmark(fileOgg.get(), workBuffer, sfz::AudioReaderType::Forward); doReaderBenchmark(fileOgg.path(), workBuffer, sfz::AudioReaderType::Forward);
} }
} }
//BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseOgg)(benchmark::State& state) //BENCHMARK_DEFINE_F(AudioReaderFixture, ReverseOgg)(benchmark::State& state)
//{ //{
// for (auto _ : state) { // for (auto _ : state) {
// doReaderBenchmark(fileOgg.get(), workBuffer, sfz::AudioReaderType::Reverse); // doReaderBenchmark(fileOgg.path(), workBuffer, sfz::AudioReaderType::Reverse);
// } // }
//} //}

View file

@ -333,12 +333,6 @@ AudioReaderPtr createAudioReader(const fs::path& path, bool reverse, std::error_
return createAudioReaderWithHandle(handle, reverse, ec); return createAudioReaderWithHandle(handle, reverse, ec);
} }
AudioReaderPtr createAudioReaderWithFd(int fd, bool reverse, std::error_code* ec)
{
SndfileHandle handle(fd, false);
return createAudioReaderWithHandle(handle, reverse, ec);
}
static AudioReaderPtr createExplicitAudioReaderWithHandle(SndfileHandle handle, AudioReaderType type, std::error_code* ec) static AudioReaderPtr createExplicitAudioReaderWithHandle(SndfileHandle handle, AudioReaderType type, std::error_code* ec)
{ {
AudioReaderPtr reader; AudioReaderPtr reader;
@ -378,10 +372,4 @@ AudioReaderPtr createExplicitAudioReader(const fs::path& path, AudioReaderType t
return createExplicitAudioReaderWithHandle(handle, type, ec); return createExplicitAudioReaderWithHandle(handle, type, ec);
} }
AudioReaderPtr createExplicitAudioReaderWithFd(int fd, AudioReaderType type, std::error_code* ec)
{
SndfileHandle handle(fd, false);
return createExplicitAudioReaderWithHandle(handle, type, ec);
}
} // namespace sfz } // namespace sfz

View file

@ -52,19 +52,9 @@ typedef std::unique_ptr<AudioReader> AudioReaderPtr;
*/ */
AudioReaderPtr createAudioReader(const fs::path& path, bool reverse, std::error_code* ec = nullptr); AudioReaderPtr createAudioReader(const fs::path& path, bool reverse, std::error_code* ec = nullptr);
/**
* @brief Create a file reader of detected type.
*/
AudioReaderPtr createAudioReaderWithFd(int fd, bool reverse, std::error_code* ec = nullptr);
/** /**
* @brief Create a file reader of explicit type. (for testing purposes) * @brief Create a file reader of explicit type. (for testing purposes)
*/ */
AudioReaderPtr createExplicitAudioReader(const fs::path& path, AudioReaderType type, std::error_code* ec = nullptr); AudioReaderPtr createExplicitAudioReader(const fs::path& path, AudioReaderType type, std::error_code* ec = nullptr);
/**
* @brief Create a file reader of explicit type. (for testing purposes)
*/
AudioReaderPtr createExplicitAudioReaderWithFd(int fd, AudioReaderType type, std::error_code* ec = nullptr);
} // namespace sfz } // namespace sfz