7.2. The CDriver Component

The SIDL specification for the CDriver component can be found in the file $STUDENT_SRC/components/sidl/arraydrivers.sidl. The implementation of this component (in the C programming language) can be found at $STUDENT_SRC/components/arrayDrivers/c/ in the two files arrayDrivers_CDriver_Impl.c and arrayDrivers_CDriver_Impl.h. Component implementation details include details of component/framework interaction that should be now familiar, and will not be discussed further in this exercise. We will focus on the handling of different types of SIDL arrays in the go method.

7.2.1. Using SIDL Raw Arrays

Raw arrays (and vectors) are used as arguments in the call to mulMatVec. Note that multidimensional SIDL raw arrays are always assumed to use column-major storage. This requirement necessitates special treatment when calling methods that use SIDL raw arrays as arguments from languages that follow a default raw-major array storage order (C and C++). The caller may choose to alter the memory layout of the array argument throughout its entire lifetime, or alternatively perform a matrix transpose operation on “native” arrays before and after every call to a SIDL method that uses raw arrays. In the example presented here, we have chosen to adopt column-major storage throughout the lifetime of the raw array argument A, as shown in the initialization code shown below

  /*      _        _           _   _           _   _ 
   *     | 1.0  4.0 |         | 1.0 |         | 3.0 |
   * A = | 2.0  5.0 |    v1 = | 2.0 |  sda1 = | 4.0 |
   *     | 3.0  6.0 |          -    -         | 5.0 | 
   *     -          -                         -     - 
   *
   * Note that A needs to be stored in column-major order to make
   * the call using SIDL raw arrays
   */
   value = 0.0;
   for (i = 0; i <= m; i++){
     for (j = 0; j <= n; j++){
       A[i*n+j] = (value += 1.0);
     }
   }

When making a call to a SIDL method that has SIDL raw arrays arguments, the dimensions of those arrays must be explicitly included in the argument list in the SIDL specification. No special “wrapping” of native arrays is needed to make a call using SIDL raw arrays arguments. This can be seen in the call to the mulMatVec method.

	retval = arrayop_LinearOp_mulMatVec(linopPort, alpha, A, v1, y, m , n, &throwaway_excpt);
   if (retval != 0){
     fprintf(stderr, "Error:: %s:%d: Error in call to mulMatVec() \n",
             __FILE__, __LINE__);
      return(-1);
   }

The requirement to use column-major memory layout is one of the restrictions imposed by Babel to allow for the use of raw arrays. See the Babel User Guide for the complete list.

7.2.2. Using SIDL Normal Arrays

SIDL “normal” arrays are implemented in the Babel runtime, with bindings in all Babel supported languages. SIDL normal arrays provided a more flexible array representation, with the ability to directly access the underlying array memory in languages that support this capability (C, C++, F90, and F77). In Python, there are situations where arrays must be copied when passing in and out, but direct access is used wherever the Numerical Python package will allow. In Java, arrays are accessed using the Java Native Interface. More information on SIDL normal arrays can be found in the Babel User Guide.

In this exercise, the method addVec uses SIDL normal arrays (sda1, and sda2). The SIDL specification of the addVec method designates sda1 as an input argument, therefore it needs to be created (more specifically, associated with memory) on the caller side before the call is made. The Babel runtime provides array manipulation bindings in Babel supported languages (except Python, which uses Numeric Python arrays). The one-dimensional, SIDL double array sda1 is created using the following code

   sda1 = sidl_double__array_create1d(m);
   if (!sda1){
      fprintf(stderr, "Error:: %s:%d: Error creating sda1.\n", 
              __FILE__, __LINE__);
      return(-1);
   }

The Babel runtime C binding contains macros that allow direct access to underlying SIDL array memory and properties (dimensions, strides, etc.), without having to go through the standard set() and get() methods. One such macro is used in this example to access the underlying memory of SIDL array sda1

   sda1_data = sidlArrayAddr1(sda1, 0);
   for (value =0.0, i = 0; i <= m; i++){
      sda1_data[i] = (double) i + 3.0 ; 
   }

Other macros are used in the loop that prints the result returned in the SIDL out array sda2, after the call to addVec.

   printf("Result2 = ");
   for ( i = sidlLower(sda2, 0); i <= sidlUpper(sda2, 0); i++){
      printf("%.2f  ", sidlArrayElem1(sda2,i));
   } 
   printf("\n");

Direct access to underlying SIDL array memory is also available in the Babel SIDL array binding in F77, F90, and C++. Example of such use is available in the discussion in Section 7.3, “Linear Array Operations Components”.