Basilisk CFD
Adaptive Cartesian mesh PDE framework
Loading...
Searching...
No Matches
balance.h
Go to the documentation of this file.
1/** @file balance.h
2 */
3// Dynamic load-balancing
4
5typedef struct {
6 short leaf, prolongation;
7 int pid;
8} NewPid;
9
10#define NEWPID() ((NewPid *)&val(newpid,0,0,0))
11
12@if TRASH
13@ define is_newpid() (!isnan(val(newpid,0,0,0)) && NEWPID()->pid > 0)
14@else
15@ define is_newpid() (NEWPID()->pid > 0)
16@endif
17
19{
20 const unsigned short sent = 1 << user, next = 1 << (user + 1);
21 Array * a = array_new();
22
24 if (level > 0 && (cell.flags & (sent|next)))
25 aparent(0).flags |= next;
26
27 bool empty = true;
29 if (cell.flags & sent) {
31 cell.flags &= ~sent;
32 empty = false;
33 }
34 else {
35 if (cell.pid >= 0 && NEWPID()->leaf)
37 if (is_refined_check()) {
38 /* check that we are not too refined i.e. that none of our
39 children are prolongations */
40 bool prolo = false;
41 for (int _c = 0; _c < 4; _c++) /* foreach_child */
42 if (NEWPID()->prolongation)
43 prolo = true;
44 if (prolo) {
45 /* if we are too refined, we unrefine before sending */
46 cell.flags |= leaf;
47 array_append (a, &cell, sizeof(Cell));
48 cell.flags &= ~leaf;
49 }
50 else
51 array_append (a, &cell, sizeof(Cell));
52 }
53 else
54 array_append (a, &cell, sizeof(Cell));
55 }
56 if (cell.flags & next)
57 cell.flags &= ~next;
58 else
59 continue;
60 }
61
62 if (empty)
63 a->len = 0;
64 return a;
65}
66
68{
69 {
70 const unsigned short _sent = 1 << user, _next = 1 << (user + 1);
71 scalar * _list = list;
72 char * _i = (char *) (t)->p;
74 Cell * c = (Cell *) _i;
75 if (c->flags & _sent) {
76 _i += size;
77 {...}
78 }
79 else
80 _i += sizeof(Cell);
81 if (c->flags & _next) {
82 assert (c->neighbors);
83 if (!(c->flags & leaf) && is_leaf(cell) &&
84 (!is_newpid() || !NEWPID()->leaf))
85 /* refined */
87 else if (!cell.neighbors)
88 /* prolongation */
90 }
91 else
92 continue;
93 }
94 }
95}
96
98{
99 const unsigned short sent = 1 << user;
100 for (int _i = 0; _i < _N; _i++) /* foreach_cell */ {
101 // root cells
102 bool root = false;
103 if ((!is_local(cell) || NEWPID()->pid - 1 != nextpid) && is_refined(cell)) {
104 for (int _c = 0; _c < 4; _c++) /* foreach_child */
105 if (is_local(cell) && NEWPID()->pid - 1 == nextpid) {
106 root = true; break;
107 }
108 if (root && cell.pid != nextpid) {
109 for (int _n = 0; _n < ; _n++)
110 if (cell.pid != nextpid && is_newpid()) {
111 if (fp)
112 fprintf (fp, "%g %g %g %d %d root\n",
113 x, y, z, NEWPID()->pid - 1, cell.pid);
114 cell.flags |= sent;
115 }
116 }
117 }
118 // children
119 if ((is_local(cell) && NEWPID()->pid - 1 == nextpid) || root) {
120 for (int _n = 0; _n < 1; _n++)
121 if (cell.neighbors && cell.pid != nextpid)
122 for (int _c = 0; _c < 4; _c++) /* foreach_child */
123 if (cell.pid != nextpid && is_newpid()) {
124 if (fp)
125 fprintf (fp, "%g %g %g %d %d nextpid\n",
126 x, y, z, NEWPID()->pid - 1, cell.pid);
127 cell.flags |= sent;
128 }
129 }
130 if (is_leaf(cell))
131 continue;
132 }
133
134 return linear_tree (sizeof(Cell) + datasize, newpid);
135}
136
137static void send_tree (Array * a, int to, MPI_Request * r)
138{
139 MPI_Isend (&a->len, 1, MPI_LONG, to, MOVED_TAG(), MPI_COMM_WORLD, &r[0]);
140 if (a->len > 0) {
141 MPI_Isend (a->p, a->len, MPI_BYTE, to, MOVED_TAG(), MPI_COMM_WORLD, &r[1]);
142 tree->dirty = true;
143 }
144}
145
146static void receive_tree (int from, scalar newpid, FILE * fp)
147{
148 Array a;
149 mpi_recv_check (&a.len, 1, MPI_LONG, from, MOVED_TAG(),
150 MPI_COMM_WORLD, MPI_STATUS_IGNORE, "receive_tree (len)");
151 if (a.len > 0) {
152 a.p = malloc (a.len);
153 if (fp)
154 fprintf (fp, "receiving %ld from %d\n", a.len, from);
156 MPI_COMM_WORLD, MPI_STATUS_IGNORE, "receive_tree (p)");
157 // const unsigned short next = 1 << (user + 1);
158 foreach_tree (&a, sizeof(Cell) + datasize, NULL) {
159 memcpy (((char *)&cell) + sizeof(Cell), ((char *)c) + sizeof(Cell),
160 datasize);
161 assert (NEWPID()->pid > 0);
162 if (fp)
163 fprintf (fp, "%g %g %g %d %d %d %d %d %d recv\n",
164 x, y, z, NEWPID()->pid - 1, cell.pid,
165 c->flags & leaf,
166 cell.flags & leaf, from, NEWPID()->leaf);
167 }
168 free (a.p);
169 tree->dirty = true;
170 }
171}
172
173static void wait_tree (Array * a, MPI_Request * r)
174{
176 if (a->len > 0)
178}
179
180static void check_flags()
181{
182#if DEBUG_MPI
183 for (int _i = 0; _i < _N; _i++) /* foreach_cell */
184 for (int _n = 0; _n < ; _n++)
185 if (allocated(0))
186 for (int i = user; i <= user + 7; i++)
187 assert (!(cell.flags & (1 << i)));
188#endif
189}
190
191struct {
192 int min; // minimum number of points per process
193 bool leaves; // balance leaves only
194
195 int npe; // number of active processes
196} mpi = {
197 1,
198 true
200
201trace
203{
204 if (npe() == 1)
205 return false;
206
207 assert (sizeof(NewPid) == sizeof(double));
208
209 check_flags();
210
211 long nl = 0, nt = 0;
212 for (int _i = 0; _i < _N; _i++) /* foreach_cell */ {
213 if (is_local(cell)) {
214 nt++;
215 if (is_leaf(cell))
216 nl++;
217 }
218 if (is_leaf(cell))
219 continue;
220 }
221
222 grid->n = grid->tn = nl;
223 grid->maxdepth = depth();
224 long nmin = nl, nmax = nl;
225 // fixme: do all reductions in one go
230 if (mpi.leaves)
231 nt = grid->tn;
232 else
234
235 long ne = max(1, nt/npe());
236
237 if (ne < mpi.min) {
238 mpi.npe = max(1, nt/mpi.min);
239 ne = max(1, nt/mpi.npe);
240 }
241 else
242 mpi.npe = npe();
243
244 if (nmax - nmin <= 1)
245 return false;
246
247 scalar newpid[];
248 double zn = z_indexing (newpid, mpi.leaves);
249 if (pid() == 0)
250 assert (zn + 1 == nt);
251
252 FILE * fp = NULL;
253#ifdef DEBUGCOND
254 extern double t;
255 if (DEBUGCOND)
256 fp = lfopen ("bal", "w");
257#elif DEBUG_MPI
258 fp = lfopen ("bal", "w");
259#endif
260
261 // compute new pid, stored in newpid[]
262 bool next = false, prev = false;
264 if (is_local(cell)) {
265 int pid = balanced_pid (newpid[], nt, mpi.npe);
266 pid = clamp (pid, cell.pid - 1, cell.pid + 1);
267 if (pid == pid() + 1)
268 next = true;
269 else if (pid == pid() - 1)
270 prev = true;
271 NEWPID()->pid = pid + 1;
272 NEWPID()->leaf = is_leaf(cell);
273 NEWPID()->prolongation = is_prolongation(cell);
274 if (fp)
275 fprintf (fp, "%g %g %d %d newpid\n", x, y, NEWPID()->pid - 1, cell.pid);
276 }
277 else
278 newpid[] = 0;
279 }
280 for (int l = 0; l <= depth(); l++)
282
283#ifdef DEBUGCOND
284 extern double t;
285 NOT_UNUSED(t);
286 if (DEBUGCOND) {
287 char name[80];
288 sprintf (name, "colls-before-%d", pid());
289 FILE * fp = fopen (name, "w");
291 fclose (fp);
292
293 sprintf (name, "pid-before-%d", pid());
294 fp = fopen (name, "w");
295 for (int _i = 0; _i < _N; _i++) /* foreach_cell */ {
296 fprintf (fp, "%g %g %g %d %d %d %d\n",
297 x, y, z, cell.pid, NEWPID()->pid - 1,
298 NEWPID()->leaf, is_leaf(cell));
299 if (NEWPID()->leaf)
301 }
302 fclose (fp);
303 }
304#endif // DEBUGCOND
305
306 Array * anext = next ? neighborhood (newpid, pid() + 1, fp) : array_new();
307 Array * aprev = prev ? neighborhood (newpid, pid() - 1, fp) : array_new();
308
309 if (fp)
310 fflush (fp);
311
312 check_flags();
313
314 // send mesh to previous/next process
315 MPI_Request rprev[2], rnext[2];
316 if (pid() > 0)
317 send_tree (aprev, pid() - 1, rprev);
318 if (pid() < npe() - 1)
319 send_tree (anext, pid() + 1, rnext);
320
321 // receive mesh from next/previous process
322 if (pid() < npe() - 1)
323 receive_tree (pid() + 1, newpid, fp);
324 if (pid() > 0)
325 receive_tree (pid() - 1, newpid, fp);
326
327 /* check that mesh was received OK and free send buffers */
328 if (pid() > 0)
331 if (pid() < npe() - 1)
334
335 if (fp)
336 fflush (fp);
337
338 // set new pids
339 int pid_changed = false;
341 if (cell.pid >= 0) {
342 if (is_newpid()) {
343 if (fp)
344 fprintf (fp, "%g %g %g %d %d %d %d %d new\n",
345 x, y, z, NEWPID()->pid - 1, cell.pid,
346 is_leaf(cell), cell.neighbors, NEWPID()->leaf);
347 if (cell.pid != NEWPID()->pid - 1) {
348 cell.pid = NEWPID()->pid - 1;
349 cell.flags &= ~(active|border);
350 if (is_local(cell))
351 cell.flags |= active;
352 pid_changed = true;
353 }
354 if (NEWPID()->leaf && !is_leaf(cell) && cell.neighbors)
356 }
357 else if (level > 0 && ((NewPid *)&coarse(newpid))->leaf)
358 cell.pid = aparent(0).pid;
359 }
360 // cleanup unused prolongations
361 if (!cell.neighbors && allocated_child(0)) {
362 if (fp)
363 fprintf (fp, "%g %g %g %d %d freechildren\n",
364 x, y, z, NEWPID()->pid - 1, cell.pid);
366 }
367 }
368
369 if (tree->dirty || pid_changed) {
370#if 1
371 // update active cells: fixme: can this be done above
373 if (!is_leaf(cell) && !is_local(cell)) {
374 unsigned short flags = cell.flags & ~active;
375 for (int _c = 0; _c < 4; _c++) /* foreach_child */
376 if (is_active(cell)) {
377 flags |= active; break;
378 }
379 cell.flags = flags;
380 }
381#endif
382 flag_border_cells(); // fixme: can this be done above?
383 pid_changed = true;
384 }
385
386 if (fp)
387 fclose (fp);
388
390 if (pid_changed)
392
393 return pid_changed;
394}
395
397{
399 for (int _s = 0; _s < 1; _s++) /* scalar in list */
401 grid->tn = 0; // so that tree is not "full" for the call below
402 boundary (list);
403 while (balance());
404}
const vector a
Definition all-mach.h:59
Array * array_new()
Definition array.h:10
void array_free(Array *a)
Definition array.h:18
void * array_append(Array *a, void *elem, size_t size)
Definition array.h:24
int npe
Definition balance.h:195
static void send_tree(Array *a, int to, MPI_Request *r)
Definition balance.h:137
if TRASH define &&NewPid *& val(newpid, 0, 0, 0)) -> pid > 0) @else @ define is_newpid()(((NewPid *)&val(newpid, 0, 0, 0)) ->pid > 0) @endif Array *linear_tree(size_t size, scalar newpid)
Definition balance.h:13
Array * neighborhood(scalar newpid, int nextpid, FILE *fp)
Definition balance.h:97
bool leaves
Definition balance.h:193
int min
Definition balance.h:192
trace bool balance()
Definition balance.h:202
macro2 foreach_tree(Array *t, size_t size, scalar *list, scalar newpid=newpid)
Definition balance.h:67
static void check_flags()
Definition balance.h:180
#define NEWPID()
Definition balance.h:10
static void receive_tree(int from, scalar newpid, FILE *fp)
Definition balance.h:146
if TRASH define is_newpid()(!isnan(val(newpid
struct @5 mpi
static void wait_tree(Array *a, MPI_Request *r)
Definition balance.h:173
void mpi_boundary_update(scalar *list)
Definition balance.h:396
#define boundary_iterate(type,...)
Definition boundaries.h:40
#define boundary(...)
define double double char flags
define l
void output_cells(FILE *fp=stdout, coord c={0}, double size=0.)
free(list1)
define VT _attribute[s.i] v y scalar * list
Definition cartesian.h:276
int y
Definition common.h:76
#define define
int x
Definition common.h:76
int z
Definition common.h:76
Grid * grid
Definition common.h:32
static number clamp(number x, number a, number b)
Definition common.h:15
size_t datasize
Definition common.h:132
#define assert(a)
Definition config.h:107
FILE * lfopen(const char *name, const char *mode)
Definition config.h:671
Point point
Definition conserving.h:86
scalar s
Definition embed-tree.h:56
scalar int i
Definition embed.h:74
double t
Definition events.h:24
macro2 foreach_cell_all()
macro2 foreach_cell_post_all(bool condition)
macro2 foreach_cell_post(bool condition)
#define depth()
Definition cartesian.h:14
int nl
Definition layers.h:9
size_t max
Definition mtrace.h:8
FILE * fp
Definition mtrace.h:7
size_t size
int int int level
trace double z_indexing(scalar index, bool leaves)
define is_active() cell(true) @define is_leaf(cell)(point.level
def _i
Definition stencils.h:405
static void set_dirty_stencil(scalar s)
Definition stencils.h:34
Definition array.h:5
Definition tree.h:51
long n
Definition common.h:27
long tn
Definition common.h:28
int maxdepth
Definition common.h:30
short leaf
Definition balance.h:6
int pid
Definition balance.h:7
scalar nt
Definition terrain.h:17
void coarsen_cell_recursive(Point point, scalar *list)
int refine_cell(Point point, scalar *list, int flag, Cache *refined)
Definition tree-common.h:23
#define MOVED_TAG()
Definition tree-mpi.h:159
trace void mpi_boundary_update_buffers()
Definition tree-mpi.h:860
static void mpi_recv_check(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status, const char *name)
Definition tree-mpi.h:236
static void flag_border_cells()
Definition tree-mpi.h:1200
static int balanced_pid(long index, long nt, int nproc)
Definition tree-mpi.h:1244
def is_refined_check()((!is_leaf(cell) &&cell .neighbors &&cell .pid >=0) &&point.i > 0 &&point.i<(1<< level)+2 *2 - 1 &&point.j > 0 &&point.j<(1<< level)+2 *2 - 1) @ macro2 for(int _i=0
define n n define coarse(a, k, p, n)((double *)(PARENT(k
def allocated(k, l, n)(mem_allocated(((Tree *) grid) -> L[point.level]->m, point.i+k, point.j+l)) @ @def NEIGHBOR(k, l, n)(((((Tree *) grid) ->L[point.level]->m) ->b[point.i+k][point.j+l])) @ @def PARENT(k, l, n)(((((Tree *) grid) ->L[point.level-1]->m) ->b[(point.i+2)/2+k][(point.j+2)/2+l])) @ @def allocated_child(k, l, n)(level< depth() &&mem_allocated(((Tree *) grid) ->L[point.level+1]->m, 2 *point.i- 2+k, 2 *point.j- 2+l)) @ @def CHILD(k, l, n)(((((Tree *) grid) ->L[point.level+1]->m) ->b[2 *point.i- 2+k][2 *point.j- 2+l])) @ @define CELL(m)(*((Cell *)(m))) @define depth()(grid->depth) @define aparent(k, l, n) CELL(PARENT(k, l, n)) @define child(k, l, n) CELL(CHILD(k, l, n)) @define cell CELL(NEIGHBOR(0, 0, 0)) @define neighbor(k, l, n) CELL(NEIGHBOR(k, l, n)) @def neighborp(l, m, n)(Point)
Definition tree.h:253
#define is_prolongation(cell)
Definition tree.h:411
bool * zn
Definition tree.h:1273
#define is_refined(cell)
Definition tree.h:410
#define tree
Definition tree.h:184
static void free_children(Point point)
Definition tree.h:1002
@ user
Definition tree.h:63
@ active
Definition tree.h:59
@ leaf
Definition tree.h:60
@ border
Definition tree.h:61
static void alloc_children(Point point)
Definition tree.h:940
scalar c
Definition vof.h:57
src vof fflush(ferr)