Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use multiprecision rational arithmetic to propagate tags #1543

Closed
wants to merge 7 commits into from

Conversation

awalls-cx18
Copy link
Contributor

@awalls-cx18 awalls-cx18 commented Jan 5, 2018

To address the problem, pointed out by Eugene Grayver, in these threads:

https://lists.gnu.org/archive/html/discuss-gnuradio/2017-11/msg00079.html
https://lists.gnu.org/archive/html/discuss-gnuradio/2017-12/msg00131.html

Avoid floating point precision problems in propagation of tags for the following cases:

  • Common relative rates that are non-terminating in binary (1/3, 1/5, 1/7, ...)
  • Large tag offsets
  • Inexact floating point reciprocals when specifying the relative rate

This change to the runtime only fixes the tag propagation problems for
blocks with a fixed/unchanging relative rate.

This change adds a dependency on the MIPR library (a fork of the GMP
library) to perform multiple precision interger rational arithmetic.
MIPR was chosen as it purports to maintain a properly working Windows
build for cross-platform compatability. Optimizations in MIPR are
also targeted to ARM in additional to x86-64.

Andy Walls added 4 commits December 11, 2017 19:25
Optimize some reference counted buffer[_reader]_sptr grabs and releases
that show up as minor CPU wasters in profiling when there are a lot of
tags or some blocks that "return 0" often.

At high sample rates (e.g. 160 Msps), this can save ~2% CPU on
blocks that propagate a fair number of tags.
Avoid floating point precision problems in propagation of tags for
the following cases:

- Common relative rates that are non-terminating in binary (1/3, 1/5, 1/7, ...)
- Large tag offsets
- Inexact floating point reciprocals when specifying the relative rate

This change to the runtime only fixes the tag propagation problems for
blocks with a fixed/unchanging relative rate.

This change adds a dependency on the MIPR library (a fork of the GMP
library) to perform multiple precision interger rational arithmetic.
MIPR was chosen as it purports to maintain a properly working Windows
build for cross-platform compatability.  Optimizations in MIPR are
also targeted to ARM in additional to x86-64.
The fractional resampler and fractional interpolator blocks' output
samples would lose sync with tag propagation after a while due to
floating point precision problems:

- The blocks did their job with mixed float & double arithmetic
to generate output samples, but the runtime used double arithmetic
to propagate tags.

- Floating point reciprocals are quite exact in the least significant
bits, so specifying relative_rate as 1.0/resample_rate introduces
a mismatch in rates.
This is a mass conversion of existing set_relative_rate(double) calls to
either the set_relative_rate(uint64_t, uint64_t) or
set_inverse_relative_rate(double) calls, where ever easily possible and
appropriate, to improve tag propagation precision for fixed relative
rates.
@noc0lour
Copy link
Member

noc0lour commented Jan 6, 2018

Thanks for fixing this!

Currently MPIR is not packaged in Debian/Ubuntu and as for as I read up it will never be packaged for either of them. Fedora/CentOs on the other hand have this package available. Problem with MPIR apparently were that it redefines symbols which are available in GMP and thus a library can't be linked directly/indirectly to both. Not sure if these problems are solvable in Debian/Ubuntu, maybe mait can comment on that before we pull this in as dependency. Is there any chance you can use GMP for this?

@awalls-cx18
Copy link
Contributor Author

awalls-cx18 commented Jan 6, 2018 via email

@awalls-cx18
Copy link
Contributor Author

After some thought, I think Debian/Ubuntu made the right call. OOT module authors on Linux that use an MP library themselves will very likely pick GMP, and this patch would force them to change to MPIR due to linker problems.

I'll add a patch to look for both MPIR and GMP and will prefer to use GMP with fallback to MIPR, if GMP is not found.

@awalls-cx18
Copy link
Contributor Author

OK, patched to search for both GMP and MIPR and to prefer GMP, if GMP is found.

@noc0lour
Copy link
Member

noc0lour commented Jan 7, 2018

OK, I'll need to update the build containers to include GMP so it will build and test.

…c build

External applications including block.h should not have to figure
out the correct #define for which MP library to use, so make the correct
GR_MPLIB_* define in gnuradio/config.h at the time libgnuradio-runtime
is configured and built.

Also fix the generation of the pkgconfig file gnuradio-runtime.pc,
so that external applications linking against libgnuradio-runtime
can easily know which MP library to link against.
@awalls-cx18
Copy link
Contributor Author

Fixed gnuradio/config.h to include a define for the proper MP library and fixed generation of gnuradio-runtime.pc for the proper MP library, so in both cases external application writers need not guess.

@noc0lour
Copy link
Member

noc0lour commented Jan 7, 2018

-- Configuring gnuradio-runtime support...
--   Dependency Boost_FOUND = 1
--   Dependency ENABLE_VOLK = ON
--   Dependency PYTHONINTERP_FOUND = TRUE
--   Dependency MPLib_FOUND = 
--   Disabling gnuradio-runtime support.
--   Override with -DENABLE_GNURADIO_RUNTIME=ON/OFF

Somehow finding GMP is not enough, it still is not enabling gnuradio-runtime.

@awalls-cx18
Copy link
Contributor Author

Per conversation on IRC, this is a CMake 2.8.12 & and not reading the CMake documentation problem with finding a module with a mixed case name. CMake 3.10.0 doesn't fail. The chosen solution is to just change "MPLib" to "MPLIB" everywhere and make the problem go away. I'll push that change soon.

@marcusmueller
Copy link
Member

To give you a bit of status insight on this PR:

We can't merge that into master right now, because of the new dependency; we'll have to discuss this. I'm not really opposed to pulling in new dependencies into 3.8, although the overall goal is to reduce dependency hell:

GMP/MPLIB/MPIR is a relatively benign dependency; however, I really need to track down availability on more than our favourite linuxes. I vaguely remember GMP and Windows having a special relationship. So, until I start pulling together the 3.8 release, this must stay unmerged (and hence, the PR stays open to force me to actually do that).

@marcusmueller marcusmueller added this to the Release 3.8 milestone Feb 3, 2018
@awalls-cx18
Copy link
Contributor Author

The GMP folks specifically refuse to support a Windows port. That is why the MPIR fork of GMP exists, to have the guts of GMP work properly on Windows.

Because of this though, the symbols of GMP and MPIR clash when linking. Thus the preferred default of GMP, so that libgnuradio*.so will likely not have linking problems with user apps under Linux.

@awalls-cx18
Copy link
Contributor Author

FYI, I didn't "roll my own" routines for multiple precision integers and rationals because I figired I'd get it wrong somewhere, and I really try to avoid "not invented here" syndrome when coding.

Thus the addition of a dependency. Yeah I agree GNURadio already has too many dependencies, but I was in situation of having to choose between the lesser of two evils with this fix. :(

set(MPLIBXX_LIBRARY ${GMPXX_LIBRARY})
set(MPLIB_PC_ADD_CFLAGS ${GMP_PC_ADD_CFLAGS})
set(MPLIB_PC_ADD_LIBS ${GMP_PC_ADD_LIBS})
else(GMP_FOUND)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we be checking whether MPIR_FOUND here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a weird CMake syntax thing, not actually an "elseif(another_condition)". See this link:
https://cmake.org/cmake/help/v3.0/command/if.html
where the "if()","else()", and "endif()" all have the same expression in parenthesis.
The expression being copied into the "else()" and endif()" is optional, according to that documentation page, so they can be removed, if you think it is too confusing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get that, but I was worried that we set the variables to their MPIR values if GMP is not found, regardless of whether MPIR was found?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I probably need to fix that. I'm a CMake noob, so any suggestions welcome.

FWIW, hopefully the "find_package_handle_standard_args(MPLIB ..)" below won't set MPLIB_FOUND because MPIR_LIBRARY and MPIRXX_LIBRARY won't be valid/set and hence MPLIB_LIBRARY and MPLIBXX_LIBRARY won't be valid/set ... I hope. :(

@marcusmueller
Copy link
Member

I'd agree, in this case, doing math right is more important than saving us a few kB of dependency that's actually available on all platforms (albeit under different names). @mbr0wn, new GMP/MPIR in 3.8?

@awalls-cx18
Copy link
Contributor Author

Two other tag infrastructure fixes I want to do are in this thread:
https://lists.gnu.org/archive/html/discuss-gnuradio/2018-01/msg00042.html
https://lists.gnu.org/archive/html/discuss-gnuradio/2018-01/msg00044.html
and they will build upon this one and use of the MP library.

But maybe these 3 collectively need to be discussed in a GREP, because

  1. I haven't done measurement of the runtime CPU performance impact
  2. For one of the remaining changes, Jeff Long is asking for something that I'm not sure is a good thing to do (leave in a mode were the runtime will still [as a convenience!?] guess about the application of the relative rate and provide approximate, but incorrect, tag propagation).

@mbr0wn

if(relative_rate < 0.0)
throw std::invalid_argument("block::set_relative_rate");
if(relative_rate <= 0.0)
throw std::invalid_argument("block::set_relative_rate: relative rate must be > 0.0");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this change!

@marcusmueller
Copy link
Member

@noc0lour need gnuradio/gnuradio-buildbot#14 for successful building on your Fedora26 worker

@marcusmueller
Copy link
Member

I'm manually rebasing this (there's really no significant clash here).

@noc0lour
Copy link
Member

The GMP dep is now available on the build CI.

@marcusmueller
Copy link
Member

I've noticed! Thank you :)

@marcusmueller
Copy link
Member

Merged per 75b4ae3. Thank you, @awalls-cx18!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants