task.c 15.2 KB
Newer Older
1
/*******************************************************************************
2
 * This file is part of SWIFT.
3
 * Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk)
4
5
6
7
 *                    Matthieu Schaller (matthieu.schaller@durham.ac.uk)
 *               2015 Peter W. Draper (p.w.draper@durham.ac.uk)
 *               2016 John A. Regan (john.a.regan@durham.ac.uk)
 *                    Tom Theuns (tom.theuns@durham.ac.uk)
8
 *
9
10
11
12
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published
 * by the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
13
 *
14
15
16
17
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
18
 *
19
20
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 *
22
23
24
25
26
27
28
29
30
 ******************************************************************************/

/* Config parameters. */
#include "../config.h"

/* Some standard headers. */
#include <float.h>
#include <limits.h>
#include <sched.h>
31
32
33
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
34

35
36
/* MPI headers. */
#ifdef WITH_MPI
37
#include <mpi.h>
38
39
#endif

40
41
42
/* This object's header. */
#include "task.h"

43
/* Local headers. */
Pedro Gonnet's avatar
Pedro Gonnet committed
44
#include "atomic.h"
45
#include "error.h"
46
#include "inline.h"
47
#include "lock.h"
48
49

/* Task type names. */
50
const char *taskID_names[task_type_count] = {
51
52
53
54
55
56
57
58
59
60
    "none",           "sort",          "self",
    "pair",           "sub_self",      "sub_pair",
    "init_grav",      "init_grav_out", "ghost_in",
    "ghost",          "ghost_out",     "extra_ghost",
    "drift_part",     "drift_gpart",   "end_force",
    "kick1",          "kick2",         "timestep",
    "send",           "recv",          "grav_long_range",
    "grav_mm",        "grav_down_in",  "grav_down",
    "grav_mesh",      "cooling",       "sourceterms",
    "stars_ghost_in", "stars_ghost",   "stars_ghost_out"};
61

62
/* Sub-task type names. */
63
const char *subtaskID_names[task_subtype_count] = {
64
65
66
    "none",          "density", "gradient",     "force", "grav",
    "external_grav", "tend",    "xv",           "rho",   "gpart",
    "multipole",     "spart",   "stars_density"};
67

68
69
70
71
72
#ifdef WITH_MPI
/* MPI communicators for the subtypes. */
MPI_Comm subtaskMPI_comms[task_subtype_count];
#endif

73
74
/**
 * @brief Computes the overlap between the parts array of two given cells.
75
 *
Matthieu Schaller's avatar
Matthieu Schaller committed
76
77
78
 * @param TYPE is the type of parts (e.g. #part, #gpart, #spart)
 * @param ARRAY is the array of this specific type.
 * @param COUNT is the number of elements in the array.
79
 */
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#define TASK_CELL_OVERLAP(TYPE, ARRAY, COUNT)                               \
  __attribute__((always_inline))                                            \
      INLINE static size_t task_cell_overlap_##TYPE(                        \
          const struct cell *restrict ci, const struct cell *restrict cj) { \
                                                                            \
    if (ci == NULL || cj == NULL) return 0;                                 \
                                                                            \
    if (ci->ARRAY <= cj->ARRAY &&                                           \
        ci->ARRAY + ci->COUNT >= cj->ARRAY + cj->COUNT) {                   \
      return cj->COUNT;                                                     \
    } else if (cj->ARRAY <= ci->ARRAY &&                                    \
               cj->ARRAY + cj->COUNT >= ci->ARRAY + ci->COUNT) {            \
      return ci->COUNT;                                                     \
    }                                                                       \
                                                                            \
    return 0;                                                               \
  }
97

Loic Hausammann's avatar
Loic Hausammann committed
98
99
100
101
TASK_CELL_OVERLAP(part, parts, count);
TASK_CELL_OVERLAP(gpart, gparts, gcount);
TASK_CELL_OVERLAP(spart, sparts, scount);

102
103
104
105
106
/**
 * @brief Returns the #task_actions for a given task.
 *
 * @param t The #task.
 */
107
108
__attribute__((always_inline)) INLINE static enum task_actions task_acts_on(
    const struct task *t) {
109
110
111
112
113
114
115

  switch (t->type) {

    case task_type_none:
      return task_action_none;
      break;

116
    case task_type_drift_part:
117
118
    case task_type_sort:
    case task_type_ghost:
119
    case task_type_extra_ghost:
Stefan Arridge's avatar
Stefan Arridge committed
120
    case task_type_cooling:
121
    case task_type_sourceterms:
122
123
124
      return task_action_part;
      break;

125
    case task_type_stars_ghost:
Loic Hausammann's avatar
Loic Hausammann committed
126
127
128
      return task_action_spart;
      break;

129
130
131
132
133
134
135
    case task_type_self:
    case task_type_pair:
    case task_type_sub_self:
    case task_type_sub_pair:
      switch (t->subtype) {

        case task_subtype_density:
136
        case task_subtype_gradient:
137
138
139
140
        case task_subtype_force:
          return task_action_part;
          break;

141
        case task_subtype_stars_density:
142
143
          return task_action_all;
          break;
144

145
        case task_subtype_grav:
146
        case task_subtype_external_grav:
147
148
149
150
151
152
153
154
155
156
          return task_action_gpart;
          break;

        default:
          error("Unknow task_action for task");
          return task_action_none;
          break;
      }
      break;

157
    case task_type_end_force:
158
159
    case task_type_kick1:
    case task_type_kick2:
160
    case task_type_timestep:
161
162
    case task_type_send:
    case task_type_recv:
163
164
165
166
167
168
169
170
      if (t->ci->count > 0 && t->ci->gcount > 0)
        return task_action_all;
      else if (t->ci->count > 0)
        return task_action_part;
      else if (t->ci->gcount > 0)
        return task_action_gpart;
      else
        error("Task without particles");
171
172
      break;

173
    case task_type_init_grav:
174
175
176
177
    case task_type_grav_mm:
      return task_action_multipole;
      break;

178
    case task_type_drift_gpart:
179
    case task_type_grav_down:
180
    case task_type_grav_mesh:
181
    case task_type_grav_long_range:
182
      return task_action_gpart;
183
      break;
184

185
    default:
186
      error("Unknown task_action for task");
187
188
189
      return task_action_none;
      break;
  }
190

191
  /* Silence compiler warnings */
192
193
  error("Unknown task_action for task");
  return task_action_none;
194
195
}

196
197
198
199
200
201
202
/**
 * @brief Compute the Jaccard similarity of the data used by two
 *        different tasks.
 *
 * @param ta The first #task.
 * @param tb The second #task.
 */
203
204
float task_overlap(const struct task *restrict ta,
                   const struct task *restrict tb) {
205
206
207
208
209
210

  if (ta == NULL || tb == NULL) return 0.f;

  const enum task_actions ta_act = task_acts_on(ta);
  const enum task_actions tb_act = task_acts_on(tb);

211
212
  /* First check if any of the two tasks are of a type that don't
     use cells. */
213
214
215
216
217
  if (ta_act == task_action_none || tb_act == task_action_none) return 0.f;

  const int ta_part = (ta_act == task_action_part || ta_act == task_action_all);
  const int ta_gpart =
      (ta_act == task_action_gpart || ta_act == task_action_all);
218
219
  const int ta_spart =
      (ta_act == task_action_spart || ta_act == task_action_all);
220
221
222
  const int tb_part = (tb_act == task_action_part || tb_act == task_action_all);
  const int tb_gpart =
      (tb_act == task_action_gpart || tb_act == task_action_all);
223
224
  const int tb_spart =
      (tb_act == task_action_spart || tb_act == task_action_all);
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262

  /* In the case where both tasks act on parts */
  if (ta_part && tb_part) {

    /* Compute the union of the cell data. */
    size_t size_union = 0;
    if (ta->ci != NULL) size_union += ta->ci->count;
    if (ta->cj != NULL) size_union += ta->cj->count;
    if (tb->ci != NULL) size_union += tb->ci->count;
    if (tb->cj != NULL) size_union += tb->cj->count;

    /* Compute the intersection of the cell data. */
    const size_t size_intersect = task_cell_overlap_part(ta->ci, tb->ci) +
                                  task_cell_overlap_part(ta->ci, tb->cj) +
                                  task_cell_overlap_part(ta->cj, tb->ci) +
                                  task_cell_overlap_part(ta->cj, tb->cj);

    return ((float)size_intersect) / (size_union - size_intersect);
  }

  /* In the case where both tasks act on gparts */
  else if (ta_gpart && tb_gpart) {

    /* Compute the union of the cell data. */
    size_t size_union = 0;
    if (ta->ci != NULL) size_union += ta->ci->gcount;
    if (ta->cj != NULL) size_union += ta->cj->gcount;
    if (tb->ci != NULL) size_union += tb->ci->gcount;
    if (tb->cj != NULL) size_union += tb->cj->gcount;

    /* Compute the intersection of the cell data. */
    const size_t size_intersect = task_cell_overlap_gpart(ta->ci, tb->ci) +
                                  task_cell_overlap_gpart(ta->ci, tb->cj) +
                                  task_cell_overlap_gpart(ta->cj, tb->ci) +
                                  task_cell_overlap_gpart(ta->cj, tb->cj);

    return ((float)size_intersect) / (size_union - size_intersect);
  }
263

Loic Hausammann's avatar
Loic Hausammann committed
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
  /* In the case where both tasks act on sparts */
  else if (ta_spart && tb_spart) {

    /* Compute the union of the cell data. */
    size_t size_union = 0;
    if (ta->ci != NULL) size_union += ta->ci->scount;
    if (ta->cj != NULL) size_union += ta->cj->scount;
    if (tb->ci != NULL) size_union += tb->ci->scount;
    if (tb->cj != NULL) size_union += tb->cj->scount;

    /* Compute the intersection of the cell data. */
    const size_t size_intersect = task_cell_overlap_spart(ta->ci, tb->ci) +
                                  task_cell_overlap_spart(ta->ci, tb->cj) +
                                  task_cell_overlap_spart(ta->cj, tb->ci) +
                                  task_cell_overlap_spart(ta->cj, tb->cj);

    return ((float)size_intersect) / (size_union - size_intersect);
  }

283
284
  /* Else, no overlap */
  return 0.f;
285
}
286

287
288
/**
 * @brief Unlock the cell held by this task.
289
 *
290
291
 * @param t The #task.
 */
292
293
void task_unlock(struct task *t) {

294
295
  const enum task_types type = t->type;
  const enum task_subtypes subtype = t->subtype;
296
297
  struct cell *ci = t->ci, *cj = t->cj;

298
  /* Act based on task type. */
299
300
  switch (type) {

301
    case task_type_end_force:
302
303
304
    case task_type_kick1:
    case task_type_kick2:
    case task_type_timestep:
305
306
307
      cell_unlocktree(ci);
      cell_gunlocktree(ci);
      break;
Matthieu Schaller's avatar
Matthieu Schaller committed
308

309
    case task_type_drift_part:
310
    case task_type_sort:
311
312
313
      cell_unlocktree(ci);
      break;

314
    case task_type_drift_gpart:
315
    case task_type_grav_mesh:
316
317
318
      cell_gunlocktree(ci);
      break;

319
    case task_type_self:
320
    case task_type_sub_self:
321
322
      if (subtype == task_subtype_grav) {
        cell_gunlocktree(ci);
323
        cell_munlocktree(ci);
324
325
326
      } else {
        cell_unlocktree(ci);
      }
327
      break;
328

329
    case task_type_pair:
330
    case task_type_sub_pair:
331
332
333
      if (subtype == task_subtype_grav) {
        cell_gunlocktree(ci);
        cell_gunlocktree(cj);
334
335
        cell_munlocktree(ci);
        cell_munlocktree(cj);
336
337
338
339
340
341
      } else {
        cell_unlocktree(ci);
        cell_unlocktree(cj);
      }
      break;

342
    case task_type_grav_down:
343
      cell_gunlocktree(ci);
344
345
346
      cell_munlocktree(ci);
      break;

347
    case task_type_grav_long_range:
348
      cell_munlocktree(ci);
349
      break;
350

351
352
353
354
355
    case task_type_grav_mm:
      cell_munlocktree(ci);
      cell_munlocktree(cj);
      break;

356
357
358
359
    default:
      break;
  }
}
360
361
362
363
364
365

/**
 * @brief Try to lock the cells associated with this task.
 *
 * @param t the #task.
 */
366
367
int task_lock(struct task *t) {

368
369
  const enum task_types type = t->type;
  const enum task_subtypes subtype = t->subtype;
370
  struct cell *ci = t->ci, *cj = t->cj;
371
372
373
374
#ifdef WITH_MPI
  int res = 0, err = 0;
  MPI_Status stat;
#endif
375

376
  switch (type) {
377

378
379
380
    /* Communication task? */
    case task_type_recv:
    case task_type_send:
381
#ifdef WITH_MPI
382
383
384
385
386
      /* Check the status of the MPI request. */
      if ((err = MPI_Test(&t->req, &res, &stat)) != MPI_SUCCESS) {
        char buff[MPI_MAX_ERROR_STRING];
        int len;
        MPI_Error_string(err, buff, &len);
387
        error("Failed to test request on send/recv task (tag=%lld, %s).",
388
389
390
              t->flags, buff);
      }
      return res;
391
#else
392
      error("SWIFT was not compiled with MPI support.");
393
#endif
394
      break;
395

396
    case task_type_end_force:
397
398
399
    case task_type_kick1:
    case task_type_kick2:
    case task_type_timestep:
400
401
402
      if (ci->hold || ci->ghold) return 0;
      if (cell_locktree(ci) != 0) return 0;
      if (cell_glocktree(ci) != 0) {
Matthieu Schaller's avatar
Matthieu Schaller committed
403
404
        cell_unlocktree(ci);
        return 0;
405
406
407
      }
      break;

408
    case task_type_drift_part:
409
    case task_type_sort:
410
      if (ci->hold) return 0;
411
412
      if (cell_locktree(ci) != 0) return 0;
      break;
413

414
    case task_type_drift_gpart:
415
    case task_type_grav_mesh:
416
417
418
419
      if (ci->ghold) return 0;
      if (cell_glocktree(ci) != 0) return 0;
      break;

420
    case task_type_self:
421
    case task_type_sub_self:
422
      if (subtype == task_subtype_grav) {
423
424
425
426
427
428
429
430
        /* Lock the gparts and the m-pole */
        if (ci->ghold || ci->mhold) return 0;
        if (cell_glocktree(ci) != 0)
          return 0;
        else if (cell_mlocktree(ci) != 0) {
          cell_gunlocktree(ci);
          return 0;
        }
431
432
433
434
      } else {
        if (cell_locktree(ci) != 0) return 0;
      }
      break;
435

436
    case task_type_pair:
437
    case task_type_sub_pair:
438
      if (subtype == task_subtype_grav) {
439
        /* Lock the gparts and the m-pole in both cells */
440
441
442
443
444
        if (ci->ghold || cj->ghold) return 0;
        if (cell_glocktree(ci) != 0) return 0;
        if (cell_glocktree(cj) != 0) {
          cell_gunlocktree(ci);
          return 0;
445
446
447
448
449
450
451
452
453
        } else if (cell_mlocktree(ci) != 0) {
          cell_gunlocktree(ci);
          cell_gunlocktree(cj);
          return 0;
        } else if (cell_mlocktree(cj) != 0) {
          cell_gunlocktree(ci);
          cell_gunlocktree(cj);
          cell_munlocktree(ci);
          return 0;
454
455
        }
      } else {
456
        /* Lock the parts in both cells */
457
458
459
460
461
462
463
464
        if (ci->hold || cj->hold) return 0;
        if (cell_locktree(ci) != 0) return 0;
        if (cell_locktree(cj) != 0) {
          cell_unlocktree(ci);
          return 0;
        }
      }
      break;
465

466
467
468
469
470
471
472
473
474
475
476
    case task_type_grav_down:
      /* Lock the gparts and the m-poles */
      if (ci->ghold || ci->mhold) return 0;
      if (cell_glocktree(ci) != 0)
        return 0;
      else if (cell_mlocktree(ci) != 0) {
        cell_gunlocktree(ci);
        return 0;
      }
      break;

477
    case task_type_grav_long_range:
478
479
480
      /* Lock the m-poles */
      if (ci->mhold) return 0;
      if (cell_mlocktree(ci) != 0) return 0;
Matthieu Schaller's avatar
Matthieu Schaller committed
481
482
      break;

483
484
485
486
487
488
489
490
491
    case task_type_grav_mm:
      /* Lock both m-poles */
      if (ci->mhold || cj->mhold) return 0;
      if (cell_mlocktree(ci) != 0) return 0;
      if (cell_mlocktree(cj) != 0) {
        cell_munlocktree(ci);
        return 0;
      }

492
493
    default:
      break;
494
495
496
497
498
  }

  /* If we made it this far, we've got a lock. */
  return 1;
}
499

500
501
502
503
504
505
506
507
508
509
510
/**
 * @brief Print basic information about a task.
 *
 * @param t The #task.
 */
void task_print(const struct task *t) {

  message("Type:'%s' sub_type:'%s' wait=%d nr_unlocks=%d skip=%d",
          taskID_names[t->type], subtaskID_names[t->subtype], t->wait,
          t->nr_unlock_tasks, t->skip);
}
511
512
513
514
515
516
517
518
519
520
521

#ifdef WITH_MPI
/**
 * @brief Create global communicators for each of the subtasks.
 */
void task_create_mpi_comms(void) {
  for (int i = 0; i < task_subtype_count; i++) {
    MPI_Comm_dup(MPI_COMM_WORLD, &subtaskMPI_comms[i]);
  }
}
#endif