Update the oversampling benchmarks to be more contained
This commit is contained in:
parent
528593fa76
commit
8e95ce63ec
2 changed files with 257 additions and 17 deletions
|
|
@ -22,17 +22,190 @@
|
|||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "Buffer.h"
|
||||
#include "Oversampler.h"
|
||||
#include "AudioBuffer.h"
|
||||
#include "SIMDHelpers.h"
|
||||
#include <benchmark/benchmark.h>
|
||||
#include <memory>
|
||||
#include <samplerate.h>
|
||||
#include <sndfile.hh>
|
||||
#include "ghc/filesystem.hpp"
|
||||
#include "hiir/Upsampler2xFpu.h"
|
||||
constexpr std::array<double, 12> coeffsStage2x {
|
||||
0.036681502163648017,
|
||||
0.13654762463195771,
|
||||
0.27463175937945411,
|
||||
0.42313861743656667,
|
||||
0.56109869787919475,
|
||||
0.67754004997416162,
|
||||
0.76974183386322659,
|
||||
0.83988962484963803,
|
||||
0.89226081800387891,
|
||||
0.9315419599631839,
|
||||
0.96209454837808395,
|
||||
0.98781637073289708
|
||||
};
|
||||
|
||||
constexpr std::array<double, 4> coeffsStage4x {
|
||||
0.042448989488488006,
|
||||
0.17072114107630679,
|
||||
0.39329183835224008,
|
||||
0.74569514831986694
|
||||
};
|
||||
|
||||
constexpr std::array<double, 3> coeffsStage8x {
|
||||
0.055748680811302048,
|
||||
0.24305119574153092,
|
||||
0.6466991311926823
|
||||
};
|
||||
|
||||
template<bool SIMD=false>
|
||||
void upsample2xStage(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xFpu<coeffsStage2x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage2x.data());
|
||||
upsampler.process_block(output.data(), input.data(), input.size());
|
||||
}
|
||||
|
||||
|
||||
template<bool SIMD=false>
|
||||
void upsample4xStage(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xFpu<coeffsStage4x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage4x.data());
|
||||
upsampler.process_block(output.data(), input.data(), input.size());
|
||||
}
|
||||
|
||||
template<bool SIMD=false>
|
||||
void upsample8xStage(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xFpu<coeffsStage8x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage8x.data());
|
||||
upsampler.process_block(output.data(), input.data(), input.size());
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
#include "hiir/Upsampler2xSse.h"
|
||||
template<>
|
||||
void upsample2xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xSse<coeffsStage2x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage2x.data());
|
||||
upsampler.process_block(output.data(), input.data(), input.size());
|
||||
}
|
||||
|
||||
template<>
|
||||
void upsample4xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xSse<coeffsStage4x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage4x.data());
|
||||
upsampler.process_block(output.data(), input.data(), input.size());
|
||||
}
|
||||
|
||||
template<>
|
||||
void upsample8xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xSse<coeffsStage8x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage8x.data());
|
||||
upsampler.process_block(output.data(), input.data(), input.size());
|
||||
}
|
||||
|
||||
#elif defined(__arm__) || defined (__aarch64__)
|
||||
|
||||
#include "hiir/Upsampler2xNeon.h"
|
||||
|
||||
template<>
|
||||
void upsample2xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xNeon<coeffsStage2x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage2x.data());
|
||||
upsampler.process_block(output.data(), input.data(), input.size());
|
||||
}
|
||||
|
||||
template<>
|
||||
void upsample4xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xNeon<coeffsStage4x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage4x.data());
|
||||
upsampler.process_block(output.data(), input.data(), input.size());
|
||||
}
|
||||
|
||||
template<>
|
||||
void upsample8xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
ASSERT(output.size() >= 2 * input.size());
|
||||
hiir::Upsampler2xNeon<coeffsStage8x.size()> upsampler;
|
||||
upsampler.set_coefs(coeffsStage8x.data());
|
||||
upsampler.process_block(output.data(), input.data(), input.size());
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<>
|
||||
void upsample2xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
upsample2xStage<false>(input, output);
|
||||
}
|
||||
template<>
|
||||
void upsample4xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
upsample4xStage<false>(input, output);
|
||||
}
|
||||
template<>
|
||||
void upsample8xStage<true>(absl::Span<const float> input, absl::Span<float> output)
|
||||
{
|
||||
upsample8xStage<false>(input, output);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T, bool SIMD=false>
|
||||
std::unique_ptr<sfz::AudioBuffer<T>> upsample2x(const sfz::AudioBuffer<T>& buffer)
|
||||
{
|
||||
// auto tempBuffer = std::make_unique<sfz::Buffer<T>>(buffer.getNumFrames() * 2);
|
||||
auto outputBuffer = std::make_unique<sfz::AudioBuffer<T>>(buffer.getNumChannels(), buffer.getNumFrames() * 2);
|
||||
for (int channelIdx = 0; channelIdx < buffer.getNumChannels(); channelIdx++) {
|
||||
upsample2xStage<SIMD>(buffer.getConstSpan(channelIdx), outputBuffer->getSpan(channelIdx));
|
||||
}
|
||||
return outputBuffer;
|
||||
}
|
||||
|
||||
template <class T, bool SIMD=false>
|
||||
std::unique_ptr<sfz::AudioBuffer<T>> upsample4x(const sfz::AudioBuffer<T>& buffer)
|
||||
{
|
||||
auto tempBuffer = std::make_unique<sfz::Buffer<T>>(buffer.getNumFrames() * 2);
|
||||
auto outputBuffer = std::make_unique<sfz::AudioBuffer<T>>(buffer.getNumChannels(), buffer.getNumFrames() * 4);
|
||||
for (int channelIdx = 0; channelIdx < buffer.getNumChannels(); channelIdx++) {
|
||||
upsample2xStage<SIMD>(buffer.getConstSpan(channelIdx), absl::MakeSpan(*tempBuffer));
|
||||
upsample4xStage<SIMD>(absl::MakeConstSpan(*tempBuffer), outputBuffer->getSpan(channelIdx));
|
||||
}
|
||||
return outputBuffer;
|
||||
}
|
||||
|
||||
template <class T, bool SIMD=false>
|
||||
std::unique_ptr<sfz::AudioBuffer<T>> upsample8x(const sfz::AudioBuffer<T>& buffer)
|
||||
{
|
||||
auto tempBuffer2x = std::make_unique<sfz::Buffer<T>>(buffer.getNumFrames() * 2);
|
||||
auto tempBuffer4x = std::make_unique<sfz::Buffer<T>>(buffer.getNumFrames() * 4);
|
||||
auto outputBuffer = std::make_unique<sfz::AudioBuffer<T>>(buffer.getNumChannels(), buffer.getNumFrames() * 8);
|
||||
for (int channelIdx = 0; channelIdx < buffer.getNumChannels(); channelIdx++) {
|
||||
upsample2xStage<SIMD>(buffer.getConstSpan(channelIdx), absl::MakeSpan(*tempBuffer2x));
|
||||
upsample4xStage<SIMD>(absl::MakeConstSpan(*tempBuffer2x), absl::MakeSpan(*tempBuffer4x));
|
||||
upsample8xStage<SIMD>(absl::MakeConstSpan(*tempBuffer4x), outputBuffer->getSpan(channelIdx));
|
||||
}
|
||||
return outputBuffer;
|
||||
}
|
||||
|
||||
|
||||
class SndFile : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& state)
|
||||
void SetUp(const ::benchmark::State& /* state */)
|
||||
{
|
||||
|
||||
const auto rootPath = getPath() / "sample1.wav";
|
||||
|
|
@ -77,7 +250,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR2X_scalar)(benchmark::State& state)
|
|||
for (auto _ : state) {
|
||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = sfz::upsample2x<float, false>(*baseBuffer);
|
||||
auto outBuffer = upsample2x<float, false>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -87,7 +260,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR4X_scalar)(benchmark::State& state)
|
|||
for (auto _ : state) {
|
||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = sfz::upsample4x<float, false>(*baseBuffer);
|
||||
auto outBuffer = upsample4x<float, false>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -97,7 +270,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR8X_scalar)(benchmark::State& state)
|
|||
for (auto _ : state) {
|
||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = sfz::upsample8x<float, false>(*baseBuffer);
|
||||
auto outBuffer = upsample8x<float, false>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +280,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR2X_vector)(benchmark::State& state)
|
|||
for (auto _ : state) {
|
||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = sfz::upsample2x<float, true>(*baseBuffer);
|
||||
auto outBuffer = upsample2x<float, true>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -117,7 +290,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR4X_vector)(benchmark::State& state)
|
|||
for (auto _ : state) {
|
||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = sfz::upsample4x<float, true>(*baseBuffer);
|
||||
auto outBuffer = upsample4x<float, true>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -127,7 +300,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR8X_vector)(benchmark::State& state)
|
|||
for (auto _ : state) {
|
||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = sfz::upsample8x<float, true>(*baseBuffer);
|
||||
auto outBuffer = upsample8x<float, true>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -291,7 +464,7 @@ BENCHMARK_DEFINE_F(SndFile, HIIR8X_default)(benchmark::State& state)
|
|||
for (auto _ : state) {
|
||||
auto baseBuffer = std::make_unique<sfz::AudioBuffer<float>>(numChannels, numFrames);
|
||||
sfz::readInterleaved<float>(*interleavedBuffer, baseBuffer->getSpan(0), baseBuffer->getSpan(1));
|
||||
auto outBuffer = sfz::upsample8x<float>(*baseBuffer);
|
||||
auto outBuffer = upsample8x<float>(*baseBuffer);
|
||||
benchmark::DoNotOptimize(outBuffer);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,54 @@
|
|||
#include <memory>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
constexpr std::array<double, 12> coeffsStage2x {
|
||||
0.036681502163648017,
|
||||
0.13654762463195771,
|
||||
0.27463175937945411,
|
||||
0.42313861743656667,
|
||||
0.56109869787919475,
|
||||
0.67754004997416162,
|
||||
0.76974183386322659,
|
||||
0.83988962484963803,
|
||||
0.89226081800387891,
|
||||
0.9315419599631839,
|
||||
0.96209454837808395,
|
||||
0.98781637073289708
|
||||
};
|
||||
|
||||
constexpr std::array<double, 4> coeffsStage4x {
|
||||
0.042448989488488006,
|
||||
0.17072114107630679,
|
||||
0.39329183835224008,
|
||||
0.74569514831986694
|
||||
};
|
||||
|
||||
constexpr std::array<double, 3> coeffsStage8x {
|
||||
0.055748680811302048,
|
||||
0.24305119574153092,
|
||||
0.6466991311926823
|
||||
};
|
||||
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
#include "hiir/Upsampler2xSse.h"
|
||||
using Upsampler2x = hiir::Upsampler2xSse<coeffsStage2x.size()>;
|
||||
using Upsampler4x = hiir::Upsampler2xSse<coeffsStage4x.size()>;
|
||||
using Upsampler8x = hiir::Upsampler2xSse<coeffsStage8x.size()>;
|
||||
#elif defined(__arm__) || defined(__aarch64__)
|
||||
#include "hiir/Upsampler2xNeon.h"
|
||||
using Upsampler2x = hiir::Upsampler2xNeon<coeffsStage2x.size()>;
|
||||
using Upsampler4x = hiir::Upsampler2xNeon<coeffsStage4x.size()>;
|
||||
using Upsampler8x = hiir::Upsampler2xNeon<coeffsStage8x.size()>;
|
||||
#else
|
||||
#include "hiir/Upsampler2xFpu.h"
|
||||
using Upsampler2x = hiir::Upsampler2xFpu<coeffsStage2x.size()>;
|
||||
using Upsampler4x = hiir::Upsampler2xFpu<coeffsStage4x.size()>;
|
||||
using Upsampler8x = hiir::Upsampler2xFpu<coeffsStage8x.size()>;
|
||||
#endif
|
||||
|
||||
|
||||
class FileFixture : public benchmark::Fixture {
|
||||
public:
|
||||
void SetUp(const ::benchmark::State& /* state */) {
|
||||
|
|
@ -82,14 +130,23 @@ BENCHMARK_DEFINE_F(FileFixture, ResampleAtOnce)(benchmark::State& state) {
|
|||
{
|
||||
sfz::Buffer<float> buffer { numFrames * sndfile.channels() };
|
||||
sfz::Buffer<float> temp { numFrames * 4 };
|
||||
|
||||
Upsampler2x upsampler2x;
|
||||
Upsampler4x upsampler4x;
|
||||
upsampler2x.set_coefs(coeffsStage2x.data());
|
||||
upsampler4x.set_coefs(coeffsStage4x.data());
|
||||
|
||||
sndfile.readf(buffer.data(), numFrames);
|
||||
sfz::readInterleaved<float>(buffer, output->getSpan(0), output->getSpan(1));
|
||||
|
||||
sfz::upsample2xStage(output->getConstSpan(0).first(numFrames), absl::MakeSpan(temp));
|
||||
sfz::upsample4xStage(absl::MakeConstSpan(temp).first(numFrames * 2), output->getSpan(0));
|
||||
upsampler2x.process_block(temp.data(), output->channelReader(0), numFrames);
|
||||
upsampler4x.process_block(output->channelWriter(0), temp.data(), numFrames * 2);
|
||||
|
||||
sfz::upsample2xStage(output->getConstSpan(1).first(numFrames), absl::MakeSpan(temp));
|
||||
sfz::upsample4xStage(absl::MakeConstSpan(temp).first(numFrames * 2), output->getSpan(1));
|
||||
upsampler2x.clear_buffers();
|
||||
upsampler4x.clear_buffers();
|
||||
|
||||
upsampler2x.process_block(temp.data(), output->channelReader(1), numFrames);
|
||||
upsampler4x.process_block(output->channelWriter(1), temp.data(), numFrames * 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,6 +167,15 @@ BENCHMARK_DEFINE_F(FileFixture, ResampleInChunks)(benchmark::State& state) {
|
|||
auto rightSpan = absl::MakeSpan(rightInput);
|
||||
auto chunkSpan = absl::MakeSpan(chunk);
|
||||
|
||||
Upsampler2x upsampler2xLeft;
|
||||
Upsampler2x upsampler2xRight;
|
||||
Upsampler4x upsampler4xLeft;
|
||||
Upsampler4x upsampler4xRight;
|
||||
upsampler2xLeft.set_coefs(coeffsStage2x.data());
|
||||
upsampler2xRight.set_coefs(coeffsStage2x.data());
|
||||
upsampler4xLeft.set_coefs(coeffsStage4x.data());
|
||||
upsampler4xRight.set_coefs(coeffsStage4x.data());
|
||||
|
||||
size_t inputFrameCounter { 0 };
|
||||
size_t outputFrameCounter { 0 };
|
||||
while(inputFrameCounter < numFrames)
|
||||
|
|
@ -122,11 +188,12 @@ BENCHMARK_DEFINE_F(FileFixture, ResampleInChunks)(benchmark::State& state) {
|
|||
);
|
||||
|
||||
sfz::readInterleaved<float>(bufferChunk, leftSpan, rightSpan);
|
||||
sfz::upsample2xStage(leftSpan.first(thisChunkSize), chunkSpan);
|
||||
sfz::upsample4xStage(chunkSpan.first(thisChunkSize * 2), output->getSpan(0).subspan(outputFrameCounter));
|
||||
|
||||
sfz::upsample2xStage(rightSpan.first(thisChunkSize), chunkSpan);
|
||||
sfz::upsample4xStage(chunkSpan.first(thisChunkSize * 2), output->getSpan(1).subspan(outputFrameCounter));
|
||||
upsampler2xLeft.process_block(chunkSpan.data(), leftSpan.data(), thisChunkSize);
|
||||
upsampler4xLeft.process_block(output->channelWriter(0) + outputFrameCounter, chunkSpan.data(), thisChunkSize * 2);
|
||||
|
||||
upsampler2xRight.process_block(chunkSpan.data(), rightSpan.data(), thisChunkSize);
|
||||
upsampler4xRight.process_block(output->channelWriter(1) + outputFrameCounter, chunkSpan.data(), thisChunkSize * 2);
|
||||
|
||||
inputFrameCounter += chunkSize;
|
||||
outputFrameCounter += chunkSize * 4;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue