Re: How to build compatible packages that use Eigen?

2023-05-04 Thread Dima Kogan
Thank you very much for the notes.

The Eigen code I see does everything with the preprocessor. Which is
fine, and doesn't mean that it must crash. For the specific package I'm
building (libg2o) Eigen is the only option, but this sounds like a
generic problem that affects all sorts of packages, not just libg2o. I'm
a bit surprised that we don't have obvious bug reports related to this.
There are lots of reports of crashes on various github pages, with the
replies being "you must match build flags, especially -m". So this
isn't a completely unknown problem.

I've seen two kinds of crashes so far:

- Mismatched alloc/free. This is described in the first email in this
  thread

- Mismatched alignment. Something calls aligned_malloc() to get a
  pointer with some alignment. And some other Eigen function then
  ingests this pointer and asserts because it isn't aligned sufficiently
  (this second function was compiled differently). I've seen this happen
  here:

https://sources.debian.org/src/eigen3/3.4.0-4/Eigen/src/Core/MapBase.h/#L198

  A number of structures in Eigen are aligned to "AlignedMax", defined
  here:


https://sources.debian.org/src/eigen3/3.4.0-4/Eigen/src/Core/util/Constants.h/#L241

  Which eventually comes from EIGEN_IDEAL_MAX_ALIGN_BYTES, defined here:


https://sources.debian.org/src/eigen3/3.4.0-4/Eigen/src/Core/util/ConfigureVectorization.h/#L57

I can imagine there are other crashes that we could get. And I'm also
suspecting that simply limiting libg2o Eigen calls to implementations
inside libg2o won't conclusively fix everything. Probably what we should
do is:

- patch the Eigen alloc/free functions to do a consistent thing

- patch Eigen to set EIGEN_IDEAL_MAX_ALIGN_BYTES to a constant maximum

I should run more experiments, though.

Thanks



Re: How to build compatible packages that use Eigen?

2023-05-04 Thread M. Zhou
I did something similar. Here is my example:

The linker script is here:
https://salsa.debian.org/science-team/blis/-/blob/master/debian/version_script.lds

This script is used like this:
https://salsa.debian.org/science-team/blis/-/blob/master/debian/patches/libblas-provider.patch

This patch aims to hide some ABIs from the external calls.


On Wed, 2023-05-03 at 22:07 -0400, Aaron M. Ucko wrote:
> Dima Kogan  writes:
> 
> > Thanks for replying
> 
> No problem.
> 
> > Sorry, I'm not familiar-enough with linker scripts. I would pass this to
> > the linker when building libg2o.so? Or the end-user would need to use
> > this when build-time linking their application? The run-time dynamic
> > linker doesn't need this, right?
> 
> AIUI, you'd supply it when building libg2o.so itself, via the
> --version-script linker option (or as an implict linker script, but I'd
> favor being more explicit here).
> 




Re: How to build compatible packages that use Eigen?

2023-05-04 Thread M. Zhou
Don't know how to address this issue but have some relevant comments.

Eigen library does not support run time dispatch for CPU ISAs.
When a package is built upon the amd64 baseline ISA but ran on a modern
CPU, the performance can be very poor.
This is why I build the tensorflow and pytorch packages against
libblas.so.3 (through update-alternatives).
A good BLAS implementation is usually faster than the Eigen
compiled in native ISA. For example, openblas.

Check if the library in question supports building against BLAS/LAPACK
instead of Eigen. Good luck if the upstream does not support that.

By the way, since there is no runtime ISA dispatch, the "-mavx" flag
is likely a baseline violation with RC severity.

I don't know whether Eigen implemented the dispatch in the latest
version. But the current state of this library still seems to dispatch
by preprocessor.

On Wed, 2023-05-03 at 14:18 -0700, Dima Kogan wrote:
> Hi. I'm packaging something that uses Eigen, and I'm running into a
> persistent compatibility issue I don't currently know how to solve. Help
> appreciated.
> 
> Here's the problem. Eigen is a C++ header-only library that's heavy into
> templating. So all the functions inside Eigen produce weak symbols, and
> usually the linker will see many identical copies of the same weak
> symbol, from each compile unit and shared object being linked. The
> linker picks ONE of the weak definitions. This is the intended behavior
> in C++ because every copy is supposed to be identical. But in Eigen
> they're not identical: it does different things based on preprocessor
> defines, and you get crashes.
> 
> Here's a simplified illustration of what happens.
> 
> 
> eigen3/Eigen/src/Core/util/Memory.h contains:
> 
>   EIGEN_DEVICE_FUNC inline void* aligned_malloc(std::size_t size)
>   {
> check_that_malloc_is_allowed();
> 
> void *result;
> #if (EIGEN_DEFAULT_ALIGN_BYTES==0) || EIGEN_MALLOC_ALREADY_ALIGNED
> 
>   EIGEN_USING_STD(malloc)
>   result = malloc(size);
> 
>   #if EIGEN_DEFAULT_ALIGN_BYTES==16
>   eigen_assert((size<16 || (std::size_t(result)%16)==0) && "System's 
> malloc returned an unaligned pointer. Compile with 
> EIGEN_MALLOC_ALREADY_ALIGNED=0 to fallback to handmade aligned memory 
> allocator.");
>   #endif
> #else
>   result = handmade_aligned_malloc(size);
> #endif
> 
> if(!result && size)
>   throw_std_bad_alloc();
> 
> return result;
>   }
> 
>   EIGEN_DEVICE_FUNC inline void aligned_free(void *ptr)
>   {
> #if (EIGEN_DEFAULT_ALIGN_BYTES==0) || EIGEN_MALLOC_ALREADY_ALIGNED
> 
>   EIGEN_USING_STD(free)
>   free(ptr);
> 
> #else
>   handmade_aligned_free(ptr);
> #endif
>   }
> 
> The EIGEN_DEFAULT_ALIGN_BYTES and EIGEN_MALLOC_ALREADY_ALIGNED macros
> can vary based on things like __SSE__ and __AVX__ and such.
> 
> Now let's say you're packaging a library. Let's call it libg2o. This is
> NOT header-only, and somewhere it does #include  which
> eventually includes Memory.h. The libg2o.so that ends up in the
> "libg2o0" package then gets a weak symbol for "aligned_malloc" and
> "aligned_free" that encodes the compiler flags that were used when
> building libg2o.so.
> 
> So far so good.
> 
> Now let's say you have a user. They're writing a program that uses both
> libg2o and Eigen. They're writing their own application, not intended to
> go into Debian. So they build with -msse -mavx and all the other fun
> stuff. THEIR weak copies of "aligned_malloc" and "aligned_free" are
> different and incompatible with the copies in libg2o. And the
> application is then likely to crash because at least something somewhere
> will be allocated with one copy and deallocated with another.
> 
> This is just terrible design from the eigen and c++ people, but that's
> what we have. Has anybody here run into this? How does one build the
> libg2o package so that users don't crash their application when using
> it? I tried to demand maximum alignment in libg2o, which fixes some
> things but not all. Currently debugging to find a better solution, but I
> suspect somebody has already fought this.
> 
> Thanks
>