From 9b7527997bbd1da4d6ea66e75e0edcef1787bf30 Mon Sep 17 00:00:00 2001 From: Izak Baldacchino <83893457+Izak8@users.noreply.github.com> Date: Fri, 24 Oct 2025 14:16:39 +1030 Subject: [PATCH 1/5] chore: reorganise directory structure (#14) Includes a partially-authored README file. However, there are still some changes to make, as there are sections which we cannot fill out yet. This commit was accidentally authored under my university GitHub identity, woops. --------- Co-authored-by: Izak Baldacchino --- comp2002-os-mergesort/Makefile => Makefile | 0 README.md | 75 +++++++++++++++++++ comp2002-os-mergesort/README.template | 57 -------------- .../mergesort.c => mergesort.c | 0 .../mergesort.h => mergesort.h | 0 .../test-mergesort.c => test-mergesort.c | 0 6 files changed, 75 insertions(+), 57 deletions(-) rename comp2002-os-mergesort/Makefile => Makefile (100%) create mode 100644 README.md delete mode 100644 comp2002-os-mergesort/README.template rename comp2002-os-mergesort/mergesort.c => mergesort.c (100%) rename comp2002-os-mergesort/mergesort.h => mergesort.h (100%) rename comp2002-os-mergesort/test-mergesort.c => test-mergesort.c (100%) diff --git a/comp2002-os-mergesort/Makefile b/Makefile similarity index 100% rename from comp2002-os-mergesort/Makefile rename to Makefile 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/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/mergesort.c similarity index 100% rename from comp2002-os-mergesort/mergesort.c rename to mergesort.c 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 100% rename from comp2002-os-mergesort/test-mergesort.c rename to test-mergesort.c From 20bddd8d5d087ae21ccfd146429af2160d743e0d Mon Sep 17 00:00:00 2001 From: Izak Baldacchino <83893457+Izak8@users.noreply.github.com> Date: Mon, 27 Oct 2025 23:04:30 +1030 Subject: [PATCH 2/5] feat: implement `merge` function (#17) Includes the implementation for the merge function. The makefile has been revamped in order to allow a unit test executable to built and run to test the function. --------- Co-authored-by: Izak Baldacchino --- Makefile | 62 +++++++++++++++++++++++++++----- merge_test.c | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ merge_test.make | 50 ++++++++++++++++++++++++++ mergesort.c | 60 +++++++++++++++++++++++++------ 4 files changed, 248 insertions(+), 19 deletions(-) create mode 100644 merge_test.c create mode 100644 merge_test.make diff --git a/Makefile b/Makefile index fb7a828..56a9055 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,56 @@ -CC = gcc -CFLAGS = -Wall -Wpointer-arith -Wstrict-prototypes -std=gnu89 -fPIC -MMD -MP -lpthread +.POSIX: +.SUFFIXES: -all: test-mergesort +# Use the system's default C compiler +# was gnu89 reallyyyy necessary .... +# surely gradescope machines have a compiler which can do post Y2K C .... -#This builds an executable -test-mergesort: test-mergesort.o mergesort.o - $(CC) $(CFLAGS) -o $@ $? +CC = cc +CFLAGS = -Wall -Wpointer-arith -Wstrict-prototypes -std=c11 -fPIC -.PHONY: clean -clean: - /bin/rm -f *.o *.d test-mergesort +# 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/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 index 3e8bf4e..deccd14 100644 --- a/mergesort.c +++ b/mergesort.c @@ -1,27 +1,67 @@ -/** - * This file implements parallel mergesort. - */ - #include -#include /* for memcpy */ -#include /* for malloc */ +#include +#include + #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){ + +/* 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){ +void my_mergesort(int left, int right) { + } /* this function will be called by the testing program. */ -void * parallel_mergesort(void *arg){ +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){ +struct argument* buildArgs(int left, int right, int level) { return NULL; } From ca16fc119e82c7be07054fea81f0af9d5350264b Mon Sep 17 00:00:00 2001 From: Izak Baldacchino <83893457+Izak8@users.noreply.github.com> Date: Wed, 29 Oct 2025 16:45:40 +1030 Subject: [PATCH 3/5] Implement `buildArgs` function (#19) Includes the definition for the `buildArgs` function and relevant unit test. Simply allocates memory on the heap and constructs a `struct argument` there. The function then returns a pointer to this memory on the heap. --- Makefile | 9 ++++---- buildargs_test.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ merge_test.c | 2 ++ merge_test.make | 50 ---------------------------------------- mergesort.c | 34 ++++++++++++++++++++++++++- 5 files changed, 99 insertions(+), 56 deletions(-) create mode 100644 buildargs_test.c delete mode 100644 merge_test.make diff --git a/Makefile b/Makefile index 56a9055..453a829 100644 --- a/Makefile +++ b/Makefile @@ -18,7 +18,7 @@ DB = echo $(LDFLAGS) $(CFLAGS) | tr ' ' '\n' > compile_flags.txt # Project Files BIN=test-mergesort -OBJ=test-mergesort.o mergesort.o +OBJ=test-mergesort.o mergesort.o SRC=$(OBJ:%.o=%.c) DEP=$(OBJ:%.o=%.d) @@ -38,8 +38,9 @@ $(BIN): $(OBJ) $(CC) -MM $< -o $@ # Unit tests -test: - make -f merge_test.make +test: mergesort.o merge_test.o buildargs_test.o + $(CC) $(CFLAGS) -o merge.test merge_test.o mergesort.o + $(CC) $(CFLAGS) -o buildargs.test buildargs_test.o mergesort.o # Generate LSP database on each clean db: @@ -49,8 +50,6 @@ 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/buildargs_test.c b/buildargs_test.c new file mode 100644 index 0000000..10a2b63 --- /dev/null +++ b/buildargs_test.c @@ -0,0 +1,60 @@ +#include +#include +#include + +#include "mergesort.h" + +int* A; +int* B; + +int cutoff; + +int main(void) { + + struct argument* p; + + { + /* check that a valid struct is built */ + printf("Test 1: a valid struct is built from valid arguments\n"); + p = buildArgs(0,4,0); + assert(p->left == 0); + assert(p->right == 4); + assert(p->level == 0); + printf("Test 1: Passed\n"); + } + + { + printf("Test 2: NULL is returned for left > right\n"); + p = buildArgs(6,5,5); + assert(p == NULL); + printf("Test 2: Passed\n"); + } + + { + printf("Test 3: NULL is returned for negative left\n"); + p = buildArgs(-1,5,5); + assert(p == NULL); + printf("Test 3: Passed\n"); + } + + { + printf("Test 4: NULL is returned for negative right\n"); + p = buildArgs(1,-5,5); + assert(p == NULL); + printf("Test 4: Passed\n"); + } + + { + printf("Test 5: NULL is returned for negative level\n"); + p = buildArgs(1,5,-5); + assert(p == NULL); + printf("Test 5: Passed\n"); + } + + { + printf("Test 6: NULL is returned for all negative arguments\n"); + p = buildArgs(-1,-5,-5); + assert(p == NULL); + printf("Test 6: Passed\n"); + } +} diff --git a/merge_test.c b/merge_test.c index 0bcf6e6..3eb0b68 100644 --- a/merge_test.c +++ b/merge_test.c @@ -8,6 +8,8 @@ int* A; int* B; +int cutoff; + void printA(size_t start, size_t end) { printf("\nA "); for(size_t i = start; i < end+1; i++) { diff --git a/merge_test.make b/merge_test.make deleted file mode 100644 index d4c3203..0000000 --- a/merge_test.make +++ /dev/null @@ -1,50 +0,0 @@ -.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 index deccd14..c1c6bc5 100644 --- a/mergesort.c +++ b/mergesort.c @@ -62,6 +62,38 @@ void * parallel_mergesort(void* arg) { /* we build the argument for the parallel_mergesort function. */ struct argument* buildArgs(int left, int right, int level) { - return NULL; + + /* left must be <= right */ + if(left > right) { + return NULL; + } + + /* left and right are positive indices */ + if((left < 0) || (right < 0) || (level < 0)) { + return NULL; + } + + + /* allocate space on the heap for an argument struct + and create a pointer to this memory */ + struct argument* args = malloc(sizeof(struct argument)); + + /* set the memory on the heap with the relevant values + and return the pointer */ + + args->left = left; + args->right = right; + + /* level > cutoff saturate */ + if(level > cutoff) { + args->level = cutoff; + } + else { + args->level = level; + } + + return args; + + /* responsibility will be on the caller to free-up memory */ } From d7b31cae118aaf59df20b0f1b7271c59df9c42ab Mon Sep 17 00:00:00 2001 From: Izak Baldacchino <83893457+Izak8@users.noreply.github.com> Date: Wed, 29 Oct 2025 16:46:07 +1030 Subject: [PATCH 4/5] chore: add `.gitignore` file (#18) Includes a gitignore file which uses the basic C/C++ template from GitHub. Also includes `compile_flags.txt` in the ignore path. --- .gitignore | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d58e18a --- /dev/null +++ b/.gitignore @@ -0,0 +1,58 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# debug information files +*.dwo + +# LSP files +compile_flags.txt From 97f716e7065c8ec0b1c484cac74092801ec103de Mon Sep 17 00:00:00 2001 From: Bunsarak Date: Wed, 29 Oct 2025 21:34:15 +1030 Subject: [PATCH 5/5] feat(sort): implement my_mergesort --- mergesort.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/mergesort.c b/mergesort.c index c1c6bc5..a393f2d 100644 --- a/mergesort.c +++ b/mergesort.c @@ -52,7 +52,14 @@ 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) { + 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. */