task.c 9.07 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 "lock.h"
47
48

/* Task type names. */
49
const char *taskID_names[task_type_count] = {
50
51
    "none",      "sort",          "self",      "pair",       "sub",
    "init",      "ghost",         "drift",     "kick",       "kick_fixdt",
Matthieu Schaller's avatar
Matthieu Schaller committed
52
53
    "send",      "recv",          "grav_mm",    "grav_up",    "grav_external",
    "part_sort", "gpart_sort", "split_cell",   "rewait"};
54

Matthieu Schaller's avatar
Matthieu Schaller committed
55
56
const char *subtaskID_names[task_type_count] = {"none",  "density",
                                                "force", "grav"};
57

58
59
60
/**
 * @brief Computes the overlap between the parts array of two given cells.
 */
61

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
size_t task_cell_overlap(const struct cell *ci, const struct cell *cj) {
  if (ci == NULL || cj == NULL) return 0;
  if (ci->parts <= cj->parts &&
      ci->parts + ci->count >= cj->parts + cj->count) {
    return cj->count;
  } else if (cj->parts <= ci->parts &&
             cj->parts + cj->count >= ci->parts + ci->count) {
    return ci->count;
  }
  return 0;
}

/**
 * @brief Compute the Jaccard similarity of the data used by two
 *        different tasks.
 *
 * @param ta The first #task.
 * @param tb The second #task.
 */

float task_overlap(const struct task *ta, const struct task *tb) {
  /* First check if any of the two tasks are of a type that don't
     use cells. */
85
  if (ta == NULL || tb == NULL || ta->type == task_type_none ||
86
87
88
89
      ta->type == task_type_part_sort || ta->type == task_type_gpart_sort ||
      ta->type == task_type_split_cell || ta->type == task_type_rewait ||
      tb->type == task_type_none || tb->type == task_type_part_sort ||
      tb->type == task_type_gpart_sort || tb->type == task_type_split_cell ||
90
      tb->type == task_type_rewait)
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
    return 0.0f;

  /* 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(ta->ci, tb->ci) + task_cell_overlap(ta->ci, tb->cj) +
      task_cell_overlap(ta->cj, tb->ci) + task_cell_overlap(ta->cj, tb->cj);

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

108
109
/**
 * @brief Unlock the cell held by this task.
110
 *
111
112
113
 * @param t The #task.
 */

114
115
116
117
118
119
120
121
122
123
124
125
126
void task_unlock(struct task *t) {

  /* Act based on task type. */
  switch (t->type) {
    case task_type_self:
    case task_type_sort:
      cell_unlocktree(t->ci);
      break;
    case task_type_pair:
    case task_type_sub:
      cell_unlocktree(t->ci);
      if (t->cj != NULL) cell_unlocktree(t->cj);
      break;
Matthieu Schaller's avatar
Matthieu Schaller committed
127
      //case task_type_grav_pp:
128
    case task_type_grav_mm:
Matthieu Schaller's avatar
Matthieu Schaller committed
129
      //case task_type_grav_down:
130
131
132
133
134
135
136
      cell_gunlocktree(t->ci);
      if (t->cj != NULL) cell_gunlocktree(t->cj);
      break;
    default:
      break;
  }
}
137
138
139
140
141
142

/**
 * @brief Try to lock the cells associated with this task.
 *
 * @param t the #task.
 */
143
144
145
146
147
148
149
150
151
152
153

int task_lock(struct task *t) {

  int type = t->type;
  struct cell *ci = t->ci, *cj = t->cj;

  /* Communication task? */
  if (type == task_type_recv || type == task_type_send) {

#ifdef WITH_MPI
    /* Check the status of the MPI request. */
154
    int res = 0, err = 0;
155
156
157
158
159
160
161
    MPI_Status stat;
    if ((err = MPI_Test(&t->req, &res, &stat)) != MPI_SUCCESS) {
      char buff[MPI_MAX_ERROR_STRING];
      int len;
      MPI_Error_string(err, buff, &len);
      error("Failed to test request on send/recv task (tag=%i, %s).", t->flags,
            buff);
162
    }
163
164
165
166
    return res;
#else
    error("SWIFT was not compiled with MPI support.");
#endif
167

168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  }

  /* Unary lock? */
  else if (type == task_type_self || type == task_type_sort ||
           (type == task_type_sub && cj == NULL)) {
    if (cell_locktree(ci) != 0) return 0;
  }

  /* Otherwise, binary lock. */
  else if (type == task_type_pair || (type == task_type_sub && cj != NULL)) {
    if (ci->hold || cj->hold) return 0;
    if (cell_locktree(ci) != 0) return 0;
    if (cell_locktree(cj) != 0) {
      cell_unlocktree(ci);
      return 0;
    }
  }

  /* Gravity tasks? */
Matthieu Schaller's avatar
Matthieu Schaller committed
187
188
  else if (type == task_type_grav_mm) {
    //|| type == task_type_grav_pp || type == task_type_grav_down) {
189
190
191
192
193
194
195
196
197
198
199
    if (ci->ghold || (cj != NULL && cj->ghold)) return 0;
    if (cell_glocktree(ci) != 0) return 0;
    if (cj != NULL && cell_glocktree(cj) != 0) {
      cell_gunlocktree(ci);
      return 0;
    }
  }

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

201
/**
202
 * @brief Remove all unlocks to tasks that are of the given type.
203
204
205
206
 *
 * @param t The #task.
 * @param type The task type ID to remove.
 */
207
208
209
210
211
212
213
214
215
216
217

void task_cleanunlock(struct task *t, int type) {

  int k;

  lock_lock(&t->lock);

  for (k = 0; k < t->nr_unlock_tasks; k++)
    if (t->unlock_tasks[k]->type == type) {
      t->nr_unlock_tasks -= 1;
      t->unlock_tasks[k] = t->unlock_tasks[t->nr_unlock_tasks];
218
219
    }

220
221
  lock_unlock_blind(&t->lock);
}
222

223
224
225
226
227
228
229
/**
 * @brief Remove an unlock_task from the given task.
 *
 * @param ta The unlocking #task.
 * @param tb The #task that will be unlocked.
 */

230
231
232
233
234
235
236
237
238
239
240
241
void task_rmunlock(struct task *ta, struct task *tb) {

  int k;

  lock_lock(&ta->lock);

  for (k = 0; k < ta->nr_unlock_tasks; k++)
    if (ta->unlock_tasks[k] == tb) {
      ta->nr_unlock_tasks -= 1;
      ta->unlock_tasks[k] = ta->unlock_tasks[ta->nr_unlock_tasks];
      lock_unlock_blind(&ta->lock);
      return;
242
    }
243
244
  error("Task not found.");
}
245

Pedro Gonnet's avatar
Pedro Gonnet committed
246
247
248
249
250
251
252
253
254
255
/**
 * @brief Remove an unlock_task from the given task.
 *
 * @param ta The unlocking #task.
 * @param tb The #task that will be unlocked.
 *
 * Differs from #task_rmunlock in that it will not fail if
 * the task @c tb is not in the unlocks of @c ta.
 */

256
257
258
259
260
261
262
263
264
265
266
void task_rmunlock_blind(struct task *ta, struct task *tb) {

  int k;

  lock_lock(&ta->lock);

  for (k = 0; k < ta->nr_unlock_tasks; k++)
    if (ta->unlock_tasks[k] == tb) {
      ta->nr_unlock_tasks -= 1;
      ta->unlock_tasks[k] = ta->unlock_tasks[ta->nr_unlock_tasks];
      break;
Pedro Gonnet's avatar
Pedro Gonnet committed
267
    }
268
269
270

  lock_unlock_blind(&ta->lock);
}
Pedro Gonnet's avatar
Pedro Gonnet committed
271

272
273
274
275
276
277
/**
 * @brief Add an unlock_task to the given task.
 *
 * @param ta The unlocking #task.
 * @param tb The #task that will be unlocked.
 */
278

279
void task_addunlock(struct task *ta, struct task *tb) {
280

281
  error("Use sched_addunlock instead.");
282

283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  /* Add the lock atomically. */
  ta->unlock_tasks[atomic_inc(&ta->nr_unlock_tasks)] = tb;

  /* Check a posteriori if we did not overshoot. */
  if (ta->nr_unlock_tasks > task_maxunlock)
    error("Too many unlock_tasks in task.");
}

void task_addunlock_old(struct task *ta, struct task *tb) {

  int k;

  lock_lock(&ta->lock);

  /* Check if ta already unlocks tb. */
  for (k = 0; k < ta->nr_unlock_tasks; k++)
    if (ta->unlock_tasks[k] == tb) {
      error("Duplicate unlock.");
      lock_unlock_blind(&ta->lock);
      return;
303
304
    }

305
306
307
308
309
310
311
312
  if (ta->nr_unlock_tasks == task_maxunlock)
    error("Too many unlock_tasks in task.");

  ta->unlock_tasks[ta->nr_unlock_tasks] = tb;
  ta->nr_unlock_tasks += 1;

  lock_unlock_blind(&ta->lock);
}
313
314
315
316

/**
 * @brief Prints the list of tasks contained in a given mask
 *
317
 * @param mask The mask to analyse
318
319
320
321
322
323
324
325
326
327
328
329
 */
void task_print_mask(unsigned int mask) {

  printf("task_print_mask: The tasks to run are [");
  for (int k = 1; k < task_type_count; k++)
    printf(" %s=%s", taskID_names[k], (mask & (1 << k)) ? "yes" : "no");
  printf(" ]\n");
}

/**
 * @brief Prints the list of subtasks contained in a given submask
 *
330
 * @param submask The submask to analyse
331
332
333
334
335
336
337
338
 */
void task_print_submask(unsigned int submask) {

  printf("task_print_submask: The subtasks to run are [");
  for (int k = 1; k < task_subtype_count; k++)
    printf(" %s=%s", subtaskID_names[k], (submask & (1 << k)) ? "yes" : "no");
  printf(" ]\n");
}