diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..56a9055 --- /dev/null +++ b/Makefile @@ -0,0 +1,56 @@ +.POSIX: +.SUFFIXES: + +# Use the system's default C compiler +# was gnu89 reallyyyy necessary .... +# surely gradescope machines have a compiler which can do post Y2K C .... + +CC = cc +CFLAGS = -Wall -Wpointer-arith -Wstrict-prototypes -std=c11 -fPIC + +# Pathname of the pkg-config compatible utility +# (not using this for this assignment at all) +#PC = pkg-config + +# Instructions to create an LSP db -- default is clangd with compile_flags.txt +# e.g. To use bear you can set DB="bear -- make" which will create compile_commands.json +DB = echo $(LDFLAGS) $(CFLAGS) | tr ' ' '\n' > compile_flags.txt + +# Project Files +BIN=test-mergesort +OBJ=test-mergesort.o mergesort.o +SRC=$(OBJ:%.o=%.c) +DEP=$(OBJ:%.o=%.d) + +all: $(BIN) + +# Build binary from objects +$(BIN): $(OBJ) + $(CC) $(CFLAGS) -o $@ $(OBJ) $(LDFLAGS) + +# Suffix rules to create .o and .d files from sources +.SUFFIXES: .c .o +.c.o: + $(CC) $(CFLAGS) $(INC) -c $< + +.SUFFIXES: .c .d +.c.d: + $(CC) -MM $< -o $@ + +# Unit tests +test: + make -f merge_test.make + +# Generate LSP database on each clean +db: + $(DB) + +clean: db + rm -fr $(BIN) + rm -fr $(OBJ) + rm -fr $(DEP) + + make -f merge_test.make clean + +# For FreeBSD make use -include +-include $(DEP) diff --git a/README.md b/README.md new file mode 100644 index 0000000..02211c3 --- /dev/null +++ b/README.md @@ -0,0 +1,75 @@ +README.template + +## Project Number/Title + +* Authors: Izak Baldacchino (a1830164), Bunsarak Ann (a1827385), Matthew Edmonds-Wilson(a1850372) +* Group name: Assignment 3 Groups 190 + +## Overview + +This program benchmarks the performance of the parallel merge sort algorithm. +Given an array of random integers of size N, and a "level", it performs merge +sort; each time the array is partitioned, a new thread is spawned to perform +the recursive merge sort on the sub-array. This continues until the "level" +is exceeded. + +## Manifest + +Makefile -- the recipes which are used to compile the project. +README.md -- this file! +mergesort.c -- contains the source for the functions which need to be implemented. +mergesort.h -- contains the declarations for the functions and structs used. +test-mergesort.c -- contains the source for the program which runs the algorithm. + +## Building the project + +To build the project simply execute `make`. This assumes it is being built on a UNIX-like +system which features some rendition of the `make` utility. In fact, any system which is +POSIX-compliant shall be able to execute and run this makefile. + +From this point execute the built executable `./test-mergesort` and provide relevant arguments. + +## Features and usage + +To run the program use `./test-mergesort N level seed` where `N` refers to the size of the generated +array, `level` refers to the number of times the array is partitioned and sorted in parallel, and +`seed` is used as the seed for generating the random array; same seed = same array. + +TODO: write more perhaps? + +## Testing + +This section should detail how you tested your code. Simply stating "I ran +it a few times and it seems to work" is not sufficient. Your testing needs +to be detailed here. + + +TODO: figure out testing scheme. + +## Known Bugs + +List known bugs that you weren't able to fix (or ran out of time to fix). + +TODO: haven't made any bugs yet ... + +## Reflection and Self Assessment + +Discuss the issues you encountered during development and testing. What +problems did you have? What did you have to research and learn on your own? +What kinds of errors did you get? How did you fix them? + +What parts of the project did you find challenging? Is there anything that +finally "clicked" for you in the process of working on this project? How well +did the development and testing process go for you? + + +TODO: haven't finished yet ... + +## Sources Used + +If you used any sources outside of the textbook, you should list them here. +If you looked something up on stackoverflow.com or you use help from AI, and +fail to cite it in this section, it will be considered plagiarism and dealt +with accordingly. So be safe CITE! + +TODO: haven't used any sources yet ... diff --git a/comp2002-os-mergesort/Makefile b/comp2002-os-mergesort/Makefile deleted file mode 100644 index fb7a828..0000000 --- a/comp2002-os-mergesort/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -CC = gcc -CFLAGS = -Wall -Wpointer-arith -Wstrict-prototypes -std=gnu89 -fPIC -MMD -MP -lpthread - -all: test-mergesort - -#This builds an executable -test-mergesort: test-mergesort.o mergesort.o - $(CC) $(CFLAGS) -o $@ $? - -.PHONY: clean -clean: - /bin/rm -f *.o *.d test-mergesort diff --git a/comp2002-os-mergesort/README.template b/comp2002-os-mergesort/README.template deleted file mode 100644 index 38d5ffb..0000000 --- a/comp2002-os-mergesort/README.template +++ /dev/null @@ -1,57 +0,0 @@ -README.template - -## Project Number/Title - -* Authors: Your Name, and your group members’ names -* Group name: Your Group Name - -## Overview - -Concisely explain what the program does. If this exceeds a couple of -sentences, you're going too far. Generally, you should be pulling this -right from the project specification. We don't want you to just cut and -paste, but paraphrase what is stated in the project specification. - -## Manifest - -A listing of source files and other non-generated files, and a brief -(one-line) explanation of the purpose of each file. - -## Building the project - -This section should tell the user how to build your code. If you are -delivering a library, where does it need to be installed, or how do you use -it? Is this an executable, if so, how can a user get up to speed as fast as -possible? - -## Features and usage - -Summarise the main features of your program. It is also appropriate to -instruct the user how to use your program. - -## Testing - -This section should detail how you tested your code. Simply stating "I ran -it a few times and it seems to work" is not sufficient. Your testing needs -to be detailed here. - -## Known Bugs - -List known bugs that you weren't able to fix (or ran out of time to fix). - -## Reflection and Self Assessment - -Discuss the issues you encountered during development and testing. What -problems did you have? What did you have to research and learn on your own? -What kinds of errors did you get? How did you fix them? - -What parts of the project did you find challenging? Is there anything that -finally "clicked" for you in the process of working on this project? How well -did the development and testing process go for you? - -## Sources Used - -If you used any sources outside of the textbook, you should list them here. -If you looked something up on stackoverflow.com or you use help from AI, and -fail to cite it in this section, it will be considered plagiarism and dealt -with accordingly. So be safe CITE! diff --git a/comp2002-os-mergesort/mergesort.c b/comp2002-os-mergesort/mergesort.c deleted file mode 100644 index 3e8bf4e..0000000 --- a/comp2002-os-mergesort/mergesort.c +++ /dev/null @@ -1,27 +0,0 @@ -/** - * This file implements parallel mergesort. - */ - -#include -#include /* for memcpy */ -#include /* for malloc */ -#include "mergesort.h" - -/* this function will be called by mergesort() and also by parallel_mergesort(). */ -void merge(int leftstart, int leftend, int rightstart, int rightend){ -} - -/* this function will be called by parallel_mergesort() as its base case. */ -void my_mergesort(int left, int right){ -} - -/* this function will be called by the testing program. */ -void * parallel_mergesort(void *arg){ - return NULL; -} - -/* we build the argument for the parallel_mergesort function. */ -struct argument * buildArgs(int left, int right, int level){ - return NULL; -} - diff --git a/merge_test.c b/merge_test.c new file mode 100644 index 0000000..0bcf6e6 --- /dev/null +++ b/merge_test.c @@ -0,0 +1,95 @@ +#include +#include +#include + +#include "mergesort.h" + +// global state is safe and good and never goes wrong and doesn't make testing difficult! +int* A; +int* B; + +void printA(size_t start, size_t end) { + printf("\nA "); + for(size_t i = start; i < end+1; i++) { + printf("%d ", A[i]); + } +} + +void printB(size_t start, size_t end) { + printf("\nB "); + for(size_t i = start; i < end+1; i++) { + printf("%d ", B[i]); + } +} + +/* unit test for merge function */ +int main(void) { + /* contrary to popular practice, malloc should not be casted + as void* is casted safely automatically */ + + /* first test: merge two halves of the full array */ + { + printf("Test 1: merge two havles of full array\n"); + A = malloc(10 * sizeof(int)); + B = malloc(10 * sizeof(int)); + + A[0] = 0; /* leftstart = 0*/ + A[1] = 1; + A[2] = 2; + A[3] = 3; + A[4] = 4; /* leftend = 4*/ + + A[5] = 3; /* rightstart = 5 */ + A[6] = 4; + A[7] = 5; + A[8] = 6; + A[9] = 7; /* rightend = 9 */ + + /* expected result is A=[0,1,2,3,3,4,4,5,6,7] */ + merge(0,4,5,9); + + assert(A[0] == 0); + assert(A[1] == 1); + assert(A[2] == 2); + assert(A[3] == 3); + assert(A[4] == 3); + assert(A[5] == 4); + assert(A[6] == 4); + assert(A[7] == 5); + assert(A[8] == 6); + assert(A[9] == 7); + + printf("Test 1: Passed\n"); + } + + + /* first test: merge two halves of the full array */ + { + printf("Test 2: merge two havles of sub-array\n"); + A = malloc(10 * sizeof(int)); + B = malloc(10 * sizeof(int)); + + A[0] = 5; + A[1] = 6; + A[2] = 7; + A[3] = 8; + A[4] = 9; + + A[5] = 10; /* leftstart = 5 */ + A[6] = 11; /* leftend = 6 */ + A[7] = 2; /* rightstart = 7 */ + A[8] = 3; + A[9] = 4; /* rightend = 9 */ + + /* expected result is A=[2,3,4,10,11] */ + merge(5,6,7,9); + + assert(A[5] == 2); + assert(A[6] == 3); + assert(A[7] == 4); + assert(A[8] == 10); + assert(A[9] == 11); + + printf("Test 2: Passed\n"); + } +} diff --git a/merge_test.make b/merge_test.make new file mode 100644 index 0000000..d4c3203 --- /dev/null +++ b/merge_test.make @@ -0,0 +1,50 @@ +.POSIX: +.SUFFIXES: + +# Use the system's default C compiler +# was gnu89 reallyyyy necessary .... +# surely gradescope machines have a compiler which can do post Y2K C .... + +CC = cc +CFLAGS = -Wall -Wpointer-arith -Wstrict-prototypes -std=c11 -fPIC + +# Pathname of the pkg-config compatible utility +# (not using this for this assignment at all) +#PC = pkg-config + +# Instructions to create an LSP db -- default is clangd with compile_flags.txt +# e.g. To use bear you can set DB="bear -- make" which will create compile_commands.json +DB = echo $(LDFLAGS) $(CFLAGS) | tr ' ' '\n' > compile_flags.txt + +# Project Files +BIN=merge_test.test +OBJ=merge_test.o mergesort.o +SRC=$(OBJ:%.o=%.c) +DEP=$(OBJ:%.o=%.d) + +all: $(BIN) + +# Build binary from objects +$(BIN): $(OBJ) + $(CC) $(CFLAGS) -o $@ $(OBJ) $(LDFLAGS) + +# Suffix rules to create .o and .d files from sources +.SUFFIXES: .c .o +.c.o: + $(CC) $(CFLAGS) $(INC) -c $< + +.SUFFIXES: .c .d +.c.d: + $(CC) -MM $< -o $@ + +# Generate LSP database on each clean +db: + $(DB) + +clean: db + rm -fr $(BIN) + rm -fr $(OBJ) + rm -fr $(DEP) + +# For FreeBSD make use -include +-include $(DEP) diff --git a/mergesort.c b/mergesort.c new file mode 100644 index 0000000..53dbe03 --- /dev/null +++ b/mergesort.c @@ -0,0 +1,74 @@ +#include +#include +#include + +#include "mergesort.h" + +/* this function will be called by mergesort() and also by parallel_mergesort(). */ + +/* merges two sub-arrays preserving order */ +void merge(int leftstart, int leftend, int rightstart, int rightend) { + + int leftindex = leftstart; + int rightindex = rightstart; + int index = leftstart; + + /* iterate through the main array A at two positions (leftstart and rightstart). + + for each index in B, insert the left or right element from A which is + of lesser value until either position is out of bounds + */ + + for(; (leftindex <= leftend) && (rightindex <= rightend); index++) { + /* choose left element from B if smaller */ + if(A[leftindex] <= A[rightindex]) { + B[index] = A[leftindex]; + leftindex++; + } + else /* choose right element */ { + B[index] = A[rightindex]; + rightindex++; + } + } + + /* loop terminates once either sub-array is out of bounds + + as such, remaining elements in either sub-array must be + copied to B + + either one of these copies may be a no-op (since only one + sub-array will have elements remaining at most) + */ + + int num_bytes_to_copy_in_total = ((rightend - leftstart) + 1) * sizeof(int); + int num_bytes_to_copy_from_left = ((leftend - leftindex) + 1) * sizeof(int); + int num_bytes_to_copy_from_right = ((rightend - rightindex) + 1) * sizeof(int); + + memcpy(&B[index], &A[leftindex], num_bytes_to_copy_from_left); + memcpy(&B[index], &A[rightindex], num_bytes_to_copy_from_right); + /* copy auxiliary array B, which is now sorted, back to A */ + memcpy(&A[leftstart], &B[leftstart], num_bytes_to_copy_in_total); +} + +/* this function will be called by parallel_mergesort() as its base case. */ +void my_mergesort(int left, int right) { + if (left >= right ) return; /* base case: array of size 0 or 1 is already sorted */ + + int mid = left + (right - left) / 2; // Split the range roughly in half + + my_mergesort(left, mid); /* sort the left half*/ + my_mergesort(mid + 1, right); /* sort the right half*/ + + merge(left, mid, mid + 1, right); /* merge the two sorted halves */ +} + +/* this function will be called by the testing program. */ +void * parallel_mergesort(void* arg) { + return NULL; +} + +/* we build the argument for the parallel_mergesort function. */ +struct argument* buildArgs(int left, int right, int level) { + return NULL; +} + diff --git a/comp2002-os-mergesort/mergesort.h b/mergesort.h similarity index 100% rename from comp2002-os-mergesort/mergesort.h rename to mergesort.h diff --git a/comp2002-os-mergesort/test-mergesort.c b/test-mergesort.c similarity index 98% rename from comp2002-os-mergesort/test-mergesort.c rename to test-mergesort.c index b56ab5a..01038b5 100644 --- a/comp2002-os-mergesort/test-mergesort.c +++ b/test-mergesort.c @@ -3,8 +3,7 @@ #include #include /* for times system call */ #include /* for gettimeofday system call */ -#include -#include /* On MacOS you won't need this line */ +#include /* On MacOS you won't need this line */ #include "mergesort.h" /* the number of levels of threads, specified by the user */