reformat, following initial convention

This commit is contained in:
Mylloon 2024-04-19 15:33:03 +02:00
parent f95dcaf491
commit 6b891cf338
Signed by: Anri
GPG key ID: A82D63DFF8D1317F
5 changed files with 266 additions and 241 deletions

5
.clang-format Normal file
View file

@ -0,0 +1,5 @@
IndentWidth: 4
InsertBraces: true
BreakBeforeBraces: Linux
AlwaysBreakAfterReturnType: TopLevelDefinitions
SpaceBeforeParens: Never

View file

@ -10,29 +10,31 @@ struct scheduler;
typedef void (*taskfunc)(void *, struct scheduler *);
typedef struct task_info {
taskfunc f;
void *closure;
taskfunc f;
void *closure;
} taskinfo;
struct scheduler {
/* Mutex qui protège la structure */
pthread_mutex_t mutex;
/* Mutex qui protège la structure */
pthread_mutex_t mutex;
/* Indicateur de changement d'état */
pthread_cond_t cond;
/* Indicateur de changement d'état */
pthread_cond_t cond;
/* Position actuelle dans la pile */
int top;
/* Position actuelle dans la pile */
int top;
/* Tâches */
taskinfo tasks[MAX_TASKS];
/* Tâches */
taskinfo tasks[MAX_TASKS];
/* Si tout est terminé */
int exit;
/* Si tout est terminé */
int exit;
};
static inline int sched_default_threads(void) {
return sysconf(_SC_NPROCESSORS_ONLN);
static inline int
sched_default_threads(void)
{
return sysconf(_SC_NPROCESSORS_ONLN);
}
/* Lance l'ordonnanceur

View file

@ -1,5 +1,7 @@
#include "../includes/quicksort.h"
int main(int argc, char *argv[]) {
return benchmark(argc, argv);
int
main(int argc, char *argv[])
{
return benchmark(argc, argv);
}

View file

@ -1,151 +1,161 @@
#include "../includes/quicksort.h"
int partition(int *a, int lo, int hi) {
int pivot = a[lo];
int i = lo - 1;
int j = hi + 1;
int t;
while (1) {
do {
i++;
} while (a[i] < pivot);
int
partition(int *a, int lo, int hi)
{
int pivot = a[lo];
int i = lo - 1;
int j = hi + 1;
int t;
while(1) {
do {
i++;
} while(a[i] < pivot);
do {
j--;
} while (a[j] > pivot);
do {
j--;
} while(a[j] > pivot);
if (i >= j) {
return j;
if(i >= j) {
return j;
}
t = a[i];
a[i] = a[j];
a[j] = t;
}
t = a[i];
a[i] = a[j];
a[j] = t;
}
}
struct quicksort_args {
int *a;
int lo, hi;
int *a;
int lo, hi;
};
struct quicksort_args *new_args(int *a, int lo, int hi) {
struct quicksort_args *args = malloc(sizeof(struct quicksort_args));
if (args == NULL) {
return NULL;
}
args->a = a;
args->lo = lo;
args->hi = hi;
return args;
}
void quicksort_serial(int *a, int lo, int hi) {
int p;
if (lo >= hi) {
return;
}
p = partition(a, lo, hi);
quicksort_serial(a, lo, p);
quicksort_serial(a, p + 1, hi);
}
void quicksort(void *closure, struct scheduler *s) {
struct quicksort_args *args = (struct quicksort_args *)closure;
int *a = args->a;
int lo = args->lo;
int hi = args->hi;
int p;
int rc;
free(closure);
if (lo >= hi) {
return;
}
if (hi - lo <= 128) {
quicksort_serial(a, lo, hi);
return;
}
p = partition(a, lo, hi);
rc = sched_spawn(quicksort, new_args(a, lo, p), s);
assert(rc >= 0);
rc = sched_spawn(quicksort, new_args(a, p + 1, hi), s);
assert(rc >= 0);
}
int benchmark(int argc, char **argv) {
int *a;
struct timespec begin, end;
double delay;
int rc;
int n = 10 * 1024 * 1024;
int nthreads = -1;
int serial = 0;
while (1) {
int opt = getopt(argc, argv, "sn:t:");
if (opt < 0) {
break;
struct quicksort_args *
new_args(int *a, int lo, int hi)
{
struct quicksort_args *args = malloc(sizeof(struct quicksort_args));
if(args == NULL) {
return NULL;
}
switch (opt) {
case 's':
serial = 1;
break;
case 'n':
n = atoi(optarg);
break;
case 't':
nthreads = atoi(optarg);
break;
default:
goto usage;
args->a = a;
args->lo = lo;
args->hi = hi;
return args;
}
void
quicksort_serial(int *a, int lo, int hi)
{
int p;
if(lo >= hi) {
return;
}
}
if (n <= 0) {
goto usage;
}
if (nthreads < 0 && !serial) {
goto usage;
}
p = partition(a, lo, hi);
quicksort_serial(a, lo, p);
quicksort_serial(a, p + 1, hi);
}
a = malloc(n * sizeof(int));
void
quicksort(void *closure, struct scheduler *s)
{
struct quicksort_args *args = (struct quicksort_args *)closure;
int *a = args->a;
int lo = args->lo;
int hi = args->hi;
int p;
int rc;
unsigned long long s = 0;
for (int i = 0; i < n; i++) {
s = s * 6364136223846793005ULL + 1442695040888963407;
a[i] = (int)((s >> 33) & 0x7FFFFFFF);
}
free(closure);
clock_gettime(CLOCK_MONOTONIC, &begin);
if(lo >= hi) {
return;
}
if (serial) {
quicksort_serial(a, 0, n - 1);
} else {
rc =
sched_init(nthreads, (n + 127) / 128, quicksort, new_args(a, 0, n - 1));
if(hi - lo <= 128) {
quicksort_serial(a, lo, hi);
return;
}
p = partition(a, lo, hi);
rc = sched_spawn(quicksort, new_args(a, lo, p), s);
assert(rc >= 0);
}
rc = sched_spawn(quicksort, new_args(a, p + 1, hi), s);
assert(rc >= 0);
}
clock_gettime(CLOCK_MONOTONIC, &end);
delay = end.tv_sec + end.tv_nsec / 1000000000.0 -
(begin.tv_sec + begin.tv_nsec / 1000000000.0);
printf("Done in %lf seconds.\n", delay);
int
benchmark(int argc, char **argv)
{
int *a;
struct timespec begin, end;
double delay;
int rc;
int n = 10 * 1024 * 1024;
int nthreads = -1;
int serial = 0;
for (int i = 0; i < n - 1; i++) {
assert(a[i] <= a[i + 1]);
}
while(1) {
int opt = getopt(argc, argv, "sn:t:");
if(opt < 0) {
break;
}
switch(opt) {
case 's':
serial = 1;
break;
case 'n':
n = atoi(optarg);
break;
case 't':
nthreads = atoi(optarg);
break;
default:
goto usage;
}
}
free(a);
return 0;
if(n <= 0) {
goto usage;
}
if(nthreads < 0 && !serial) {
goto usage;
}
a = malloc(n * sizeof(int));
unsigned long long s = 0;
for(int i = 0; i < n; i++) {
s = s * 6364136223846793005ULL + 1442695040888963407;
a[i] = (int)((s >> 33) & 0x7FFFFFFF);
}
clock_gettime(CLOCK_MONOTONIC, &begin);
if(serial) {
quicksort_serial(a, 0, n - 1);
} else {
rc = sched_init(nthreads, (n + 127) / 128, quicksort,
new_args(a, 0, n - 1));
assert(rc >= 0);
}
clock_gettime(CLOCK_MONOTONIC, &end);
delay = end.tv_sec + end.tv_nsec / 1000000000.0 -
(begin.tv_sec + begin.tv_nsec / 1000000000.0);
printf("Done in %lf seconds.\n", delay);
for(int i = 0; i < n - 1; i++) {
assert(a[i] <= a[i + 1]);
}
free(a);
return 0;
usage:
printf("quicksort [-n size] [-t threads] [-s]\n");
return 1;
printf("quicksort [-n size] [-t threads] [-s]\n");
return 1;
}

View file

@ -6,110 +6,116 @@
static struct scheduler sched;
/* Lance une tâche de la pile */
void *worker_routine(void *arg) {
struct scheduler *s = (struct scheduler *)arg;
void *
worker_routine(void *arg)
{
struct scheduler *s = (struct scheduler *)arg;
while (1) {
while(1) {
pthread_mutex_lock(&s->mutex);
if(s->exit == 1) {
pthread_mutex_unlock(&s->mutex);
printf("finalement..rien a faire, ciao\n");
break;
}
// S'il on a rien à faire
if(s->top == -1) {
// printf("attend..\n");
pthread_cond_wait(&s->cond, &s->mutex);
pthread_mutex_unlock(&s->mutex);
// printf("reveillé!\n");
continue;
}
// printf("lancement tâche #%d\n", s->top);
// Extrait la tâche de la pile
taskfunc f = s->tasks[s->top].f;
void *closure = s->tasks[s->top].closure;
s->top--;
pthread_mutex_unlock(&s->mutex);
// Exécute la tâche
f(closure, s);
// Signale s'il n'y a plus rien à faire
if(s->top == -1) {
printf("va falloir partir\n");
pthread_mutex_lock(&s->mutex);
s->exit = 1;
pthread_cond_broadcast(&s->cond);
pthread_mutex_unlock(&s->mutex);
}
}
return NULL;
}
int
sched_init(int nthreads, int qlen, taskfunc f, void *closure)
{
if(nthreads == 0) {
nthreads = sched_default_threads();
}
// TODO : Actuellement on n'utilises pas qlen
// => On utilise une pile de taille fixe
(void)qlen;
sched.top = -1;
sched.exit = 0;
if(pthread_mutex_init(&sched.mutex, NULL) != 0) {
fprintf(stderr, "Can't init mutex\n");
return -1;
}
if(pthread_cond_init(&sched.cond, NULL) != 0) {
fprintf(stderr, "Can't init condition variable\n");
return -1;
}
pthread_t threads[nthreads];
for(int i = 0; i < nthreads; ++i) {
if(pthread_create(&threads[i], NULL, worker_routine, &sched) != 0) {
fprintf(stderr, "Can't create threads\n");
return -1;
}
}
if(sched_spawn(f, closure, &sched) != 0) {
fprintf(stderr, "Can't create the initial task\n");
return -1;
}
for(int i = 0; i < nthreads; ++i) {
if((pthread_join(threads[i], NULL) != 0)) {
fprintf(stderr, "Can't wait the thread %d\n", i);
return -1;
}
}
return 1;
}
int
sched_spawn(taskfunc f, void *closure, struct scheduler *s)
{
pthread_mutex_lock(&s->mutex);
if (s->exit == 1) {
pthread_mutex_unlock(&s->mutex);
printf("finalement..rien a faire, ciao\n");
break;
if(s->top + 1 >= MAX_TASKS) {
pthread_mutex_unlock(&s->mutex);
errno = EAGAIN;
fprintf(stderr, "Stack is full\n");
return -1;
}
// S'il on a rien à faire
if (s->top == -1) {
// printf("attend..\n");
pthread_cond_wait(&s->cond, &s->mutex);
pthread_mutex_unlock(&s->mutex);
// printf("reveillé!\n");
continue;
}
// printf("lancement tâche #%d\n", s->top);
s->tasks[++s->top] = (taskinfo){f, closure};
// Extrait la tâche de la pile
taskfunc f = s->tasks[s->top].f;
void *closure = s->tasks[s->top].closure;
s->top--;
pthread_cond_signal(&s->cond);
pthread_mutex_unlock(&s->mutex);
// Exécute la tâche
f(closure, s);
// Signale s'il n'y a plus rien à faire
if (s->top == -1) {
printf("va falloir partir\n");
pthread_mutex_lock(&s->mutex);
s->exit = 1;
pthread_cond_broadcast(&s->cond);
pthread_mutex_unlock(&s->mutex);
}
}
return NULL;
}
int sched_init(int nthreads, int qlen, taskfunc f, void *closure) {
if (nthreads == 0) {
nthreads = sched_default_threads();
}
// TODO : Actuellement on n'utilises pas qlen
// => On utilise une pile de taille fixe
(void)qlen;
sched.top = -1;
sched.exit = 0;
if (pthread_mutex_init(&sched.mutex, NULL) != 0) {
fprintf(stderr, "Can't init mutex\n");
return -1;
}
if (pthread_cond_init(&sched.cond, NULL) != 0) {
fprintf(stderr, "Can't init condition variable\n");
return -1;
}
pthread_t threads[nthreads];
for (int i = 0; i < nthreads; ++i) {
if (pthread_create(&threads[i], NULL, worker_routine, &sched) != 0) {
fprintf(stderr, "Can't create threads\n");
return -1;
}
}
if (sched_spawn(f, closure, &sched) != 0) {
fprintf(stderr, "Can't create the initial task\n");
return -1;
}
for (int i = 0; i < nthreads; ++i) {
if ((pthread_join(threads[i], NULL) != 0)) {
fprintf(stderr, "Can't wait the thread %d\n", i);
return -1;
}
}
return 1;
}
int sched_spawn(taskfunc f, void *closure, struct scheduler *s) {
pthread_mutex_lock(&s->mutex);
if (s->top + 1 >= MAX_TASKS) {
pthread_mutex_unlock(&s->mutex);
errno = EAGAIN;
fprintf(stderr, "Stack is full\n");
return -1;
}
s->tasks[++s->top] = (taskinfo){f, closure};
pthread_cond_signal(&s->cond);
pthread_mutex_unlock(&s->mutex);
return 0;
return 0;
}