diff --git a/aim-sort/Makefile b/aim-sort/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..89195153257195b95b406c0c4b5634519557acd4 --- /dev/null +++ b/aim-sort/Makefile @@ -0,0 +1,57 @@ +# Compilation settings: +CFLAGS=-Wall -std=gnu99 $(MYCFLAGS) +LDFLAGS=-lm $(MYLDFLAGS) + +OPTCFLAGS=$(CFLAGS) -O3 -march=native -DNDEBUG +DBGCFLAGS=$(CFLAGS) -ggdb3 + +# Benchmarking settings: +RUNS=4 +ITERS=20 + + +###### + + +.PHONY: all clean benchmark evaluate asm +all: aim-opt aim-dbg + + +random: random.c + $(CC) $(OPTCFLAGS) -o $@ $^ $(LDFLAGS) + +aim-opt: aim-run.c exercise.c + $(CC) $(OPTCFLAGS) -o $@ $^ $(LDFLAGS) + +aim-dbg: aim-run.c exercise.c + $(CC) $(DBGCFLAGS) -o $@ $^ $(LDFLAGS) + + +exercise-opt.s: exercise.c + $(CC) $(OPTCFLAGS) -fverbose-asm -S $< -o $@ + +exercise-dbg.s: exercise.c + $(CC) $(DBGCFLAGS) -fverbose-asm -S $< -o $@ + +asm: exercise-dbg.s exercise-opt.s + + +clean: + rm -f *.o *.s aim-opt aim-dbg output.pbm random + + +benchmark: aim-opt + @{ echo; \ + top -b -n 5 | head -n 5; \ + echo; \ + echo '>>> Will compute time needed for $(ITERS) iterations averaged over $(RUNS) runs.'; \ + echo '>>> The measured mean time, its probable lower and upper bounds and S.D.'; \ + echo '>>> are printed out. See the header of statistics.awk for details.'; } >&2 + @(for i in `seq 1 $(RUNS)`; do \ + ./aim-opt $(ITERS) test16384.pbm output.pbm | tee /dev/stderr; \ + done) | awk -f statistics.awk + +evaluate: aim-opt + for s in 64 1024; do ./aim-opt 1 test$$s.pbm output.pbm; done >/dev/null + # Consider the optimistic estimate + make -s benchmark | { read m o p s; echo $$m $$o $$p $$s >&2; echo $$o; } diff --git a/aim-sort/aim-run.c b/aim-sort/aim-run.c new file mode 100644 index 0000000000000000000000000000000000000000..b50edfd206b0a2b60602bb7f3cb9aa68947b710e --- /dev/null +++ b/aim-sort/aim-run.c @@ -0,0 +1,84 @@ +#include <limits.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <assert.h> + +#include "aim.h" + + +typedef int_fast64_t timestamp_t; + +static timestamp_t +get_timer(void) +{ + struct timeval t; + gettimeofday(&t, NULL); + return 1000000*t.tv_sec + t.tv_usec; +} + +int * seq_load(char *file, int * length) { + FILE *f = fopen(file, "r"); + if (!f) { + printf("Could not read input file.\n"); + exit(1); + } + char *line = NULL; + size_t ll = 0, i = 0; + int * seq = NULL; + while (getline(&line, &ll, f) != -1) { + if (seq == NULL) { + int l = atoi(line); + seq = malloc(sizeof(int)*l); + (*length) = l; + } else { + seq[i++] = atoi(line); + } + } + fclose(f); + assert(seq); + assert(i == (*length)); + return seq; +} + +void seq_store(char *file, int *seq, int length) { + FILE *f = fopen(file, "w"); + fprintf(f, "%i\n", length); + assert(f); + for (int i = 0; i < length; i++) { + fprintf(f, "%i\n", seq[i]); + } + fclose(f); + return; +} + + +int +main(int argc, char *argv[]) +{ + if (argc != 4) { + fprintf(stderr, "%s ITERATIONS SRCSEQ.txt OUTSEQ.txt\n", argv[0]); + return EXIT_FAILURE; + } + + int length; + int * seq = seq_load(argv[2], &length); + timestamp_t t0 = get_timer(); + + /* Pre-warm the CPU! Neccessary for benchmarking w/ dynamic + * cpufreq policy. */ + while (get_timer() - t0 < 500000); + t0 = get_timer(); + + int iters = atoi(argv[1]); + for (int j = 0; j < iters; j++) { + exercise(seq, length); + } + + t0 = get_timer() - t0; + // time spent: + printf("%.3f\n", (double) t0/1e6); + seq_store(argv[3], seq, length); + return EXIT_SUCCESS; +} diff --git a/aim-sort/aim.h b/aim-sort/aim.h new file mode 100644 index 0000000000000000000000000000000000000000..bbefc9914335941b588e96cd9748712fad919547 --- /dev/null +++ b/aim-sort/aim.h @@ -0,0 +1,8 @@ +#ifndef AIM__AIM_H +#define AIM__AIM_H + +#include <stdbool.h> + +void exercise(int * seq, size_t length); + +#endif diff --git a/aim-sort/exercise.c b/aim-sort/exercise.c new file mode 100644 index 0000000000000000000000000000000000000000..2abc36cf009c1559e786552db1bed5714ee8258b --- /dev/null +++ b/aim-sort/exercise.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include "aim.h" +#include <stdint.h> +#include <math.h> +#include <stdlib.h> + +static int qcomp(int *a, int *b) { + return (*a) - (*b); +} + +void exercise(int * seq, size_t length) { + qsort(seq, length, sizeof(int), (__compar_fn_t) &qcomp); +} diff --git a/aim-sort/random.c b/aim-sort/random.c new file mode 100644 index 0000000000000000000000000000000000000000..e4c0a50e335cf367671827b7eced22f71fe4eb03 --- /dev/null +++ b/aim-sort/random.c @@ -0,0 +1,17 @@ +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> + +int main(int argc, char **argv) { + if (argc != 2) { fprintf(stderr, "Usage: %s count\n", argv[0]); exit(1); } + int count = atoi(argv[1]); + if (count <= 0) { + fprintf(stderr, "Invalid count given: %i\n", count); + exit(2); + } + + printf("%i\n", count); + for (int i = 0; i < count; i++) { + printf("%i\n", rand()); + } +} diff --git a/aim-sort/statistics.awk b/aim-sort/statistics.awk new file mode 100644 index 0000000000000000000000000000000000000000..27719f6a7067956bda564eb2a317a52513ea9a90 --- /dev/null +++ b/aim-sort/statistics.awk @@ -0,0 +1,29 @@ +# We will compute the mean and standard deviation of the numbers on stdin. +# We can interpret the standard deviation [*] like this: +# +# With probability 68%, the actual mean time M is within one S.D. s +# around the measured mean m: M \in (m-s,m+s) +# +# [*] We assume the numbers (time taken) are approximately normally +# distributed around the measured mean. + +BEGIN { + sum = 0 + sqsum = 0 +} + +{ + sum = sum + $1 + sqsum = sqsum + $1*$1 +} + +END { + n = NR + mean = sum / n + # Exercise: This method of variance computation might be + # sub-optimal. Try to find out why and implement a better + # method. + var = (n * sqsum - sum * sum) / (n * (n-1)) + sd = sqrt(var) + print mean, mean - sd, mean + sd, sd +}