scheduler.c 55.8 KB
Newer Older
1
2
/*******************************************************************************
 * This file is part of SWIFT.
3
 * Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk)
4
 *                    Matthieu Schaller (matthieu.schaller@durham.ac.uk)
5
 *               2016 Peter W. Draper (p.w.draper@durham.ac.uk)
6
 *
7
8
9
10
 * 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.
11
 *
12
13
14
15
 * 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.
16
 *
17
18
 * 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/>.
19
 *
20
21
22
23
24
25
 ******************************************************************************/

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

/* Some standard headers. */
26
27
28
#include <limits.h>
#include <math.h>
#include <pthread.h>
29
30
31
32
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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

38
39
40
/* This object's header. */
#include "scheduler.h"

41
42
/* Local headers. */
#include "atomic.h"
43
#include "cycle.h"
44
#include "engine.h"
45
#include "error.h"
46
#include "intrinsics.h"
47
#include "kernel_hydro.h"
48
#include "queue.h"
49
#include "sort_part.h"
50
51
#include "space.h"
#include "task.h"
52
#include "timers.h"
53
#include "tools.h"
54

55
56
57
58
59
/**
 * @brief Re-set the list of active tasks.
 */
void scheduler_clear_active(struct scheduler *s) { s->active_count = 0; }

60
61
62
63
64
65
66
/**
 * @brief Add an unlock_task to the given task.
 *
 * @param s The #scheduler.
 * @param ta The unlocking #task.
 * @param tb The #task that will be unlocked.
 */
67
68
void scheduler_addunlock(struct scheduler *s, struct task *ta,
                         struct task *tb) {
69
70
71
72
73
#ifdef SWIFT_DEBUG_CHECKS
  if (ta == NULL) error("Unlocking task is NULL.");
  if (tb == NULL) error("Unlocked task is NULL.");
#endif

74
75
76
77
78
  /* Get an index at which to store this unlock. */
  const int ind = atomic_inc(&s->nr_unlocks);

  /* Does the buffer need to be grown? */
  if (ind == s->size_unlocks) {
79
    /* Allocate the new buffer. */
80
81
82
    struct task **unlocks_new;
    int *unlock_ind_new;
    const int size_unlocks_new = s->size_unlocks * 2;
83
84
    if ((unlocks_new = (struct task **)malloc(sizeof(struct task *) *
                                              size_unlocks_new)) == NULL ||
85
86
        (unlock_ind_new = (int *)malloc(sizeof(int) * size_unlocks_new)) ==
            NULL)
87
      error("Failed to re-allocate unlocks.");
88

89
    /* Wait for all writes to the old buffer to complete. */
90
91
92
    while (s->completed_unlock_writes < ind)
      ;

93
    /* Copy the buffers. */
94
95
96
97
98
99
    memcpy(unlocks_new, s->unlocks, sizeof(struct task *) * ind);
    memcpy(unlock_ind_new, s->unlock_ind, sizeof(int) * ind);
    free(s->unlocks);
    free(s->unlock_ind);
    s->unlocks = unlocks_new;
    s->unlock_ind = unlock_ind_new;
100

101
    /* Publish the new buffer size. */
102
103
    s->size_unlocks = size_unlocks_new;
  }
104

105
  /* Wait for there to actually be space at my index. */
106
107
  while (ind > s->size_unlocks)
    ;
108
109
110
111

  /* Write the unlock to the scheduler. */
  s->unlocks[ind] = tb;
  s->unlock_ind[ind] = ta - s->tasks;
112
  atomic_inc(&s->completed_unlock_writes);
lhausamm's avatar
lhausamm committed
113
114
115

}

116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
void scheduler_write_dependency(struct scheduler *s) {

  message("Writing dependencies");
  
  char filename[200] = "dependency_graph.dot";
  char tmp[200]; /* text to write */
  char *line = NULL; /* buff for reading line */
  size_t len = 0;
  ssize_t read;
  FILE *f; /* file containing the output */
  int test;
  int i,j;

  struct task *ta, *tb;

  /* create file */
  f = open_and_check_file(filename, "w");

  /* write header */
  fprintf(f, "digraph task_dep {\n");
  fprintf(f, "\t compound=true;\n");
  fprintf(f, "\t ratio=0.66;\n");
  fprintf(f, "\t node[nodesep=0.15];\n");

  fclose(f);
  
  /* loop over all tasks */
  for(i=0; i < s->nr_tasks; i++)
144
    {
145
146
147
148
      ta = &s->tasks[i];

      /* and theirs dependencies */
      for(j=0; j < ta->nr_unlock_tasks; j++)
149
	{
150
151
152
153
154
155
156
157
158
159
160
161
162
	  tb = ta->unlock_tasks[j];

	  /* construct line */
	  sprintf(tmp, "\t %s_%s->%s_%s;\n",
		  taskID_names[ta->type],
		  subtaskID_names[ta->subtype],
		  taskID_names[tb->type],
		  subtaskID_names[tb->subtype]
		  );

	  f = open_and_check_file(filename, "r");

	  /* check if dependency already written */
163
	  test = 1;
164
	  /* loop over all lines */
165
166
	  while (test && (read = getline(&line, &len, f)) != -1)
	    {
167
	      /* check if line == dependency word */
168
	      if (strcmp(tmp, line) == 0)
169
		  test = 0;	      
170
171
172
173
	    }

	  fclose(f);

174
175
176
177
178
179
180
181
182
	  
	  /* Not written yet => write it */
	  if (test)
	    {
	      f = open_and_check_file(filename, "a");
	      fprintf(f, tmp);
	      fclose(f);	  
	    }
	}      
183
    }
lhausamm's avatar
lhausamm committed
184

185
186
187
  f = open_and_check_file(filename, "a");
  fprintf(f, "}");
  fclose(f);
188
189
}

190
/**
191
 * @brief Split a hydrodynamic task if too large.
192
 *
193
194
 * @param t The #task
 * @param s The #scheduler we are working in.
195
 */
196
static void scheduler_splittask_hydro(struct task *t, struct scheduler *s) {
197

198
199
200
  /* Iterate on this task until we're done with it. */
  int redo = 1;
  while (redo) {
201

202
203
    /* Reset the redo flag. */
    redo = 0;
204

205
    /* Non-splittable task? */
206
207
    if ((t->ci == NULL) || (t->type == task_type_pair && t->cj == NULL) ||
        t->ci->count == 0 || (t->cj != NULL && t->cj->count == 0)) {
208
      t->type = task_type_none;
209
210
      t->subtype = task_subtype_none;
      t->cj = NULL;
211
212
213
      t->skip = 1;
      break;
    }
214

215
216
    /* Self-interaction? */
    if (t->type == task_type_self) {
217

218
219
220
221
222
      /* Get a handle on the cell involved. */
      struct cell *ci = t->ci;

      /* Foreign task? */
      if (ci->nodeID != s->nodeID) {
223
        t->skip = 1;
224
        break;
225
226
      }

227
      /* Is this cell even split and the task does not violate h ? */
228
      if (cell_can_split_self_task(ci)) {
229

230
        /* Make a sub? */
231
        if (scheduler_dosub && ci->count < space_subsize_self) {
232

233
234
235
236
237
          /* convert to a self-subtask. */
          t->type = task_type_sub_self;

          /* Otherwise, make tasks explicitly. */
        } else {
238

239
240
241
242
243
244
245
246
          /* Take a step back (we're going to recycle the current task)... */
          redo = 1;

          /* Add the self tasks. */
          int first_child = 0;
          while (ci->progeny[first_child] == NULL) first_child++;
          t->ci = ci->progeny[first_child];
          for (int k = first_child + 1; k < 8; k++)
247
            if (ci->progeny[k] != NULL && ci->progeny[k]->count)
248
              scheduler_splittask_hydro(
249
                  scheduler_addtask(s, task_type_self, t->subtype, 0, 0,
250
                                    ci->progeny[k], NULL),
251
252
                  s);

253
254
          /* Make a task for each pair of progeny */
          for (int j = 0; j < 8; j++)
255
            if (ci->progeny[j] != NULL && ci->progeny[j]->count)
256
              for (int k = j + 1; k < 8; k++)
257
                if (ci->progeny[k] != NULL && ci->progeny[k]->count)
258
259
                  scheduler_splittask_hydro(
                      scheduler_addtask(s, task_type_pair, t->subtype,
260
                                        sub_sid_flag[j][k], 0, ci->progeny[j],
261
262
                                        ci->progeny[k]),
                      s);
263
        }
264
      } /* Cell is split */
265

266
    } /* Self interaction */
267

268
269
    /* Pair interaction? */
    else if (t->type == task_type_pair) {
270

271
272
273
      /* Get a handle on the cells involved. */
      struct cell *ci = t->ci;
      struct cell *cj = t->cj;
274

275
276
277
278
279
      /* Foreign task? */
      if (ci->nodeID != s->nodeID && cj->nodeID != s->nodeID) {
        t->skip = 1;
        break;
      }
280

281
282
283
      /* Get the sort ID, use space_getsid and not t->flags
         to make sure we get ci and cj swapped if needed. */
      double shift[3];
Matthieu Schaller's avatar
Matthieu Schaller committed
284
      const int sid = space_getsid(s->space, &ci, &cj, shift);
285

286
      /* Should this task be split-up? */
287
      if (cell_can_split_pair_task(ci) && cell_can_split_pair_task(cj)) {
288
289

        /* Replace by a single sub-task? */
290
291
        if (scheduler_dosub && /* Use division to avoid integer overflow. */
            ci->count * sid_scale[sid] < space_subsize_pair / cj->count &&
292
            !sort_is_corner(sid)) {
293
294
295
296
297

          /* Make this task a sub task. */
          t->type = task_type_sub_pair;

          /* Otherwise, split it. */
298
299
        } else {

300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
          /* Take a step back (we're going to recycle the current task)... */
          redo = 1;

          /* For each different sorting type... */
          switch (sid) {

            case 0: /* (  1 ,  1 ,  1 ) */
              t->ci = ci->progeny[7];
              t->cj = cj->progeny[0];
              t->flags = 0;
              break;

            case 1: /* (  1 ,  1 ,  0 ) */
              t->ci = ci->progeny[6];
              t->cj = cj->progeny[0];
              t->flags = 1;
316
              scheduler_splittask_hydro(
317
                  scheduler_addtask(s, task_type_pair, t->subtype, 1, 0,
318
                                    ci->progeny[7], cj->progeny[1]),
319
                  s);
320
              scheduler_splittask_hydro(
321
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
322
                                    ci->progeny[6], cj->progeny[1]),
323
                  s);
324
              scheduler_splittask_hydro(
325
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
326
                                    ci->progeny[7], cj->progeny[0]),
327
328
329
330
331
332
333
334
335
336
337
338
339
                  s);
              break;

            case 2: /* (  1 ,  1 , -1 ) */
              t->ci = ci->progeny[6];
              t->cj = cj->progeny[1];
              t->flags = 2;
              break;

            case 3: /* (  1 ,  0 ,  1 ) */
              t->ci = ci->progeny[5];
              t->cj = cj->progeny[0];
              t->flags = 3;
340
              scheduler_splittask_hydro(
341
                  scheduler_addtask(s, task_type_pair, t->subtype, 3, 0,
342
                                    ci->progeny[7], cj->progeny[2]),
343
                  s);
344
              scheduler_splittask_hydro(
345
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
346
                                    ci->progeny[5], cj->progeny[2]),
347
                  s);
348
              scheduler_splittask_hydro(
349
                  scheduler_addtask(s, task_type_pair, t->subtype, 6, 0,
350
                                    ci->progeny[7], cj->progeny[0]),
351
352
353
354
355
356
357
                  s);
              break;

            case 4: /* (  1 ,  0 ,  0 ) */
              t->ci = ci->progeny[4];
              t->cj = cj->progeny[0];
              t->flags = 4;
358
              scheduler_splittask_hydro(
359
                  scheduler_addtask(s, task_type_pair, t->subtype, 5, 0,
360
                                    ci->progeny[5], cj->progeny[0]),
361
                  s);
362
              scheduler_splittask_hydro(
363
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
364
                                    ci->progeny[6], cj->progeny[0]),
365
                  s);
366
              scheduler_splittask_hydro(
367
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
368
                                    ci->progeny[7], cj->progeny[0]),
369
                  s);
370
              scheduler_splittask_hydro(
371
                  scheduler_addtask(s, task_type_pair, t->subtype, 3, 0,
372
                                    ci->progeny[4], cj->progeny[1]),
373
                  s);
374
              scheduler_splittask_hydro(
375
                  scheduler_addtask(s, task_type_pair, t->subtype, 4, 0,
376
                                    ci->progeny[5], cj->progeny[1]),
377
                  s);
378
              scheduler_splittask_hydro(
379
                  scheduler_addtask(s, task_type_pair, t->subtype, 6, 0,
380
                                    ci->progeny[6], cj->progeny[1]),
381
                  s);
382
              scheduler_splittask_hydro(
383
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
384
                                    ci->progeny[7], cj->progeny[1]),
385
                  s);
386
              scheduler_splittask_hydro(
387
                  scheduler_addtask(s, task_type_pair, t->subtype, 1, 0,
388
                                    ci->progeny[4], cj->progeny[2]),
389
                  s);
390
              scheduler_splittask_hydro(
391
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
392
                                    ci->progeny[5], cj->progeny[2]),
393
                  s);
394
              scheduler_splittask_hydro(
395
                  scheduler_addtask(s, task_type_pair, t->subtype, 4, 0,
396
                                    ci->progeny[6], cj->progeny[2]),
397
                  s);
398
              scheduler_splittask_hydro(
399
                  scheduler_addtask(s, task_type_pair, t->subtype, 5, 0,
400
                                    ci->progeny[7], cj->progeny[2]),
401
                  s);
402
              scheduler_splittask_hydro(
403
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
404
                                    ci->progeny[4], cj->progeny[3]),
405
                  s);
406
              scheduler_splittask_hydro(
407
                  scheduler_addtask(s, task_type_pair, t->subtype, 1, 0,
408
                                    ci->progeny[5], cj->progeny[3]),
409
                  s);
410
              scheduler_splittask_hydro(
411
                  scheduler_addtask(s, task_type_pair, t->subtype, 3, 0,
412
                                    ci->progeny[6], cj->progeny[3]),
413
                  s);
414
              scheduler_splittask_hydro(
415
                  scheduler_addtask(s, task_type_pair, t->subtype, 4, 0,
416
                                    ci->progeny[7], cj->progeny[3]),
417
418
419
420
421
422
423
                  s);
              break;

            case 5: /* (  1 ,  0 , -1 ) */
              t->ci = ci->progeny[4];
              t->cj = cj->progeny[1];
              t->flags = 5;
424
              scheduler_splittask_hydro(
425
                  scheduler_addtask(s, task_type_pair, t->subtype, 5, 0,
426
                                    ci->progeny[6], cj->progeny[3]),
427
                  s);
428
              scheduler_splittask_hydro(
429
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
430
                                    ci->progeny[4], cj->progeny[3]),
431
                  s);
432
              scheduler_splittask_hydro(
433
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
434
                                    ci->progeny[6], cj->progeny[1]),
435
436
437
438
439
440
441
442
443
444
445
446
447
                  s);
              break;

            case 6: /* (  1 , -1 ,  1 ) */
              t->ci = ci->progeny[5];
              t->cj = cj->progeny[2];
              t->flags = 6;
              break;

            case 7: /* (  1 , -1 ,  0 ) */
              t->ci = ci->progeny[4];
              t->cj = cj->progeny[3];
              t->flags = 6;
448
              scheduler_splittask_hydro(
449
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
450
                                    ci->progeny[5], cj->progeny[2]),
451
                  s);
452
              scheduler_splittask_hydro(
453
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
454
                                    ci->progeny[4], cj->progeny[2]),
455
                  s);
456
              scheduler_splittask_hydro(
457
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
458
                                    ci->progeny[5], cj->progeny[3]),
459
460
461
462
463
464
465
466
467
468
469
470
471
                  s);
              break;

            case 8: /* (  1 , -1 , -1 ) */
              t->ci = ci->progeny[4];
              t->cj = cj->progeny[3];
              t->flags = 8;
              break;

            case 9: /* (  0 ,  1 ,  1 ) */
              t->ci = ci->progeny[3];
              t->cj = cj->progeny[0];
              t->flags = 9;
472
              scheduler_splittask_hydro(
473
                  scheduler_addtask(s, task_type_pair, t->subtype, 9, 0,
474
                                    ci->progeny[7], cj->progeny[4]),
475
                  s);
476
              scheduler_splittask_hydro(
477
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
478
                                    ci->progeny[3], cj->progeny[4]),
479
                  s);
480
              scheduler_splittask_hydro(
481
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
482
                                    ci->progeny[7], cj->progeny[0]),
483
484
485
486
487
488
489
                  s);
              break;

            case 10: /* (  0 ,  1 ,  0 ) */
              t->ci = ci->progeny[2];
              t->cj = cj->progeny[0];
              t->flags = 10;
490
              scheduler_splittask_hydro(
491
                  scheduler_addtask(s, task_type_pair, t->subtype, 11, 0,
492
                                    ci->progeny[3], cj->progeny[0]),
493
                  s);
494
              scheduler_splittask_hydro(
495
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
496
                                    ci->progeny[6], cj->progeny[0]),
497
                  s);
498
              scheduler_splittask_hydro(
499
                  scheduler_addtask(s, task_type_pair, t->subtype, 6, 0,
500
                                    ci->progeny[7], cj->progeny[0]),
501
                  s);
502
              scheduler_splittask_hydro(
503
                  scheduler_addtask(s, task_type_pair, t->subtype, 9, 0,
504
                                    ci->progeny[2], cj->progeny[1]),
505
                  s);
506
              scheduler_splittask_hydro(
507
                  scheduler_addtask(s, task_type_pair, t->subtype, 10, 0,
508
                                    ci->progeny[3], cj->progeny[1]),
509
                  s);
510
              scheduler_splittask_hydro(
511
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
512
                                    ci->progeny[6], cj->progeny[1]),
513
                  s);
514
              scheduler_splittask_hydro(
515
                  scheduler_addtask(s, task_type_pair, t->subtype, 7, 0,
516
                                    ci->progeny[7], cj->progeny[1]),
517
                  s);
518
              scheduler_splittask_hydro(
519
                  scheduler_addtask(s, task_type_pair, t->subtype, 1, 0,
520
                                    ci->progeny[2], cj->progeny[4]),
521
                  s);
522
              scheduler_splittask_hydro(
523
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
524
                                    ci->progeny[3], cj->progeny[4]),
525
                  s);
526
              scheduler_splittask_hydro(
527
                  scheduler_addtask(s, task_type_pair, t->subtype, 10, 0,
528
                                    ci->progeny[6], cj->progeny[4]),
529
                  s);
530
              scheduler_splittask_hydro(
531
                  scheduler_addtask(s, task_type_pair, t->subtype, 11, 0,
532
                                    ci->progeny[7], cj->progeny[4]),
533
                  s);
534
              scheduler_splittask_hydro(
535
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
536
                                    ci->progeny[2], cj->progeny[5]),
537
                  s);
538
              scheduler_splittask_hydro(
539
                  scheduler_addtask(s, task_type_pair, t->subtype, 1, 0,
540
                                    ci->progeny[3], cj->progeny[5]),
541
                  s);
542
              scheduler_splittask_hydro(
543
                  scheduler_addtask(s, task_type_pair, t->subtype, 9, 0,
544
                                    ci->progeny[6], cj->progeny[5]),
545
                  s);
546
              scheduler_splittask_hydro(
547
                  scheduler_addtask(s, task_type_pair, t->subtype, 10, 0,
548
                                    ci->progeny[7], cj->progeny[5]),
549
550
551
552
553
554
555
                  s);
              break;

            case 11: /* (  0 ,  1 , -1 ) */
              t->ci = ci->progeny[2];
              t->cj = cj->progeny[1];
              t->flags = 11;
556
              scheduler_splittask_hydro(
557
                  scheduler_addtask(s, task_type_pair, t->subtype, 11, 0,
558
                                    ci->progeny[6], cj->progeny[5]),
559
                  s);
560
              scheduler_splittask_hydro(
561
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
562
                                    ci->progeny[2], cj->progeny[5]),
563
                  s);
564
              scheduler_splittask_hydro(
565
                  scheduler_addtask(s, task_type_pair, t->subtype, 6, 0,
566
                                    ci->progeny[6], cj->progeny[1]),
567
568
569
570
571
572
573
                  s);
              break;

            case 12: /* (  0 ,  0 ,  1 ) */
              t->ci = ci->progeny[1];
              t->cj = cj->progeny[0];
              t->flags = 12;
574
              scheduler_splittask_hydro(
575
                  scheduler_addtask(s, task_type_pair, t->subtype, 11, 0,
576
                                    ci->progeny[3], cj->progeny[0]),
577
                  s);
578
              scheduler_splittask_hydro(
579
                  scheduler_addtask(s, task_type_pair, t->subtype, 5, 0,
580
                                    ci->progeny[5], cj->progeny[0]),
581
                  s);
582
              scheduler_splittask_hydro(
583
                  scheduler_addtask(s, task_type_pair, t->subtype, 2, 0,
584
                                    ci->progeny[7], cj->progeny[0]),
585
                  s);
586
              scheduler_splittask_hydro(
587
                  scheduler_addtask(s, task_type_pair, t->subtype, 9, 0,
588
                                    ci->progeny[1], cj->progeny[2]),
589
                  s);
590
              scheduler_splittask_hydro(
591
                  scheduler_addtask(s, task_type_pair, t->subtype, 12, 0,
592
                                    ci->progeny[3], cj->progeny[2]),
593
                  s);
594
              scheduler_splittask_hydro(
595
                  scheduler_addtask(s, task_type_pair, t->subtype, 8, 0,
596
                                    ci->progeny[5], cj->progeny[2]),
597
                  s);
598
              scheduler_splittask_hydro(
599
                  scheduler_addtask(s, task_type_pair, t->subtype, 5, 0,
600
                                    ci->progeny[7], cj->progeny[2]),
601
                  s);
602
              scheduler_splittask_hydro(
603
                  scheduler_addtask(s, task_type_pair, t->subtype, 3, 0,
604
                                    ci->progeny[1], cj->progeny[4]),
605
                  s);
606
              scheduler_splittask_hydro(
607
                  scheduler_addtask(s, task_type_pair, t->subtype, 6, 0,
608
                                    ci->progeny[3], cj->progeny[4]),
609
                  s);
610
              scheduler_splittask_hydro(
611
                  scheduler_addtask(s, task_type_pair, t->subtype, 12, 0,
612
                                    ci->progeny[5], cj->progeny[4]),
613
                  s);
614
              scheduler_splittask_hydro(
615
                  scheduler_addtask(s, task_type_pair, t->subtype, 11, 0,
616
                                    ci->progeny[7], cj->progeny[4]),
617
                  s);
618
              scheduler_splittask_hydro(
619
                  scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
620
                                    ci->progeny[1], cj->progeny[6]),
621
                  s);
622
              scheduler_splittask_hydro(
623
                  scheduler_addtask(s, task_type_pair, t->subtype, 3, 0,
624
                                    ci->progeny[3], cj->progeny[6]),
625
                  s);
626
              scheduler_splittask_hydro(
627
                  scheduler_addtask(s, task_type_pair, t->subtype, 9, 0,
628
                                    ci->progeny[5], cj->progeny[6]),
629
                  s);
630
              scheduler_splittask_hydro(
631
                  scheduler_addtask(s, task_type_pair, t->subtype, 12, 0,
632
                                    ci->progeny[7], cj->progeny[6]),
633
634
635
                  s);
              break;
          } /* switch(sid) */
636
637
        }

638
639
640
641
642
643
644
645
646
647
648
        /* Otherwise, break it up if it is too large? */
      } else if (scheduler_doforcesplit && ci->split && cj->split &&
                 (ci->count > space_maxsize / cj->count)) {

        // message( "force splitting pair with %i and %i parts." , ci->count ,
        // cj->count );

        /* Replace the current task. */
        t->type = task_type_none;

        for (int j = 0; j < 8; j++)
649
          if (ci->progeny[j] != NULL && ci->progeny[j]->count)
650
            for (int k = 0; k < 8; k++)
651
              if (cj->progeny[k] != NULL && cj->progeny[k]->count) {
652
653
                struct task *tl =
                    scheduler_addtask(s, task_type_pair, t->subtype, 0, 0,
654
                                      ci->progeny[j], cj->progeny[k]);
655
                scheduler_splittask_hydro(tl, s);
656
657
658
659
660
661
662
                tl->flags = space_getsid(s->space, &t->ci, &t->cj, shift);
              }
      }
    } /* pair interaction? */
  }   /* iterate over the current task. */
}

663
664
665
666
667
668
/**
 * @brief Split a gravity task if too large.
 *
 * @param t The #task
 * @param s The #scheduler we are working in.
 */
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
static void scheduler_splittask_gravity(struct task *t, struct scheduler *s) {

  /* Iterate on this task until we're done with it. */
  int redo = 1;
  while (redo) {

    /* Reset the redo flag. */
    redo = 0;

    /* Non-splittable task? */
    if ((t->ci == NULL) || (t->type == task_type_pair && t->cj == NULL)) {
      t->type = task_type_none;
      t->subtype = task_subtype_none;
      t->cj = NULL;
      t->skip = 1;
      break;
    }

    /* Self-interaction? */
    if (t->type == task_type_self) {

      /* Get a handle on the cell involved. */
      struct cell *ci = t->ci;

      /* Foreign task? */
      if (ci->nodeID != s->nodeID) {
        t->skip = 1;
        break;
      }

699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
      /* Should we split this task? */
      if (ci->split && ci->gcount > space_subsize_self_grav) {

        /* Take a step back (we're going to recycle the current task)... */
        redo = 1;

        /* Add the self tasks. */
        int first_child = 0;
        while (ci->progeny[first_child] == NULL) first_child++;
        t->ci = ci->progeny[first_child];
        for (int k = first_child + 1; k < 8; k++)
          if (ci->progeny[k] != NULL)
            scheduler_splittask_gravity(
                scheduler_addtask(s, task_type_self, t->subtype, 0, 0,
                                  ci->progeny[k], NULL),
                s);

        /* Make a task for each pair of progeny */
        if (t->subtype != task_subtype_external_grav) {
          for (int j = 0; j < 8; j++)
            if (ci->progeny[j] != NULL)
              for (int k = j + 1; k < 8; k++)
                if (ci->progeny[k] != NULL)
                  scheduler_splittask_gravity(
                      scheduler_addtask(s, task_type_pair, t->subtype,
                                        sub_sid_flag[j][k], 0, ci->progeny[j],
                                        ci->progeny[k]),
                      s);
727
        }
728
      } /* Cell is split */
729
730
731
732
733

    } /* Self interaction */

    /* Pair interaction? */
    else if (t->type == task_type_pair) {
734
735
736

      /* Get a handle on the cells involved. */
      struct cell *ci = t->ci;
737
738
739
740
741
742
743
744
      struct cell *cj = t->cj;

      /* Foreign task? */
      if (ci->nodeID != s->nodeID && cj->nodeID != s->nodeID) {
        t->skip = 1;
        break;
      }
    } /* pair interaction? */
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
  }   /* iterate over the current task. */
}

/**
 * @brief Mapper function to split tasks that may be too large.
 *
 * @param map_data the tasks to process
 * @param num_elements the number of tasks.
 * @param extra_data The #scheduler we are working in.
 */
void scheduler_splittasks_mapper(void *map_data, int num_elements,
                                 void *extra_data) {

  /* Extract the parameters. */
  struct scheduler *s = (struct scheduler *)extra_data;
  struct task *tasks = (struct task *)map_data;
761

762
763
  for (int ind = 0; ind < num_elements; ind++) {
    struct task *t = &tasks[ind];
764
765
766
767
768
769
770
771
772
773

    /* Invoke the correct splitting strategy */
    if (t->subtype == task_subtype_density) {
      scheduler_splittask_hydro(t, s);
    } else if (t->subtype == task_subtype_external_grav) {
      scheduler_splittask_gravity(t, s);
    } else if (t->subtype == task_subtype_grav) {
      scheduler_splittask_gravity(t, s);
    } else if (t->type == task_type_grav_top_level ||
               t->type == task_type_grav_ghost) {
774
      /* For future use */
775
776
777
    } else {
      error("Unexpected task sub-type");
    }
778
  }
779
}
780

Matthieu Schaller's avatar
Matthieu Schaller committed
781
782
783
784
785
/**
 * @brief Splits all the tasks in the scheduler that are too large.
 *
 * @param s The #scheduler.
 */
786
void scheduler_splittasks(struct scheduler *s) {
787

788
789
  /* Call the mapper on each current task. */
  threadpool_map(s->threadpool, scheduler_splittasks_mapper, s->tasks,
790
                 s->nr_tasks, sizeof(struct task), 0, s);
791
792
}

793
794
795
796
797
798
799
/**
 * @brief Add a #task to the #scheduler.
 *
 * @param s The #scheduler we are working in.
 * @param type The type of the task.
 * @param subtype The sub-type of the task.
 * @param flags The flags of the task.
800
801
 * @param implicit If true, only use this task to unlock dependencies, i.e.
 *        this task is never enqueued.
802
803
804
 * @param ci The first cell to interact.
 * @param cj The second cell to interact.
 */
805
struct task *scheduler_addtask(struct scheduler *s, enum task_types type,
806
807
                               enum task_subtypes subtype, int flags,
                               int implicit, struct cell *ci, struct cell *cj) {
808

809
810
811
812
813
814
#ifdef SWIFT_DEBUG_CHECKS
  if (ci == NULL && cj != NULL)
    error("Added a task with ci==NULL and cj!=NULL type=%s/%s",
          taskID_names[type], subtaskID_names[subtype]);
#endif

815
  /* Get the next free task. */
Pedro Gonnet's avatar
Pedro Gonnet committed
816
  const int ind = atomic_inc(&s->tasks_next);
Matthieu Schaller's avatar
Matthieu Schaller committed
817

818
  /* Overflow? */
819
820
821
822
823
  if (ind >= s->size)
    error(
        "Task list overflow (%d). Need to increase "
        "Scheduler:tasks_per_cell.",
        ind);
824
825

  /* Get a pointer to the new task. */
Pedro Gonnet's avatar
Pedro Gonnet committed
826
  struct task *t = &s->tasks[ind];
827
828
829
830
831

  /* Copy the data. */
  t->type = type;
  t->subtype = subtype;
  t->flags = flags;
832
  t->wait = 0;
833
834
  t->ci = ci;
  t->cj = cj;
835
  t->skip = 1; /* Mark tasks as skip by default. */
836
  t->implicit = implicit;
837
838
839
  t->weight = 0;
  t->rank = 0;
  t->nr_unlock_tasks