task.c 19.5 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
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",
                                             "drift_gpart_out",
                                             "end_force",
                                             "kick1",
                                             "kick2",
                                             "timestep",
                                             "send",
                                             "recv",
                                             "grav_long_range",
                                             "grav_mm",
                                             "grav_down_in",
                                             "grav_down",
                                             "grav_mesh",
                                             "cooling",
                                             "star_formation",
                                             "sourceterms",
                                             "logger",
                                             "stars_ghost_in",
                                             "stars_ghost",
Loic Hausammann's avatar
Loic Hausammann committed
82
83
                                             "stars_ghost_out",
                                             "stars_sort"};
84

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

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

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

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

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

  switch (t->type) {

    case task_type_none:
      return task_action_none;
      break;

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

148
149
150
    case task_type_star_formation:
      return task_action_all;

151
    case task_type_stars_ghost:
Loic Hausammann's avatar
Loic Hausammann committed
152
    case task_type_stars_sort:
Loic Hausammann's avatar
Loic Hausammann committed
153
154
155
      return task_action_spart;
      break;

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

168
        case task_subtype_stars_density:
169
170
          return task_action_all;
          break;
171

172
        case task_subtype_grav:
173
        case task_subtype_external_grav:
174
175
176
177
178
179
180
181
182
183
          return task_action_gpart;
          break;

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

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

201
    case task_type_init_grav:
202
    case task_type_grav_mm:
203
    case task_type_grav_long_range:
204
205
206
      return task_action_multipole;
      break;

207
    case task_type_drift_gpart:
208
    case task_type_grav_down:
209
    case task_type_grav_mesh:
210
      return task_action_gpart;
211
      break;
212

213
    default:
214
      error("Unknown task_action for task");
215
216
217
      return task_action_none;
      break;
  }
218

219
  /* Silence compiler warnings */
220
221
  error("Unknown task_action for task");
  return task_action_none;
222
223
}

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

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

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

  /* 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;
259
260
261
262
    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;
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277

    /* 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;
278
279
280
281
    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;
282
283
284
285
286
287
288
289
290

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

Loic Hausammann's avatar
Loic Hausammann committed
292
293
294
295
296
  /* 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;
297
298
299
300
    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
301
302
303
304
305
306
307
308
309
310

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

311
312
  /* Else, no overlap */
  return 0.f;
313
}
314

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

322
323
  const enum task_types type = t->type;
  const enum task_subtypes subtype = t->subtype;
324
325
  struct cell *ci = t->ci, *cj = t->cj;

326
  /* Act based on task type. */
327
328
  switch (type) {

329
    case task_type_end_force:
330
331
    case task_type_kick1:
    case task_type_kick2:
332
    case task_type_logger:
333
    case task_type_timestep:
334
335
336
      cell_unlocktree(ci);
      cell_gunlocktree(ci);
      break;
Matthieu Schaller's avatar
Matthieu Schaller committed
337

338
    case task_type_drift_part:
339
    case task_type_sort:
340
341
342
      cell_unlocktree(ci);
      break;

343
    case task_type_drift_gpart:
344
    case task_type_grav_mesh:
345
346
347
      cell_gunlocktree(ci);
      break;

Loic Hausammann's avatar
Loic Hausammann committed
348
349
350
351
    case task_type_stars_sort:
      cell_sunlocktree(ci);
      break;

352
    case task_type_self:
353
    case task_type_sub_self:
354
355
      if (subtype == task_subtype_grav) {
        cell_gunlocktree(ci);
356
        cell_munlocktree(ci);
Loic Hausammann's avatar
Loic Hausammann committed
357
358
      } else if (subtype == task_subtype_stars_density) {
        cell_sunlocktree(ci);
359
360
361
      } else {
        cell_unlocktree(ci);
      }
362
      break;
363

364
    case task_type_pair:
365
    case task_type_sub_pair:
366
367
368
      if (subtype == task_subtype_grav) {
        cell_gunlocktree(ci);
        cell_gunlocktree(cj);
369
370
        cell_munlocktree(ci);
        cell_munlocktree(cj);
Loic Hausammann's avatar
Loic Hausammann committed
371
372
373
      } else if (subtype == task_subtype_stars_density) {
        cell_sunlocktree(ci);
        cell_sunlocktree(cj);
374
375
376
377
378
379
      } else {
        cell_unlocktree(ci);
        cell_unlocktree(cj);
      }
      break;

380
    case task_type_grav_down:
381
      cell_gunlocktree(ci);
382
383
384
      cell_munlocktree(ci);
      break;

385
    case task_type_grav_long_range:
386
      cell_munlocktree(ci);
387
      break;
388

389
390
391
392
393
    case task_type_grav_mm:
      cell_munlocktree(ci);
      cell_munlocktree(cj);
      break;

394
395
396
397
    default:
      break;
  }
}
398
399
400
401
402
403

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

406
407
  const enum task_types type = t->type;
  const enum task_subtypes subtype = t->subtype;
408
  struct cell *ci = t->ci, *cj = t->cj;
409
410
411
412
#ifdef WITH_MPI
  int res = 0, err = 0;
  MPI_Status stat;
#endif
413

414
  switch (type) {
415

416
417
418
    /* Communication task? */
    case task_type_recv:
    case task_type_send:
419
#ifdef WITH_MPI
420
421
422
423
424
      /* 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);
425
426
427
428
        error(
            "Failed to test request on send/recv task (type=%s/%s tag=%lld, "
            "%s).",
            taskID_names[t->type], subtaskID_names[t->subtype], t->flags, buff);
429
430
      }
      return res;
431
#else
432
      error("SWIFT was not compiled with MPI support.");
433
#endif
434
      break;
435

436
    case task_type_end_force:
437
438
    case task_type_kick1:
    case task_type_kick2:
Loikki's avatar
Loikki committed
439
    case task_type_logger:
440
    case task_type_timestep:
441
      if (ci->hydro.hold || ci->grav.phold) return 0;
442
443
      if (cell_locktree(ci) != 0) return 0;
      if (cell_glocktree(ci) != 0) {
Matthieu Schaller's avatar
Matthieu Schaller committed
444
445
        cell_unlocktree(ci);
        return 0;
446
447
448
      }
      break;

449
    case task_type_drift_part:
450
    case task_type_sort:
451
      if (ci->hydro.hold) return 0;
452
453
      if (cell_locktree(ci) != 0) return 0;
      break;
454

Loic Hausammann's avatar
Loic Hausammann committed
455
456
457
458
459
    case task_type_stars_sort:
      if (ci->stars.hold) return 0;
      if (cell_slocktree(ci) != 0) return 0;
      break;

460
    case task_type_drift_gpart:
461
    case task_type_grav_mesh:
462
      if (ci->grav.phold) return 0;
463
464
465
      if (cell_glocktree(ci) != 0) return 0;
      break;

466
    case task_type_self:
467
    case task_type_sub_self:
468
      if (subtype == task_subtype_grav) {
469
        /* Lock the gparts and the m-pole */
470
        if (ci->grav.phold || ci->grav.mhold) return 0;
471
472
473
474
475
476
        if (cell_glocktree(ci) != 0)
          return 0;
        else if (cell_mlocktree(ci) != 0) {
          cell_gunlocktree(ci);
          return 0;
        }
Loic Hausammann's avatar
Loic Hausammann committed
477
478
479
      } else if (subtype == task_subtype_stars_density) {
        if (ci->stars.hold) return 0;
        if (cell_slocktree(ci) != 0) return 0;
480
      } else {
Loic Hausammann's avatar
Loic Hausammann committed
481
        if (ci->hydro.hold) return 0;
482
483
484
        if (cell_locktree(ci) != 0) return 0;
      }
      break;
485

486
    case task_type_pair:
487
    case task_type_sub_pair:
488
      if (subtype == task_subtype_grav) {
489
        /* Lock the gparts and the m-pole in both cells */
490
        if (ci->grav.phold || cj->grav.phold) return 0;
491
492
493
494
        if (cell_glocktree(ci) != 0) return 0;
        if (cell_glocktree(cj) != 0) {
          cell_gunlocktree(ci);
          return 0;
495
496
497
498
499
500
501
502
503
        } 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;
504
        }
Loic Hausammann's avatar
Loic Hausammann committed
505
506
507
508
509
510
511
      } else if (subtype == task_subtype_stars_density) {
        if (ci->stars.hold || cj->stars.hold) return 0;
        if (cell_slocktree(ci) != 0) return 0;
        if (cell_slocktree(cj) != 0) {
          cell_sunlocktree(ci);
          return 0;
        }
512
      } else {
513
        /* Lock the parts in both cells */
514
        if (ci->hydro.hold || cj->hydro.hold) return 0;
515
516
517
518
519
520
521
        if (cell_locktree(ci) != 0) return 0;
        if (cell_locktree(cj) != 0) {
          cell_unlocktree(ci);
          return 0;
        }
      }
      break;
522

523
524
    case task_type_grav_down:
      /* Lock the gparts and the m-poles */
525
      if (ci->grav.phold || ci->grav.mhold) return 0;
526
527
528
529
530
531
532
533
      if (cell_glocktree(ci) != 0)
        return 0;
      else if (cell_mlocktree(ci) != 0) {
        cell_gunlocktree(ci);
        return 0;
      }
      break;

534
    case task_type_grav_long_range:
535
      /* Lock the m-poles */
536
      if (ci->grav.mhold) return 0;
537
      if (cell_mlocktree(ci) != 0) return 0;
Matthieu Schaller's avatar
Matthieu Schaller committed
538
539
      break;

540
541
    case task_type_grav_mm:
      /* Lock both m-poles */
542
      if (ci->grav.mhold || cj->grav.mhold) return 0;
543
544
545
546
547
548
      if (cell_mlocktree(ci) != 0) return 0;
      if (cell_mlocktree(cj) != 0) {
        cell_munlocktree(ci);
        return 0;
      }

549
550
    default:
      break;
551
552
553
554
555
  }

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

557
558
559
560
561
562
563
564
565
566
567
/**
 * @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);
}
568

569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
/**
 * @brief Get the group name of a task.
 *
 * This is used to group tasks with similar actions in the task dependency
 * graph.
 *
 * @param t The #task.
 * @param group (return) The group name (should be allocated)
 */
void task_get_group_name(const struct task *t, char *cluster) {

  if (t->type == task_type_grav_long_range || t->type == task_type_grav_mm ||
      t->type == task_type_grav_mesh) {

    strcpy(cluster, "Gravity");
    return;
  }

  switch (t->subtype) {
    case task_subtype_density:
      strcpy(cluster, "Density");
      break;
    case task_subtype_gradient:
      strcpy(cluster, "Gradient");
      break;
    case task_subtype_force:
      strcpy(cluster, "Force");
      break;
    case task_subtype_grav:
      strcpy(cluster, "Gravity");
      break;
    case task_subtype_stars_density:
      strcpy(cluster, "Stars");
      break;
    default:
      strcpy(cluster, "None");
      break;
  }
}

/**
 * @brief Generate the full name of a #task.
 *
 * @param type The #task type.
 * @param subtype The #task type.
 * @param name (return) The formatted string
 */
void task_get_full_name(enum task_types type, enum task_subtypes subtype,
                        char *name) {

#ifdef SWIFT_DEBUG_CHECKS
  /* Check input */
  if ((type < 0) || (type >= task_type_count))
    error("Unknown task type %i", type);

  if ((subtype < 0) || (subtype >= task_subtype_count))
    error("Unknown task subtype %i with type %s", subtype, taskID_names[type]);
#endif

  /* Full task name */
  if (subtype == task_subtype_none)
    sprintf(name, "%s", taskID_names[type]);
  else
    sprintf(name, "%s_%s", taskID_names[type], subtaskID_names[subtype]);
}

635
636
637
638
639
640
641
642
643
644
#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