task.c 16.8 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. */
Loic Hausammann's avatar
Format    
Loic Hausammann committed
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
const char *taskID_names[task_type_count] = {"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",
                                             "star_formation",
                                             "sourceterms",
                                             "stars_ghost_in",
                                             "stars_ghost",
                                             "stars_ghost_out",
                                             "logger"};
82

83
/* Sub-task type names. */
84
const char *subtaskID_names[task_subtype_count] = {
85
86
87
    "none",          "density", "gradient",     "force", "grav",
    "external_grav", "tend",    "xv",           "rho",   "gpart",
    "multipole",     "spart",   "stars_density"};
88

89
90
91
92
93
#ifdef WITH_MPI
/* MPI communicators for the subtypes. */
MPI_Comm subtaskMPI_comms[task_subtype_count];
#endif

94
95
/**
 * @brief Computes the overlap between the parts array of two given cells.
96
 *
Matthieu Schaller's avatar
Matthieu Schaller committed
97
98
99
 * @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.
100
 */
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#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;                                                               \
  }
118

119
TASK_CELL_OVERLAP(part, hydro.parts, hydro.count);
120
121
TASK_CELL_OVERLAP(gpart, grav.parts, grav.count);
TASK_CELL_OVERLAP(spart, stars.parts, stars.count);
Loic Hausammann's avatar
Loic Hausammann committed
122

123
124
125
126
127
/**
 * @brief Returns the #task_actions for a given task.
 *
 * @param t The #task.
 */
128
129
__attribute__((always_inline)) INLINE static enum task_actions task_acts_on(
    const struct task *t) {
130
131
132
133
134
135
136

  switch (t->type) {

    case task_type_none:
      return task_action_none;
      break;

137
    case task_type_drift_part:
138
139
    case task_type_sort:
    case task_type_ghost:
140
    case task_type_extra_ghost:
Stefan Arridge's avatar
Stefan Arridge committed
141
    case task_type_cooling:
142
    case task_type_sourceterms:
143
144
145
      return task_action_part;
      break;

146
147
148
    case task_type_star_formation:
      return task_action_all;

149
    case task_type_stars_ghost:
Loic Hausammann's avatar
Loic Hausammann committed
150
151
152
      return task_action_spart;
      break;

153
154
155
156
157
158
159
    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:
160
        case task_subtype_gradient:
161
162
163
164
        case task_subtype_force:
          return task_action_part;
          break;

165
        case task_subtype_stars_density:
166
167
          return task_action_all;
          break;
168

169
        case task_subtype_grav:
170
        case task_subtype_external_grav:
171
172
173
174
175
176
177
178
179
180
          return task_action_gpart;
          break;

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

181
    case task_type_end_force:
182
183
    case task_type_kick1:
    case task_type_kick2:
Loikki's avatar
Loikki committed
184
    case task_type_logger:
185
    case task_type_timestep:
186
187
    case task_type_send:
    case task_type_recv:
188
      if (t->ci->hydro.count > 0 && t->ci->grav.count > 0)
189
        return task_action_all;
190
      else if (t->ci->hydro.count > 0)
191
        return task_action_part;
192
      else if (t->ci->grav.count > 0)
193
194
195
        return task_action_gpart;
      else
        error("Task without particles");
196
197
      break;

198
    case task_type_init_grav:
199
    case task_type_grav_mm:
200
    case task_type_grav_long_range:
201
202
203
      return task_action_multipole;
      break;

204
    case task_type_drift_gpart:
205
    case task_type_grav_down:
206
    case task_type_grav_mesh:
207
      return task_action_gpart;
208
      break;
209

210
    default:
211
      error("Unknown task_action for task");
212
213
214
      return task_action_none;
      break;
  }
215

216
  /* Silence compiler warnings */
217
218
  error("Unknown task_action for task");
  return task_action_none;
219
220
}

221
222
223
224
225
226
227
/**
 * @brief Compute the Jaccard similarity of the data used by two
 *        different tasks.
 *
 * @param ta The first #task.
 * @param tb The second #task.
 */
228
229
float task_overlap(const struct task *restrict ta,
                   const struct task *restrict tb) {
230
231
232
233
234
235

  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);

236
237
  /* First check if any of the two tasks are of a type that don't
     use cells. */
238
239
240
241
242
  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);
243
244
  const int ta_spart =
      (ta_act == task_action_spart || ta_act == task_action_all);
245
246
247
  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);
248
249
  const int tb_spart =
      (tb_act == task_action_spart || tb_act == task_action_all);
250
251
252
253
254
255

  /* 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;
256
257
258
259
    if (ta->ci != NULL) size_union += ta->ci->hydro.count;
    if (ta->cj != NULL) size_union += ta->cj->hydro.count;
    if (tb->ci != NULL) size_union += tb->ci->hydro.count;
    if (tb->cj != NULL) size_union += tb->cj->hydro.count;
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274

    /* 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;
275
276
277
278
    if (ta->ci != NULL) size_union += ta->ci->grav.count;
    if (ta->cj != NULL) size_union += ta->cj->grav.count;
    if (tb->ci != NULL) size_union += tb->ci->grav.count;
    if (tb->cj != NULL) size_union += tb->cj->grav.count;
279
280
281
282
283
284
285
286
287

    /* 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);
  }
288

Loic Hausammann's avatar
Loic Hausammann committed
289
290
291
292
293
  /* 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;
294
295
296
297
    if (ta->ci != NULL) size_union += ta->ci->stars.count;
    if (ta->cj != NULL) size_union += ta->cj->stars.count;
    if (tb->ci != NULL) size_union += tb->ci->stars.count;
    if (tb->cj != NULL) size_union += tb->cj->stars.count;
Loic Hausammann's avatar
Loic Hausammann committed
298
299
300
301
302
303
304
305
306
307

    /* 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);
  }

308
309
  /* Else, no overlap */
  return 0.f;
310
}
311

312
313
/**
 * @brief Unlock the cell held by this task.
314
 *
315
316
 * @param t The #task.
 */
317
318
void task_unlock(struct task *t) {

319
320
  const enum task_types type = t->type;
  const enum task_subtypes subtype = t->subtype;
321
322
  struct cell *ci = t->ci, *cj = t->cj;

323
  /* Act based on task type. */
324
325
  switch (type) {

326
    case task_type_end_force:
327
    case task_type_kick1:
Loikki's avatar
Loikki committed
328
    case task_type_logger:
329
330
    case task_type_kick2:
    case task_type_timestep:
331
332
333
      cell_unlocktree(ci);
      cell_gunlocktree(ci);
      break;
Matthieu Schaller's avatar
Matthieu Schaller committed
334

335
    case task_type_drift_part:
336
    case task_type_sort:
337
338
339
      cell_unlocktree(ci);
      break;

340
    case task_type_drift_gpart:
341
    case task_type_grav_mesh:
342
343
344
      cell_gunlocktree(ci);
      break;

345
    case task_type_self:
346
    case task_type_sub_self:
347
348
      if (subtype == task_subtype_grav) {
        cell_gunlocktree(ci);
349
        cell_munlocktree(ci);
350
351
352
      } else {
        cell_unlocktree(ci);
      }
353
      break;
354

355
    case task_type_pair:
356
    case task_type_sub_pair:
357
358
359
      if (subtype == task_subtype_grav) {
        cell_gunlocktree(ci);
        cell_gunlocktree(cj);
360
361
        cell_munlocktree(ci);
        cell_munlocktree(cj);
362
363
364
365
366
367
      } else {
        cell_unlocktree(ci);
        cell_unlocktree(cj);
      }
      break;

368
    case task_type_grav_down:
369
      cell_gunlocktree(ci);
370
371
372
      cell_munlocktree(ci);
      break;

373
    case task_type_grav_long_range:
374
      cell_munlocktree(ci);
375
      break;
376

377
378
379
380
381
    case task_type_grav_mm:
      cell_munlocktree(ci);
      cell_munlocktree(cj);
      break;

382
383
384
385
    default:
      break;
  }
}
386
387
388
389
390
391

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

394
395
  const enum task_types type = t->type;
  const enum task_subtypes subtype = t->subtype;
396
  struct cell *ci = t->ci, *cj = t->cj;
397
398
399
400
#ifdef WITH_MPI
  int res = 0, err = 0;
  MPI_Status stat;
#endif
401

402
  switch (type) {
403

404
405
406
    /* Communication task? */
    case task_type_recv:
    case task_type_send:
407
#ifdef WITH_MPI
408
409
410
411
412
      /* 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);
413
        error("Failed to test request on send/recv task (tag=%lld, %s).",
414
415
416
              t->flags, buff);
      }
      return res;
417
#else
418
      error("SWIFT was not compiled with MPI support.");
419
#endif
420
      break;
421

422
    case task_type_end_force:
423
424
    case task_type_kick1:
    case task_type_kick2:
Loikki's avatar
Loikki committed
425
    case task_type_logger:
426
    case task_type_timestep:
427
      if (ci->hydro.hold || ci->grav.phold) return 0;
428
429
      if (cell_locktree(ci) != 0) return 0;
      if (cell_glocktree(ci) != 0) {
Matthieu Schaller's avatar
Matthieu Schaller committed
430
431
        cell_unlocktree(ci);
        return 0;
432
433
434
      }
      break;

435
    case task_type_drift_part:
436
    case task_type_sort:
437
      if (ci->hydro.hold) return 0;
438
439
      if (cell_locktree(ci) != 0) return 0;
      break;
440

441
    case task_type_drift_gpart:
442
    case task_type_grav_mesh:
443
      if (ci->grav.phold) return 0;
444
445
446
      if (cell_glocktree(ci) != 0) return 0;
      break;

447
    case task_type_self:
448
    case task_type_sub_self:
449
      if (subtype == task_subtype_grav) {
450
        /* Lock the gparts and the m-pole */
451
        if (ci->grav.phold || ci->grav.mhold) return 0;
452
453
454
455
456
457
        if (cell_glocktree(ci) != 0)
          return 0;
        else if (cell_mlocktree(ci) != 0) {
          cell_gunlocktree(ci);
          return 0;
        }
458
459
460
461
      } else {
        if (cell_locktree(ci) != 0) return 0;
      }
      break;
462

463
    case task_type_pair:
464
    case task_type_sub_pair:
465
      if (subtype == task_subtype_grav) {
466
        /* Lock the gparts and the m-pole in both cells */
467
        if (ci->grav.phold || cj->grav.phold) return 0;
468
469
470
471
        if (cell_glocktree(ci) != 0) return 0;
        if (cell_glocktree(cj) != 0) {
          cell_gunlocktree(ci);
          return 0;
472
473
474
475
476
477
478
479
480
        } 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;
481
482
        }
      } else {
483
        /* Lock the parts in both cells */
484
        if (ci->hydro.hold || cj->hydro.hold) return 0;
485
486
487
488
489
490
491
        if (cell_locktree(ci) != 0) return 0;
        if (cell_locktree(cj) != 0) {
          cell_unlocktree(ci);
          return 0;
        }
      }
      break;
492

493
494
    case task_type_grav_down:
      /* Lock the gparts and the m-poles */
495
      if (ci->grav.phold || ci->grav.mhold) return 0;
496
497
498
499
500
501
502
503
      if (cell_glocktree(ci) != 0)
        return 0;
      else if (cell_mlocktree(ci) != 0) {
        cell_gunlocktree(ci);
        return 0;
      }
      break;

504
    case task_type_grav_long_range:
505
      /* Lock the m-poles */
506
      if (ci->grav.mhold) return 0;
507
      if (cell_mlocktree(ci) != 0) return 0;
Matthieu Schaller's avatar
Matthieu Schaller committed
508
509
      break;

510
511
    case task_type_grav_mm:
      /* Lock both m-poles */
512
      if (ci->grav.mhold || cj->grav.mhold) return 0;
513
514
515
516
517
518
      if (cell_mlocktree(ci) != 0) return 0;
      if (cell_mlocktree(cj) != 0) {
        cell_munlocktree(ci);
        return 0;
      }

519
520
    default:
      break;
521
522
523
524
525
  }

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

527
528
529
530
531
532
533
534
535
536
537
/**
 * @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);
}
538
539
540
541
542
543
544
545
546
547
548

#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