-
Notifications
You must be signed in to change notification settings - Fork 203
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 pointers to pass in s32fc arguments #695
Conversation
if [ -f ./cpu_features/list_cpu_features ]; then | ||
./cpu_features/list_cpu_features | ||
fi |
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 made this change because list_cpu_features
does not seem to be present on s390x, which caused CI to fail.
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.
It is worth noting that in the x86_64 SYS V C ABI, complex T
arguments are passed through memory, anyways (p.22, "Passing", clause 5), so the pointer deref happens anyways. We're not introducing any extra overhead for the "flagship" architecture here.
I forgot to update the code sample for The documentation for |
Note: This PR is an alternative to #488, which proposes to replace VOLK's C++ API, but is stalled due to difficulties with MSVC. In comparison, this PR makes a less drastic API change, but does have the drawback of using pointers to pass in complex scalar inputs, which could be confusing. (Elsewhere in VOLK, pointers are only used for vectors and scalar outputs.) I think it's worth accepting that drawback to have VOLK (and packages that depend on it, like GNU Radio and Gqrx) run on all architectures. |
I'd like to summarize our problem here too. From its inception, VOLK is a C library with an interface that pretends to be C++ in some cases. This is an issue because C complex and std::complex are not necessarily binary compatible as discussed in #442 . The clean solution here would be:
This sounds like a simple solution but it isn't. Besides multiple hardware architectures (x86, ARM, ...) we also target multiple platforms (Linux, Mac, Windows). On Windows, the default compiler is MSVC. The MSVC C compiler lacks C complex support. I thought about the proposed solution here. However, this solution makes the interface less verbose. The whole "pass a single value by pointer" thing works but obstructs the interface. The VOLK interface itself should be as verbose as possible. If a scalar is not passed by value, it is easier to misinterpret this as a vector input. We need additional documentation that is easy to miss in this case. Some alternative approaches might be:
|
Thanks for providing a summary of the issue. I agree that API changes should be carefully considered, and I'd be happy to see one of the alternatives adopted in place of what I've proposed here. This PR is intended as a pragmatic solution in case the alternatives don't work out. Until a solution is found, users could work around this issue by calling the affected kernels from C. I might take a crack at making that change in GNU Radio. |
Would it be possible to add wrappers around the new, pointer based, API that replicates the currrent, value based, API? In this case, we could mark the value based API as deprecated and issue a warning. We do this with other kernels as well. |
That sounds like a reasonable approach. I'll take a crack at it to see how it goes. |
I tried this, but ran into the difficulty that MSVC doesn't support (standard) complex numbers in C, which precludes using VOLK from C. I believe this is same problem that stalled #488. |
9f5354e
to
250a36c
Compare
I've updated the PR to take this approach, and CI seems to be happy. I'll update the documentation for the old kernels as well to point to the new ones. |
This avoids undefined behaviour arising from incompatibility between complex numbers in C and C++. Signed-off-by: Clayton Smith <argilo@gmail.com>
I tested this against GNU Radio ( Then I updated VOLK's version number to 3.0.1, and applied the following patch to GNU Radio: gnuradio/gnuradio@main...argilo:gnuradio:volk-s32fc-pointer After this change, the deprecation warnings disappear and all tests still pass. |
In three cases, GNU Radio was using |
The updated GNU Radio code also passes CI with VOLK 3.0.0, so it should be possible to use any combination of old/new GNU Radio with old/new VOLK. |
I tested the VOLK & GNU Radio changes on ppc64le (using docker multiarch). Before the changes, 10 GNU Radio tests out of 265 fail, and afterwards all tests pass. 🎉 |
I also tested Gqrx, and it runs normally on ppc64le with these changes in place. |
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.
LGTM. Thanks for taking the time to fix this issue and for being persistent on it.
I feel like this is a solution that can work for existing users as well as new users on more architectures.
This kernel has been in use on https://github.com/jj1bdx/airspy-fmradion for a long time. Thanks for the fix! |
You're welcome! Is the new version working well for your application? |
I updated the sample code above to include the exact VOLK version number which includes the fixes. |
@argilo After a few hours of trial, I have to conclude that:
|
Could you try reverting this commit ( If not, perhaps you could try doing a |
Your suggestion of reverting e77c668 worked (no calculation issue happened) on compiling and running Ubuntu 22.04.3 x86_64. In short, your suggestion in #695 (comment) worked. |
I'll have a look over e77c668 to see if there is anything that could explain the problem. What behaviour are you seeing from the |
The symptom I see in 3.1.0 is that the (complex) absolute value of each element of the computed result vector rapidly converges to zero, which should not happen in the normal calculation. This is the code I've been using volk_32fc_x2_s32fc_multiply_conjugate_add_32fc kernel: |
I tried running airspy-fmradion inside valgrind, and valgrind reported many errors due to use of uninitialized memory. I wonder if that could be causing trouble. |
The errors occur because |
@argilo |
I'm glad to hear it! Thanks for sharing the results of your testing. |
@argilo I had to fix another bug for the stable operation of the adaptive multipath filter in airspy-fmradion. This is not related to this issue but rather an irregular/illegal value handling during the calculation. Details: jj1bdx/airspy-fmradion#42 (comment) |
Use pointers to pass in s32fc arguments
Fixes #442.
Will allow gnuradio/gnuradio#6300 and gqrx-sdr/gqrx#781 to be fixed.
VOLK uses the same function signatures in both C and C++. This mostly works, except for arguments of type
lv_32fc_t
, which arefloat complex
in C andstd::complex<float>
in C++. The language specifications for C and C++ both guarantee that these have the same memory representation, but not that they have the same calling convention.To avoid the problem, we can replace the three instances of
lv_32fc_t
arguments withlv_32fc_t*
, which should work in both C and C++.This change intentionally breaks the API, since the current API has Undefined Behaviour. If merged, the next version of VOLK should be 4.0.0 to reflect the API incompatibility.To preserve backwards compatibility, I've made the current kernels into wrappers around new ones. Users wishing to use the new kernels while still supporting older VOLK versions could do the following:After these changes, VOLK's tests pass on all platforms, including ppc64le and s390x.
Affected kernels are:
volk_32fc_s32fc_multiply_32fc
(12 usages in GNU Radio)volk_32fc_s32fc_x2_rotator_32fc
(1 usage in GNU Radio)volk_32fc_x2_s32fc_multiply_conjugate_add_32fc
(not used in GNU Radio)