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

Fix broken openmp atomic usage #1234

Merged
merged 4 commits into from
Oct 1, 2022

Conversation

p12tic
Copy link
Contributor

@p12tic p12tic commented Sep 22, 2022

OMP_ATOMIC_UPDATE and OMP_ATOMIC_WRITE are currently completely broken.

Currently OMP_ATOMIC_UPDATE and OMP_ATOMIC_WRITE are defined as follows:

#define OMP_ATOMIC_UPDATE _Pragma("omp atomic update")
#define OMP_ATOMIC_WRITE _Pragma("omp atomic write")

These macros are used as follows:

#pragma OMP_ATOMIC_UPDATE
#pragma OMP_ATOMIC_WRITE

Which results in the following code after preprocessor expansion:

#pragma _Pragma("omp atomic update")
#pragma _Pragma("omp atomic write")

This is invalid pragma which is ignored by the compiler. The correct usage of _Pragma is without #pragma as follows:

_Pragma("omp atomic update")
_Pragma("omp atomic write")

Fixing this issue reveals another problem that "omp atomic" is very restrictive in what expressions it accepts. In many cases the expressions include access to std::vector and so on, which "omp atomic" does not support.

This problem is addressed by using boost::atomic_ref which allows to apply atomic operations on any variable. Because "omp atomic" is hard to use, it is replaced with boost::atomic_ref in all cases.

As a result of this change we need to bump Boost dependency to 1.73.

@simogasp
Copy link
Member

This must come from an old legacy code that has been merge. And it's indeed disturbing.
Can't we just make a find and replace for all those macro and replace them with the proper pragmas instead of using boost?
I don't know if mixing different things (omp, boost concurrency) is a good idea, especially when OpenMP has its own way to manage atomicity.

@p12tic
Copy link
Contributor Author

p12tic commented Sep 23, 2022

@simogasp
It's unfortunately not easily possible. For example this does not work:

std::vector<int> x;
...
#pragma omp atomic
x[i]++;

OpenMP requires a separate variable in the expression to be modified. E.g.

std::vector<int> x;
...

auto& element = x[i];
#pragma omp atomic
element++;

I would also like to point out that usage of OpenMP does not change the underlying memory model that is defined by the C++ standard. As a consequence we can use whatever synchronization primitives we want without risk of breakage.

This PR should be viewed in light of #1236 which would move off OpenMP synchronization primitives in the rest of codebase.

@p12tic
Copy link
Contributor Author

p12tic commented Sep 27, 2022

@fabiencastan @simogasp Is there anything missing from this PR that prevents it from being merged? It fixes a quite important issue in a way that prevents the issue from happening ever again and is actually more convenient compared to proper usage of #pragma omp atomic.

@p12tic p12tic force-pushed the fix-openmp-atomics branch 2 times, most recently from a7e6791 to a6107e1 Compare September 29, 2022 08:58
@p12tic
Copy link
Contributor Author

p12tic commented Sep 30, 2022

@fabiencastan @simogasp Just a friendly ping :-)

It would be great if you could indicate if this PR will potentially be accepted. If not, I will create a separate PR that fixes the bug and refactor my other code to not assume that related changes will be accepted upstream.

@fabiencastan fabiencastan changed the title Fix completely broken openmp atomic usage Fix broken openmp atomic usage Sep 30, 2022
@fabiencastan fabiencastan added this to the 2.5.0 milestone Sep 30, 2022
p12tic added 4 commits October 1, 2022 14:52
OMP_ATOMIC_UPDATE and OMP_ATOMIC_WRITE are currently completely broken.

Currently OMP_ATOMIC_UPDATE and OMP_ATOMIC_WRITE are defined as follows:

> #define OMP_ATOMIC_UPDATE _Pragma("omp atomic update")
> #define OMP_ATOMIC_WRITE  _Pragma("omp atomic write")

These macros are used as follows:

> #pragma OMP_ATOMIC_UPDATE
> #pragma OMP_ATOMIC_WRITE

Which results in the following code after preprocessor expansion:

> #pragma _Pragma("omp atomic update")
> #pragma _Pragma("omp atomic write")

This is invalid pragma which is ignored by the compiler. The correct
usage of _Pragma is without #pragma as follows:

> _Pragma("omp atomic update")
> _Pragma("omp atomic write")

Fixing this issue reveals another problem that "omp atomic" is very
restrictive in what expressions it accepts. In many cases the
expressions include access to std::vector and so on, which "omp atomic"
does not support.

This problem is addressed by using boost::atomic_ref which allows to
apply atomic operations on any variable. Because "omp atomic" is hard to
use, it is replaced with boost::atomic_ref in all cases.
@p12tic p12tic force-pushed the fix-openmp-atomics branch from a6107e1 to d80d1ff Compare October 1, 2022 11:52
@fabiencastan fabiencastan merged commit 3d8ec2a into alicevision:develop Oct 1, 2022
@p12tic p12tic deleted the fix-openmp-atomics branch October 1, 2022 21:00
@p12tic
Copy link
Contributor Author

p12tic commented Oct 1, 2022

Thanks Fabien.

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

Successfully merging this pull request may close these issues.

3 participants