BoostGSoC21 / math

Boost.org math module
http://boost.org/libs/math
Boost Software License 1.0
0 stars 1 forks source link

test/fft_compile.cpp segfaults after compiling with clang. #4

Closed cosurgi closed 3 years ago

cosurgi commented 3 years ago

The offending line is here

    transform_api< std::complex<double>,     3,boost::math::fft::fftw_dft >();
ckormanyos commented 3 years ago

Good find.

So the state is commented out, but still seg-fault, correct?

ckormanyos commented 3 years ago

I added the other 4 clang builds to the develop branch protection. So to test this, I'll go ahead and make a PR out of this.

cosurgi commented 3 years ago

Yes, this line will produce a segfault. So I turn it off when using clang.

ckormanyos commented 3 years ago

turn it off when using clang

OK. But that means we need to figure out why and fix it, right?

I will be happy to take a look if I can reproduce the error locally and move forward from there.

cosurgi commented 3 years ago

Yes. This is why we have this issue :)

cosurgi commented 3 years ago
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007f251fb19428 in ?? () from /lib/x86_64-linux-gnu/libfftw3.so.3
(gdb) bt
#0  0x00007f251fb19428 in ?? () from /lib/x86_64-linux-gnu/libfftw3.so.3
#1  0x00007f251f9e61fd in ?? () from /lib/x86_64-linux-gnu/libfftw3.so.3
#2  0x00000000004049f5 in boost::math::fft::detail::fftw_traits_c_interface<double>::plan_execute (plan=0xbbe920, in=0x7ffcdc484cc8, out=0x7ffcdc484cc8) at /usr/include/boost/math/fft/fftw_backend.hpp:66
#3  0x000000000040497c in boost::math::fft::fftw_dft<std::complex<double> >::execute (this=0x7ffcdc484ae8, plan=0xbbe920, in=0x7ffcdc484cc8, out=0x7ffcdc484cc8) at /usr/include/boost/math/fft/fftw_backend.hpp:139
#4  0x0000000000403f0c in boost::math::fft::fftw_dft<std::complex<double> >::forward (this=0x7ffcdc484ae8, in=0x7ffcdc484cc8, out=0x7ffcdc484cc8) at /usr/include/boost/math/fft/fftw_backend.hpp:202
#5  0x000000000040548f in boost::math::fft::dft<std::complex<double>, boost::math::fft::fftw_dft>::execute<__gnu_cxx::__normal_iterator<std::complex<double>*, std::vector<std::complex<double>, std::allocator<std::complex<double> > > >, std::complex<double>*> (this=0x7ffcdc484ae8, ex=boost::math::fft::dft<std::complex<double>, fftw_dft>::execution_type::forward, in_first={_M_value = 0 + 0i}, in_last=
  {_M_value = 0 + 3.2114266979681025e-322i}, out=0x7ffcdc484cc8) at /usr/include/boost/math/fft.hpp:78
#6  0x00000000004053d7 in boost::math::fft::dft<std::complex<double>, boost::math::fft::fftw_dft>::forward<__gnu_cxx::__normal_iterator<std::complex<double>*, std::vector<std::complex<double>, std::allocator<std::complex<double> > > >, std::complex<double>*> (this=0x7ffcdc484ae8, in_first={_M_value = 0 + 0i}, in_last={_M_value = 0 + 3.2114266979681025e-322i}, out=0x7ffcdc484cc8) at /usr/include/boost/math/fft.hpp:136
#7  0x0000000000402e1b in boost::math::fft::dft_forward<boost::math::fft::fftw_dft, __gnu_cxx::__normal_iterator<std::complex<double>*, std::vector<std::complex<double>, std::allocator<std::complex<double> > > >, std::complex<double>*> (input_begin={_M_value = 0 + 0i}, input_end={_M_value = 0 + 3.2114266979681025e-322i}, output=0x7ffcdc484cc8) at /usr/include/boost/math/fft.hpp:165
#8  0x00000000004018ac in transform_api<std::complex<double>, 3, boost::math::fft::fftw_dft> () at fft_compile.cpp:32
#9  0x00000000004013a4 in main () at fft_compile.cpp:57
ckormanyos commented 3 years ago

Yes. This is why we have this issue

Understood. I'll investigate at convenient time.

This reminds me, ... as soon as we get a bit more stable, we should verify the quality aspects of the code with a bunch of address, undefined-behavior, etc. sanitizers. We also need to check threading and sanity of FFTs within tsan environment. All of this is TBD.

cosurgi commented 3 years ago

I suspect it's memory alignment.

cosurgi commented 3 years ago

OK. But that means we need to figure out why and fix it, right?

ahh... I'm sorry. I corrected the commit title. Yes, it was very misleading. I hope the git push --force won't cause you troubles - the commit diff is the same.

I did this commit, because I realized that in the preceding commit, the problematic line was disabled even with g++.

Lagrang3 commented 3 years ago

I can reproduce the seg. fault with the following example, compiling with clang

#include <boost/math/fft/fftw_backend.hpp>
#include <vector>
#include <complex>
#include <array>
#include <iostream>

using namespace boost::math::fft;

template<class T>
void test()
{
  using complex_t = std::complex<T>;
  using fftw_t = typename detail::fftw_traits_c_interface<T>::complex_value_type;
  using plan_t = typename detail::fftw_traits_c_interface<T>::plan_type;

  int x=1;
  std::array<complex_t,11> A;
  plan_t plan = detail::fftw_traits_c_interface<T>::plan_construct(
      A.size(),
      nullptr,
      nullptr,
      FFTW_BACKWARD,FFTW_ESTIMATE|FFTW_PRESERVE_INPUT); 

  const int algmnt_null = detail::fftw_traits_c_interface<T>::alignment_of(nullptr);
  const int algmnt_A    = detail::fftw_traits_c_interface<T>::alignment_of(reinterpret_cast<T*>(A.data()));

  std::cerr << ("alignment: "+std::to_string(algmnt_null)+" vs " +
  std::to_string(algmnt_A)) << "\n";

  detail::fftw_traits_c_interface<T>::plan_execute(plan, 
          reinterpret_cast<fftw_t*>(A.data()), 
          reinterpret_cast<fftw_t*>(A.data())
          );
  detail::fftw_traits_c_interface<T>::plan_destroy(plan);
}
int main()
{
  test<float>();
  test<double>();
  test<long double>();
  return 0;
}

it seems to occur when the alignment of the plan differs from the alignment of the input data. Notice that without the int x; variable in the stack, the alignment of the std::array<...> A is 0, and the seg. fault doesn't happen. Also when std::vector<...> A; the alignment is again 0 and there is no seg. fault.

Lagrang3 commented 3 years ago

FFTW provides a function int fftw_alignment_of(double* p) that could be used to "determine where a given array is aligned like the original array for which a plan was created" (see the documentation). But they don't seem to provide a function to test for the alignment of a given plan.

Lagrang3 commented 3 years ago

in mind I have at least 3 possible solutions:

  1. internally create two plans, one with the default mechanism that allows for optimization in case of aligned data and a backup plan for use when the data is not aligned.
  2. create an aligned working space on which the fft will be performed if the input/output is not aligned, the aligned memory store will be used only once, hence allocated every time the execution is called and the input/output is not aligned.
  3. create an aligned working space on which the fft will be performed if the input/output is not aligned, but keep this memory allocated for the entire life of the plan.

@cosurgi , @ckormanyos: any preference?

Lagrang3 commented 3 years ago

This commit 7077dfa, fixes the seg. fault and in this commit 354f44f I added a test with a run on unaligned input/output data; that would trigger the error if it not were fixed.

ckormanyos commented 3 years ago

Nice job! Thanks.