diff options
author | Thomas Habets <thomas@habets.se> | 2020-01-03 18:16:03 +0000 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2020-01-04 23:35:20 -0800 |
commit | eae138c160a6fb2834eb5eda392d0ed25fbc48d0 (patch) | |
tree | 4746bd59abb3d00658a0ed56630265b652338c4b /gr-fft | |
parent | ebe8ffc58503a1b4f167a13d5663e8849379eaaf (diff) |
gr-fft: Modernize fft code
* Add const where possible
* Disable copy assignment and copy constructor where not safe (for now) to copy
* Manual memory management -> smart pointers and vectors
* De-pointerify where possible
* assert -> static_assert
Diffstat (limited to 'gr-fft')
-rw-r--r-- | gr-fft/include/gnuradio/fft/fft.h | 54 | ||||
-rw-r--r-- | gr-fft/include/gnuradio/fft/goertzel.h | 2 | ||||
-rw-r--r-- | gr-fft/include/gnuradio/fft/goertzel_fc.h | 4 | ||||
-rw-r--r-- | gr-fft/lib/fft.cc | 80 | ||||
-rw-r--r-- | gr-fft/lib/fft_vcc_fftw.cc | 22 | ||||
-rw-r--r-- | gr-fft/lib/fft_vcc_fftw.h | 10 | ||||
-rw-r--r-- | gr-fft/lib/fft_vfc_fftw.cc | 18 | ||||
-rw-r--r-- | gr-fft/lib/fft_vfc_fftw.h | 8 | ||||
-rw-r--r-- | gr-fft/lib/goertzel.cc | 2 | ||||
-rw-r--r-- | gr-fft/lib/goertzel_fc_impl.cc | 6 | ||||
-rw-r--r-- | gr-fft/lib/goertzel_fc_impl.h | 6 |
11 files changed, 90 insertions, 122 deletions
diff --git a/gr-fft/include/gnuradio/fft/fft.h b/gr-fft/include/gnuradio/fft/fft.h index d6f52d4c7d..749a5e874c 100644 --- a/gr-fft/include/gnuradio/fft/fft.h +++ b/gr-fft/include/gnuradio/fft/fft.h @@ -29,6 +29,7 @@ #include <gnuradio/fft/api.h> #include <gnuradio/gr_complex.h> +#include <volk/volk_alloc.hh> #include <boost/thread.hpp> namespace gr { @@ -36,6 +37,7 @@ namespace fft { /*! \brief Helper function for allocating complex* buffers + * TODO: Remove once the single user of this stops using it. */ FFT_API gr_complex* malloc_complex(int size); @@ -48,6 +50,7 @@ FFT_API float* malloc_float(int size); FFT_API double* malloc_double(int size); /*! \brief Helper function for freeing fft buffers + * TODO: Remove once the single user of this stops using it. */ FFT_API void free(void* b); @@ -71,14 +74,17 @@ public: */ class FFT_API fft_complex { - int d_fft_size; + const int d_fft_size; int d_nthreads; - gr_complex* d_inbuf; - gr_complex* d_outbuf; + volk::vector<gr_complex> d_inbuf; + volk::vector<gr_complex> d_outbuf; void* d_plan; public: fft_complex(int fft_size, bool forward = true, int nthreads = 1); + // Copy disabled due to d_plan. + fft_complex(const fft_complex&) = delete; + fft_complex& operator=(const fft_complex&) = delete; virtual ~fft_complex(); /* @@ -86,11 +92,11 @@ public: * into which input and output take place. It's done this way in * order to ensure optimal alignment for SIMD instructions. */ - gr_complex* get_inbuf() const { return d_inbuf; } - gr_complex* get_outbuf() const { return d_outbuf; } + gr_complex* get_inbuf() { return d_inbuf.data(); } + gr_complex* get_outbuf() { return d_outbuf.data(); } - int inbuf_length() const { return d_fft_size; } - int outbuf_length() const { return d_fft_size; } + int inbuf_length() const { return d_inbuf.size(); } + int outbuf_length() const { return d_outbuf.size(); } /*! * Set the number of threads to use for caclulation. @@ -115,14 +121,17 @@ public: */ class FFT_API fft_real_fwd { - int d_fft_size; + const int d_fft_size; int d_nthreads; - float* d_inbuf; - gr_complex* d_outbuf; + volk::vector<float> d_inbuf; + volk::vector<gr_complex> d_outbuf; void* d_plan; public: fft_real_fwd(int fft_size, int nthreads = 1); + // Copy disabled due to d_plan. + fft_real_fwd(const fft_real_fwd&) = delete; + fft_real_fwd& operator=(const fft_real_fwd&) = delete; virtual ~fft_real_fwd(); /* @@ -130,11 +139,11 @@ public: * into which input and output take place. It's done this way in * order to ensure optimal alignment for SIMD instructions. */ - float* get_inbuf() const { return d_inbuf; } - gr_complex* get_outbuf() const { return d_outbuf; } + float* get_inbuf() { return d_inbuf.data(); } + gr_complex* get_outbuf() { return d_outbuf.data(); } - int inbuf_length() const { return d_fft_size; } - int outbuf_length() const { return d_fft_size / 2 + 1; } + int inbuf_length() const { return d_inbuf.size(); } + int outbuf_length() const { return d_outbuf.size(); } /*! * Set the number of threads to use for caclulation. @@ -159,14 +168,17 @@ public: */ class FFT_API fft_real_rev { - int d_fft_size; + const int d_fft_size; int d_nthreads; - gr_complex* d_inbuf; - float* d_outbuf; + volk::vector<gr_complex> d_inbuf; + volk::vector<float> d_outbuf; void* d_plan; public: fft_real_rev(int fft_size, int nthreads = 1); + // Copy disabled due to d_plan. + fft_real_rev(const fft_real_rev&) = delete; + fft_real_rev& operator=(const fft_real_rev&) = delete; virtual ~fft_real_rev(); /* @@ -174,11 +186,11 @@ public: * into which input and output take place. It's done this way in * order to ensure optimal alignment for SIMD instructions. */ - gr_complex* get_inbuf() const { return d_inbuf; } - float* get_outbuf() const { return d_outbuf; } + gr_complex* get_inbuf() { return d_inbuf.data(); } + float* get_outbuf() { return d_outbuf.data(); } - int inbuf_length() const { return d_fft_size / 2 + 1; } - int outbuf_length() const { return d_fft_size; } + int inbuf_length() const { return d_inbuf.size(); } + int outbuf_length() const { return d_outbuf.size(); } /*! * Set the number of threads to use for caclulation. diff --git a/gr-fft/include/gnuradio/fft/goertzel.h b/gr-fft/include/gnuradio/fft/goertzel.h index 38b03a1b25..e807e23cbc 100644 --- a/gr-fft/include/gnuradio/fft/goertzel.h +++ b/gr-fft/include/gnuradio/fft/goertzel.h @@ -41,7 +41,7 @@ public: void set_params(int rate, int len, float freq); // Process a input array - gr_complex batch(float* in); + gr_complex batch(const float* in); // Process sample by sample void input(const float& in); diff --git a/gr-fft/include/gnuradio/fft/goertzel_fc.h b/gr-fft/include/gnuradio/fft/goertzel_fc.h index 75d97380fd..3539697561 100644 --- a/gr-fft/include/gnuradio/fft/goertzel_fc.h +++ b/gr-fft/include/gnuradio/fft/goertzel_fc.h @@ -45,9 +45,9 @@ public: virtual void set_rate(int rate) = 0; - virtual float freq() = 0; + virtual float freq() const = 0; - virtual int rate() = 0; + virtual int rate() const = 0; }; } /* namespace fft */ diff --git a/gr-fft/lib/fft.cc b/gr-fft/lib/fft.cc index bc73e31b2f..c48fb6dc47 100644 --- a/gr-fft/lib/fft.cc +++ b/gr-fft/lib/fft.cc @@ -47,7 +47,6 @@ static int my_fftw_read_char(void* f) { return fgetc((FILE*)f); } #include <stdio.h> #include <stdlib.h> #include <string.h> -#include <cassert> #include <stdexcept> #include <boost/filesystem/operations.hpp> @@ -167,37 +166,24 @@ static void export_wisdom() // ---------------------------------------------------------------- fft_complex::fft_complex(int fft_size, bool forward, int nthreads) + : d_fft_size(fft_size), d_nthreads(nthreads), d_inbuf(fft_size), d_outbuf(fft_size) { // Hold global mutex during plan construction and destruction. planner::scoped_lock lock(planner::mutex()); - assert(sizeof(fftwf_complex) == sizeof(gr_complex)); + static_assert(sizeof(fftwf_complex) == sizeof(gr_complex)); if (fft_size <= 0) { throw std::out_of_range("fft_impl_fftw: invalid fft_size"); } - d_fft_size = fft_size; - d_inbuf = (gr_complex*)volk_malloc(sizeof(gr_complex) * inbuf_length(), - volk_get_alignment()); - if (d_inbuf == 0) { - throw std::runtime_error("volk_malloc"); - } - d_outbuf = (gr_complex*)volk_malloc(sizeof(gr_complex) * outbuf_length(), - volk_get_alignment()); - if (d_outbuf == 0) { - volk_free(d_inbuf); - throw std::runtime_error("volk_malloc"); - } - - d_nthreads = nthreads; config_threading(nthreads); lock_wisdom(); import_wisdom(); // load prior wisdom from disk d_plan = fftwf_plan_dft_1d(fft_size, - reinterpret_cast<fftwf_complex*>(d_inbuf), - reinterpret_cast<fftwf_complex*>(d_outbuf), + reinterpret_cast<fftwf_complex*>(d_inbuf.data()), + reinterpret_cast<fftwf_complex*>(d_outbuf.data()), forward ? FFTW_FORWARD : FFTW_BACKWARD, FFTW_MEASURE); @@ -215,8 +201,6 @@ fft_complex::~fft_complex() planner::scoped_lock lock(planner::mutex()); fftwf_destroy_plan((fftwf_plan)d_plan); - volk_free(d_inbuf); - volk_free(d_outbuf); } void fft_complex::set_nthreads(int n) @@ -236,36 +220,28 @@ void fft_complex::execute() { fftwf_execute((fftwf_plan)d_plan); } // ---------------------------------------------------------------- fft_real_fwd::fft_real_fwd(int fft_size, int nthreads) + : d_fft_size(fft_size), + d_nthreads(nthreads), + d_inbuf(fft_size), + d_outbuf(fft_size / 2 + 1) { // Hold global mutex during plan construction and destruction. planner::scoped_lock lock(planner::mutex()); - assert(sizeof(fftwf_complex) == sizeof(gr_complex)); + static_assert(sizeof(fftwf_complex) == sizeof(gr_complex)); if (fft_size <= 0) { throw std::out_of_range("gr::fft: invalid fft_size"); } - d_fft_size = fft_size; - d_inbuf = (float*)volk_malloc(sizeof(float) * inbuf_length(), volk_get_alignment()); - if (d_inbuf == 0) { - throw std::runtime_error("volk_malloc"); - } - - d_outbuf = (gr_complex*)volk_malloc(sizeof(gr_complex) * outbuf_length(), - volk_get_alignment()); - if (d_outbuf == 0) { - volk_free(d_inbuf); - throw std::runtime_error("volk_malloc"); - } - - d_nthreads = nthreads; config_threading(nthreads); lock_wisdom(); import_wisdom(); // load prior wisdom from disk - d_plan = fftwf_plan_dft_r2c_1d( - fft_size, d_inbuf, reinterpret_cast<fftwf_complex*>(d_outbuf), FFTW_MEASURE); + d_plan = fftwf_plan_dft_r2c_1d(fft_size, + d_inbuf.data(), + reinterpret_cast<fftwf_complex*>(d_outbuf.data()), + FFTW_MEASURE); if (d_plan == NULL) { fprintf(stderr, "gr::fft::fft_real_fwd: error creating plan\n"); @@ -281,8 +257,6 @@ fft_real_fwd::~fft_real_fwd() planner::scoped_lock lock(planner::mutex()); fftwf_destroy_plan((fftwf_plan)d_plan); - volk_free(d_inbuf); - volk_free(d_outbuf); } void fft_real_fwd::set_nthreads(int n) @@ -303,30 +277,20 @@ void fft_real_fwd::execute() { fftwf_execute((fftwf_plan)d_plan); } // ---------------------------------------------------------------- fft_real_rev::fft_real_rev(int fft_size, int nthreads) + : d_fft_size(fft_size), + d_nthreads(nthreads), + d_inbuf(fft_size / 2 + 1), + d_outbuf(fft_size) { // Hold global mutex during plan construction and destruction. planner::scoped_lock lock(planner::mutex()); - assert(sizeof(fftwf_complex) == sizeof(gr_complex)); + static_assert(sizeof(fftwf_complex) == sizeof(gr_complex)); if (fft_size <= 0) { throw std::out_of_range("gr::fft::fft_real_rev: invalid fft_size"); } - d_fft_size = fft_size; - d_inbuf = (gr_complex*)volk_malloc(sizeof(gr_complex) * inbuf_length(), - volk_get_alignment()); - if (d_inbuf == 0) { - throw std::runtime_error("volk_malloc"); - } - - d_outbuf = (float*)volk_malloc(sizeof(float) * outbuf_length(), volk_get_alignment()); - if (d_outbuf == 0) { - volk_free(d_inbuf); - throw std::runtime_error("volk_malloc"); - } - - d_nthreads = nthreads; config_threading(nthreads); lock_wisdom(); import_wisdom(); // load prior wisdom from disk @@ -334,8 +298,10 @@ fft_real_rev::fft_real_rev(int fft_size, int nthreads) // FIXME If there's ever a chance that the planning functions // will be called in multiple threads, we've got to ensure single // threaded access. They are not thread-safe. - d_plan = fftwf_plan_dft_c2r_1d( - fft_size, reinterpret_cast<fftwf_complex*>(d_inbuf), d_outbuf, FFTW_MEASURE); + d_plan = fftwf_plan_dft_c2r_1d(fft_size, + reinterpret_cast<fftwf_complex*>(d_inbuf.data()), + d_outbuf.data(), + FFTW_MEASURE); if (d_plan == NULL) { fprintf(stderr, "gr::fft::fft_real_rev: error creating plan\n"); @@ -351,8 +317,6 @@ fft_real_rev::~fft_real_rev() planner::scoped_lock lock(planner::mutex()); fftwf_destroy_plan((fftwf_plan)d_plan); - volk_free(d_inbuf); - volk_free(d_outbuf); } void fft_real_rev::set_nthreads(int n) diff --git a/gr-fft/lib/fft_vcc_fftw.cc b/gr-fft/lib/fft_vcc_fftw.cc index 0d9b7d1c6b..404ffc538e 100644 --- a/gr-fft/lib/fft_vcc_fftw.cc +++ b/gr-fft/lib/fft_vcc_fftw.cc @@ -52,18 +52,16 @@ fft_vcc_fftw::fft_vcc_fftw(int fft_size, io_signature::make(1, 1, fft_size * sizeof(gr_complex))), d_fft_size(fft_size), d_forward(forward), + d_fft(fft_size, forward, nthreads), d_shift(shift) { - d_fft = new fft_complex(d_fft_size, forward, nthreads); if (!set_window(window)) throw std::runtime_error("fft_vcc: window not the same length as fft_size"); } -fft_vcc_fftw::~fft_vcc_fftw() { delete d_fft; } +void fft_vcc_fftw::set_nthreads(int n) { d_fft.set_nthreads(n); } -void fft_vcc_fftw::set_nthreads(int n) { d_fft->set_nthreads(n); } - -int fft_vcc_fftw::nthreads() const { return d_fft->nthreads(); } +int fft_vcc_fftw::nthreads() const { return d_fft.nthreads(); } bool fft_vcc_fftw::set_window(const std::vector<float>& window) { @@ -90,7 +88,7 @@ int fft_vcc_fftw::work(int noutput_items, // copy input into optimally aligned buffer if (!d_window.empty()) { - gr_complex* dst = d_fft->get_inbuf(); + gr_complex* dst = d_fft.get_inbuf(); if (!d_forward && d_shift) { unsigned int offset = (!d_forward && d_shift) ? (d_fft_size / 2) : 0; int fft_m_offset = d_fft_size - offset; @@ -103,30 +101,30 @@ int fft_vcc_fftw::work(int noutput_items, } } else { if (!d_forward && d_shift) { // apply an ifft shift on the data - gr_complex* dst = d_fft->get_inbuf(); + gr_complex* dst = d_fft.get_inbuf(); unsigned int len = (unsigned int)(floor( d_fft_size / 2.0)); // half length of complex array memcpy(&dst[0], &in[len], sizeof(gr_complex) * (d_fft_size - len)); memcpy(&dst[d_fft_size - len], &in[0], sizeof(gr_complex) * len); } else { - memcpy(d_fft->get_inbuf(), in, input_data_size); + memcpy(d_fft.get_inbuf(), in, input_data_size); } } // compute the fft - d_fft->execute(); + d_fft.execute(); // copy result to our output if (d_forward && d_shift) { // apply a fft shift on the data unsigned int len = (unsigned int)(ceil(d_fft_size / 2.0)); memcpy(&out[0], - &d_fft->get_outbuf()[len], + &d_fft.get_outbuf()[len], sizeof(gr_complex) * (d_fft_size - len)); memcpy(&out[d_fft_size - len], - &d_fft->get_outbuf()[0], + &d_fft.get_outbuf()[0], sizeof(gr_complex) * len); } else { - memcpy(out, d_fft->get_outbuf(), output_data_size); + memcpy(out, d_fft.get_outbuf(), output_data_size); } in += d_fft_size; diff --git a/gr-fft/lib/fft_vcc_fftw.h b/gr-fft/lib/fft_vcc_fftw.h index 631e41d9ca..cbf04c8c91 100644 --- a/gr-fft/lib/fft_vcc_fftw.h +++ b/gr-fft/lib/fft_vcc_fftw.h @@ -32,11 +32,11 @@ namespace fft { class FFT_API fft_vcc_fftw : public fft_vcc { private: - fft_complex* d_fft; - unsigned int d_fft_size; + const unsigned int d_fft_size; + const bool d_forward; + fft_complex d_fft; std::vector<float> d_window; - bool d_forward; - bool d_shift; + const bool d_shift; public: fft_vcc_fftw(int fft_size, @@ -45,8 +45,6 @@ public: bool shift, int nthreads = 1); - ~fft_vcc_fftw(); - void set_nthreads(int n); int nthreads() const; bool set_window(const std::vector<float>& window); diff --git a/gr-fft/lib/fft_vfc_fftw.cc b/gr-fft/lib/fft_vfc_fftw.cc index b2f2ebc4d7..320d90fcc8 100644 --- a/gr-fft/lib/fft_vfc_fftw.cc +++ b/gr-fft/lib/fft_vfc_fftw.cc @@ -47,18 +47,16 @@ fft_vfc_fftw::fft_vfc_fftw(int fft_size, io_signature::make(1, 1, fft_size * sizeof(float)), io_signature::make(1, 1, fft_size * sizeof(gr_complex))), d_fft_size(fft_size), - d_forward(forward) + d_forward(forward), + d_fft(fft_size, forward, nthreads) { - d_fft = new fft_complex(d_fft_size, d_forward, nthreads); if (!set_window(window)) throw std::runtime_error("fft_vfc: window not the same length as fft_size"); } -fft_vfc_fftw::~fft_vfc_fftw() { delete d_fft; } +void fft_vfc_fftw::set_nthreads(int n) { d_fft.set_nthreads(n); } -void fft_vfc_fftw::set_nthreads(int n) { d_fft->set_nthreads(n); } - -int fft_vfc_fftw::nthreads() const { return d_fft->nthreads(); } +int fft_vfc_fftw::nthreads() const { return d_fft.nthreads(); } bool fft_vfc_fftw::set_window(const std::vector<float>& window) { @@ -84,20 +82,20 @@ int fft_vfc_fftw::work(int noutput_items, // copy input into optimally aligned buffer if (!d_window.empty()) { - gr_complex* dst = d_fft->get_inbuf(); + gr_complex* dst = d_fft.get_inbuf(); for (unsigned int i = 0; i < d_fft_size; i++) // apply window dst[i] = in[i] * d_window[i]; } else { - gr_complex* dst = d_fft->get_inbuf(); + gr_complex* dst = d_fft.get_inbuf(); for (unsigned int i = 0; i < d_fft_size; i++) // float to complex conversion dst[i] = in[i]; } // compute the fft - d_fft->execute(); + d_fft.execute(); // copy result to output stream - memcpy(out, d_fft->get_outbuf(), output_data_size); + memcpy(out, d_fft.get_outbuf(), output_data_size); in += d_fft_size; out += d_fft_size; diff --git a/gr-fft/lib/fft_vfc_fftw.h b/gr-fft/lib/fft_vfc_fftw.h index 47c1ca529c..acee4c38bf 100644 --- a/gr-fft/lib/fft_vfc_fftw.h +++ b/gr-fft/lib/fft_vfc_fftw.h @@ -32,10 +32,10 @@ namespace fft { class FFT_API fft_vfc_fftw : public fft_vfc { private: - fft_complex* d_fft; - unsigned int d_fft_size; + const unsigned int d_fft_size; + const bool d_forward; + fft_complex d_fft; std::vector<float> d_window; - bool d_forward; public: fft_vfc_fftw(int fft_size, @@ -43,8 +43,6 @@ public: const std::vector<float>& window, int nthreads = 1); - ~fft_vfc_fftw(); - void set_nthreads(int n); int nthreads() const; bool set_window(const std::vector<float>& window); diff --git a/gr-fft/lib/goertzel.cc b/gr-fft/lib/goertzel.cc index 96b41b0126..f50ffeb81f 100644 --- a/gr-fft/lib/goertzel.cc +++ b/gr-fft/lib/goertzel.cc @@ -45,7 +45,7 @@ void goertzel::set_params(int rate, int len, float freq) d_processed = 0; } -gr_complex goertzel::batch(float* in) +gr_complex goertzel::batch(const float* in) { d_d1 = 0.0; d_d2 = 0.0; diff --git a/gr-fft/lib/goertzel_fc_impl.cc b/gr-fft/lib/goertzel_fc_impl.cc index a8f9d58b5a..4f40de439e 100644 --- a/gr-fft/lib/goertzel_fc_impl.cc +++ b/gr-fft/lib/goertzel_fc_impl.cc @@ -40,9 +40,9 @@ goertzel_fc_impl::goertzel_fc_impl(int rate, int len, float freq) io_signature::make(1, 1, sizeof(float)), io_signature::make(1, 1, sizeof(gr_complex)), len), - d_goertzel(rate, len, freq) + d_goertzel(rate, len, freq), + d_len(len) { - d_len = len; d_rate = rate; d_freq = freq; } @@ -65,7 +65,7 @@ int goertzel_fc_impl::work(int noutput_items, gr_vector_const_void_star& input_items, gr_vector_void_star& output_items) { - float* in = (float*)input_items[0]; + const float* in = static_cast<const float*>(input_items[0]); gr_complex* out = (gr_complex*)output_items[0]; for (int i = 0; i < noutput_items; i++) { diff --git a/gr-fft/lib/goertzel_fc_impl.h b/gr-fft/lib/goertzel_fc_impl.h index c84512b586..e771bc153c 100644 --- a/gr-fft/lib/goertzel_fc_impl.h +++ b/gr-fft/lib/goertzel_fc_impl.h @@ -33,7 +33,7 @@ class FFT_API goertzel_fc_impl : public goertzel_fc { private: goertzel d_goertzel; - int d_len; + const int d_len; float d_freq; int d_rate; @@ -45,8 +45,8 @@ public: void set_freq(float freq); void set_rate(int rate); - float freq() { return d_freq; } - int rate() { return d_rate; } + float freq() const { return d_freq; } + int rate() const { return d_rate; } int work(int noutput_items, gr_vector_const_void_star& input_items, |