Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
allow the size of multidimentional objects to be given thru annotations in parsing...
authormquinson <mquinson@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
Fri, 30 Sep 2005 11:50:25 +0000 (11:50 +0000)
committermquinson <mquinson@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
Fri, 30 Sep 2005 11:50:25 +0000 (11:50 +0000)
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@1737 48e7efb5-ca39-0410-a469-dd3cf9ba447f

ChangeLog
TODO
include/gras/datadesc.h
src/gras/DataDesc/cbps.c
src/gras/DataDesc/ddt_create.c
src/gras/DataDesc/ddt_parse.c

index 3e8aa0d..35c5ffa 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -24,6 +24,10 @@ SimGrid (3.0.1) unstable; urgency=low
   * Add additionnal checkings on channel values in communication [AL]
   * 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
+    to be given thru annotations.
+
   GRAS performance improvements: [MQ]
   [DataDesc]
   * Reduce the amount of cbps creation/destruction by making it static to 
diff --git a/TODO b/TODO
index 98359e5..b2e95ff 100644 (file)
--- a/TODO
+++ b/TODO
       portable to ARM, at least.
     - Handle struct/union/enum embeeded within another container 
       (needs modifications in DataDesc, too)
-    - Allow sizes for multi-dimensional objects (such as matrices)
  
     - Check short a, b;
     - Check short ***
index 31a4e36..e259f44 100644 (file)
@@ -80,26 +80,43 @@ gras_datadesc_type_t gras_datadesc_by_name(const char *name);
  *  into your code), and give some information to GRAS about your pointer. 
  
  *  GRAS_ANNOTE takes two arguments being the key name and the key value. For now, the only accepted key name 
- *  is "size", to specify the length of the pointed array. It can either be the string "1" (without the quote)
- *  or the name of another field of the structure.
+ *  is "size", to specify the length of the pointed array. It can either be:
+ *    - the string "1" (without the quote),
+ *    - the name of another field of the structure
+ *    - a sort of computed expression for multidimensional arrays (see below -- pay attention to the warnings below).
  *  
  *  Here is an example:\verbatim GRAS_DEFINE_TYPE(s_clause,
   struct s_array {
+    struct s_array *father GRAS_ANNOTE(size,1);
     int length;
     int *data GRAS_ANNOTE(size,length);
-    struct s_array *father GRAS_ANNOTE(size,1);
+    int rows;
+    int cols;
+    int *matrix GRAS_ANNOTE(size,rows*cols);
  }
 ;)\endverbatim
- * It specifies that the structure s_array contains two fields, and that the size of the array pointed 
- * by \a data is the \a length field, and that the \a father field is a simple reference.
+ * It specifies that the structure s_array contains five fields, that the \a father field is a simple reference,
+ * that the size of the array pointed by \a data is the \a length field, and that the \a matrix field is an array
+ * which size is the result of \a rows times \a cols.
  * 
+ *  \warning The mecanism for multidimensional arrays is known to be fragile and cumbersome. If you want to use it, 
+ *  you have to understand how it is implemented: the multiplication is performed using the sizes stack. In previous example,
+ *  a \ref gras_datadesc_cb_push_int callback is added to the \a rows field and a \ref gras_datadesc_cb_push_int_mult one is 
+ *  added to \a cols. So, when the structure is sent, the rows field push its value onto the stack, then the \a cols field 
+ *  retrieve this value from the stack, compute (and push) the multiplication value. The \a matrix field can then retrive this
+ *  value by poping the array. There is several ways for this to go wrong:
+ *   - if the matrix field is placed before the sizes, the right value won't get pushed into the stack soon enough. Reorder your structure fields if needed.
+ *   - if you write GRAS_ANNOTE(size,cols*rows); in previous example (inverting rows and cols in annotation),
+ *     \a rows will be given a \ref gras_datadesc_cb_push_int_mult. This cannot work since it will try to 
+ *     pop the value which will be pushed by \a cols <i>afterward</i>.
+ *   - if you have more than one matrix in your structure, don't interleave the size. They are pushed/poped in the structure order.
+ *   - if some of the sizes are used in more than one matrix, you cannot use this mecanism -- sorry.
+ *
  * If you cannot express your datadescs with this mechanism, you'll have to use the more advanced 
  * (and somehow complex) one described below.
- * 
- *  \warning Since GRAS_DEFINE_TYPE is a macro, you shouldn't  put any comma in your type definition 
- *  (comma separates macro args). 
- * 
- *  For example, change \verbatim int a, b;\endverbatim to \verbatim int a;
+ *
+ *  \warning Since GRAS_DEFINE_TYPE is a macro, you shouldn't put any comma in your type definition 
+ *  (comma separates macro args). For example, change \verbatim int a, b;\endverbatim to \verbatim int a;
  int b;\endverbatim
  */
 /** @{ */
@@ -246,6 +263,9 @@ void gras_datadesc_cb_field_recv(gras_datadesc_type_t    type,
 /** \brief Add a pre-send callback to the given field resulting in its value to be pushed */
 void gras_datadesc_cb_field_push (gras_datadesc_type_t   type,
                                  const char            *field_name);
+/** \brief Add a pre-send callback to the given field resulting in its value multiplied to any previously pushed value and then pushed back */
+void gras_datadesc_cb_field_push_multiplier (gras_datadesc_type_t type,
+                                            const char          *field_name);
 
 /******************************
  * Get stuff within datadescs *
@@ -261,6 +281,7 @@ int gras_datadesc_get_id(gras_datadesc_type_t ddt);
  * 
  * Sometimes, one of the callbacks need to leave information for the next ones. If this is a simple integer (such as
  * an array size), you can use the functions described here. If not, you'll have to play with the complete cbps interface.
+ *
  * 
  * Here is an example:\verbatim
 struct s_array {
@@ -277,6 +298,27 @@ gras_datadesc_struct_append(my_type,"data",
 gras_datadesc_struct_close(my_type);
 \endverbatim
 
+ *
+ * The *_mult versions are intended for multi-dimensional arrays: They multiply their value to the previously pushed one 
+ * (by another field callback) and push the result of the multiplication back. An example of use follows. Please note
+ * that the first field needs a regular push callback, not a multiplier one. Think of it as a stacked calculator (man dc(1)).\verbatim
+struct s_matrix {
+  int row;
+  int col;
+  int *data;
+}
+[...]
+my_type=gras_datadesc_struct("s_matrix");
+gras_datadesc_struct_append(my_type,"row", gras_datadesc_by_name("int"));
+gras_datadesc_cb_field_send (my_type, "length", gras_datadesc_cb_push_int);
+gras_datadesc_struct_append(my_type,"col", gras_datadesc_by_name("int"));
+gras_datadesc_cb_field_send (my_type, "length", gras_datadesc_cb_push_int_mult);
+
+gras_datadesc_struct_append(my_type,"data",
+                            gras_datadesc_array_dyn ("s_matrix::data",gras_datadesc_by_name("int"), gras_datadesc_cb_pop));
+gras_datadesc_struct_close(my_type);
+\endverbatim
  */
 /* @{ */
 
@@ -286,11 +328,17 @@ int
 gras_cbps_i_pop(gras_cbps_t ps);
 
 int gras_datadesc_cb_pop(gras_datadesc_type_t typedesc, gras_cbps_t vars, void *data);
+
 void gras_datadesc_cb_push_int(gras_datadesc_type_t typedesc, gras_cbps_t vars, void *data);
 void gras_datadesc_cb_push_uint(gras_datadesc_type_t typedesc, gras_cbps_t vars, void *data);
 void gras_datadesc_cb_push_lint(gras_datadesc_type_t typedesc, gras_cbps_t vars, void *data);
 void gras_datadesc_cb_push_ulint(gras_datadesc_type_t typedesc, gras_cbps_t vars, void *data);
 
+void gras_datadesc_cb_push_int_mult(gras_datadesc_type_t typedesc, gras_cbps_t vars, void *data);
+void gras_datadesc_cb_push_uint_mult(gras_datadesc_type_t typedesc, gras_cbps_t vars, void *data);
+void gras_datadesc_cb_push_lint_mult(gras_datadesc_type_t typedesc, gras_cbps_t vars, void *data);
+void gras_datadesc_cb_push_ulint_mult(gras_datadesc_type_t typedesc, gras_cbps_t vars, void *data);
+
 
 /* @} */
 
index df24554..6f21158 100644 (file)
@@ -323,27 +323,63 @@ int gras_datadesc_cb_pop(gras_datadesc_type_t ignored, gras_cbps_t vars, void *d
   return gras_cbps_i_pop(vars);
 }
 
+/* ************************* */
+/* **** PUSHy callbacks **** */
+/* ************************* */
+
 /** \brief Cb to push an integer. Must be attached to the field you want to push */
 void gras_datadesc_cb_push_int(gras_datadesc_type_t ignored, gras_cbps_t vars, void *data) {
-   int *i = (int*)data;
-   gras_cbps_i_push(vars, (int) *i);
+  int *i = (int*)data;
+  gras_cbps_i_push(vars, (int) *i);
 }
 
 /** \brief Cb to push an unsigned integer. Must be attached to the field you want to push */
 void gras_datadesc_cb_push_uint(gras_datadesc_type_t ignored, gras_cbps_t vars, void *data) {
-   unsigned int *i = (unsigned int*)data;
-   gras_cbps_i_push(vars, (int) *i);
+  unsigned int *i = (unsigned int*)data;
+  gras_cbps_i_push(vars, (int) *i);
 }
 
 /** \brief Cb to push an long integer. Must be attached to the field you want to push
  */
 void gras_datadesc_cb_push_lint(gras_datadesc_type_t ignored, gras_cbps_t vars, void *data) {
-   long int *i = (long int*)data;
-   gras_cbps_i_push(vars, (int) *i);
+  long int *i = (long int*)data;
+  gras_cbps_i_push(vars, (int) *i);
 }
-/** \brief Cb to push an long integer. Must be attached to the field you want to push
+/** \brief Cb to push an unsigned long integer. Must be attached to the field you want to push
  */
 void gras_datadesc_cb_push_ulint(gras_datadesc_type_t ignored, gras_cbps_t vars, void *data) {
-   unsigned long int *i = (unsigned long int*)data;
-   gras_cbps_i_push(vars, (int) *i);
+  unsigned long int *i = (unsigned long int*)data;
+  gras_cbps_i_push(vars, (int) *i);
+}
+
+/* ************************************ */
+/* **** PUSHy multiplier callbacks **** */
+/* ************************************ */
+/** \brief Cb to push an integer as multiplier. Must be attached to the field you want to push */
+void gras_datadesc_cb_push_int_mult(gras_datadesc_type_t ignored, gras_cbps_t vars, void *data) {
+  int *i = (int*)data;
+  (*i) * gras_cbps_i_pop(vars);
+  gras_cbps_i_push(vars, (int) *i);
+}
+
+/** \brief Cb to push an unsigned integer as multiplier. Must be attached to the field you want to push */
+void gras_datadesc_cb_push_uint_mult(gras_datadesc_type_t ignored, gras_cbps_t vars, void *data) {
+  unsigned int *i = (unsigned int*)data;
+  (*i) * gras_cbps_i_pop(vars);
+  gras_cbps_i_push(vars, (int) *i);
+}
+
+/** \brief Cb to push an long integer as multiplier. Must be attached to the field you want to push
+ */
+void gras_datadesc_cb_push_lint_mult(gras_datadesc_type_t ignored, gras_cbps_t vars, void *data) {
+  long int *i = (long int*)data;
+  (*i) * gras_cbps_i_pop(vars);
+  gras_cbps_i_push(vars, (int) *i);
+}
+/** \brief Cb to push an unsigned long integer as multiplier. Must be attached to the field you want to push
+ */
+void gras_datadesc_cb_push_ulint_mult(gras_datadesc_type_t ignored, gras_cbps_t vars, void *data) {
+  unsigned long int *i = (unsigned long int*)data;
+  (*i) * gras_cbps_i_pop(vars);
+  gras_cbps_i_push(vars, (int) *i);
 }
index 6caa963..465c939 100644 (file)
@@ -692,6 +692,7 @@ void gras_datadesc_cb_field_send (gras_datadesc_type_t          type,
    field->send = send;
 }
 
+
 /**
  * The value, which must be an int, unsigned int, long int or unsigned long int
  * is pushed to the stacks of sizes and can then be retrieved with 
@@ -719,6 +720,38 @@ void gras_datadesc_cb_field_push (gras_datadesc_type_t  type,
       xbt_abort();
    }
 }
+
+/**
+ * Any previously pushed value is poped and the field value is multiplied to
+ * it. The result is then pushed back into the stack of sizes. It can then be
+ * retrieved with \ref gras_datadesc_ref_pop_arr or directly with \ref
+ * gras_cbps_i_pop.
+ *
+ * The field must be an int, unsigned int, long int or unsigned long int.
+ */
+void gras_datadesc_cb_field_push_multiplier (gras_datadesc_type_t  type,
+                                            const char         *field_name) {
+   
+   gras_dd_cat_field_t  field=gras_dd_find_field(type,field_name);
+   gras_datadesc_type_t sub_type=field->type;
+   
+   DEBUG3("add a PUSHy cb to '%s' field (type '%s') of '%s'",
+         field_name,sub_type->name,type->name);
+   if (!strcmp("int",sub_type->name)) {
+      field->send = gras_datadesc_cb_push_int_mult;
+   } else if (!strcmp("unsigned int",sub_type->name)) {
+      field->send = gras_datadesc_cb_push_uint_mult;
+   } else if (!strcmp("long int",sub_type->name)) {
+      field->send = gras_datadesc_cb_push_lint_mult;
+   } else if (!strcmp("unsigned long int",sub_type->name)) {
+      field->send = gras_datadesc_cb_push_ulint_mult;
+   } else {
+      ERROR1("Field %s is not an int, unsigned int, long int neither unsigned long int",
+            sub_type->name);
+      xbt_abort();
+   }
+}
+
 /**
  * The given datadesc must be a struct or union (abort if not).
  * (useful to put the function pointers to the right value, for example)
index 64361e2..341767e 100644 (file)
@@ -358,15 +358,14 @@ static void parse_statement(char   *definition,
 
        while ( (gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump()) == GRAS_DDT_PARSE_TOKEN_EMPTY );
 
+       /* get the value */
+
        if (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_WORD) 
          PARSE_ERROR1("Unparsable annotation: Expected key value, got '%s'",gras_ddt_parse_text);
        keyval = (char*)strdup(gras_ddt_parse_text);
 
        while ( (gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump()) == GRAS_DDT_PARSE_TOKEN_EMPTY );
 
-       if (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_RP) 
-         PARSE_ERROR1("Unparsable annotation: Expected parenthesis, got '%s'",gras_ddt_parse_text);
-
        /* Done with parsing the annotation. Now deal with it by replacing previously pushed type with the right one */
 
        DEBUG2("Anotation: %s=%s",keyname,keyval);
@@ -379,7 +378,6 @@ static void parse_statement(char     *definition,
          if (!strcmp(keyval,"1")) {
            change_to_ref(identifiers);
            free(keyval);
-           continue;
          } else {
            char *p;
            int fixed = 1;
@@ -390,19 +388,39 @@ static void parse_statement(char   *definition,
              change_to_fixed_array(identifiers,atoi(keyval));
              change_to_ref(identifiers);
              free(keyval);
-             continue;
 
            } else {
              change_to_ref_pop_array(identifiers);
              xbt_dynar_push(fields_to_push,&keyval);
-             continue;
            }
          }
-         THROW_IMPOSSIBLE;
-
        } else {
          PARSE_ERROR1("Unknown annotation type: '%s'",keyname);
        }
+
+       /* Get all the multipliers */
+       while (gras_ddt_parse_tok_num == GRAS_DDT_PARSE_TOKEN_STAR) {
+
+         gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump();
+
+         if (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_WORD) 
+           PARSE_ERROR1("Unparsable annotation: Expected field name after '*', got '%s'",gras_ddt_parse_text);
+         
+         keyval = xbt_malloc(strlen(gras_ddt_parse_text)+2);
+         sprintf(keyval,"*%s",gras_ddt_parse_text);
+
+         /* ask caller to push field as a multiplier */
+         xbt_dynar_push(fields_to_push,&keyval);
+
+         /* skip blanks after this block*/
+         while ( (gras_ddt_parse_tok_num = gras_ddt_parse_lex_n_dump()) 
+                 == GRAS_DDT_PARSE_TOKEN_EMPTY );
+       }
+
+       if (gras_ddt_parse_tok_num != GRAS_DDT_PARSE_TOKEN_RP) 
+         PARSE_ERROR1("Unparsable annotation: Expected parenthesis, got '%s'",
+                      gras_ddt_parse_text);
+
        continue;
 
        /* End of annotation handling */
@@ -503,8 +521,15 @@ static gras_datadesc_type_t parse_struct(char *definition) {
     /* Make sure that all fields declaring a size push it into the cbps */
     xbt_dynar_foreach(fields_to_push,i, name) {
       DEBUG1("struct_type=%p",(void*)struct_type);
-      VERB2("Push field '%s' into size stack of %p", name, (void*)struct_type);
-      gras_datadesc_cb_field_push(struct_type, name);
+      if (name[0] == '*') {
+       VERB2("Push field '%s' as a multiplier into size stack of %p",
+             name+1, (void*)struct_type);
+       gras_datadesc_cb_field_push_multiplier(struct_type, name+1);
+      } else {
+       VERB2("Push field '%s' into size stack of %p",
+             name, (void*)struct_type);
+       gras_datadesc_cb_field_push(struct_type, name);
+      }
       free(name);
     }
     xbt_dynar_reset(fields_to_push);