Commit caa45874 authored by Edwin Carlinet's avatar Edwin Carlinet
Browse files

Range algorithm migration.

parent 6fd35d58
......@@ -85,6 +85,7 @@ distcheck-linux-clang-debug:
--config $PYLENE_CONFIGURATION
--target run-all-benchmarks
- ctest -L SpeedTests -V
tags: [ "pylene-benchmarks" ]
when: manual
dependencies: []
artifacts:
......
#include <mln/core/image/image2d.hpp>
#include <mln/core/colors.hpp>
#include <mln/core/algorithm/fill.hpp>
#include <mln/core/algorithm/copy.hpp>
#include <mln/core/algorithm/paste.hpp>
#include <mln/core/algorithm/transform.hpp>
#include <mln/core/algorithm/generate.hpp>
#include <mln/core/algorithm/accumulate.hpp>
#include <mln/core/algorithm/for_each.hpp>
#include <mln/core/algorithm/sort.hpp>
#include <algorithm>
#include <numeric>
namespace baseline
{
template <class V>
void fill(mln::image2d<V>& ima, V value)
{
std::ptrdiff_t stride = ima.index_strides()[0];
V* buffer = &ima.at(ima.domain().pmin);
std::size_t height = ima.nrows();
std::size_t width = ima.ncols();
for (std::size_t i = 0; i < height; ++i, buffer += stride)
std::fill(buffer, buffer + width, value);
}
template <class V>
void copy(const mln::image2d<V>& in, mln::image2d<V>& out)
{
std::ptrdiff_t istride = in.index_strides()[0];
std::ptrdiff_t ostride = out.index_strides()[0];
const V* ibuffer = &in.at(in.domain().pmin);
V* obuffer = &out.at(out.domain().pmin);
std::size_t height = in.nrows();
std::size_t width = in.ncols();
assert(out.nrows() == height);
assert(out.ncols() == width);
for (std::size_t i = 0; i < height; ++i, ibuffer += istride, obuffer += ostride)
std::copy(ibuffer, ibuffer + width, obuffer);
}
template <class V>
void paste(const mln::image2d<V>& in, mln::image2d<V>& out)
{
std::ptrdiff_t istride = in.index_strides()[0];
std::ptrdiff_t ostride = out.index_strides()[0];
const V* ibuffer = &in.at(in.domain().pmin);
V* obuffer = &out.at(in.domain().pmin);
std::size_t height = in.nrows();
std::size_t width = in.ncols();
assert(out.nrows() == height);
assert(out.ncols() == width);
for (std::size_t i = 0; i < height; ++i, ibuffer += istride, obuffer += ostride)
std::copy(ibuffer, ibuffer + width, obuffer);
}
template <class F, class U, class V>
void transform(const mln::image2d<U>& in, mln::image2d<V>& out, F f)
{
std::ptrdiff_t istride = in.index_strides()[0];
std::ptrdiff_t ostride = out.index_strides()[0];
const U* ibuffer = &in.at(in.domain().pmin);
V* obuffer = &out.at(in.domain().pmin);
std::size_t height = in.nrows();
std::size_t width = in.ncols();
assert(out.nrows() == height);
assert(out.ncols() == width);
for (std::size_t i = 0; i < height; ++i, ibuffer += istride, obuffer += ostride)
std::transform(ibuffer, ibuffer + width, obuffer, f);
}
template <class F, class U>
void for_each(mln::image2d<U>& in, F f)
{
std::ptrdiff_t istride = in.index_strides()[0];
U* ibuffer = &in.at(in.domain().pmin);
std::size_t height = in.nrows();
std::size_t width = in.ncols();
for (std::size_t i = 0; i < height; ++i, ibuffer += istride)
std::for_each(ibuffer, ibuffer + width, f);
}
template <class V, class Generator>
void generate(mln::image2d<V>& ima, Generator g)
{
std::ptrdiff_t stride = ima.index_strides()[0];
V* buffer = &ima.at(ima.domain().pmin);
std::size_t height = ima.nrows();
std::size_t width = ima.ncols();
for (std::size_t i = 0; i < height; ++i, buffer += stride)
std::generate(buffer, buffer + width, g);
}
template <class U, class V, class BinaryOperator>
V accumulate(const mln::image2d<U>& ima, V init, BinaryOperator op)
{
std::ptrdiff_t stride = ima.index_strides()[0];
const U* buffer = &ima.at(ima.domain().pmin);
std::size_t height = ima.nrows();
std::size_t width = ima.ncols();
for (std::size_t i = 0; i < height; ++i, buffer += stride)
init = op(init, std::accumulate(buffer, buffer + width, init, op));
return init;
}
}
void fill_baseline(mln::image2d<mln::uint8>& ima, mln::uint8 v) { baseline::fill(ima, v); }
void fill_baseline(mln::image2d<mln::rgb8>& ima, mln::rgb8 v) { baseline::fill(ima, v); }
void fill(mln::image2d<mln::uint8>& ima, mln::uint8 v) { mln::experimental::fill(ima, v); }
void fill(mln::image2d<mln::rgb8>& ima, mln::rgb8 v) { mln::experimental::fill(ima, v); }
void copy_baseline(const mln::image2d<mln::uint8>& in, mln::image2d<mln::uint8>& out) { return baseline::copy(in, out); }
void copy_baseline(const mln::image2d<mln::rgb8>& in, mln::image2d<mln::rgb8>& out){ return baseline::copy(in, out); }
void copy(const mln::image2d<mln::uint8>& in, mln::image2d<mln::uint8>& out) { return mln::experimental::copy(in, out); }
void copy(const mln::image2d<mln::rgb8>& in, mln::image2d<mln::rgb8>& out){ return mln::experimental::copy(in, out); }
void paste_baseline(const mln::image2d<mln::uint8>& in, mln::image2d<mln::uint8>& out) { return baseline::paste(in, out); }
void paste_baseline(const mln::image2d<mln::rgb8>& in, mln::image2d<mln::rgb8>& out){ return baseline::paste(in, out); }
void paste(const mln::image2d<mln::uint8>& in, mln::image2d<mln::uint8>& out) { return mln::experimental::paste(in, out); }
void paste(const mln::image2d<mln::rgb8>& in, mln::image2d<mln::rgb8>& out){ return mln::experimental::paste(in, out); }
namespace
{
static auto plus_one = [](auto x) -> decltype(x) { return x + 1; };
static auto plus_one_inplace = [](auto& x) { x += 1; };
}
void transform_baseline(const mln::image2d<mln::uint8>& in, mln::image2d<mln::uint8>& out) { return baseline::transform(in, out, plus_one); }
void transform_baseline(const mln::image2d<mln::rgb8>& in, mln::image2d<mln::rgb8>& out){ return baseline::transform(in, out, plus_one); }
void transform(const mln::image2d<mln::uint8>& in, mln::image2d<mln::uint8>& out) { return mln::experimental::transform(in, out, plus_one); }
void transform(const mln::image2d<mln::rgb8>& in, mln::image2d<mln::rgb8>& out){ return mln::experimental::transform(in, out, plus_one); }
void for_each_baseline(mln::image2d<mln::uint8>& in) { return baseline::for_each(in, plus_one_inplace); }
void for_each_baseline(mln::image2d<mln::rgb8>& in){ return baseline::for_each(in, plus_one_inplace); }
void for_each(mln::image2d<mln::uint8>& in) { return mln::experimental::for_each(in, plus_one_inplace); }
void for_each(mln::image2d<mln::rgb8>& in){ return mln::experimental::for_each(in, plus_one_inplace); }
namespace
{
static int cpt = 0;
static auto iota_generator = []() -> int { return cpt++; };
}
void generate_baseline(mln::image2d<mln::uint8>& ima) { baseline::generate(ima, iota_generator); }
void generate(mln::image2d<mln::uint8>& ima) { mln::experimental::generate(ima, iota_generator); }
#include <mln/accu/accumulators/sum.hpp>
int accumulate_baseline(const mln::image2d<mln::uint8>& ima) { return baseline::accumulate(ima, 0, std::plus<>{}); }
int accumulate(const mln::image2d<mln::uint8>& ima) { return mln::experimental::accumulate(ima, 0, std::plus<>{}); }
int accumulate_accu(const mln::image2d<mln::uint8>& ima) { return mln::experimental::accumulate(ima, mln::accu::features::sum<int>()); }
std::vector<mln::point2d> sort_points(const mln::image2d<mln::uint8>& ima) { return mln::experimental::sort_points(ima); }
std::vector<mln::point2d> sort_points(const mln::image2d<int>& ima) { return mln::experimental::sort_points(ima); }
std::vector<mln::point2d> sort_points(const mln::image2d<mln::rgb8>& ima) { return mln::experimental::sort_points(ima, mln::lexicographicalorder_less<mln::rgb8>()); }
#include <benchmark/benchmark.h>
#include <mln/core/image/image2d.hpp>
#include <mln/core/algorithm/transform.hpp>
#include <mln/core/algorithm/clone.hpp>
#include <mln/io/imread.hpp>
void fill_baseline(mln::image2d<mln::uint8>& ima, mln::uint8 v);
void fill_baseline(mln::image2d<mln::rgb8>& ima, mln::rgb8 v);
void fill(mln::image2d<mln::uint8>& ima, mln::uint8 v);
void fill(mln::image2d<mln::rgb8>& ima, mln::rgb8 v);
void copy_baseline(const mln::image2d<mln::uint8>& in, mln::image2d<mln::uint8>& out);
void copy_baseline(const mln::image2d<mln::rgb8>& in, mln::image2d<mln::rgb8>& out);
void copy(const mln::image2d<mln::uint8>& in, mln::image2d<mln::uint8>& out);
void copy(const mln::image2d<mln::rgb8>& in, mln::image2d<mln::rgb8>& out);
void paste_baseline(const mln::image2d<mln::uint8>& in, mln::image2d<mln::uint8>& out);
void paste_baseline(const mln::image2d<mln::rgb8>& in, mln::image2d<mln::rgb8>& out);
void paste(const mln::image2d<mln::uint8>& in, mln::image2d<mln::uint8>& out);
void paste(const mln::image2d<mln::rgb8>& in, mln::image2d<mln::rgb8>& out);
void transform_baseline(const mln::image2d<mln::uint8>& in, mln::image2d<mln::uint8>& out);
void transform_baseline(const mln::image2d<mln::rgb8>& in, mln::image2d<mln::rgb8>& out);
void transform(const mln::image2d<mln::uint8>& in, mln::image2d<mln::uint8>& out);
void transform(const mln::image2d<mln::rgb8>& in, mln::image2d<mln::rgb8>& out);
void for_each_baseline(mln::image2d<mln::uint8>& in);
void for_each_baseline(mln::image2d<mln::rgb8>& in);
void for_each(mln::image2d<mln::uint8>& in);
void for_each(mln::image2d<mln::rgb8>& in);
void generate_baseline(mln::image2d<mln::uint8>& ima);
void generate(mln::image2d<mln::uint8>& ima);
int accumulate_baseline(const mln::image2d<mln::uint8>& ima);
int accumulate_accu(const mln::image2d<mln::uint8>& ima);
int accumulate(const mln::image2d<mln::uint8>& ima);
std::vector<mln::point2d> sort_points(const mln::image2d<mln::uint8>& ima);
std::vector<mln::point2d> sort_points(const mln::image2d<int>& ima);
std::vector<mln::point2d> sort_points(const mln::image2d<mln::rgb8>& ima);
class Bench : public benchmark::Fixture
{
virtual void SetUp(const benchmark::State&) override
{
const char* filename = "Space1_20MB.jpg";
mln::io::imread(filename, m_input_rgb8);
m_input_uint8 = mln::clone(mln::red(m_input_rgb8));
m_pixel_count = m_input_rgb8.domain().size();
}
protected:
std::size_t m_pixel_count;
mln::image2d<mln::uint8> m_input_uint8;
mln::image2d<mln::rgb8> m_input_rgb8;
};
BENCHMARK_F(Bench, fill_buffer2d_uint8_baseline)(benchmark::State& st)
{
while (st.KeepRunning())
fill_baseline(m_input_uint8, 69);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, fill_buffer2d_uint8)(benchmark::State& st)
{
while (st.KeepRunning())
fill(m_input_uint8, 69);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, fill_ibuffer2d_rgb8_baseline)(benchmark::State& st)
{
while (st.KeepRunning())
fill_baseline(m_input_rgb8, mln::rgb8{2,3,4});
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, fill_ibuffer2d_rgb8)(benchmark::State& st)
{
while (st.KeepRunning())
fill(m_input_rgb8, mln::rgb8{2,3,4});
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, copy_buffer2d_uint8_baseline)(benchmark::State& st)
{
mln::image2d<mln::uint8> output_uint8(m_input_uint8, mln::init());
while (st.KeepRunning())
copy_baseline(m_input_uint8, output_uint8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, copy_buffer2d_uint8)(benchmark::State& st)
{
mln::image2d<mln::uint8> output_uint8(m_input_uint8, mln::init());
while (st.KeepRunning())
copy(m_input_uint8, output_uint8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, copy_ibuffer2d_rgb8_baseline)(benchmark::State& st)
{
mln::image2d<mln::rgb8> output_rgb8(m_input_rgb8, mln::init());
while (st.KeepRunning())
copy_baseline(m_input_rgb8, output_rgb8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, copy_ibuffer2d_rgb8)(benchmark::State& st)
{
mln::image2d<mln::rgb8> output_rgb8(m_input_rgb8, mln::init());
while (st.KeepRunning())
copy(m_input_rgb8, output_rgb8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
//////// PASTE //////////////////
BENCHMARK_F(Bench, paste_buffer2d_uint8_baseline)(benchmark::State& st)
{
mln::image2d<mln::uint8> output_uint8(m_input_uint8, mln::init());
while (st.KeepRunning())
paste_baseline(m_input_uint8, output_uint8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, paste_buffer2d_uint8)(benchmark::State& st)
{
mln::image2d<mln::uint8> output_uint8(m_input_uint8, mln::init());
while (st.KeepRunning())
paste(m_input_uint8, output_uint8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, paste_ibuffer2d_rgb8_baseline)(benchmark::State& st)
{
mln::image2d<mln::rgb8> output_rgb8(m_input_rgb8, mln::init());
while (st.KeepRunning())
paste_baseline(m_input_rgb8, output_rgb8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, paste_ibuffer2d_rgb8)(benchmark::State& st)
{
mln::image2d<mln::rgb8> output_rgb8(m_input_rgb8, mln::init());
while (st.KeepRunning())
paste(m_input_rgb8, output_rgb8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
//////// TRANSFORM //////////////////
BENCHMARK_F(Bench, transform_buffer2d_uint8_baseline)(benchmark::State& st)
{
mln::image2d<mln::uint8> output_uint8(m_input_uint8, mln::init());
while (st.KeepRunning())
transform_baseline(m_input_uint8, output_uint8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, transform_buffer2d_uint8)(benchmark::State& st)
{
mln::image2d<mln::uint8> output_uint8(m_input_uint8, mln::init());
while (st.KeepRunning())
transform(m_input_uint8, output_uint8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, transform_ibuffer2d_rgb8_baseline)(benchmark::State& st)
{
mln::image2d<mln::rgb8> output_rgb8(m_input_rgb8, mln::init());
while (st.KeepRunning())
transform_baseline(m_input_rgb8, output_rgb8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, transform_ibuffer2d_rgb8)(benchmark::State& st)
{
mln::image2d<mln::rgb8> output_rgb8(m_input_rgb8, mln::init());
while (st.KeepRunning())
transform(m_input_rgb8, output_rgb8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
//////// FOR_EACH //////////////////
BENCHMARK_F(Bench, for_each_buffer2d_uint8_baseline)(benchmark::State& st)
{
while (st.KeepRunning())
for_each_baseline(m_input_uint8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, for_each_buffer2d_uint8)(benchmark::State& st)
{
while (st.KeepRunning())
for_each(m_input_uint8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, for_each_ibuffer2d_rgb8_baseline)(benchmark::State& st)
{
while (st.KeepRunning())
for_each_baseline(m_input_rgb8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, for_each_ibuffer2d_rgb8)(benchmark::State& st)
{
while (st.KeepRunning())
for_each(m_input_rgb8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
/////////// GENERATE /////////////////
BENCHMARK_F(Bench, generate_buffer2d_uint8_baseline)(benchmark::State& st)
{
mln::image2d<mln::uint8> output_uint8(m_input_uint8, mln::init());
while (st.KeepRunning())
generate_baseline(output_uint8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, generate_buffer2d_uint8)(benchmark::State& st)
{
mln::image2d<mln::uint8> output_uint8(m_input_uint8, mln::init());
while (st.KeepRunning())
generate(output_uint8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
/////////// ACCUMULATE /////////////////
BENCHMARK_F(Bench, accumulate_buffer2d_uint8_baseline)(benchmark::State& st)
{
while (st.KeepRunning())
accumulate_baseline(m_input_uint8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, accumulate_buffer2d_uint8_accu)(benchmark::State& st)
{
while (st.KeepRunning())
accumulate_accu(m_input_uint8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, accumulate_buffer2d_uint8)(benchmark::State& st)
{
while (st.KeepRunning())
accumulate(m_input_uint8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
/////////// SORT /////////////////
BENCHMARK_F(Bench, sort_points_buffer2d_small_int)(benchmark::State& st)
{
while (st.KeepRunning())
sort_points(m_input_uint8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, sort_points_buffer2d_large_int)(benchmark::State& st)
{
auto bit_mix = [](mln::rgb8 x) -> int {
int res = 0;
res |= ((x[0] & (1 << 7)) << 16) | ((x[1] & (1 << 7)) << 15) | ((x[2] & (1 << 7)) << 14);
res |= ((x[0] & (1 << 6)) << 14) | ((x[1] & (1 << 6)) << 13) | ((x[2] & (1 << 6)) << 12);
res |= ((x[0] & (1 << 5)) << 12) | ((x[1] & (1 << 5)) << 11) | ((x[2] & (1 << 5)) << 10);
res |= ((x[0] & (1 << 4)) << 10) | ((x[1] & (1 << 4)) << 9) | ((x[2] & (1 << 4)) << 8);
res |= ((x[0] & (1 << 3)) << 8) | ((x[1] & (1 << 3)) << 7) | ((x[2] & (1 << 3)) << 6);
res |= ((x[0] & (1 << 2)) << 6) | ((x[1] & (1 << 2)) << 5) | ((x[2] & (1 << 2)) << 4);
res |= ((x[0] & (1 << 1)) << 4) | ((x[1] & (1 << 1)) << 3) | ((x[2] & (1 << 1)) << 2);
res |= ((x[0] & (1 << 0)) << 2) | ((x[1] & (1 << 0)) << 1) | ((x[2] & (1 << 1)) << 0);
return res;
};
mln::image2d<int> tmp = mln::experimental::transform(m_input_rgb8, bit_mix);
while (st.KeepRunning())
sort_points(tmp);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_F(Bench, sort_points_buffer2d_rgb8_lex)(benchmark::State& st)
{
while (st.KeepRunning())
sort_points(m_input_rgb8);
st.SetBytesProcessed(st.iterations() * m_pixel_count);
}
BENCHMARK_MAIN();
......@@ -80,7 +80,7 @@ unsigned threshold3(const image2d<uint8>& f, uint8 v)
unsigned threshold4(const image2d<uint8>& f, uint8 v)
{
return accumulate(f < v, accu::accumulators::sum<unsigned>());
return mln::accumulate(f < v, accu::accumulators::sum<unsigned>());
}
void threshold5(const image2d<uint8>& f, image2d<bool>& out, uint8 v)
......@@ -108,5 +108,5 @@ void threshold5(const image2d<uint8>& f, image2d<bool>& out, uint8 v)
void threshold6(const image2d<uint8>& f, image2d<bool>& out, uint8 v)
{
copy(f < v, out);
mln::copy(f < v, out);
}
......@@ -36,6 +36,7 @@ set(src_standalone
BMNeighborhood.cpp
BMReference_Neighborhood.cpp
BMReference_Linear.cpp
BMAlgorithms.cpp
)
set_source_files_properties(${src_standalone} PROPERTIES COMPILE_FLAGS ${STANDALONE_COMPILE_FLAGS})
......@@ -44,6 +45,7 @@ set_source_files_properties(${src_standalone} PROPERTIES COMPILE_FLAGS ${STANDAL
enable_testing()
add_benchmark(BMAlgorithms BMAlgorithms.cpp BMAlgorithms_main.cpp)
add_benchmark(BMNeighborhood BMNeighborhood.cpp BMNeighborhood_main.cpp)
add_benchmark(BMRotation BMRotation.cpp)
add_benchmark(BMDilation BMDilation.cpp)
......
f7673886b29b0b1c6c4ee524e30a6485
8f60b1ec12116a9af6a9aa3c9cedad98
d0f76f7c435caa6feb87b64f246b0563
86347f0ad49ade9a7d558f24f52a681f
2b5ece70d9e6bf82255c18acc74403a6
243ac9f763fcb854b021ffd9993213ad
0e52ca75826c746e4a2c02f677eadbef
8e2839094e3bc54f132e7fa92159c0e9
a8f834e2db1f04ee9e576229d0987ba0
c23bac3ec4e8a94c26ef21d0e38cebda
954d1bb38b850720b5bc1c5e0a74bf61
1dafe8d2dd7bef956d3ff153dc38a979
2374df6f0ac6e675d94fc5cd8ea6e636
a0cc5bf891ae2a525bcb81d85b9e1c66
68ee3420f10b13329408f3a4372870ab
8f685eb6abff44278cac97c64c8cd2d6
b271fd36e9263289691982c51fd99e16
98d55d6e190055ed232a8e70acd3a09f
db61e6ffda3b848c723cd656199cf85a
6ee589d646aa695c4a8f8716a67caa52
acc1307a0bffc094a029a441a066bd63
12f8914932e1d3eb14ce1095824bda38