|
| 1 | +/* |
| 2 | + * Copyright (C) 2012-2020 Euclid Science Ground Segment |
| 3 | + * |
| 4 | + * This library is free software; you can redistribute it and/or modify it under |
| 5 | + * the terms of the GNU Lesser General Public License as published by the Free |
| 6 | + * Software Foundation; either version 3.0 of the License, or (at your option) |
| 7 | + * any later version. |
| 8 | + * |
| 9 | + * This library is distributed in the hope that it will be useful, but WITHOUT |
| 10 | + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
| 11 | + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more |
| 12 | + * details. |
| 13 | + * |
| 14 | + * You should have received a copy of the GNU Lesser General Public License |
| 15 | + * along with this library; if not, write to the Free Software Foundation, Inc., |
| 16 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 17 | + */ |
| 18 | + |
| 19 | +/** |
| 20 | + * @file src/program/BenchBackgroundConvolution.cpp |
| 21 | + * @date 27/03/19 |
| 22 | + * @author aalvarez |
| 23 | + */ |
| 24 | + |
| 25 | +#include <map> |
| 26 | +#include <string> |
| 27 | + |
| 28 | +#include <boost/program_options.hpp> |
| 29 | +#include <boost/timer/timer.hpp> |
| 30 | +#include <random> |
| 31 | +#include "ElementsKernel/ProgramHeaders.h" |
| 32 | +#include "ElementsKernel/Real.h" |
| 33 | +#include "SEImplementation/Segmentation/BackgroundConvolution.h" |
| 34 | +#include "SEFramework/Image/VectorImage.h" |
| 35 | +#include "SEUtils/IsClose.h" |
| 36 | + |
| 37 | +#if BOOST_VERSION < 105600 |
| 38 | +#include <boost/units/detail/utility.hpp> |
| 39 | +using boost::units::detail::demangle; |
| 40 | +#else |
| 41 | +using boost::core::demangle; |
| 42 | +#endif |
| 43 | + |
| 44 | +namespace po = boost::program_options; |
| 45 | +namespace timer = boost::timer; |
| 46 | +using namespace SExtractor; |
| 47 | + |
| 48 | +static Elements::Logging logger = Elements::Logging::getLogger("BenchBackgroundConvolution"); |
| 49 | + |
| 50 | +class BenchBackgroundConvolution : public Elements::Program { |
| 51 | +private: |
| 52 | + std::default_random_engine random_generator; |
| 53 | + std::uniform_real_distribution<SeFloat> random_dist{0, 1}; |
| 54 | + |
| 55 | +public: |
| 56 | + |
| 57 | + po::options_description defineSpecificProgramOptions() override { |
| 58 | + po::options_description options{}; |
| 59 | + options.add_options() |
| 60 | + ("image-start", po::value<int>()->default_value(100), "Image start size") |
| 61 | + ("image-step-size", po::value<int>()->default_value(3), "Image step size") |
| 62 | + ("image-nsteps", po::value<int>()->default_value(1), "Number of steps for the image") |
| 63 | + ("kernel-start", po::value<int>()->default_value(3), "Kernel start size") |
| 64 | + ("kernel-step-size", po::value<int>()->default_value(4), "Kernel step size") |
| 65 | + ("kernel-nsteps", po::value<int>()->default_value(2), "Number of steps for the kernel") |
| 66 | + ("repeat", po::value<int>()->default_value(5), "Repeat") |
| 67 | + ("measures", po::value<int>()->default_value(10), "Number of measures"); |
| 68 | + return options; |
| 69 | + } |
| 70 | + |
| 71 | + std::shared_ptr<VectorImage<SeFloat>> generateImage(int size) { |
| 72 | + auto img = VectorImage<SeFloat>::create(size, size); |
| 73 | + for (int x = 0; x < size; ++x) { |
| 74 | + for (int y = 0; y < size; ++y) { |
| 75 | + img->setValue(x, y, random_dist(random_generator)); |
| 76 | + } |
| 77 | + } |
| 78 | + return img; |
| 79 | + } |
| 80 | + |
| 81 | + Elements::ExitCode mainMethod(std::map<std::string, po::variable_value>& args) override { |
| 82 | + |
| 83 | + auto img_start = args["image-start"].as<int>(); |
| 84 | + auto img_step_size = args["image-step-size"].as<int>(); |
| 85 | + auto img_nsteps = args["image-nsteps"].as<int>(); |
| 86 | + auto krn_start = args["kernel-start"].as<int>(); |
| 87 | + auto krn_step_size = args["kernel-step-size"].as<int>(); |
| 88 | + auto krn_nsteps = args["kernel-nsteps"].as<int>(); |
| 89 | + auto repeat = args["repeat"].as<int>(); |
| 90 | + auto measures = args["measures"].as<int>(); |
| 91 | + |
| 92 | + std::cout << "Image,Kernel,Implementation,Time" << std::endl; |
| 93 | + |
| 94 | + for (int img_step = 0; img_step < img_nsteps; ++img_step) { |
| 95 | + auto img_size = img_start + img_step * img_step_size; |
| 96 | + auto image = generateImage(img_size); |
| 97 | + auto variance = generateImage(img_size); |
| 98 | + |
| 99 | + for (int krn_step = 0; krn_step < krn_nsteps; ++krn_step) { |
| 100 | + auto krn_size = krn_start + krn_step * krn_step_size; |
| 101 | + |
| 102 | + logger.info() << "Using an image of " << img_size << "x" << img_size; |
| 103 | + logger.info() << "Using a kernel of " << krn_size << "x" << krn_size; |
| 104 | + |
| 105 | + auto kernel = generateImage(krn_size); |
| 106 | + |
| 107 | + logger.info() << "Timing Direct implementation"; |
| 108 | + auto direct_result = benchmark<BgConvolutionImageSource>(image, variance, kernel, repeat, measures); |
| 109 | + |
| 110 | + logger.info() << "Timing DFT implementation"; |
| 111 | + auto dft_result = benchmark<BgDFTConvolutionImageSource>(image, variance, kernel, repeat, measures); |
| 112 | + |
| 113 | + logger.info() << "Comparing results"; |
| 114 | + verifyResults(direct_result, dft_result); |
| 115 | + } |
| 116 | + } |
| 117 | + |
| 118 | + return Elements::ExitCode::OK; |
| 119 | + } |
| 120 | + |
| 121 | + template<typename BackgroundConvolution> |
| 122 | + std::shared_ptr<VectorImage<SeFloat>> |
| 123 | + benchmark(std::shared_ptr<VectorImage<SeFloat>>& image, std::shared_ptr<VectorImage<SeFloat>>& variance, |
| 124 | + std::shared_ptr<VectorImage<SeFloat>>& kernel, int repeat, int measures) { |
| 125 | + auto conv_name = demangle(typeid(BackgroundConvolution).name()); |
| 126 | + |
| 127 | + auto bg_convolution = std::make_shared<BackgroundConvolution>(image, variance, 0.5, kernel); |
| 128 | + |
| 129 | + std::shared_ptr<VectorImage<SeFloat>> result; |
| 130 | + |
| 131 | + for (int m = 0; m < measures; ++m) { |
| 132 | + logger.info() << conv_name << " " << m + 1 << "/" << measures; |
| 133 | + timer::cpu_timer timer; |
| 134 | + timer.stop(); |
| 135 | + |
| 136 | + for (int r = 0; r < repeat; ++r) { |
| 137 | + timer.start(); |
| 138 | + result = bg_convolution->getImageTile(0, 0, image->getWidth(), image->getHeight())->getImage(); |
| 139 | + timer.stop(); |
| 140 | + } |
| 141 | + |
| 142 | + std::cout << image->getWidth() << ',' << kernel->getWidth() << ",\"" << conv_name << "\"," << timer.elapsed().wall |
| 143 | + << std::endl; |
| 144 | + } |
| 145 | + |
| 146 | + return result; |
| 147 | + } |
| 148 | + |
| 149 | + void verifyResults(std::shared_ptr<VectorImage<SeFloat>> a, std::shared_ptr<VectorImage<SeFloat>> b) { |
| 150 | + bool all_equal = true; |
| 151 | + for (int x = 0; x < a->getWidth(); ++x) { |
| 152 | + for (int y = 0; y < a->getHeight(); ++y) { |
| 153 | + auto av = a->getValue(x, y); |
| 154 | + auto bv = b->getValue(x, y); |
| 155 | + if (!isClose(av, bv, 1e-3, 1e-3)) { |
| 156 | + logger.info() << "Mismatch at " << x << ',' << y << ": " |
| 157 | + << av << " != " << bv; |
| 158 | + all_equal = false; |
| 159 | + } |
| 160 | + } |
| 161 | + } |
| 162 | + if (all_equal) { |
| 163 | + logger.info() << "All elements are equal!"; |
| 164 | + } else { |
| 165 | + logger.warn() << "Convoluted images are not equal!"; |
| 166 | + } |
| 167 | + } |
| 168 | +}; |
| 169 | + |
| 170 | +MAIN_FOR(BenchBackgroundConvolution) |
0 commit comments