Audio reader benchmark in real conditions
This commit is contained in:
parent
dc422d07d9
commit
942f93fc8d
3 changed files with 84 additions and 102 deletions
|
|
@ -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);
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue