From 766b6632afb49e33cfade70b9c064b37da3883cc Mon Sep 17 00:00:00 2001 From: Marcus Holland-Moritz Date: Sat, 24 Feb 2024 21:07:49 +0100 Subject: [PATCH] chore(ricepp): add fits benchmark --- ricepp/CMakeLists.txt | 3 + ricepp/ricepp_benchmark_fits.cpp | 193 +++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 ricepp/ricepp_benchmark_fits.cpp diff --git a/ricepp/CMakeLists.txt b/ricepp/CMakeLists.txt index d89560cb..0b3729b1 100644 --- a/ricepp/CMakeLists.txt +++ b/ricepp/CMakeLists.txt @@ -150,6 +150,9 @@ if(WITH_BENCHMARKS) if(benchmark_FOUND) add_executable(ricepp_benchmark ricepp_benchmark.cpp) target_link_libraries(ricepp_benchmark ricepp benchmark::benchmark) + + add_executable(ricepp_benchmark_fits ricepp_benchmark_fits.cpp) + target_link_libraries(ricepp_benchmark_fits ricepp benchmark::benchmark) endif() endif() diff --git a/ricepp/ricepp_benchmark_fits.cpp b/ricepp/ricepp_benchmark_fits.cpp new file mode 100644 index 00000000..d3c02b3a --- /dev/null +++ b/ricepp/ricepp_benchmark_fits.cpp @@ -0,0 +1,193 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/** + * \author Marcus Holland-Moritz (github@mhxnet.de) + * \copyright Copyright (c) Marcus Holland-Moritz + * + * This file is part of ricepp. + * + * ricepp is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ricepp is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ricepp. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +namespace { + +std::filesystem::path const g_testdata_dir{ + "/home/mhx/git/github/dwarfs/@ricepp-testdata"}; + +struct config { + unsigned component_stream_count; + unsigned unused_lsb_count; +}; + +std::map const g_camera_info = { + {"ASI178MC", {2, 0}}, {"ASI294MC", {2, 2}}, {"ASI1600MM", {1, 4}}, + {"ASI2600MC", {2, 0}}, {"ASI2600MM", {1, 0}}, {"ASI6200MC", {2, 0}}, +}; + +std::string format_percentage(double value) { + std::ostringstream oss; + oss << std::fixed << std::setprecision(2) << "(" << value << "%)"; + return oss.str(); +} + +class ricepp_bm : public ::benchmark::Fixture { + public: + void SetUp(::benchmark::State const& state) { + if (state.thread_index() > 0) { + latch_->wait(); + return; + } + + auto const [camera, test, operation] = [&] { + std::string name{state.name()}; + auto const pos1 = name.find('/'); + auto const pos2 = name.find('/', pos1 + 1); + return std::make_tuple(name.substr(0, pos1), + name.substr(pos1 + 1, pos2 - pos1 - 1), + name.substr(pos2 + 1)); + }(); + + auto const& camera_info = g_camera_info.at(camera); + + codec_ = ricepp::create_codec({ + .block_size = 128, + .component_stream_count = camera_info.component_stream_count, + .byteorder = std::endian::big, + .unused_lsb_count = camera_info.unused_lsb_count, + }); + + if (data_.empty()) { + std::filesystem::path testdata_dir; + if (auto dir = std::getenv("RICEPP_FITS_TESTDATA_DIR")) { + testdata_dir = dir; + } else { + testdata_dir = g_testdata_dir; + } + + data_ = load_fits_data(testdata_dir / camera / (test + ".fit")); + + encoded_ = codec_->encode(data_); + } + + latch_->count_down(); + } + + void TearDown(::benchmark::State const& state) { + latch_.reset(); + latch_.emplace(1); + } + + std::vector load_fits_data(std::filesystem::path const& path) { + static constexpr size_t kBlockSize = 2880; + static constexpr size_t kDataSize = 8 * 1024 * 1024; + + std::ifstream ifs{path, std::ios::binary}; + if (!ifs) { + throw std::runtime_error{"failed to open file: " + path.string()}; + } + + // skip a bunch of header blocks + ifs.seekg(8 * kBlockSize, std::ios::beg); + + std::vector data; + data.resize(kDataSize / sizeof(data[0])); + ifs.read(reinterpret_cast(data.data()), kDataSize); + + if (!ifs) { + throw std::runtime_error{"failed to read data from file: " + + path.string()}; + } + + return data; + } + + std::unique_ptr> codec_; + std::vector data_; + std::vector encoded_; + std::optional latch_{1}; +}; + +} // namespace + +#define RICEPP_BENCHMARK(camera, test) \ + BENCHMARK_DEFINE_F(ricepp_bm, encode_##camera##_##test) \ + (::benchmark::State & state) { \ + thread_local std::vector encoded; \ + encoded.resize(codec_->worst_case_encoded_bytes(data_)); \ + for (auto _ : state) { \ + auto r = codec_->encode(encoded, data_); \ + ::benchmark::DoNotOptimize(r); \ + } \ + state.SetBytesProcessed(static_cast(state.iterations()) * \ + data_.size() * sizeof(data_[0])); \ + state.SetLabel(format_percentage(100.0 * encoded_.size() / \ + (data_.size() * sizeof(data_[0])))); \ + } \ + BENCHMARK_DEFINE_F(ricepp_bm, decode_##camera##_##test) \ + (::benchmark::State & state) { \ + thread_local std::vector decoded; \ + decoded.resize(data_.size()); \ + for (auto _ : state) { \ + codec_->decode(decoded, encoded_); \ + } \ + state.SetBytesProcessed(static_cast(state.iterations()) * \ + data_.size() * sizeof(data_[0])); \ + } \ + BENCHMARK_REGISTER_F(ricepp_bm, encode_##camera##_##test) \ + ->Unit(benchmark::kMillisecond) \ + ->ThreadRange(1, 8) \ + ->UseRealTime() \ + ->Name(#camera "/" #test "/encode"); \ + BENCHMARK_REGISTER_F(ricepp_bm, decode_##camera##_##test) \ + ->Unit(benchmark::kMillisecond) \ + ->ThreadRange(1, 8) \ + ->UseRealTime() \ + ->Name(#camera "/" #test "/decode"); + +RICEPP_BENCHMARK(ASI1600MM, dark_120s_g139) +RICEPP_BENCHMARK(ASI1600MM, dark_1s_g0) +RICEPP_BENCHMARK(ASI1600MM, flat_h_2s_g0) +RICEPP_BENCHMARK(ASI1600MM, light_g_60s_g0) +RICEPP_BENCHMARK(ASI1600MM, light_s_120s_g139) +RICEPP_BENCHMARK(ASI178MC, bias_g0) +RICEPP_BENCHMARK(ASI178MC, dark_60s_g0) +RICEPP_BENCHMARK(ASI178MC, flat_g0) +RICEPP_BENCHMARK(ASI178MC, light_60s_g0) +RICEPP_BENCHMARK(ASI2600MC, flat_g0) +RICEPP_BENCHMARK(ASI2600MC, light_180s_g100) +RICEPP_BENCHMARK(ASI2600MM, bias_g0) +RICEPP_BENCHMARK(ASI2600MM, bias_g100) +RICEPP_BENCHMARK(ASI2600MM, bias_g300) +RICEPP_BENCHMARK(ASI2600MM, dark_900s_g300) +RICEPP_BENCHMARK(ASI2600MM, flat_h_g0) +RICEPP_BENCHMARK(ASI2600MM, light_b_30s_g0) +RICEPP_BENCHMARK(ASI2600MM, light_h_120s_g300) +RICEPP_BENCHMARK(ASI294MC, light_120s_g200) +RICEPP_BENCHMARK(ASI294MC, light_180s_g0) +RICEPP_BENCHMARK(ASI294MC, light_60s_g0) +RICEPP_BENCHMARK(ASI6200MC, light_60s_g100) + +BENCHMARK_MAIN();