BRL-CAD
parallel.h
Go to the documentation of this file.
1/* P A R A L L E L . H
2 * BRL-CAD
3 *
4 * Copyright (c) 2004-2023 United States Government as represented by
5 * the U.S. Army Research Laboratory.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public License
9 * version 2.1 as published by the Free Software Foundation.
10 *
11 * This library is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this file; see the file named COPYING for more
18 * information.
19 */
20
21#ifndef BU_PARALLEL_H
22#define BU_PARALLEL_H
23
24#include "common.h"
25
26#include <setjmp.h> /* for bu_setjmp */
27
28#include "bu/defines.h"
29
30__BEGIN_DECLS
31
32/** @addtogroup bu_parallel
33 * @brief
34 * Thread based parallelism routines.
35 */
36/** @{ */
37
38/**
39 * MAX_PSW - The maximum number of processors that can be expected on
40 * this hardware. Used to allocate application-specific per-processor
41 * tables at compile-time and represent a hard limit on the number of
42 * processors/threads that may be spawned. The actual number of
43 * available processors is found at runtime by calling bu_avail_cpus()
44 */
45#define MAX_PSW 1024
46
47/**
48 * @brief
49 * subroutine to determine if we are multi-threaded
50 *
51 * This subroutine is separated off from parallel.c so that bu_bomb()
52 * and others can call it, without causing either parallel.c or
53 * semaphore.c to get referenced and thus causing the loader to drag
54 * in all the parallel processing stuff from the vendor library.
55 *
56 */
57
58/**
59 * This routine is DEPRECATED, do not use it. If you need a means to
60 * determine when an application is running bu_parallel(), please
61 * report this to our developers.
62 *
63 * Previously, this was a library-stateful way for bu_bomb() to tell
64 * if a parallel application is running. This routine now simply
65 * returns zero all the time, which permits BU_SETJUMP() error
66 * handling during bu_bomb().
67 */
68DEPRECATED BU_EXPORT extern int bu_is_parallel(void);
69
70/**
71 * returns the CPU number of the current bu_parallel() invoked thread.
72 */
73BU_EXPORT extern int bu_parallel_id(void);
74
75/**
76 * @brief
77 * process management routines
78 */
79
80/**
81 * @brief
82 * routines for parallel processing
83 *
84 * Machine-specific routines for portable parallel processing.
85 *
86 */
87
88/**
89 * Without knowing what the current UNIX "nice" value is, change to a
90 * new absolute "nice" value. (The system routine makes a relative
91 * change).
92 */
93BU_EXPORT extern void bu_nice_set(int newnice);
94
95/**
96 * Return the maximum number of physical CPUs that are considered to
97 * be available to this process now.
98 */
99BU_EXPORT extern size_t bu_avail_cpus(void);
100
101
102/**
103 * Create parallel threads of execution.
104 *
105 * This function creates (at most) 'ncpu' copies of function 'func'
106 * all running in parallel, passing 'data' to each invocation.
107 * Specifying ncpu=0 will specify automatic parallelization, invoking
108 * parallel threads as cores become available. This is particularly
109 * useful during recursive invocations where the ncpu core count is
110 * limited by the parent context.
111 *
112 * Locking and work dispatching are handled by 'func' using a
113 * "self-dispatching" paradigm. This means you must manually protect
114 * shared data structures, e.g., via BU_SEMAPHORE_ACQUIRE().
115 * Lock-free execution is often possible by creating data containers
116 * with MAX_PSW elements as bu_parallel will never execute more than
117 * that many threads of execution.
118 *
119 * All invocations of the specified 'func' callback function are
120 * passed two parameters: 1) it's assigned thread number and 2) a
121 * shared 'data' pointer for application use. Threads are assigned
122 * increasing numbers, starting with zero. Processes may also call
123 * bu_parallel_id() to obtain their thread number.
124 *
125 * Threads created with bu_parallel() may specify utilization of
126 * affinity locking to keep threads on a given physical CPU core.
127 * This behavior can be enabled at runtime by setting the environment
128 * variable LIBBU_AFFINITY=1. Note that this option may increase or
129 * even decrease performance, particularly on platforms with advanced
130 * scheduling, so testing is recommended.
131 *
132 * This function will not return control until all invocations of the
133 * subroutine are finished.
134 *
135 * In following is a working stand-alone example demonstrating how to
136 * call the bu_parallel() interface.
137 *
138 * @code
139 * void shoot_cells_in_series(int width, int height) {
140 * int i, j;
141 * for (i=0; i<height; i++) {
142 * for (j=0; j<width; j++) {
143 * printf("Shooting cell (%d, %d) on CPU %d\n", i, j, bu_parallel_id());
144 * }
145 * }
146 * }
147 *
148 * void shoot_row_per_thread(int cpu, void *mydata) {
149 * int i, j, width;
150 * width = *(int *)mydata;
151 * for (i=0; i<width; i++) {
152 * printf("Shooting cell (%d, %d) on CPU %d\n", i, cpu, bu_parallel_id());
153 * }
154 * }
155 *
156 * void shoot_cells_in_parallel(int width, int height) {
157 * bu_parallel(shoot_row_per_thread, height, &width);
158 * // we don't reach here until all threads complete
159 * }
160 *
161 * int main(int ac, char *av[]) {
162 * int width = 4, height = 4;
163 * printf("\nShooting cells one at a time, 4x4 grid:\n");
164 * shoot_cells_in_series(width, height);
165 * printf("\nShooting cells in parallel with 4 threads, one per row:\n");
166 * shoot_cells_in_parallel(width, height);
167 * return 0;
168 * }
169 * @endcode
170 */
171BU_EXPORT extern void bu_parallel(void (*func)(int func_cpu_id, void *func_data), size_t ncpu, void *data);
172
173
174/**
175 * @brief
176 * semaphore implementation
177 *
178 * Machine-specific routines for parallel processing. Primarily for
179 * handling semaphores to protect critical sections of code.
180 *
181 * The new paradigm: semaphores are referred to, not by a pointer, but
182 * by a small integer. This module is now responsible for obtaining
183 * whatever storage is needed to implement each semaphore.
184 *
185 * Note that these routines can't use bu_log() for error logging,
186 * because bu_log() acquires semaphore #0 (BU_SEM_SYSCALL).
187 */
188
189/**
190 *
191 */
192BU_EXPORT extern int bu_semaphore_register(const char *name);
193
194
195/**
196 * emaphores available for both library and application
197 * use.
198 *
199 */
200#define BU_SEMAPHORE_DEFINE(x) x = bu_semaphore_register(CPP_STR(x))
201
202/**
203 * This semaphore is intended for short-lived protection.
204 *
205 * It is provided for both library and application use, code that
206 * doesn't call into a BRL-CAD library.
207 */
208BU_EXPORT extern int BU_SEM_GENERAL;
209
210/**
211 * This semaphore is intended to protect general system calls.
212 *
213 * It is provided for both library and application use, code that
214 * doesn't call into a BRL-CAD library.
215 */
216BU_EXPORT extern int BU_SEM_SYSCALL;
217
218/**
219 * FIXME: this one shouldn't need to be global.
220 */
221BU_EXPORT extern int BU_SEM_MAPPEDFILE;
222
223
224/*
225 * Automatic restart capability in bu_bomb(). The return from
226 * BU_SETJUMP is the return from the setjmp(). It is 0 on the first
227 * pass through, and non-zero when re-entered via a longjmp() from
228 * bu_bomb(). This is only safe to use in non-parallel applications.
229 */
230#define BU_SETJUMP setjmp((bu_setjmp_valid[bu_parallel_id()]=1, bu_jmpbuf[bu_parallel_id()]))
231#define BU_UNSETJUMP (bu_setjmp_valid[bu_parallel_id()]=0)
232
233/* These are global because BU_SETJUMP must be macro. Please don't touch. */
234BU_EXPORT extern int bu_setjmp_valid[MAX_PSW]; /* !0 = bu_jmpbuf is valid */
235BU_EXPORT extern jmp_buf bu_jmpbuf[MAX_PSW]; /* for BU_SETJUMP() */
236
237
238/**
239 * Prepare 'nsemaphores' independent critical section semaphores. Die
240 * on error.
241 *
242 * Takes the place of 'n' separate calls to old RES_INIT(). Start by
243 * allocating array of "struct bu_semaphores", which has been arranged
244 * to contain whatever this system needs.
245 *
246 */
247BU_EXPORT extern void bu_semaphore_init(unsigned int nsemaphores);
248
249/**
250 * Release all initialized semaphores and any associated memory.
251 *
252 * FIXME: per hacking, rename to bu_semaphore_clear()
253 */
254BU_EXPORT extern void bu_semaphore_free(void);
255
256BU_EXPORT extern void bu_semaphore_acquire(unsigned int i);
257
258BU_EXPORT extern void bu_semaphore_release(unsigned int i);
259
260/** @} */
261
262__END_DECLS
263
264#endif /* BU_PARALLEL_H */
265
266/*
267 * Local Variables:
268 * mode: C
269 * tab-width: 8
270 * indent-tabs-mode: t
271 * c-file-style: "stroustrup"
272 * End:
273 * ex: shiftwidth=4 tabstop=8
274 */
Header file for the BRL-CAD common definitions.
void bu_semaphore_acquire(unsigned int i)
int bu_setjmp_valid[MAX_PSW]
int BU_SEM_SYSCALL
void bu_nice_set(int newnice)
process management routines
void bu_semaphore_free(void)
void bu_semaphore_init(unsigned int nsemaphores)
int bu_parallel_id(void)
DEPRECATED int bu_is_parallel(void)
subroutine to determine if we are multi-threaded
#define MAX_PSW
Definition: parallel.h:45
int BU_SEM_GENERAL
int BU_SEM_MAPPEDFILE
size_t bu_avail_cpus(void)
jmp_buf bu_jmpbuf[MAX_PSW]
void bu_parallel(void(*func)(int func_cpu_id, void *func_data), size_t ncpu, void *data)
int bu_semaphore_register(const char *name)
semaphore implementation
void bu_semaphore_release(unsigned int i)
#define DEPRECATED
Definition: common.h:400