Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
openmp.h
Go to the documentation of this file.
1/*
2 This file is part of Ansel,
3 Copyright (C) 2026 Aurélien PIERRE.
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18#ifndef DT_SYSTEM_OPENMP_H
19#define DT_SYSTEM_OPENMP_H
20
21/* OpenMP wrappers: the pragma shorthands used across the pixel code, with
22 * single-threaded fallbacks when OpenMP is disabled. Self-contained on purpose:
23 * low-level compute units include this instead of darktable.h. */
24
25#ifdef _OPENMP
26# include <omp.h>
27
28#ifndef dt_omp_nontemporal
29// Clang 10+ supports the nontemporal() OpenMP directive
30// GCC 9 recognizes it as valid, but does not do anything with it
31// GCC 10+ ???
32#if (__clang__+0 >= 10 || __GNUC__ >= 9)
33# define dt_omp_nontemporal(...) nontemporal(__VA_ARGS__)
34#else
35// GCC7/8 only support OpenMP 4.5, which does not have the nontemporal() directive.
36# define dt_omp_nontemporal(var, ...)
37#endif
38#endif /* dt_omp_nontemporal */
39
40#define OMP_PRAGMA(x) _Pragma(#x)
41#define __OMP_PARALLEL__(...) OMP_PRAGMA(omp parallel default(firstprivate) __VA_ARGS__)
42#define __OMP_PARALLEL_FOR__(...) OMP_PRAGMA(omp parallel for default(firstprivate) schedule(static) __VA_ARGS__)
43#define __OMP_PARALLEL_FOR_SIMD__(...) OMP_PRAGMA(omp parallel for simd default(firstprivate) schedule(simd:static) __VA_ARGS__)
44#define __OMP_FOR_SIMD__(...) OMP_PRAGMA(omp for simd schedule(simd:static) __VA_ARGS__)
45#define __OMP_FOR__(...) OMP_PRAGMA(omp for schedule(static) __VA_ARGS__)
46#define __OMP_SIMD__(...) OMP_PRAGMA(omp simd __VA_ARGS__)
47#define __OMP_DECLARE_SIMD__(...) OMP_PRAGMA(omp declare simd __VA_ARGS__)
48
49// CLang 20 supports OpenMP 5.1 default(firstprivate) but only for C files.
50// C++ files still need to use default(none) until further notice.
51// Change that when baseline CLang is upgraded.
52#define __OMP_PARALLEL_FOR_CPP__(...) OMP_PRAGMA(omp parallel for default(none) schedule(static) __VA_ARGS__)
53
54#else /* _OPENMP */
55
56# define omp_get_max_threads() 1
57# define omp_get_thread_num() 0
58
59#define __OMP_PARALLEL__(...)
60#define __OMP_PARALLEL_FOR__(...)
61#define __OMP_PARALLEL_FOR_SIMD__(...)
62#define __OMP_FOR_SIMD__(...)
63#define __OMP_FOR__(...)
64#define __OMP_SIMD__(...)
65#define __OMP_DECLARE_SIMD__(...)
66
67#define __OMP_PARALLEL_FOR_CPP__(...)
68
69#endif /* _OPENMP */
70
71#if defined(__x86_64__) || defined(__i386__)
72#include <immintrin.h>
73#endif
74
75#ifdef __cplusplus
76extern "C" {
77#endif
78
83
84static inline int dt_get_thread_num()
85{
86#ifdef _OPENMP
87 return omp_get_thread_num();
88#else
89 return 0;
90#endif
91}
92
93// after writing data using copy_pixel_nontemporal, it is necessary to
94// ensure that the writes have completed before attempting reads from
95// a different core. This function produces the required memory
96// fence to ensure proper visibility
97static inline void dt_sfence()
98{
99#if defined(__x86_64__) || defined(__i386__)
100 _mm_sfence();
101#else
102 // the following generates an MFENCE instruction on x86/x64. We
103 // only really need SFENCE, which is less expensive, but none of the
104 // other memory orders generate *any* fence instructions on x64.
106#endif
107}
108
109// if the copy_pixel_nontemporal() writes were inside an OpenMP
110// parallel loop, the OpenMP parallelization will have performed a
111// memory fence before resuming single-threaded operation, so a
112// dt_sfence would be superfluous. But if compiled without OpenMP
113// parallelization, we should play it safe and emit a memory fence.
114// This function should be used right after a parallelized for loop,
115// where it will produce a barrier only if needed.
116#ifdef _OPENMP
117#define dt_omploop_sfence()
118#else
119#define dt_omploop_sfence() dt_sfence()
120#endif
121
122#ifdef __cplusplus
123}
124#endif
125
126#endif // DT_SYSTEM_OPENMP_H
127
128// clang-format off
129// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
130// vim: shiftwidth=2 expandtab tabstop=2 cindent
131// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
132// clang-format on
int dt_get_num_openmp_threads(void)
Definition darktable.c:518
static void dt_sfence()
Definition openmp.h:97
static int dt_get_thread_num()
Definition openmp.h:84
#define omp_get_thread_num()
Definition openmp.h:57