diff --git a/automate.c b/automate.c new file mode 100644 index 0000000000..ef6d331d92 --- /dev/null +++ b/automate.c @@ -0,0 +1,85 @@ +#include +#include +#include + +long long sequential_compute(const char *path, + long long (*f)(long long, long long)); + +long long parallel_compute(const char *path, + int n_proc, + long long (*f)(long long, long long)); + +long long add(long long a, long long b){ return a + b; } +long long mul(long long a, long long b){ return a * b; } +long long mx (long long a, long long b){ return a > b ? a : b; } + +void generate_numbers(const char *path, int N) +{ + FILE *fp = fopen(path,"w"); + if(!fp) + { + perror("fopen"); + exit(1); + } + + for(int i=0;i +#include + +long long sequential_compute(const char *path, + long long (*f)(long long, long long)); + +long long parallel_compute(const char *path, + int n_proc, + long long (*f)(long long, long long)); + +long long add(long long a, long long b){ return a + b; } +long long mul(long long a, long long b){ return a * b; } +long long mx (long long a, long long b){ return a > b ? a : b; } + +int main() +{ + const char *path = "numbers.txt"; + + FILE *out = fopen("process_scaling.csv","w"); + if(!out) + { + perror("fopen"); + return 1; + } + + fprintf(out,"processes,time\n"); + + // different numbers of processes + for(int p = 1; p <= 16; p++) + { + clock_t start,end; + + start = clock(); + + parallel_compute(path,p,add); + parallel_compute(path,p,mul); + parallel_compute(path,p,mx); + + end = clock(); + + double time_taken = + (double)(end-start)/CLOCKS_PER_SEC; + + fprintf(out,"%d,%f\n",p,time_taken); + + printf("Processes %d done\n",p); + } + + fclose(out); + + printf("Results saved to process_scaling.csv\n"); + + return 0; +} \ No newline at end of file diff --git a/compute.c b/compute.c new file mode 100644 index 0000000000..81fec632f5 --- /dev/null +++ b/compute.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include + +static long long *read_numbers(const char *path, int *out_n){ + FILE *fp = fopen(path, "r"); + if (!fp) { perror("fopen"); return NULL;} + int cap = 64, n = 0; + long long *arr = malloc(cap * sizeof *arr); + if (!arr) {fclose(fp); return NULL;} + long long v; + while (fscanf(fp, " %lld", &v) == 1){ + if (n == cap){ + cap *= 2; + long long *tmp = realloc(arr, cap * sizeof *arr); + if (!tmp) {free(arr); fclose(fp); return NULL;} + arr = tmp;} + arr[n++] = v; + int c = fgetc(fp); + if (c != ',' && c != EOF) ungetc(c, fp); + } + + fclose(fp); + *out_n = n; + return arr; +} + +static long long reduce(const long long *arr, int n,long long (*f)(long long, long long)){ + long long acc = arr[0]; + for (int i = 1; i < n; i++) acc = f(acc, arr[i]); + return acc;} + +long long sequential_compute(const char *path,long long (*f)(long long, long long)){ + int n; + long long *arr = read_numbers(path, &n); + if (!arr || n == 0){ + free(arr); + fprintf(stderr, "sequential_compute: no numbers read\n"); + return LLONG_MIN; + } + long long acc = arr[n - 1]; + for (int i = n - 1; i-- > 0; ) acc = f(arr[i], acc); + free(arr); + return acc; +} + +long long parallel_compute(const char *path,int n_proc,long long (*f)(long long, long long)){ + if (n_proc <= 0){ + fprintf(stderr, "parallel_compute: n_proc must be > 0\n"); + return LLONG_MIN;} + + int n; + long long *arr = read_numbers(path, &n); + if (!arr || n == 0){ + free(arr); + fprintf(stderr, "parallel_compute: no numbers read\n"); + return LLONG_MIN;} + + if (n_proc > n) n_proc = n; + int chunk = n / n_proc; + int leftover = n % n_proc; + int (*pipes)[2] = malloc(n_proc * sizeof *pipes); + pid_t *pids = malloc(n_proc * sizeof *pids); + if (!pipes || !pids) { + free(arr); free(pipes); free(pids); + return LLONG_MIN; + } + + for (int i = 0; i < n_proc; i++){ + if (pipe(pipes[i]) == -1){ + perror("pipe"); + for (int j = 0; j < i; j++){ + close(pipes[j][0]); + close(pipes[j][1]);} + free(arr); free(pipes); free(pids); + return LLONG_MIN; + } + } + + int spawned = 0; + for (int i = 0; i < n_proc; i++){ + int start = i*chunk; + int end = start + chunk + (i == n_proc - 1 ? leftover : 0); + + pids[i] = fork(); + if (pids[i] < 0){ + perror("fork"); + for (int j = 0; j < spawned;j++){ + kill(pids[j], SIGTERM); + waitpid(pids[j], NULL, 0);} + for (int j = 0; j < n_proc;j++){ + close(pipes[j][0]); + close(pipes[j][1]);} + free(arr); free(pipes); free(pids); + return LLONG_MIN;} + + if (pids[i] == 0) { + for (int j = 0; j < n_proc; j++) { + close(pipes[j][0]); + if (j != i) close(pipes[j][1]);} + long long partial = reduce(arr + start, end - start, f); + int written = write(pipes[i][1], &partial, sizeof partial); + (void)written; + close(pipes[i][1]); + free(arr); free(pipes); free(pids); + _exit(0); + } + spawned++;} + + for (int i = 0; i < n_proc; i++) + close(pipes[i][1]); + + long long *partials = malloc(n_proc * sizeof *partials); + if (!partials) { + for (int i = 0; i < n_proc; i++) close(pipes[i][0]); + for (int i = 0; i < n_proc; i++) waitpid(pids[i], NULL, 0); + free(arr); free(pipes); free(pids); + return LLONG_MIN; + } + + for (int i = 0; i < n_proc; i++){ + int r = read(pipes[i][0], &partials[i], sizeof partials[i]); + if (r != (int)sizeof partials[i]){ + fprintf(stderr, "parallel_compute: short read from child %d\n", i); + partials[i] = 0; + } + close(pipes[i][0]);} + for (int i = 0; i < n_proc; i++) waitpid(pids[i], NULL, 0); + + long long result = reduce(partials,n_proc,f); + + free(arr); free(pipes); free(pids); free(partials); + return result; +} + +#ifdef COMPUTE_TEST +long long add(long long a, long long b) { return a + b;} +long long mul(long long a, long long b) { return a * b;} +long long mx (long long a, long long b) { return a > b? a : b;} + +int main(int argc, char *argv[]) +{ + const char *path = argc > 1 ? argv[1] : "numbers.txt"; + + printf("Part1-sequential_compute\n"); + printf("sum = %lld\n", sequential_compute(path, add)); + printf("product = %lld\n", sequential_compute(path, mul)); + printf("max = %lld\n", sequential_compute(path, mx)); + + printf("\nPart2-parallel_compute (4 procs)\n"); + printf("sum = %lld\n", parallel_compute(path, 4, add)); + printf("prod = %lld\n", parallel_compute(path, 4, mul)); + printf("max = %lld\n", parallel_compute(path, 4, mx)); + + return 0; +} +#endif + + diff --git a/numbers.txt b/numbers.txt new file mode 100644 index 0000000000..2fc6ceb25f --- /dev/null +++ b/numbers.txt @@ -0,0 +1 @@ +1,2,3,4,5,6,7,8,9,10 diff --git a/process_scaling.csv b/process_scaling.csv new file mode 100644 index 0000000000..0843d22545 --- /dev/null +++ b/process_scaling.csv @@ -0,0 +1,17 @@ +processes,time +1,2.502263 +2,2.398349 +3,2.442807 +4,2.675024 +5,2.558864 +6,2.229776 +7,2.031597 +8,2.047933 +9,2.423471 +10,2.503948 +11,2.393296 +12,2.291219 +13,2.233890 +14,2.167401 +15,2.411243 +16,2.153978 diff --git a/results.csv b/results.csv new file mode 100644 index 0000000000..31a70d7b69 --- /dev/null +++ b/results.csv @@ -0,0 +1,51 @@ +N,seq_time,par_time +1000,0.000278,0.001678 +101000,0.025293,0.028198 +201000,0.055328,0.058385 +301000,0.092299,0.098093 +401000,0.133344,0.132219 +501000,0.171204,0.163994 +601000,0.209125,0.197229 +701000,0.242274,0.251044 +801000,0.285125,0.271136 +901000,0.332160,0.305844 +1001000,0.347259,0.394467 +1101000,0.480947,0.440557 +1201000,0.527320,0.437721 +1301000,0.446075,0.469071 +1401000,0.515478,0.436285 +1501000,0.524197,0.468181 +1601000,0.521664,0.490741 +1701000,0.549413,0.550071 +1801000,0.731894,0.778137 +1901000,0.821788,0.815614 +2001000,0.710408,0.728659 +2101000,0.862667,0.963047 +2201000,1.045063,1.033249 +2301000,0.935393,1.195454 +2401000,1.548874,1.030068 +2501000,1.111333,0.906074 +2601000,1.219223,1.447804 +2701000,1.374043,1.302392 +2801000,1.734898,1.318979 +2901000,1.080929,1.128941 +3001000,1.304952,1.258263 +3101000,1.017442,1.010833 +3201000,1.290110,1.170737 +3301000,1.316924,1.042860 +3401000,1.418169,1.212233 +3501000,1.538255,1.287164 +3601000,1.268677,1.459031 +3701000,1.401894,1.390480 +3801000,1.425571,1.417154 +3901000,1.659142,1.307537 +4001000,1.685081,1.344943 +4101000,1.305627,1.188571 +4201000,1.384767,1.294613 +4301000,1.448628,1.337252 +4401000,1.468510,1.604637 +4501000,1.641293,1.589458 +4601000,1.671218,1.602195 +4701000,1.619908,1.699248 +4801000,1.650899,1.657043 +4901000,1.700224,1.624811