/* 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();