From a988405fd31edb2a8735fa7130972b107620a8a2 Mon Sep 17 00:00:00 2001 From: Nikolaj Date: Tue, 26 Oct 2021 14:15:16 +0200 Subject: [PATCH] A3 :tada: --- A1/src.zip | Bin 0 -> 10427 bytes A2/Makefile | 23 +++++++++ A2/fauxgrep-mt.c | 87 ++++++++++++++++++++++++++++++++ A2/fauxgrep.c | 82 ++++++++++++++++++++++++++++++ A2/fhistogram-mt.c | 87 ++++++++++++++++++++++++++++++++ A2/fhistogram.c | 93 ++++++++++++++++++++++++++++++++++ A2/fibs.c | 122 +++++++++++++++++++++++++++++++++++++++++++++ A2/histogram.h | 71 ++++++++++++++++++++++++++ A2/job_queue.c | 21 ++++++++ A2/job_queue.h | 30 +++++++++++ 10 files changed, 616 insertions(+) create mode 100644 A1/src.zip create mode 100644 A2/Makefile create mode 100644 A2/fauxgrep-mt.c create mode 100644 A2/fauxgrep.c create mode 100644 A2/fhistogram-mt.c create mode 100644 A2/fhistogram.c create mode 100644 A2/fibs.c create mode 100644 A2/histogram.h create mode 100644 A2/job_queue.c create mode 100644 A2/job_queue.h diff --git a/A1/src.zip b/A1/src.zip new file mode 100644 index 0000000000000000000000000000000000000000..5eb9a4ca8532b9a269d2c833b7b5105e20170fdf GIT binary patch literal 10427 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 +#include +#include +#include + +#include +#include +#include + +// err.h contains various nonstandard BSD extensions, but they are +// very handy. +#include + +#include + +#include "job_queue.h" + +int main(int argc, char * const *argv) { + if (argc < 2) { + err(1, "usage: [-n INT] STRING paths..."); + exit(1); + } + + int num_threads = 1; + char const *needle = argv[1]; + char * const *paths = &argv[2]; + + + if (argc > 3 && strcmp(argv[1], "-n") == 0) { + // Since atoi() simply returns zero on syntax errors, we cannot + // distinguish between the user entering a zero, or some + // non-numeric garbage. In fact, we cannot even tell whether the + // given option is suffixed by garbage, i.e. '123foo' returns + // '123'. A more robust solution would use strtol(), but its + // interface is more complicated, so here we are. + num_threads = atoi(argv[2]); + + if (num_threads < 1) { + err(1, "invalid thread count: %s", argv[2]); + } + + needle = argv[3]; + paths = &argv[4]; + + } else { + needle = argv[1]; + paths = &argv[2]; + } + + assert(0); // Initialise the job queue and some worker threads here. + + // FTS_LOGICAL = follow symbolic links + // FTS_NOCHDIR = do not change the working directory of the process + // + // (These are not particularly important distinctions for our simple + // uses.) + int fts_options = FTS_LOGICAL | FTS_NOCHDIR; + + FTS *ftsp; + if ((ftsp = fts_open(paths, fts_options, NULL)) == NULL) { + err(1, "fts_open() failed"); + return -1; + } + + FTSENT *p; + while ((p = fts_read(ftsp)) != NULL) { + switch (p->fts_info) { + case FTS_D: + break; + case FTS_F: + assert(0); // Process the file p->fts_path, somehow. + break; + default: + break; + } + } + + fts_close(ftsp); + + assert(0); // Shut down the job queue and the worker threads here. + + return 0; +} diff --git a/A2/fauxgrep.c b/A2/fauxgrep.c new file mode 100644 index 0000000..80eedc8 --- /dev/null +++ b/A2/fauxgrep.c @@ -0,0 +1,82 @@ +// Setting _DEFAULT_SOURCE is necessary to activate visibility of +// certain header file contents on GNU/Linux systems. +#define _DEFAULT_SOURCE + +#include +#include +#include +#include + +#include +#include +#include + +// err.h contains various nonstandard BSD extensions, but they are +// very handy. +#include + +int fauxgrep_file(char const *needle, char const *path) { + FILE *f = fopen(path, "r"); + + if (f == NULL) { + warn("failed to open %s", path); + return -1; + } + + char *line = NULL; + size_t linelen = 0; + int lineno = 1; + + while (getline(&line, &linelen, f) != -1) { + if (strstr(line, needle) != NULL) { + printf("%s:%d: %s", path, lineno, line); + } + + lineno++; + } + + free(line); + fclose(f); + + return 0; +} + +int main(int argc, char * const *argv) { + if (argc < 2) { + err(1, "usage: STRING paths..."); + exit(1); + } + + char const *needle = argv[1]; + char * const *paths = &argv[2]; + + // FTS_LOGICAL = follow symbolic links + // FTS_NOCHDIR = do not change the working directory of the process + // + // (These are not particularly important distinctions for our simple + // uses.) + int fts_options = FTS_LOGICAL | FTS_NOCHDIR; + + FTS *ftsp; + if ((ftsp = fts_open(paths, fts_options, NULL)) == NULL) { + err(1, "fts_open() failed"); + return -1; + } + + FTSENT *p; + while ((p = fts_read(ftsp)) != NULL) { + switch (p->fts_info) { + case FTS_D: + break; + case FTS_F: + fauxgrep_file(needle, p->fts_path); + break; + default: + break; + } + } + + fts_close(ftsp); + + return 0; +} diff --git a/A2/fhistogram-mt.c b/A2/fhistogram-mt.c new file mode 100644 index 0000000..b6b4537 --- /dev/null +++ b/A2/fhistogram-mt.c @@ -0,0 +1,87 @@ +// Setting _DEFAULT_SOURCE is necessary to activate visibility of +// certain header file contents on GNU/Linux systems. +#define _DEFAULT_SOURCE + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "job_queue.h" + +pthread_mutex_t stdout_mutex = PTHREAD_MUTEX_INITIALIZER; + +// err.h contains various nonstandard BSD extensions, but they are +// very handy. +#include + +#include "histogram.h" + +int main(int argc, char * const *argv) { + if (argc < 2) { + err(1, "usage: paths..."); + exit(1); + } + + int num_threads = 1; + char * const *paths = &argv[1]; + + if (argc > 3 && strcmp(argv[1], "-n") == 0) { + // Since atoi() simply returns zero on syntax errors, we cannot + // distinguish between the user entering a zero, or some + // non-numeric garbage. In fact, we cannot even tell whether the + // given option is suffixed by garbage, i.e. '123foo' returns + // '123'. A more robust solution would use strtol(), but its + // interface is more complicated, so here we are. + num_threads = atoi(argv[2]); + + if (num_threads < 1) { + err(1, "invalid thread count: %s", argv[2]); + } + + paths = &argv[3]; + } else { + paths = &argv[1]; + } + + assert(0); // Initialise the job queue and some worker threads here. + + // FTS_LOGICAL = follow symbolic links + // FTS_NOCHDIR = do not change the working directory of the process + // + // (These are not particularly important distinctions for our simple + // uses.) + int fts_options = FTS_LOGICAL | FTS_NOCHDIR; + + FTS *ftsp; + if ((ftsp = fts_open(paths, fts_options, NULL)) == NULL) { + err(1, "fts_open() failed"); + return -1; + } + + FTSENT *p; + while ((p = fts_read(ftsp)) != NULL) { + switch (p->fts_info) { + case FTS_D: + break; + case FTS_F: + assert(0); // Process the file p->fts_path, somehow. + break; + default: + break; + } + } + + fts_close(ftsp); + + assert(0); // Shut down the job queue and the worker threads here. + + move_lines(9); + + return 0; +} diff --git a/A2/fhistogram.c b/A2/fhistogram.c new file mode 100644 index 0000000..e070983 --- /dev/null +++ b/A2/fhistogram.c @@ -0,0 +1,93 @@ +// Setting _DEFAULT_SOURCE is necessary to activate visibility of +// certain header file contents on GNU/Linux systems. +#define _DEFAULT_SOURCE + +#include +#include +#include +#include +#include + +#include +#include +#include + +// err.h contains various nonstandard BSD extensions, but they are +// very handy. +#include + +#include "histogram.h" + +int global_histogram[8] = { 0 }; + +int fhistogram(char const *path) { + FILE *f = fopen(path, "r"); + + int local_histogram[8] = { 0 }; + + if (f == NULL) { + fflush(stdout); + warn("failed to open %s", path); + return -1; + } + + int i = 0; + + char c; + while (fread(&c, sizeof(c), 1, f) == 1) { + i++; + update_histogram(local_histogram, c); + if ((i % 100000) == 0) { + merge_histogram(local_histogram, global_histogram); + print_histogram(global_histogram); + } + } + + fclose(f); + + merge_histogram(local_histogram, global_histogram); + print_histogram(global_histogram); + + return 0; +} + +int main(int argc, char * const *argv) { + if (argc < 2) { + err(1, "usage: paths..."); + exit(1); + } + + char * const *paths = &argv[1]; + + // FTS_LOGICAL = follow symbolic links + // FTS_NOCHDIR = do not change the working directory of the process + // + // (These are not particularly important distinctions for our simple + // uses.) + int fts_options = FTS_LOGICAL | FTS_NOCHDIR; + + FTS *ftsp; + if ((ftsp = fts_open(paths, fts_options, NULL)) == NULL) { + err(1, "fts_open() failed"); + return -1; + } + + FTSENT *p; + while ((p = fts_read(ftsp)) != NULL) { + switch (p->fts_info) { + case FTS_D: + break; + case FTS_F: + fhistogram(p->fts_path); + break; + default: + break; + } + } + + fts_close(ftsp); + + move_lines(9); + + return 0; +} diff --git a/A2/fibs.c b/A2/fibs.c new file mode 100644 index 0000000..e92c6d7 --- /dev/null +++ b/A2/fibs.c @@ -0,0 +1,122 @@ +// This program reads a newline-separated sequence of integers from +// standard input. For each such integer, the corresponding Fibonacci +// number is printed. This is similar to the programs we saw at the +// November 20 lecture. + +// Setting _DEFAULT_SOURCE is necessary to activate visibility of +// certain header file contents on GNU/Linux systems. +#define _DEFAULT_SOURCE + +#include +#include +#include +#include +#include + +#include +#include +#include + +// err.h contains various nonstandard BSD extensions, but they are +// very handy. +#include + +#include "job_queue.h" + +// Whenever we print to the screen, we will first lock this mutex. +// This ensures that multiple threads do not try to print +// concurrently. +pthread_mutex_t stdout_mutex = PTHREAD_MUTEX_INITIALIZER; + +// A simple recursive (inefficient) implementation of the Fibonacci +// function. +int fib (int n) { + if (n < 2) { + return 1; + } else { + return fib(n-1) + fib(n-2); + } +} + +// This function converts a line to an integer, computes the +// corresponding Fibonacci number, then prints the result to the +// screen. +void fib_line(const char *line) { + int n = atoi(line); + int fibn = fib(n); + assert(pthread_mutex_lock(&stdout_mutex) == 0); + printf("fib(%d) = %d\n", n, fibn); + assert(pthread_mutex_unlock(&stdout_mutex) == 0); +} + +// Each thread will run this function. The thread argument is a +// pointer to a job queue. +void* worker(void *arg) { + struct job_queue *jq = arg; + + while (1) { + char *line; + if (job_queue_pop(jq, (void**)&line) == 0) { + fib_line(line); + free(line); + } else { + // If job_queue_pop() returned non-zero, that means the queue is + // being killed (or some other error occured). In any case, + // that means it's time for this thread to die. + break; + } + } + + return NULL; +} + +int main(int argc, char * const *argv) { + int num_threads = 1; + + if (argc == 3 && strcmp(argv[1], "-n") == 0) { + // Since atoi() simply returns zero on syntax errors, we cannot + // distinguish between the user entering a zero, or some + // non-numeric garbage. In fact, we cannot even tell whether the + // given option is suffixed by garbage, i.e. '123foo' returns + // '123'. A more robust solution would use strtol(), but its + // interface is more complicated, so here we are. + num_threads = atoi(argv[2]); + + if (num_threads < 1) { + err(1, "invalid thread count: %s", argv[2]); + } + } + + // Create job queue. + struct job_queue jq; + job_queue_init(&jq, 64); + + // Start up the worker threads. + pthread_t *threads = calloc(num_threads, sizeof(pthread_t)); + for (int i = 0; i < num_threads; i++) { + if (pthread_create(&threads[i], NULL, &worker, &jq) != 0) { + err(1, "pthread_create() failed"); + } + } + + + // Now read lines from stdin until EOF. + char *line = NULL; + ssize_t line_len; + size_t buf_len = 0; + while ((line_len = getline(&line, &buf_len, stdin)) != -1) { + job_queue_push(&jq, (void*)strdup(line)); + } + free(line); + + // Destroy the queue. + job_queue_destroy(&jq); + + // Wait for all threads to finish. This is important, at some may + // still be working on their job. + for (int i = 0; i < num_threads; i++) { + if (pthread_join(threads[i], NULL) != 0) { + err(1, "pthread_join() failed"); + } + } +} diff --git a/A2/histogram.h b/A2/histogram.h new file mode 100644 index 0000000..967e00a --- /dev/null +++ b/A2/histogram.h @@ -0,0 +1,71 @@ +// This header file contains not just function prototypes, but also +// the definitions. This means it does not need to be compiled +// separately. +// +// You should not need to modify this file. + +#ifndef HISTOGRAM_H +#define HISTOGRAM_H + +// Move the cursor down 'n' lines. Negative 'n' supported. +static void move_lines(int n) { + if (n < 0) { + printf("\033[%dA", -n); + } else { + printf("\033[%dB", n); + } +} + +// Clear from cursor to end of line. +static void clear_line() { + printf("\033[K"); +} + +// Print a visual representation of a histogram to the screen. After +// printing, the cursor is moved back to the beginning of the output. +// This means that next time print_histogram() is called, the previous +// output will be overwritten. +static void print_histogram(int histogram[8]) { + int64_t bits_seen = 0; + + for (int i = 0; i < 8; i++) { + bits_seen += histogram[i]; + } + + for (int i = 0; i < 8; i++) { + clear_line(); + printf("Bit %d: ", i); + + double proportion = histogram[i] / ((double)bits_seen); + for (int i = 0; i < 60*proportion; i++) { + printf("*"); + } + printf("\n"); + } + + clear_line(); + printf("%ld bits processed.\n", (long)bits_seen); + move_lines(-9); +} + +// Merge the former histogram into the latter, setting the former to +// zero in the process. +static void merge_histogram(int from[8], int to[8]) { + for (int i = 0; i < 8; i++) { + to[i] += from[i]; + from[i] = 0; + } +} + +// Update the histogram with the bits of a byte. +static void update_histogram(int histogram[8], unsigned char byte) { + // For all bits in a byte... + for (int i = 0; i < 8; i++) { + // count if bit 'i' is set. + if (byte & (1< +#include +#include + +#include "job_queue.h" + +int job_queue_init(struct job_queue *job_queue, int capacity) { + assert(0); +} + +int job_queue_destroy(struct job_queue *job_queue) { + assert(0); +} + +int job_queue_push(struct job_queue *job_queue, void *data) { + assert(0); +} + +int job_queue_pop(struct job_queue *job_queue, void **data) { + assert(0); +} diff --git a/A2/job_queue.h b/A2/job_queue.h new file mode 100644 index 0000000..e21a00f --- /dev/null +++ b/A2/job_queue.h @@ -0,0 +1,30 @@ +#ifndef JOB_QUEUE_H +#define JOB_QUEUE_H + +#include + +struct job_queue { + int dummy; +}; + +// Initialise a job queue with the given capacity. The queue starts out +// empty. Returns non-zero on error. +int job_queue_init(struct job_queue *job_queue, int capacity); + +// Destroy the job queue. Blocks until the queue is empty before it +// is destroyed. +int job_queue_destroy(struct job_queue *job_queue); + +// Push an element onto the end of the job queue. Blocks if the +// job_queue is full (its size is equal to its capacity). Returns +// non-zero on error. It is an error to push a job onto a queue that +// has been destroyed. +int job_queue_push(struct job_queue *job_queue, void *data); + +// Pop an element from the front of the job queue. Blocks if the +// job_queue contains zero elements. Returns non-zero on error. If +// job_queue_destroy() has been called (possibly after the call to +// job_queue_pop() blocked), this function will return -1. +int job_queue_pop(struct job_queue *job_queue, void **data); + +#endif