Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add a yummy matrix multiplication rpc thing
authormquinson <mquinson@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
Sun, 2 Oct 2005 19:28:02 +0000 (19:28 +0000)
committermquinson <mquinson@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
Sun, 2 Oct 2005 19:28:02 +0000 (19:28 +0000)
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@1743 48e7efb5-ca39-0410-a469-dd3cf9ba447f

ChangeLog
configure.ac
doc/module-gras.doc
examples/gras/Makefile.am
examples/gras/mmrpc/.cvsignore [new file with mode: 0644]
examples/gras/mmrpc/Makefile.am [new file with mode: 0644]
examples/gras/mmrpc/mmrpc.c [new file with mode: 0644]
examples/gras/mmrpc/mmrpc_deployment.xml [new file with mode: 0644]
examples/gras/mmrpc/test_rl.in [new file with mode: 0755]
examples/gras/mmrpc/test_sg.in [new file with mode: 0755]

index 35c5ffa..d89fbfd 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -25,8 +25,10 @@ SimGrid (3.0.1) unstable; urgency=low
   * New: MSG_task_get_source to see on which host a task was generated [HC]
 
   GRAS new functionnalities: [MQ]
   * New: MSG_task_get_source to see on which host a task was generated [HC]
 
   GRAS new functionnalities: [MQ]
-  * enhance the parsing macro to allow the size of multidimentional objects
+  * Enhance the parsing macro to allow the size of multidimentional objects
     to be given thru annotations.
     to be given thru annotations.
+  * New example (and documentation): Matrix Multiplication a la RPC manner 
+    (as when I was young!) and fix a bunch of bugs found on the way.
 
   GRAS performance improvements: [MQ]
   [DataDesc]
 
   GRAS performance improvements: [MQ]
   [DataDesc]
index 2b8d5d1..abd7132 100644 (file)
@@ -245,6 +245,7 @@ AC_CONFIG_FILES([
       examples/gras/timer/Makefile  examples/gras/timer/test_sg examples/gras/timer/test_rl
       examples/gras/chrono/Makefile examples/gras/chrono/test_sg examples/gras/chrono/test_rl
       examples/gras/tokenS/Makefile examples/gras/tokenS/test_sg examples/gras/tokenS/test_rl
       examples/gras/timer/Makefile  examples/gras/timer/test_sg examples/gras/timer/test_rl
       examples/gras/chrono/Makefile examples/gras/chrono/test_sg examples/gras/chrono/test_rl
       examples/gras/tokenS/Makefile examples/gras/tokenS/test_sg examples/gras/tokenS/test_rl
+      examples/gras/mmrpc/Makefile examples/gras/mmrpc/test_sg examples/gras/mmrpc/test_rl
     examples/amok/Makefile       
       examples/amok/bandwidth/Makefile examples/amok/bandwidth/test_sg examples/amok/bandwidth/test_rl
   doc/Makefile
     examples/amok/Makefile       
       examples/amok/bandwidth/Makefile examples/amok/bandwidth/test_sg examples/amok/bandwidth/test_rl
   doc/Makefile
@@ -266,6 +267,7 @@ AC_CONFIG_FILES([
      examples/gras/timer/test_sg  examples/gras/timer/test_rl   \
      examples/gras/chrono/test_sg examples/gras/chrono/test_rl  \
      examples/gras/tokenS/test_sg examples/gras/tokenS/test_rl  \
      examples/gras/timer/test_sg  examples/gras/timer/test_rl   \
      examples/gras/chrono/test_sg examples/gras/chrono/test_rl  \
      examples/gras/tokenS/test_sg examples/gras/tokenS/test_rl  \
+     examples/gras/mmrpc/test_sg examples/gras/mmrpc/test_rl  \
      examples/msg/run_msg_test                                  \
     ; do                                                        \
       test -e $file && chmod +x $file;                          \
      examples/msg/run_msg_test                                  \
     ; do                                                        \
       test -e $file && chmod +x $file;                          \
index adeb57f..a43fec7 100644 (file)
@@ -49,7 +49,8 @@
     There is for now rather few examples of GRAS, but it's better than
     nothing, isn't it?
     
     There is for now rather few examples of GRAS, but it's better than
     nothing, isn't it?
     
-       - \ref GRAS_ex_ping 
+       - \ref GRAS_ex_ping
+       - \ref GRAS_ex_mmrpc
        - \ref GRAS_ex_timer
               
     @{ */     
        - \ref GRAS_ex_timer
               
     @{ */     
     the code of the client and of the server is placed in the same file. See
     the \ref GRAS_main_generation section if wondering.
 
     the code of the client and of the server is placed in the same file. See
     the \ref GRAS_main_generation section if wondering.
 
-    \section GRAS_ex_ping_over Overview
+    \section GRAS_ex_ping_toc Table of contents of the ping example
       - \ref GRAS_ex_ping_common
         - \ref GRAS_ex_ping_initial
         - \ref GRAS_ex_ping_register
       - \ref GRAS_ex_ping_common
         - \ref GRAS_ex_ping_initial
         - \ref GRAS_ex_ping_register
     This function, called by both the client and the server is in charge of
     declaring the existing messages to GRAS. Since the payload does not
     involve any newly created types but only int, this is quite easy. 
     This function, called by both the client and the server is in charge of
     declaring the existing messages to GRAS. Since the payload does not
     involve any newly created types but only int, this is quite easy. 
-    (to exchange more complicated types, see \ref GRAS_dd)
+    (to exchange more complicated types, see \ref GRAS_dd or 
+    \ref GRAS_ex_mmrpc for an example).
     
     \skip register_messages
     \until }
 
     
     \skip register_messages
     \until }
 
+    [Back to \ref GRAS_ex_ping_toc]
+
     \section GRAS_ex_ping_server 2) Server's code
     
     \subsection GRAS_ex_ping_serdata 2.a) The server's globals
     \section GRAS_ex_ping_server 2) Server's code
     
     \subsection GRAS_ex_ping_serdata 2.a) The server's globals
     \subsection GRAS_ex_ping_sermain 2.c) The "main" of the server
     
     This is the "main" of the server. As explained in the \ref
     \subsection GRAS_ex_ping_sermain 2.c) The "main" of the server
     
     This is the "main" of the server. As explained in the \ref
-    GRAS_main_generation, you don't have to (and shouldn't) write any main()
+    GRAS_main_generation, 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.
     
     \skip server
     \until end_of_server
     function yourself. Instead, you just have to write a regular function
     like this one which will act as a main.
     
     \skip server
     \until end_of_server
+
+    [Back to \ref GRAS_ex_ping_toc]
     
     \section GRAS_ex_ping_client 3) Client's code
     
     \subsection GRAS_ex_ping_climain 3.a) Client's "main" function
     
     
     \section GRAS_ex_ping_client 3) Client's code
     
     \subsection GRAS_ex_ping_climain 3.a) Client's "main" function
     
+    This function is quite straightforward, and the inlined comments should
+    be enough to understand it.
+
+    \skip client
+    \until end_of_client
+
+    [Back to \ref GRAS_ex_ping_toc]
+ */
+
+---------------------------------------------------------------------
+-------------------------- MM RPC -----------------------------------
+---------------------------------------------------------------------
+
+/** \page GRAS_ex_mmrpc A simple RPC for matrix multiplication
+
+    <center>[\ref GRAS_API]</center>
+
+    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 (\ref GRAS_ex_ping).
+
+    It works the following way (not very different from the ping example):
+     - Both the client and the server register all needed messages and datatypes
+     - The server registers a callback to the "request" message, which computes
+       what needs to be and returns the result to the expeditor.
+     - The client creates two matrices, ask for their multiplication and check 
+       the server's answer.
+    This example resides in the <b>examples/gras/mmrpc/mmrpc.c</b> file. (See
+    the \ref GRAS_main_generation section if wondering why both the server
+    and the client live in the same source file)
+
+    \section GRAS_ex_mmrpc_toc Table of contents of the mmrpc example
+      - \ref GRAS_ex_mmrpc_common
+        - \ref GRAS_ex_mmrpc_initial
+        - \ref GRAS_ex_mmrpc_dataregister
+        - \ref GRAS_ex_mmrpc_msgregister
+      - \ref GRAS_ex_mmrpc_server
+       - \ref GRAS_ex_mmrpc_sercb
+       - \ref GRAS_ex_mmrpc_sermain
+      - \ref GRAS_ex_mmrpc_client
+       - \ref GRAS_ex_mmrpc_climain
+       
+    <hr>
+
+    \dontinclude gras/mmrpc/mmrpc.c
+    
+    \section GRAS_ex_mmrpc_common 1) Common code to the client and the server 
+    
+    \subsection GRAS_ex_mmrpc_initial 1.a) Initial settings
+    
+    Let's first load the gras header, specify the matrix size and declare a 
+    logging category (see \ref XBT_log for more info on logging).
+    
+    \skip include
+    \until XBT_LOG
+
+    \subsection GRAS_ex_mmrpc_dataregister 1.b) Register the data types
+
+    The messages involved in this example do use structures as payload, 
+    so we have to declare it to GRAS. Hopefully, this can be done easily by enclosing 
+    the structure declaration within a GRAS_DEFINE macro call. It will then copy this 
+    declaration into an hidden string variable, which can be automatically parsed at 
+    run time. Of course, the declaration is also copied unmodified by this macro, so that it
+    gets parsed by the compiler also. 
+
+    There is some semantic that GRAS cannot guess alone and you need to  <i>annotate</i>
+    your declaration to add some. For example, the ctn pointer can be a reference to an 
+    object or a whole array (in which case you also has to specify its size). This is done 
+    with the GRAS_ANNOTE call. It is removed from the text passed to the compiler, but it helps
+    GRAS getting some information about the semantic of your data. Here, it says that \a ctn is an 
+    array, which size is the result of the operation \a rows * \a cols (with \a rows and \a cols 
+    being the other fields of the structure). 
+
+    Please note that this annotation mechanism is not as robust and cool as this example seems to 
+    imply. If you want to use it yourself, you'd better use the exact right syntax, which is 
+    detailed in the \ref GRAS_dd section.
+
+    \skip GRAS_DEFINE
+    \until matrix_t
+
+    \subsection GRAS_ex_mmrpc_msgregister 1.c) Register the messages
+    
+    This function, called by both the client and the server is in charge of
+    declaring the existing messages to GRAS. Note the use of the \ref gras_datadesc_by_symbol 
+    function to parse and retrieve the structure declaration which were passed to \ref GRAS_DEFINE 
+    above. 
+
+    The datatype description builded that way can then be used to build an array datatype or 
+    to declare messages.
+    
+    \skip register_messages
+    \until }
+
+    [Back to \ref GRAS_ex_mmrpc_toc]
+
+    \section GRAS_ex_mmrpc_server 2) Server's code
+    
+    \subsection GRAS_ex_mmrpc_sercb 2.a) The callback to the mmrpc message
+
+    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 \ref GRAS_ex_ping_sercb). This is because the payload is
+    an array here (ie a pointer) whereas it is a scalar in the ping example.
+    
+    \skip server_cb_request_handler
+    \until end_of_server_cb_request_handler
+
+    \subsection GRAS_ex_mmrpc_sermain 2.b) The "main" of the server
+    
+    This is the "main" of the server. As explained in the \ref
+    GRAS_main_generation, 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.
+    
+    \skip server
+    \until end_of_server
+    
+    [Back to \ref GRAS_ex_mmrpc_toc]
+
+    \section GRAS_ex_mmrpc_client 3) Client's code
+    
+    \subsection GRAS_ex_mmrpc_climain 3.a) Client's "main" function
+    
+    This function is quite straightforward, and the inlined comments should
+    be enough to understand it.
+
     \skip client
     \until end_of_client
     \skip client
     \until end_of_client
+
+    [Back to \ref GRAS_ex_mmrpc_toc]
   */
 
 ---------------------------------------------------------------------
   */
 
 ---------------------------------------------------------------------
index 08dea3b..20598c2 100644 (file)
@@ -1,3 +1,3 @@
-SUBDIRS= ping timer chrono tokenS
+SUBDIRS= ping timer chrono tokenS mmrpc
 
 include $(top_srcdir)/acmacro/dist-files.mk
 
 include $(top_srcdir)/acmacro/dist-files.mk
diff --git a/examples/gras/mmrpc/.cvsignore b/examples/gras/mmrpc/.cvsignore
new file mode 100644 (file)
index 0000000..3fe84b0
--- /dev/null
@@ -0,0 +1,8 @@
+.deps .libs Makefile Makefile.in _*.c mmrpc_server mmrpc_client mmrpc_simulator
+test_sg
+test_rl
+mmrpc.Makefile.am
+mmrpc.Makefile.local
+mmrpc.Makefile.remote
+mmrpc.deploy.sh
+mmrpc.trace
diff --git a/examples/gras/mmrpc/Makefile.am b/examples/gras/mmrpc/Makefile.am
new file mode 100644 (file)
index 0000000..46d2014
--- /dev/null
@@ -0,0 +1,23 @@
+INCLUDES= -I$(top_srcdir)/include
+TESTS= test_rl test_sg
+EXTRA_DIST=mmrpc_deployment.xml $(TESTS)
+
+# AUTOMAKE variable definition
+noinst_PROGRAMS=mmrpc_client mmrpc_server mmrpc_simulator
+
+mmrpc_simulator_SOURCES=       _mmrpc_simulator.c mmrpc.c
+mmrpc_simulator_LDADD= $(top_builddir)/src/libsimgrid.la
+
+mmrpc_client_SOURCES=  _mmrpc_client.c mmrpc.c
+mmrpc_client_LDADD=    $(top_builddir)/src/libgras.la
+
+mmrpc_server_SOURCES=  _mmrpc_server.c mmrpc.c
+mmrpc_server_LDADD=    $(top_builddir)/src/libgras.la
+
+# Take care of generatated sources
+NAME=mmrpc
+PROCESSES= client server
+include $(top_srcdir)/examples/temps-gras-stub.mk
+
+# Cruft
+include $(top_srcdir)/acmacro/dist-files.mk
diff --git a/examples/gras/mmrpc/mmrpc.c b/examples/gras/mmrpc/mmrpc.c
new file mode 100644 (file)
index 0000000..b64153b
--- /dev/null
@@ -0,0 +1,213 @@
+/* $Id$ */
+
+/* GridRPC - Fake Grid RPC thingy doing matrix multiplications (as expected)*/
+
+/* Copyright (c) 2005 Martin Quinson. All rights reserved.                  */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "gras.h"
+
+#define MATSIZE 128
+
+XBT_LOG_NEW_DEFAULT_CATEGORY(MatMult,"Messages specific to this example");
+
+GRAS_DEFINE_TYPE(s_matrix,
+struct s_matrix {
+  int rows;
+  int cols;
+  double *ctn GRAS_ANNOTE(size, rows*cols);
+};);
+typedef struct s_matrix matrix_t;
+
+static void mat_dump(matrix_t *mat, const char* name) {
+  int i,j;
+
+  printf(">>> Matrix %s dump (%d x %d)\n",name,mat->rows,mat->cols);
+  for (i=0; i<mat->rows; i++) {
+    printf("  ");
+    for (j=0; j<mat->cols; j++)
+      printf(" %.2f",mat->ctn[i*mat->cols + j]);
+    printf("\n");
+  }
+  printf("<<< end of matrix %s dump\n",name);
+}
+
+/* register messages which may be sent and their payload
+   (common to client and server) */
+static void register_messages(void) {
+  gras_datadesc_type_t matrix_type, request_type;
+
+  matrix_type=gras_datadesc_by_symbol(s_matrix);
+  request_type=gras_datadesc_array_fixed("matrix_t[2]",matrix_type,2);
+  
+  gras_msgtype_declare("answer", matrix_type);
+  gras_msgtype_declare("request", request_type);
+}
+
+/* Function prototypes */
+int server (int argc,char *argv[]);
+int client (int argc,char *argv[]);
+
+/* **********************************************************************
+ * Server code
+ * **********************************************************************/
+
+static int server_cb_request_handler(gras_socket_t expeditor, void *payload_data) {
+                            
+  /* 1. Get the payload into the data variable */
+  matrix_t *data=(matrix_t*)payload_data;
+  matrix_t result;
+  int i,j,k;
+   
+  /* 2. Make some room to return the result */
+  result.rows = data[0].rows;
+  result.cols = data[1].cols;
+  result.ctn = xbt_malloc0(sizeof(double) * result.rows * result.cols);
+
+  /* 3. Do the computation */
+  for (i=0; i<result.rows; i++) 
+    for (j=0; j<result.cols; j++) 
+      for (k=0; k<data[1].rows; k++) 
+       result.ctn[i*result.cols + j] +=  data[0].ctn[i*result.cols +k] *data[1].ctn[k*result.cols +j];
+
+  /* 4. Send it back as payload of a pong message to the expeditor */
+  gras_msg_send(expeditor, gras_msgtype_by_name("answer"), &result);
+
+  /* 5. Cleanups */
+  free(data[0].ctn); 
+  free(data[1].ctn);
+  free(data);
+  free(result.ctn);
+  gras_socket_close(expeditor);
+   
+  return 1;
+} /* end_of_server_cb_request_handler */
+
+int server (int argc,char *argv[]) {
+  xbt_ex_t e; 
+  gras_socket_t sock;
+  int port = 4000;
+  
+  /* 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 */
+  INFO1("Launch server (port=%d)", port);
+  TRY {
+    sock = gras_socket_server(port);
+  } CATCH(e) {
+    RETHROW0("Unable to establish a server socket: %s");
+  }
+
+  /* 4. Register the known messages and payloads. */
+  register_messages();
+   
+  /* 5. Register my callback */
+  gras_cb_register(gras_msgtype_by_name("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();
+   
+  INFO0("Done.");
+  return 0;
+} /* end_of_server */
+
+/* **********************************************************************
+ * Client code
+ * **********************************************************************/
+
+/* Function prototypes */
+
+int client(int argc,char *argv[]) {
+  xbt_ex_t e; 
+  gras_socket_t toserver=NULL; /* peer */
+
+  gras_socket_t from;
+  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]);
+  } 
+
+  INFO2("Launch client (server on %s:%d)",host,port);
+   
+  /* 3. Wait for the server startup */
+  gras_os_sleep(1);
+   
+  /* 4. Create a socket to speak to the server */
+  TRY {
+    toserver=gras_socket_client(host,port);
+  } CATCH(e) {
+    RETHROW0("Unable to connect to the server: %s");
+  }
+  INFO2("Connected to %s:%d.",host,port);    
+
+
+  /* 5. Register the messages (before use) */
+  register_messages();
+
+  /* 6. Keep the user informed of what's going on */
+  INFO2(">>>>>>>> Connected to server which is on %s:%d <<<<<<<<", 
+       gras_socket_peer_name(toserver),gras_socket_peer_port(toserver));
+
+  /* 7. Prepare and send the request to the server */
+
+  request[0].rows=request[0].cols=request[1].rows=request[1].cols=MATSIZE;
+
+  request[0].ctn=xbt_malloc0(sizeof(double)*MATSIZE*MATSIZE);
+  request[1].ctn=xbt_malloc0(sizeof(double)*MATSIZE*MATSIZE);
+
+  for (i=0; i<MATSIZE; i++) {
+    request[0].ctn[i*MATSIZE+i] = 1;
+    for (j=0; j<MATSIZE; j++)
+      request[1].ctn[i*MATSIZE+j] = i*MATSIZE+j;
+  }
+  //  mat_dump(&request[0],"C:sent0");
+  //  mat_dump(&request[1],"C:sent1");
+
+  gras_msg_send(toserver, gras_msgtype_by_name("request"), &request);
+
+  free(request[0].ctn);
+  free(request[1].ctn);
+
+  INFO2(">>>>>>>> Request sent to %s:%d <<<<<<<<",
+       gras_socket_peer_name(toserver),gras_socket_peer_port(toserver));
+
+  /* 8. Wait for the answer from the server, and deal with issues */
+  gras_msg_wait(6000,gras_msgtype_by_name("answer"),&from,&answer);
+
+  //  mat_dump(&answer,"C:answer");
+  for (i=0; i<MATSIZE*MATSIZE; i++) 
+    xbt_assert(answer.ctn[i]==i);
+
+  /* 9. Keep the user informed of what's going on, again */
+  INFO2(">>>>>>>> Got answer from %s:%d <<<<<<<<", 
+       gras_socket_peer_name(from),gras_socket_peer_port(from));
+
+  /* 10. Free the allocated resources, and shut GRAS down */
+  gras_socket_close(toserver);
+  gras_exit();
+  INFO0("Done.");
+  return 0;
+} /* end_of_client */
diff --git a/examples/gras/mmrpc/mmrpc_deployment.xml b/examples/gras/mmrpc/mmrpc_deployment.xml
new file mode 100644 (file)
index 0000000..78dc211
--- /dev/null
@@ -0,0 +1,11 @@
+<?xml version='1.0'?>
+<!DOCTYPE platform_description SYSTEM "surfxml.dtd">
+<platform_description>
+  <process host="Tremblay" function="server">
+     <argument value="4000"/>       <!-- port number -->
+  </process>
+  <process host="Fafard" function="client">
+     <argument value="Tremblay"/>   <!-- server host -->
+     <argument value="4000"/>       <!-- port number -->
+  </process>
+</platform_description>
diff --git a/examples/gras/mmrpc/test_rl.in b/examples/gras/mmrpc/test_rl.in
new file mode 100755 (executable)
index 0000000..75d74cf
--- /dev/null
@@ -0,0 +1,11 @@
+#! @BASH@ -e
+if [ x@EXEEXT@ = x ] ; then 
+#  exenv="libtool --mode=execute valgrind --show-reachable=yes --run-libc-freeres=no "
+  exenv=$SG_TEST_EXENV
+else
+  exenv=wine
+fi
+    
+$exenv ./mmrpc_server@EXEEXT@ 4002 $@ &
+sleep 1
+$exenv ./mmrpc_client@EXEEXT@ 127.0.0.1 4002 $@
diff --git a/examples/gras/mmrpc/test_sg.in b/examples/gras/mmrpc/test_sg.in
new file mode 100755 (executable)
index 0000000..454c243
--- /dev/null
@@ -0,0 +1,9 @@
+#! @BASH@
+if [ x@EXEEXT@ = x ] ; then 
+  exenv=$SG_TEST_EXENV
+else
+  exenv=wine
+fi
+
+exec $exenv ./mmrpc_simulator@EXEEXT@ @top_srcdir@/examples/msg/small_platform.xml @srcdir@/mmrpc_deployment.xml $@
+