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
Conversation
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.
|
Thanks for fixing this! Currently |
|
On Sat, 2018-01-06 at 14:23 +0000, Andrej Rode wrote:
Thanks for fixing this!
You're welcome. I must confess though, that like all things I fix, I
needed this working for myself. :)
Currently MPIR is not packaged in Debian/Ubuntu and as for as I read
up it will never be packaged for either of them.
And apparently GMP will never be ported and verified for Windows. That
is why the MPIR fork of GMP exists.
Fedora/CentOs on the other hand have this package available.
Yes. The installed headers are /usr/include/mirpxx.h and
/usr/include/mpir.h . The installed libraries are libmpirxx.so and
libmpir.so .
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.
I can believe that, skimming the header files.
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?
There are a few options, I guess:
1. Toss MPIR, and just use GMP. Windows compatability then falls on
the maintainer of the Windows port. Probably not a nice thing to do to
Geof.
2. Convince Debian/Ubuntu to actually package MPIR. Unlikely, I guess?
3. Add a pybombs recipe for MPIR that correctly builds on
Debian/Ubuntu. This will probably exclude a distro packaged version of
gnuradio being available.
4. Package MIPR as a sublibrary of GNURadio, sort of like how many GNU
packages do this for readline, etc. FSF may have some heartburn with
this, since GNURadio is a FSF project.
5. Conditional compilation or C++ abstraction to use MPIR on Windows
and GMP on Linux.
6. Use the boost native multiprecision ipmlementation which is cross
platform, but not optimized like GMP and MPIR.
I'd prefer option 2, but option 5 is within my control to fix without
external parties involved.
I'm not that good with C++ abstraction, so if I implement option 5,
I'll probably start with a conditional compilation approach.
|
|
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. |
|
OK, patched to search for both GMP and MIPR and to prefer GMP, if GMP is found. |
|
OK, I'll need to update the build containers to include |
…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.
|
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. |
Somehow finding |
|
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. |
|
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). |
|
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. |
|
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) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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. :(
|
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? |
|
Two other tag infrastructure fixes I want to do are in this thread: But maybe these 3 collectively need to be discussed in a GREP, because
|
| 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"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this change!
|
@noc0lour need gnuradio/gnuradio-buildbot#14 for successful building on your Fedora26 worker |
5b6a32e
to
d4c4e3b
Compare
|
I'm manually rebasing this (there's really no significant clash here). |
|
The GMP dep is now available on the build CI. |
|
I've noticed! Thank you :) |
|
Merged per 75b4ae3. Thank you, @awalls-cx18!! |
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:
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.