SimGrid 3.6.2
Scalable simulation of distributed systems
|
This example implements a remote matrix multiplication. It involves a client (creating the matrices and sending the multiplications requests) and a server (computing the multiplication on client's behalf).
This example also constitutes a more advanced example of data description mechanisms, since the message payload type is a bit more complicated than in other examples such as the ping one (The classical Ping-Pong in GRAS).
It works the following way (not very different from the ping example):
This example resides in the examples/gras/mmrpc/mmrpc.c file. (See the Lesson 1: Setting up your own project of the tutorial if wondering why both the server and the client live in the same source file)
This loads the gras header and declare the function's prototypes as well as the matrix size.
#include "gras.h" #define MATSIZE 128 /* register messages which may be sent and their payload (common to client and server) */ void mmrpc_register_messages(void); /* Function prototypes */ int server(int argc, char *argv[]); int client(int argc, char *argv[]);
The messages involved in a matrix of double. This type is automatically known by the GRAS mecanism, using the gras_datadesc_matrix() function of the xbt/matrix module.
Let's first load the module header and declare a logging category (see Logging support for more info on logging). This logging category does live in this file (ie the required symbols are defined here and declared as "extern" in any other file using them). That is why we use XBT_LOG_NEW_DEFAULT_CATEGORY here and XBT_LOG_EXTERNAL_DEFAULT_CATEGORY in mmrpc_client.c and mmrpc_server.c.
#include "mmrpc.h" XBT_LOG_NEW_DEFAULT_CATEGORY(MatMult, "Messages specific to this example");
This function, called by both the client and the server is in charge of declaring the existing messages to GRAS.
The datatype description builded that way can then be used to build an array datatype or to declare messages.
void mmrpc_register_messages(void) { gras_datadesc_type_t matrix_type, request_type; matrix_type = gras_datadesc_matrix(gras_datadesc_by_name("double"), NULL); request_type = gras_datadesc_array_fixed("s_matrix_t(double)[2]", matrix_type, 2); gras_msgtype_declare("answer", matrix_type); gras_msgtype_declare("request", request_type); }
[Back to Table of contents of the mmrpc example]
All module symbols live in the mmrpc_common.c file. We thus have to define GRAS_DEFINE_TYPE_EXTERN to the preprocessor so that the GRAS_DEFINE_TYPE symbols don't get included here. Likewise, we use XBT_LOG_EXTERNAL_DEFAULT_CATEGORY to get the log category in here.
#define GRAS_DEFINE_TYPE_EXTERN #include "xbt/matrix.h" #include "mmrpc.h" XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(MatMult);
Here is the callback run when the server receives any mmrpc message (this will be registered later by the server). Note the way we get the message payload. In the ping example, there was one additional level of pointer indirection (see 2.b) The callback to the ping message). This is because the payload is an array here (ie a pointer) whereas it is a scalar in the ping example.
static int server_cb_request_handler(gras_msg_cb_ctx_t ctx, void *payload_data) { gras_socket_t expeditor = gras_msg_cb_ctx_from(ctx); /* 1. Get the payload into the data variable */ xbt_matrix_t *request = (xbt_matrix_t *) payload_data; xbt_matrix_t result; /* 2. Do the computation */ result = xbt_matrix_double_new_mult(request[0], request[1]); /* 3. Send it back as payload of a pong message to the expeditor */ gras_msg_send(expeditor, "answer", &result); /* 4. Cleanups */ xbt_matrix_free(request[0]); xbt_matrix_free(request[1]); xbt_matrix_free(result); return 0; } /* end_of_server_cb_request_handler */
This is the "main" of the server. As explained in the tutorial, Lesson 1: Setting up your own project, you must not write any main() function yourself. Instead, you just have to write a regular function like this one which will act as a main.
int server(int argc, char *argv[]) { gras_socket_t sock = NULL; int port = 4002; /* 1. Init the GRAS infrastructure */ gras_init(&argc, argv); /* 2. Get the port I should listen on from the command line, if specified */ if (argc == 2) { port = atoi(argv[1]); } /* 3. Create my master socket */ XBT_INFO("Launch server (port=%d)", port); TRY { sock = gras_socket_server(port); } CATCH_ANONYMOUS { RETHROWF("Unable to establish a server socket: %s"); } /* 4. Register the known messages and payloads. */ mmrpc_register_messages(); /* 5. Register my callback */ gras_cb_register("request", &server_cb_request_handler); /* 6. Wait up to 10 minutes for an incomming message to handle */ gras_msg_handle(600.0); /* 7. Free the allocated resources, and shut GRAS down */ gras_socket_close(sock); gras_exit(); return 0; } /* end_of_server */
[Back to Table of contents of the mmrpc example]
As for the server, some extra love is needed to make sure that automatic datatype parsing and log categories do work even if we are using several files.
#define GRAS_DEFINE_TYPE_EXTERN #include "xbt/matrix.h" #include "mmrpc.h" XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(MatMult);
This function is quite straightforward, and the inlined comments should be enough to understand it.
int client(int argc, char *argv[]) { xbt_ex_t e; gras_socket_t toserver = NULL; /* peer */ int connected = 0; gras_socket_t from; xbt_matrix_t request[2], answer; int i, j; const char *host = "127.0.0.1"; int port = 4000; /* 1. Init the GRAS's infrastructure */ gras_init(&argc, argv); /* 2. Get the server's address. The command line override defaults when specified */ if (argc == 3) { host = argv[1]; port = atoi(argv[2]); } XBT_INFO("Launch client (server on %s:%d)", host, port); /* 3. Create a socket to speak to the server */ while (!connected) { TRY { toserver = gras_socket_client(host, port); connected = 1; } CATCH(e) { if (e.category != system_error) RETHROWF("Unable to connect to the server: %s"); xbt_ex_free(e); gras_os_sleep(0.05); } } XBT_INFO("Connected to %s:%d.", host, port); /* 4. Register the messages (before use) */ mmrpc_register_messages(); /* 5. Keep the user informed of what's going on */ XBT_INFO(">>>>>>>> Connected to server which is on %s:%d <<<<<<<<", gras_socket_peer_name(toserver), gras_socket_peer_port(toserver)); /* 6. Prepare and send the request to the server */ request[0] = xbt_matrix_double_new_id(MATSIZE, MATSIZE); request[1] = xbt_matrix_double_new_rand(MATSIZE, MATSIZE); /* xbt_matrix_dump(request[0],"C:sent0",0,xbt_matrix_dump_display_double); xbt_matrix_dump(request[1],"C:sent1",0,xbt_matrix_dump_display_double); */ gras_msg_send(toserver, "request", &request); xbt_matrix_free(request[0]); XBT_INFO(">>>>>>>> Request sent to %s:%d <<<<<<<<", gras_socket_peer_name(toserver), gras_socket_peer_port(toserver)); /* 7. Wait for the answer from the server, and deal with issues */ gras_msg_wait(6000, "answer", &from, &answer); /* xbt_matrix_dump(answer,"C:answer",0,xbt_matrix_dump_display_double); */ for (i = 0; i < MATSIZE; i++) for (j = 0; i < MATSIZE; i++) xbt_assert(xbt_matrix_get_as(answer, i, j, double) == xbt_matrix_get_as(request[1], i, j, double), "Answer does not match expectations. Found %f at cell %d,%d instead of %f", xbt_matrix_get_as(answer, i, j, double), i, j, xbt_matrix_get_as(request[1], i, j, double)); /* 8. Keep the user informed of what's going on, again */ XBT_INFO(">>>>>>>> Got answer from %s:%d (values are right) <<<<<<<<", gras_socket_peer_name(from), gras_socket_peer_port(from)); /* 9. Free the allocated resources, and shut GRAS down */ xbt_matrix_free(request[1]); xbt_matrix_free(answer); gras_socket_close(toserver); gras_exit(); return 0; } /* end_of_client */
[Back to Table of contents of the mmrpc example]
Back to the main Simgrid Documentation page |
The version of Simgrid documented here is v3.6.2. Documentation of other versions can be found in their respective archive files (directory doc/html). |
Generated for SimGridAPI by
![]() |