Add matrixmul stuff in a separate directory
[eleutheria.git] / pthreads / matrixmul / matrixmul.c
blobe11064143a391916874347f6821f90c82a51ac72
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 typedef struct matrix {
9 unsigned int rows;
10 unsigned int cols;
11 int **data;
12 } matrix_t;
14 typedef struct matrix_index {
15 unsigned int row;
16 unsigned int col;
17 } matindex_t;
19 typedef enum {
20 MM_OK,
21 MM_ENOMEM,
22 MM_EIO
23 } mmret_t;
25 matrix_t *mat1, *mat2, *mat3;
27 /* function prototypes */
28 mmret_t matrix_alloc(matrix_t **mat, unsigned int rows, unsigned int cols);
29 void matrix_free(matrix_t **mat);
30 mmret_t matrix_read(const char *path, matrix_t **mat);
31 void matrix_print(const matrix_t *mat);
32 void *mulvect(void *arg);
33 void diep(const char *s);
35 int main(int argc, char *argv[])
37 pthread_t *tid;
38 matindex_t *v;
39 unsigned int i, j, k, mdepth = 0, numthreads;
41 /* check argument count */
42 if (argc != 3) {
43 fprintf(stderr, "Usage: %s matfile1 matfile2\n", argv[0]);
44 exit(EXIT_FAILURE);
47 /* read matrix data from files */
48 if (matrix_read(argv[1], &mat1) != MM_OK)
49 goto CLEANUP_AND_EXIT;
50 mdepth++;
52 if (matrix_read(argv[2], &mat2) != MM_OK)
53 goto CLEANUP_AND_EXIT;
54 mdepth++;
56 /* is the multiplication feasible by definition? */
57 if (mat1->cols != mat2->rows) {
58 fprintf(stderr, "Matrices' dimensions size must satisfy (NxM)(MxK)=(NxK)\n");
59 goto CLEANUP_AND_EXIT;
62 /* allocate memory for the result */
63 if (matrix_alloc(&mat3, mat1->rows, mat2->cols) != MM_OK)
64 goto CLEANUP_AND_EXIT;
65 mdepth++;
67 /* how many threads do we need ? */
68 numthreads = mat1->rows * mat2->cols;
70 /* v[k] holds the (i, j) pair in the k-th computation */
71 if ((v = malloc(numthreads * sizeof *v)) == NULL) {
72 perror("malloc");
73 goto CLEANUP_AND_EXIT;
75 mdepth++;
77 /* allocate memory for the threads' ids */
78 if ((tid = malloc(numthreads * sizeof *tid)) == NULL) {
79 perror("malloc");
80 goto CLEANUP_AND_EXIT;
82 mdepth++;
84 /* create the threads */
85 for (i = 0; i < mat1->rows; i++) {
86 for (j = 0; j < mat2->cols; j++) {
87 k = i*mat1->rows + j;
88 v[k].row = i;
89 v[k].col = j;
90 if (pthread_create(&tid[k], NULL, mulvect, (void *)&v[k])) {
91 perror("pthread_create");
92 goto CLEANUP_AND_EXIT;
97 /* make sure all threads are done */
98 for (i = 0; i < numthreads; i++)
99 if (pthread_join(tid[i], NULL)) {
100 perror("pthread_join");
101 goto CLEANUP_AND_EXIT;
104 /* print the result */
105 matrix_print(mat3);
107 CLEANUP_AND_EXIT:;
108 switch(mdepth) {
109 case 5: free(tid);
110 case 4: free(v);
111 case 3: matrix_free(&mat3);
112 case 2: matrix_free(&mat2);
113 case 1: matrix_free(&mat1);
114 case 0: ; /* free nothing */
117 return EXIT_SUCCESS;
120 mmret_t matrix_alloc(matrix_t **mat, unsigned int rows, unsigned int cols)
122 unsigned int i, j, mdepth = 0;
124 *mat = malloc(sizeof **mat);
125 if (*mat == NULL)
126 goto CLEANUP_AND_RETURN;
127 mdepth++;
129 (*mat)->rows = rows;
130 (*mat)->cols = cols;
132 (*mat)->data = malloc(rows * sizeof(int *));
133 if ((*mat)->data == NULL)
134 goto CLEANUP_AND_RETURN;
135 mdepth++;
137 for (i = 0; i < rows; i++) {
138 (*mat)->data[i] = malloc(cols * sizeof(int));
139 if ((*mat)->data[i] == NULL) {
140 if (i != 0)
141 mdepth++;
142 goto CLEANUP_AND_RETURN;
145 return MM_OK;
147 CLEANUP_AND_RETURN:;
148 perror("malloc");
149 switch(mdepth) {
150 case 3: for (j = 0; j < i; j++) free((*mat)->data[j]);
151 case 2: free((*mat)->data);
152 case 1: free(*mat);
153 case 0: ; /* free nothing */
156 return MM_ENOMEM;
159 void matrix_free(matrix_t **mat)
161 unsigned int i;
163 for (i = 0; i < (*mat)->rows; i++)
164 free((*mat)->data[i]);
166 free((*mat)->data);
167 free(*mat);
170 mmret_t matrix_read(const char *path, matrix_t **mat)
172 FILE *fp;
173 unsigned int i, j, rows, cols;
175 /* open file */
176 if ((fp = fopen(path, "r")) == NULL) {
177 fprintf(stderr, "Error opening file: %s\n", path);
178 return MM_EIO;
181 /* read matrix dimensions */
182 fscanf(fp, "%u%u", &rows, &cols);
184 /* allocate memory for matrix */
185 if (matrix_alloc(mat, rows, cols) == MM_ENOMEM) {
186 fclose(fp);
187 return MM_ENOMEM;
190 /* read matrix elements */
191 for (i = 0; i < (*mat)->rows; i++) {
192 for (j = 0; j < (*mat)->cols; j++) {
193 fscanf(fp, "%d", &(*mat)->data[i][j]);
197 /* close file */
198 fclose(fp);
200 return MM_OK;
203 void matrix_print(const matrix_t *mat)
205 unsigned int i, j;
207 for (i = 0; i < mat->rows; i++) {
208 for (j = 0; j < mat->cols; j++) {
209 printf("%d ", mat->data[i][j]);
211 printf("\n");
216 void *mulvect(void *arg)
218 unsigned int i, row, col;
220 row = *((int *)arg + 0);
221 col = *((int *)arg + 1);
223 mat3->data[row][col] = 0;
224 for (i = 0; i < mat1->cols; i++)
225 mat3->data[row][col] += mat1->data[row][i] * mat2->data[i][col];
227 pthread_exit(NULL);
230 void diep(const char *s)
232 perror(s);
233 exit(EXIT_FAILURE);