Skip to content
Snippets Groups Projects
Commit 7b1c778e authored by Pedro Gonnet's avatar Pedro Gonnet
Browse files

Merge branch 'scheduler_mask' into 'master'

Use the mask to only enqueue tasks that we want everywhere and not just in scheduler_start()

That fixes bug #59 and is compatible with the new version of scheduler_done() that is in the parallel_sort branch.

I have also made scheduler_unlock() closer to scheduler_done().

See merge request !58
parents beb73995 be66acf4
No related branches found
No related tags found
No related merge requests found
/******************************************************************************* /*******************************************************************************
* This file is part of SWIFT. * This file is part of SWIFT.
* Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk) * Copyright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk)
* Matthieu Schaller (matthieu.schaller@durham.ac.uk)
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Lesser General Public License as published
...@@ -779,6 +780,7 @@ void scheduler_reset(struct scheduler *s, int size) { ...@@ -779,6 +780,7 @@ void scheduler_reset(struct scheduler *s, int size) {
s->nr_tasks = 0; s->nr_tasks = 0;
s->tasks_next = 0; s->tasks_next = 0;
s->waiting = 0; s->waiting = 0;
s->mask = 0;
/* Set the task pointers in the queues. */ /* Set the task pointers in the queues. */
for (k = 0; k < s->nr_queues; k++) s->queues[k].tasks = s->tasks; for (k = 0; k < s->nr_queues; k++) s->queues[k].tasks = s->tasks;
...@@ -884,13 +886,16 @@ void scheduler_start(struct scheduler *s, unsigned int mask) { ...@@ -884,13 +886,16 @@ void scheduler_start(struct scheduler *s, unsigned int mask) {
struct task *t, *tasks = s->tasks; struct task *t, *tasks = s->tasks;
// ticks tic; // ticks tic;
/* Store the mask */
s->mask = mask;
/* Run through the tasks and set their waits. */ /* Run through the tasks and set their waits. */
// tic = getticks(); // tic = getticks();
for (k = nr_tasks - 1; k >= 0; k--) { for (k = nr_tasks - 1; k >= 0; k--) {
t = &tasks[tid[k]]; t = &tasks[tid[k]];
t->wait = 0; t->wait = 0;
t->rid = -1; t->rid = -1;
if (!((1 << t->type) & mask) || t->skip) continue; if (!((1 << t->type) & s->mask) || t->skip) continue;
for (j = 0; j < t->nr_unlock_tasks; j++) for (j = 0; j < t->nr_unlock_tasks; j++)
atomic_inc(&t->unlock_tasks[j]->wait); atomic_inc(&t->unlock_tasks[j]->wait);
} }
...@@ -898,13 +903,13 @@ void scheduler_start(struct scheduler *s, unsigned int mask) { ...@@ -898,13 +903,13 @@ void scheduler_start(struct scheduler *s, unsigned int mask) {
// CPU_TPS * 1000 ); // CPU_TPS * 1000 );
/* Don't enqueue link tasks directly. */ /* Don't enqueue link tasks directly. */
mask &= ~(1 << task_type_link); s->mask &= ~(1 << task_type_link);
/* Loop over the tasks and enqueue whoever is ready. */ /* Loop over the tasks and enqueue whoever is ready. */
// tic = getticks(); // tic = getticks();
for (k = 0; k < nr_tasks; k++) { for (k = 0; k < nr_tasks; k++) {
t = &tasks[tid[k]]; t = &tasks[tid[k]];
if (((1 << t->type) & mask) && !t->skip) { if (((1 << t->type) & s->mask) && !t->skip) {
if (t->wait == 0) { if (t->wait == 0) {
scheduler_enqueue(s, t); scheduler_enqueue(s, t);
pthread_cond_broadcast(&s->sleep_cond); pthread_cond_broadcast(&s->sleep_cond);
...@@ -930,14 +935,16 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) { ...@@ -930,14 +935,16 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) {
int err; int err;
#endif #endif
/* Ignore skipped tasks. */ /* Ignore skipped tasks and tasks not in the mask. */
if (t->skip || atomic_cas(&t->rid, -1, 0) != -1) return; if (t->skip || ((1 << t->type) & ~(s->mask) && t->type != task_type_link) ||
atomic_cas(&t->rid, -1, 0) != -1)
return;
/* If this is an implicit task, just pretend it's done. */ /* If this is an implicit task, just pretend it's done. */
if (t->implicit) { if (t->implicit) {
for (int j = 0; j < t->nr_unlock_tasks; j++) { for (int j = 0; j < t->nr_unlock_tasks; j++) {
struct task *t2 = t->unlock_tasks[j]; struct task *t2 = t->unlock_tasks[j];
if (atomic_dec(&t2->wait) == 1 && !t2->skip) scheduler_enqueue(s, t2); if (atomic_dec(&t2->wait) == 1) scheduler_enqueue(s, t2);
} }
} }
...@@ -1026,28 +1033,18 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) { ...@@ -1026,28 +1033,18 @@ void scheduler_enqueue(struct scheduler *s, struct task *t) {
struct task *scheduler_done(struct scheduler *s, struct task *t) { struct task *scheduler_done(struct scheduler *s, struct task *t) {
int k, res;
struct task *t2, *next = NULL;
struct cell *super = t->ci->super;
/* Release whatever locks this task held. */ /* Release whatever locks this task held. */
if (!t->implicit) task_unlock(t); if (!t->implicit) task_unlock(t);
/* Loop through the dependencies and add them to a queue if /* Loop through the dependencies and add them to a queue if
they are ready. */ they are ready. */
for (k = 0; k < t->nr_unlock_tasks; k++) { for (int k = 0; k < t->nr_unlock_tasks; k++) {
t2 = t->unlock_tasks[k]; struct task *t2 = t->unlock_tasks[k];
if ((res = atomic_dec(&t2->wait)) < 1) error("Negative wait!"); int res = atomic_dec(&t2->wait);
if (res == 1 && !t2->skip) { if (res < 1) {
if (0 && !t2->implicit && t2->ci->super == super && error("Negative wait!");
(next == NULL || t2->weight > next->weight) && task_lock(t2)) { } else if (res == 1) {
if (next != NULL) { scheduler_enqueue(s, t2);
task_unlock(next);
scheduler_enqueue(s, next);
}
next = t2;
} else
scheduler_enqueue(s, t2);
} }
} }
...@@ -1055,16 +1052,15 @@ struct task *scheduler_done(struct scheduler *s, struct task *t) { ...@@ -1055,16 +1052,15 @@ struct task *scheduler_done(struct scheduler *s, struct task *t) {
if (!t->implicit) { if (!t->implicit) {
t->toc = getticks(); t->toc = getticks();
pthread_mutex_lock(&s->sleep_mutex); pthread_mutex_lock(&s->sleep_mutex);
if (next == NULL) atomic_dec(&s->waiting); atomic_dec(&s->waiting);
pthread_cond_broadcast(&s->sleep_cond); pthread_cond_broadcast(&s->sleep_cond);
pthread_mutex_unlock(&s->sleep_mutex); pthread_mutex_unlock(&s->sleep_mutex);
} }
/* Start the clock on the follow-up task. */ /* Return the next best task. Note that we currently do not
if (next != NULL) next->tic = getticks(); implement anything that does this, as getting it to respect
priorities is too tricky and currently unnecessary. */
/* Return the next best task. */ return NULL;
return next;
} }
/** /**
...@@ -1079,31 +1075,31 @@ struct task *scheduler_done(struct scheduler *s, struct task *t) { ...@@ -1079,31 +1075,31 @@ struct task *scheduler_done(struct scheduler *s, struct task *t) {
struct task *scheduler_unlock(struct scheduler *s, struct task *t) { struct task *scheduler_unlock(struct scheduler *s, struct task *t) {
int k, res;
struct task *t2, *next = NULL;
/* Loop through the dependencies and add them to a queue if /* Loop through the dependencies and add them to a queue if
they are ready. */ they are ready. */
for (k = 0; k < t->nr_unlock_tasks; k++) { for (int k = 0; k < t->nr_unlock_tasks; k++) {
t2 = t->unlock_tasks[k]; struct task *t2 = t->unlock_tasks[k];
if ((res = atomic_dec(&t2->wait)) < 1) error("Negative wait!"); int res = atomic_dec(&t2->wait);
if (res == 1 && !t2->skip) scheduler_enqueue(s, t2); if (res < 1) {
error("Negative wait!");
} else if (res == 1) {
scheduler_enqueue(s, t2);
}
} }
/* Task definitely done. */ /* Task definitely done. */
if (!t->implicit) { if (!t->implicit) {
t->toc = getticks(); t->toc = getticks();
pthread_mutex_lock(&s->sleep_mutex); pthread_mutex_lock(&s->sleep_mutex);
if (next == NULL) atomic_dec(&s->waiting); atomic_dec(&s->waiting);
pthread_cond_broadcast(&s->sleep_cond); pthread_cond_broadcast(&s->sleep_cond);
pthread_mutex_unlock(&s->sleep_mutex); pthread_mutex_unlock(&s->sleep_mutex);
} }
/* Start the clock on the follow-up task. */ /* Return the next best task. Note that we currently do not
if (next != NULL) next->tic = getticks(); implement anything that does this, as getting it to respect
priorities is too tricky and currently unnecessary. */
/* Return the next best task. */ return NULL;
return next;
} }
/** /**
......
/******************************************************************************* /*******************************************************************************
* This file is part of SWIFT. * This file is part of SWIFT.
* Copyright (c) 2013 Pedro Gonnet (pedro.gonnet@durham.ac.uk) * Copyright (c) 2013 Pedro Gonnet (pedro.gonnet@durham.ac.uk)
* Matthieu Schaller (matthieu.schaller@durham.ac.uk)
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Lesser General Public License as published
...@@ -50,6 +51,9 @@ struct scheduler { ...@@ -50,6 +51,9 @@ struct scheduler {
/* Scheduler flags. */ /* Scheduler flags. */
unsigned int flags; unsigned int flags;
/* Scheduler mask */
unsigned int mask;
/* Number of queues in this scheduler. */ /* Number of queues in this scheduler. */
int nr_queues; int nr_queues;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment