Remove whitespace
[eleutheria.git] / pthreads / matrixmul.c
blobd723d0987b16d04800fa5e264475b014c9946632
1 /* compile with:
2 gcc matrixmul.c -o matrixmul -lpthread -Wall -W -Wextra -ansi -pedantic */
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <pthread.h>
8 struct matrix {
9 unsigned int rows;
10 unsigned int cols;
11 int **data;
14 struct matrix_index {
15 unsigned int row;
16 unsigned int col;
19 struct matrix *mat1 = NULL;
20 struct matrix *mat2 = NULL;
21 struct matrix *mat3 = NULL;
23 typedef enum {
24 mm_error_none,
25 mm_error_no_memory,
26 mm_error_io
27 } mm_error;
29 /* function prototypes */
30 mm_error matrix_alloc(struct matrix **mat, unsigned int rows, unsigned int cols);
31 void matrix_free(struct matrix **mat);
32 mm_error matrix_read(const char *path, struct matrix **mat);
33 void matrix_print(const struct matrix *mat);
34 void *mulvect(void *arg);
35 void diep(const char *s);
37 int main(int argc, char *argv[])
39 pthread_t *tid;
40 struct matrix_index *v;
41 unsigned int i, j, k, mdepth = 0, numthreads;
43 /* check argument count */
44 if (argc != 3) {
45 fprintf(stderr, "Usage: %s matfile1 matfile2\n", argv[0]);
46 exit(EXIT_FAILURE);
49 /* read matrix data from files */
50 if (matrix_read(argv[1], &mat1) != mm_error_none)
51 goto CLEANUP_AND_EXIT;
52 mdepth++;
54 if (matrix_read(argv[2], &mat2) != mm_error_none)
55 goto CLEANUP_AND_EXIT;
56 mdepth++;
58 /* is the multiplication feasible by definition? */
59 if (mat1->cols != mat2->rows) {
60 fprintf(stderr, "Matrices' dimensions size must satisfy (NxM)(MxK)=(NxK)\n");
61 goto CLEANUP_AND_EXIT;
64 /* allocate memory for the result */
65 if (matrix_alloc(&mat3, mat1->rows, mat2->cols) != mm_error_none)
66 goto CLEANUP_AND_EXIT;
67 mdepth++;
69 /* how many threads do we need ? */
70 numthreads = mat1->rows * mat2->cols;
72 /* v[k] holds the (i, j) pair in the k-th computation */
73 if ((v = malloc(numthreads * sizeof *v)) == NULL) {
74 perror("malloc");
75 goto CLEANUP_AND_EXIT;
77 mdepth++;
79 /* allocate memory for the threads' ids */
80 if ((tid = malloc(numthreads * sizeof *tid)) == NULL) {
81 perror("malloc");
82 goto CLEANUP_AND_EXIT;
84 mdepth++;
86 /* create the threads */
87 for (i = 0; i < mat1->rows; i++) {
88 for (j = 0; j < mat2->cols; j++) {
89 k = i*mat1->rows + j;
90 v[k].row = i;
91 v[k].col = j;
92 if (pthread_create(&tid[k], NULL, mulvect, (void *)&v[k])) {
93 perror("pthread_create");
94 goto CLEANUP_AND_EXIT;
99 /* make sure all threads are done */
100 for (i = 0; i < numthreads; i++)
101 if (pthread_join(tid[i], NULL)) {
102 perror("pthread_join");
103 goto CLEANUP_AND_EXIT;
106 /* print the result */
107 matrix_print(mat3);
109 CLEANUP_AND_EXIT:;
110 switch(mdepth) {
111 case 5:
112 free(tid);
113 case 4:
114 free(v);
115 case 3:
116 matrix_free(&mat3);
117 case 2:
118 matrix_free(&mat2);
119 case 1:
120 matrix_free(&mat1);
121 case 0:
122 ; /* free nothing */
125 return EXIT_SUCCESS;
128 mm_error matrix_alloc(struct matrix **mat, unsigned int rows, unsigned int cols)
130 unsigned int i, j, mdepth = 0;
132 *mat = malloc(sizeof **mat);
133 if (*mat == NULL)
134 goto CLEANUP_AND_RETURN;
135 mdepth++;
137 (*mat)->rows = rows;
138 (*mat)->cols = cols;
140 (*mat)->data = malloc(rows * sizeof(int *));
141 if ((*mat)->data == NULL)
142 goto CLEANUP_AND_RETURN;
143 mdepth++;
145 for (i = 0; i < rows; i++) {
146 (*mat)->data[i] = malloc(cols * sizeof(int));
147 if ((*mat)->data[i] == NULL) {
148 if (i != 0)
149 mdepth++;
150 goto CLEANUP_AND_RETURN;
153 return mm_error_none;
155 CLEANUP_AND_RETURN:;
156 perror("malloc");
157 switch(mdepth) {
158 case 3:
159 for (j = 0; j < i; j++)
160 free((*mat)->data[j]);
161 case 2:
162 free((*mat)->data);
163 case 1:
164 free(*mat);
165 case 0:
166 ; /* free nothing */
169 return mm_error_no_memory;
172 void matrix_free(struct matrix **mat)
174 unsigned int i;
176 for (i = 0; i < (*mat)->rows; i++)
177 free((*mat)->data[i]);
179 free(*mat);
182 mm_error matrix_read(const char *path, struct matrix **mat)
184 FILE *fp;
185 unsigned int i, j, rows, cols;
187 /* open file */
188 if ((fp = fopen(path, "r")) == NULL) {
189 fprintf(stderr, "Error opening file: %s\n", path);
190 return mm_error_io;
193 /* read matrix dimensions */
194 fscanf(fp, "%u%u", &rows, &cols);
196 /* allocate memory for matrix */
197 if (matrix_alloc(mat, rows, cols) == mm_error_no_memory) {
198 fclose(fp);
199 return mm_error_no_memory;
202 /* read matrix elements */
203 for (i = 0; i < (*mat)->rows; i++) {
204 for (j = 0; j < (*mat)->cols; j++) {
205 fscanf(fp, "%d", &(*mat)->data[i][j]);
209 /* close file */
210 fclose(fp);
212 return mm_error_none;
215 void matrix_print(const struct matrix *mat)
217 unsigned int i, j;
219 for (i = 0; i < mat->rows; i++) {
220 for (j = 0; j < mat->cols; j++) {
221 printf("%d ", mat->data[i][j]);
223 printf("\n");
228 void *mulvect(void *arg)
230 unsigned int i, row, col;
232 row = *((int *)arg + 0);
233 col = *((int *)arg + 1);
235 mat3->data[row][col] = 0;
236 for (i=0; i<mat1->cols; i++)
237 mat3->data[row][col] += mat1->data[row][i] * mat2->data[i][col];
239 pthread_exit(NULL);
242 void diep(const char *s)
244 perror(s);
245 exit(EXIT_FAILURE);