BRL-CAD
Loading...
Searching...
No Matches
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-2025 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
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 4096 /* FIXME: just enough for 64 x 64 threads */
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 */
69
70/**
71 * Returns the CPU number of the current bu_parallel() invoked thread.
72 *
73 * This routine is intended for indexing into per-cpu memory buffers.
74 * Values will be any number in the range of 0 to MAX_PSW. They are
75 * not guaranteed to be in any range except for non-parallel
76 * applications which will have ID 0 for the main process's thread.
77 */
78BU_EXPORT extern int bu_parallel_id(void);
79
80/**
81 * Returns the OS thread ID of the calling thread.
82 *
83 * This routine is intended for diagnostic and unique ID purposes, not
84 * for indexing into per-cpu memory buffers as values can be anything.
85 */
86BU_EXPORT extern int bu_thread_id(void);
87
88
89/**
90 * @brief
91 * routines for parallel processing
92 *
93 * Machine-specific routines for portable parallel processing.
94 *
95 */
96
97/**
98 * Without knowing what the current UNIX "nice" value is, change to a
99 * new absolute "nice" value. (The system routine makes a relative
100 * change).
101 */
103
104/**
105 * Return the maximum number of physical CPUs that are considered to
106 * be available to this process now.
107 */
108BU_EXPORT extern size_t bu_avail_cpus(void);
109
110
111/**
112 * Create parallel threads of execution.
113 *
114 * This function creates (at most) 'ncpu' copies of function 'func'
115 * all running in parallel, passing 'data' to each invocation.
116 * Specifying ncpu=0 will specify automatic parallelization, invoking
117 * parallel threads as cores become available. This is particularly
118 * useful during recursive invocations where the ncpu core count is
119 * limited by the parent context.
120 *
121 * Locking and work dispatching are handled by 'func' using a
122 * "self-dispatching" paradigm. This means you must manually protect
123 * shared data structures, e.g., via bu_semaphore_acquire().
124 *
125 * Lock-free execution is typically possible by creating data
126 * containers with MAX_PSW elements as bu_parallel will never execute
127 * more than that many threads. Calling bu_parallel_id() provides the
128 * id of the current thread, which can be used as an index into a
129 * MAX_PSW per-cpu array. The id is also passed as the func_cpu_id
130 * parameter to the bu_parallel callback function.
131 *
132 * All invocations of the specified 'func' callback function are
133 * passed two parameters: 1) it's assigned thread number and 2) a
134 * shared 'data' pointer for application use. Threads are assigned
135 * increasing numbers, starting with zero. Processes may also call
136 * bu_parallel_id() to obtain their thread number.
137 *
138 * Threads created with bu_parallel() may specify utilization of
139 * affinity locking to keep threads on a given physical CPU core.
140 * This behavior can be enabled at runtime by setting the environment
141 * variable LIBBU_AFFINITY=1. Note that this option may increase or
142 * even decrease performance, particularly on platforms with advanced
143 * scheduling, so testing is recommended.
144 *
145 * This function will not return control until all invocations of the
146 * subroutine are finished.
147 *
148 * In following is a working stand-alone example demonstrating how to
149 * call the bu_parallel() interface.
150 *
151 * @code
152 * void shoot_cells_in_series(int width, int height) {
153 * int i, j;
154 * for (i=0; i<height; i++) {
155 * for (j=0; j<width; j++) {
156 * printf("Shooting cell (%d, %d) on CPU %d\n", i, j, bu_parallel_id());
157 * }
158 * }
159 * }
160 *
161 * void shoot_row_per_thread(int cpu, void *mydata) {
162 * int i, j, width;
163 * width = *(int *)mydata;
164 * for (i=0; i<width; i++) {
165 * printf("Shooting cell (%d, %d) on CPU %d\n", i, cpu, bu_parallel_id());
166 * }
167 * }
168 *
169 * void shoot_cells_in_parallel(int width, int height) {
170 * bu_parallel(shoot_row_per_thread, height, &width);
171 * // we don't reach here until all threads complete
172 * }
173 *
174 * int main(int ac, char *av[]) {
175 * int width = 4, height = 4;
176 * printf("\nShooting cells one at a time, 4x4 grid:\n");
177 * shoot_cells_in_series(width, height);
178 * printf("\nShooting cells in parallel with 4 threads, one per row:\n");
179 * shoot_cells_in_parallel(width, height);
180 * return 0;
181 * }
182 * @endcode
183 */
184BU_EXPORT extern void bu_parallel(void (*func)(int func_cpu_id, void *func_data), size_t ncpu, void *data);
185
186
187/**
188 * @brief
189 * semaphore implementation
190 *
191 * Machine-specific routines for parallel processing. Primarily for
192 * handling semaphores to protect critical sections of code.
193 *
194 * The new paradigm: semaphores are referred to, not by a pointer, but
195 * by a small integer. This module is now responsible for obtaining
196 * whatever storage is needed to implement each semaphore.
197 *
198 * Note that these routines can't use bu_log() for error logging,
199 * because bu_log() acquires semaphore #0 (BU_SEM_SYSCALL).
200 */
201
202/**
203 *
204 */
205BU_EXPORT extern int bu_semaphore_register(const char *name);
206
207
208/**
209 * emaphores available for both library and application
210 * use.
211 *
212 */
213#define BU_SEMAPHORE_DEFINE(x) x = bu_semaphore_register(CPP_STR(x))
214
215/**
216 * This semaphore is intended for short-lived protection.
217 *
218 * It is provided for both library and application use, code that
219 * doesn't call into a BRL-CAD library.
220 */
221BU_EXPORT extern int BU_SEM_GENERAL;
222
223/**
224 * This semaphore is intended to protect general system calls.
225 *
226 * It is provided for both library and application use, code that
227 * doesn't call into a BRL-CAD library.
228 */
229BU_EXPORT extern int BU_SEM_SYSCALL;
230
231/**
232 * FIXME: this one shouldn't need to be global.
233 */
235
236
237/*
238 * Automatic restart capability in bu_bomb(). The return from
239 * BU_SETJUMP is the return from the setjmp(). It is 0 on the first
240 * pass through, and non-zero when re-entered via a longjmp() from
241 * bu_bomb(). This is only safe to use in non-parallel applications.
242 */
243#define BU_SETJUMP setjmp((bu_setjmp_valid[bu_parallel_id()]=1, bu_jmpbuf[bu_parallel_id()]))
244#define BU_UNSETJUMP (bu_setjmp_valid[bu_parallel_id()]=0)
246/* These are global because BU_SETJUMP must be macro. Please don't touch. */
247BU_EXPORT extern int bu_setjmp_valid[MAX_PSW]; /* !0 = bu_jmpbuf is valid */
248BU_EXPORT extern jmp_buf bu_jmpbuf[MAX_PSW]; /* for BU_SETJUMP() */
249
250
251/**
252 * Prepare 'nsemaphores' independent critical section semaphores. Die
253 * on error.
254 *
255 * Takes the place of 'n' separate calls to old RES_INIT(). Start by
256 * allocating array of "struct bu_semaphores", which has been arranged
257 * to contain whatever this system needs.
258 *
259 */
260BU_EXPORT extern void bu_semaphore_init(unsigned int nsemaphores);
262/**
263 * Release all initialized semaphores and any associated memory.
264 *
265 * FIXME: per hacking, rename to bu_semaphore_clear()
266 */
267BU_EXPORT extern void bu_semaphore_free(void);
268
269BU_EXPORT extern void bu_semaphore_acquire(unsigned int i);
270
271BU_EXPORT extern void bu_semaphore_release(unsigned int i);
272
273/** @} */
274
276
277#endif /* BU_PARALLEL_H */
278
279/*
280 * Local Variables:
281 * mode: C
282 * tab-width: 8
283 * indent-tabs-mode: t
284 * c-file-style: "stroustrup"
285 * End:
286 * ex: shiftwidth=4 tabstop=8
287 */
Definition dvec.h:74
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)
routines for parallel processing
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)
int bu_thread_id(void)
#define DEPRECATED
Definition common.h:401