1 /* pmm - parallel matrix multiplication "double diffusion" */
3 /* Copyright (c) 2006-2008 The SimGrid team. All rights reserved. */
5 /* This program is free software; you can redistribute it and/or modify it
6 * under the terms of the license (GNU LGPL) which comes with this package. */
9 #include "xbt/matrix.h"
10 #include "amok/peermanagement.h"
12 #define PROC_MATRIX_SIZE 3
13 #define NEIGHBOR_COUNT PROC_MATRIX_SIZE - 1
14 #define SLAVE_COUNT (PROC_MATRIX_SIZE*PROC_MATRIX_SIZE)
16 #define DATA_MATRIX_SIZE 18
17 const int submatrix_size = DATA_MATRIX_SIZE / PROC_MATRIX_SIZE;
19 XBT_LOG_NEW_DEFAULT_CATEGORY(pmm, "Parallel Matrix Multiplication");
21 /* struct for recovering results */
22 GRAS_DEFINE_TYPE(s_result, struct s_result {
24 int rowpos; xbt_matrix_t C GRAS_ANNOTE(subtype, double);});
26 typedef struct s_result result_t;
28 /* struct to send initial data to slave */
29 GRAS_DEFINE_TYPE(s_pmm_assignment, struct s_pmm_assignment {
32 xbt_peer_t line[NEIGHBOR_COUNT];
33 xbt_peer_t row[NEIGHBOR_COUNT];
34 xbt_matrix_t A GRAS_ANNOTE(subtype, double);
35 xbt_matrix_t B GRAS_ANNOTE(subtype, double);});
37 typedef struct s_pmm_assignment s_pmm_assignment_t;
39 /* register messages which may be sent (common to client and server) */
40 static void register_messages(void)
42 gras_datadesc_type_t result_type;
43 gras_datadesc_type_t pmm_assignment_type;
45 gras_datadesc_set_const("NEIGHBOR_COUNT", NEIGHBOR_COUNT);
46 result_type = gras_datadesc_by_symbol(s_result);
47 pmm_assignment_type = gras_datadesc_by_symbol(s_pmm_assignment);
49 /* receive a final result from slave */
50 gras_msgtype_declare("result", result_type);
52 /* send from master to slave to assign a position and some data */
53 gras_msgtype_declare("pmm_slave", pmm_assignment_type);
55 /* send data between slaves */
56 gras_msgtype_declare("dataA",
57 gras_datadesc_matrix(gras_datadesc_by_name("double"),
59 gras_msgtype_declare("dataB",
60 gras_datadesc_matrix(gras_datadesc_by_name("double"),
64 /* Function prototypes */
65 int slave(int argc, char *argv[]);
66 int master(int argc, char *argv[]);
69 /* **********************************************************************
71 * **********************************************************************/
73 /* Global private data */
75 int nbr_row, nbr_line;
80 int master(int argc, char *argv[])
90 xbt_dynar_t peers; /* group of slaves */
91 xbt_peer_t grid[SLAVE_COUNT]; /* The slaves as an array */
92 gras_socket_t socket[SLAVE_COUNT]; /* sockets for brodcast to slaves */
94 /* Init the GRAS's infrastructure */
95 gras_init(&argc, argv);
99 /* Initialize data matrices */
100 A = xbt_matrix_double_new_id(DATA_MATRIX_SIZE, DATA_MATRIX_SIZE);
101 B = xbt_matrix_double_new_seq(DATA_MATRIX_SIZE, DATA_MATRIX_SIZE);
102 C = xbt_matrix_double_new_zeros(DATA_MATRIX_SIZE, DATA_MATRIX_SIZE);
104 /* Create the connexions */
105 xbt_assert0(argc > 1, "Usage: master <port>");
106 gras_socket_server(atoi(argv[1]));
107 peers = amok_pm_group_new("pmm");
109 /* friends, we're ready. Come and play */
110 INFO0("Wait for peers for 2 sec");
111 gras_msg_handleall(2);
112 while (xbt_dynar_length(peers)<9) {
113 INFO1("Got only %ld pals. Wait 2 more seconds", xbt_dynar_length(peers));
114 gras_msg_handleall(2);
116 INFO1("Good. Got %ld pals", xbt_dynar_length(peers));
118 for (i = 0; i < xbt_dynar_length(peers) && i < SLAVE_COUNT; i++) {
119 xbt_dynar_get_cpy(peers, i, &grid[i]);
120 socket[i] = gras_socket_client(grid[i]->name, grid[i]->port);
122 xbt_assert2(i == SLAVE_COUNT,
123 "Not enough slaves for this setting (got %d of %d). Change the deployment file",
126 /* Kill surnumerous slaves */
127 for (i = SLAVE_COUNT; i < xbt_dynar_length(peers);) {
130 xbt_dynar_remove_at(peers, i, &h);
131 INFO2("Too much slaves. Killing %s:%d", h->name, h->port);
132 amok_pm_kill_hp(h->name, h->port);
137 /* Assign job to slaves */
138 int row = 0, line = 0;
139 INFO0("XXXXXXXXXXXXXXXXXXXXXX begin Multiplication");
140 for (i = 0; i < SLAVE_COUNT; i++) {
141 s_pmm_assignment_t assignment;
144 assignment.linepos = line; // assigned line
145 assignment.rowpos = row; // assigned row
148 for (j = 0, k = 0; j < PROC_MATRIX_SIZE; j++) {
149 if (i != j * PROC_MATRIX_SIZE + (row)) {
150 assignment.row[k] = grid[j * PROC_MATRIX_SIZE + (row)];
154 for (j = 0, k = 0; j < PROC_MATRIX_SIZE; j++) {
155 if (i != (line) * PROC_MATRIX_SIZE + j) {
156 assignment.line[k] = grid[(line) * PROC_MATRIX_SIZE + j];
161 assignment.A = xbt_matrix_new_sub(A,
162 submatrix_size, submatrix_size,
163 submatrix_size * line,
164 submatrix_size * row, NULL);
166 xbt_matrix_new_sub(B, submatrix_size, submatrix_size,
167 submatrix_size * line, submatrix_size * row, NULL);
169 if (row >= PROC_MATRIX_SIZE) {
174 gras_msg_send(socket[i], "pmm_slave", &assignment);
175 xbt_matrix_free(assignment.A);
176 xbt_matrix_free(assignment.B);
179 /* (have a rest while the slave perform the multiplication) */
181 /* Retrieve the results */
182 for (i = 0; i < SLAVE_COUNT; i++) {
183 gras_msg_wait(6000, "result", &from, &result);
184 VERB2("%d slaves are done already. Waiting for %d", i + 1, SLAVE_COUNT);
185 xbt_matrix_copy_values(C, result.C, submatrix_size, submatrix_size,
186 submatrix_size * result.linepos,
187 submatrix_size * result.rowpos, 0, 0, NULL);
188 xbt_matrix_free(result.C);
192 if (xbt_matrix_double_is_seq(C))
193 INFO0("XXXXXXXXXXXXXXXXXXXXXX Ok, the result matches expectations");
195 WARN0("the result seems wrong");
196 if (DATA_MATRIX_SIZE < 30) {
197 INFO0("The Result of Multiplication is :");
198 xbt_matrix_dump(C, "C:res", 0, xbt_matrix_dump_display_double);
200 INFO1("Matrix size too big (%d>30) to be displayed here",
205 amok_pm_group_shutdown("pmm"); /* Ok, we're out of here */
207 for (i = 0; i < SLAVE_COUNT; i++)
208 gras_socket_close(socket[i]);
215 } /* end_of_master */
217 /* **********************************************************************
219 * **********************************************************************/
221 static int pmm_worker_cb(gras_msg_cb_ctx_t ctx, void *payload)
223 /* Recover my initialized Data and My Position */
224 s_pmm_assignment_t assignment = *(s_pmm_assignment_t *) payload;
225 gras_socket_t master = gras_msg_cb_ctx_from(ctx);
230 xbt_matrix_t bA = xbt_matrix_new(submatrix_size, submatrix_size,
231 sizeof(double), NULL);
232 xbt_matrix_t bB = xbt_matrix_new(submatrix_size, submatrix_size,
233 sizeof(double), NULL);
236 xbt_matrix_t mydataA, mydataB;
238 xbt_matrix_double_new_zeros(submatrix_size, submatrix_size);
242 gras_socket_t from; /* to exchange data with my neighbor */
244 /* sockets for brodcast to other slave */
245 gras_socket_t socket_line[PROC_MATRIX_SIZE - 1];
246 gras_socket_t socket_row[PROC_MATRIX_SIZE - 1];
247 memset(socket_line, 0, sizeof(socket_line));
248 memset(socket_row, 0, sizeof(socket_row));
252 gras_os_sleep(1); /* wait for my pals */
254 myline = assignment.linepos;
255 myrow = assignment.rowpos;
256 mydataA = assignment.A;
257 mydataB = assignment.B;
260 INFO0("Receive my pos and assignment");
262 INFO2("Receive my pos (%d,%d) and assignment", myline, myrow);
264 /* Get my neighborhood from the assignment message (skipping myself) */
265 for (i = 0; i < PROC_MATRIX_SIZE - 1; i++) {
266 socket_line[i] = gras_socket_client(assignment.line[i]->name,
267 assignment.line[i]->port);
268 xbt_peer_free(assignment.line[i]);
270 for (i = 0; i < PROC_MATRIX_SIZE - 1; i++) {
271 socket_row[i] = gras_socket_client(assignment.row[i]->name,
272 assignment.row[i]->port);
273 xbt_peer_free(assignment.row[i]);
276 for (step = 0; step < PROC_MATRIX_SIZE; step++) {
278 /* a line brodcast */
279 if (myline == step) {
280 VERB2("LINE: step(%d) = Myline(%d). Broadcast my data.", step, myline);
281 for (l = 0; l < PROC_MATRIX_SIZE - 1; l++) {
282 VERB1("LINE: Send to %s", gras_socket_peer_name(socket_row[l]));
283 gras_msg_send(socket_row[l], "dataB", &mydataB);
288 bB = xbt_matrix_new_sub(mydataB,
289 submatrix_size, submatrix_size, 0, 0, NULL);
293 gras_msg_wait(600, "dataB", &from, &bB);
296 RETHROW0("Can't get a data message from line : %s");
298 VERB3("LINE: step(%d) <> Myline(%d). Receive data from %s", step,
299 myline, gras_socket_peer_name(from));
304 VERB2("ROW: step(%d)=myrow(%d). Broadcast my data.", step, myrow);
305 for (l = 1; l < PROC_MATRIX_SIZE; l++) {
306 VERB1("ROW: Send to %s", gras_socket_peer_name(socket_line[l - 1]));
307 gras_msg_send(socket_line[l - 1], "dataA", &mydataA);
310 bA = xbt_matrix_new_sub(mydataA,
311 submatrix_size, submatrix_size, 0, 0, NULL);
315 gras_msg_wait(1200, "dataA", &from, &bA);
318 RETHROW0("Can't get a data message from row : %s");
320 VERB3("ROW: step(%d)<>myrow(%d). Receive data from %s", step, myrow,
321 gras_socket_peer_name(from));
323 xbt_matrix_double_addmult(bA, bB, bC);
327 /* send Result to master */
329 result.linepos = myline;
330 result.rowpos = myrow;
333 gras_msg_send(master, "result", &result);
336 RETHROW0("Failed to send answer to server: %s");
338 VERB2(">>>>>>>> Result sent to %s:%d <<<<<<<<",
339 gras_socket_peer_name(master), gras_socket_peer_port(master));
340 /* Free the allocated resources, and shut GRAS down */
346 xbt_matrix_free(mydataA);
347 xbt_matrix_free(mydataB);
348 /* FIXME: some are said to be unknown
349 gras_socket_close(master);
350 gras_socket_close(from);
351 for (l=0; l < PROC_MATRIX_SIZE-1; l++) {
353 gras_socket_close(socket_line[l]);
355 gras_socket_close(socket_row[l]);
361 int slave(int argc, char *argv[])
363 gras_socket_t mysock;
364 gras_socket_t master = NULL;
368 /* Init the GRAS's infrastructure */
369 gras_init(&argc, argv);
371 if (argc != 3 && argc != 2)
372 xbt_die("Usage: slave masterhost:masterport [rank]");
376 rank = atoi(argv[2]);
378 /* Register the known messages and my callback */
380 gras_cb_register("pmm_slave", pmm_worker_cb);
382 /* Create the connexions */
383 mysock = gras_socket_server_range(3000, 9999, 0, 0);
384 INFO1("Sensor %d starting", rank);
388 master = gras_socket_client_from_string(argv[1]);
392 if (e.category != system_error)
399 /* Join and run the group */
400 rank = amok_pm_group_join(master, "pmm");
401 amok_pm_mainloop(600);
404 gras_socket_close(mysock);
405 // gras_socket_close(master); Unknown