In this section, we present some of the implementation details of
(non-driver) components that provide ports with SIDL arrays as
arguments. The student source contains implementation of three
components, CArrayOp,
F77ArrayOp, and
F90ArrayOp, implemented in C, F77, and F90
respectively.
Code for the CArrayOp component can be found in the
directory , in the
two $STUDENT_SRC/components/arrayOps/cImpl files
arrayOps_CArrayOp_Impl.c and
arrayOps_CArrayOp_Impl.h. Private component state is
represented by entries in the struct
arrayOps_CArrayOp__data in the header file
arrayOps_CArrayOp_Impl.h
struct arrayOps_CArrayOp__data {
/* DO-NOT-DELETE splicer.begin(arrayOps.CArrayOp._data) */
gov_cca_Services frameworkServices;
double *myVector;
int myVecLen;
/* DO-NOT-DELETE splicer.end(arrayOps.CArrayOp._data) */
};
Private component data is initialized and associated with the component
instance in the component constructor method
impl_arrayOps_CArrayOp__ctor
struct arrayOps_CArrayOp__data *pd = (struct arrayOps_CArrayOp__data*)
calloc(1, sizeof(struct arrayOps_CArrayOp__data));
arrayOps_CArrayOp__set_data(self, pd);
arrayop_LinearOp_init(self);
return;
Note the use of the built-in method
arrayOps_CArrayOp__set_data to associate the
newly allocated struct with this component
instance. A corresponding method,
arrayOps_CArrayOp__get_data is used to access
this private data.
The method impl_arrayOps_CArrayOp_mulMatVec uses SIDL
raw arrays (array A, and vectors x
and y). Multi-dimension SIDL raw arrays are assumed to
be stored in column-major order, as shown in the code to multiply array
A and vector x
for (i= 0; i <= m; i++){
y[i] = 0.0;
for (j = 0 ; j <= n; j++){
y[i] += alpha * A[j*m + i] * x[j]; /* Raw array A is column-major */
}
pd->myVector[i] += y[i];
y[i] = pd->myVector[i];
}
The method impl_arrayOps_CArrayOp_addVec
uses the more flexible SIDL normal arrays. SIDL normal arrays are
represented in C using a struct
sidl_, where
XXX__array is the actual type
of array elements. In this example, the SIDL XXXout
normal array *r is created (and underlying memory
allocated) in the call
*r = sidl_double__array_create1d(n);
Direct access to a SIDL normal array's underlying memory is acheived via
the C macro sidlArrayAddr1 (for 1-dimensional arrays
*r and v).
![]() |
Note |
|---|---|
|
When implementing a method that has SIDL normal arrays as arguments, it should not be assumed that the array is contiguous in memory (stride=1). SIDL normal arrays allow for different strides in all dimensions. As such, the correct code for vector addition has the form
vstride = sidlStride(v, 0);
for ( i = 0; i <= n; i++){
rdata[i] = pd->myVector[i] += beta * vdata[i*vstride];
}
No stride is used when accessing the vector |
Code for the F77ArrayOp component can be found in the
directory , in
$STUDENT_SRC/components/arrayOps/f77Impl file arrayOps_f77ArrayOp_Impl.f.
Private component state is represented by entries an an array of SIDL
opaque types. It is the responsibility of the programmer
to ensure consistency of the treatment of entries in this array across
method calls (this is similar to the way entries into common
blocks are manipulated). Code for the creation and initialization
of the private component state can be found in the component constructor
method arrayOps_F77ArrayOp__ctor_fi.
integer *8 stateArray, intArray, tmp
tmp = 0
call sidl_opaque__array_create1d_f(3, stateArray)
call sidl_int__array_create1d_f(2, intArray)
if ((statearray .ne. 0) .and. (intArray .ne. 0)) then
call sidl_opaque__array_set1_f(statearray, 0, tmp)
call sidl_opaque__array_set1_f(statearray, 1, intArray)
call sidl_opaque__array_set1_f(statearray, 2, tmp)
else
. . .
The SIDL built-in method
arrayOps_F77ArrayOp__set_data_f is used to
associate the newly created SIDL opaque array with
this instance of the component. The method
arrayOps_F77ArrayOp__get_data_f is used to
retrieve this private data for further manipulation.
The method
arrayOps_F77ArrayOp_mulMatVec_fi uses SIDL
raw arrays arguments. In F77 implementation, SIDL raw arrays appear as
regular F77 arrays, with zero-based indexing. The component uses the
SIDL normal array accVector to store the running
sum of the linear matrix operations. Note that this enables the
dynamic sizing of this vector at runtime to match the dimensions of
the array and vector arguments. Direct access to the underlying
memory for SIDL normal arrays is done through the
sidl_double__array_access_f method (for arrays of
SIDL type double). This method computes uses a
reference array (nativeVec) of
size one, and computes the offset (refindex) that
needs to be added to indices into nativeVec to
access memory associated with SIDL normal array
accVector.
call sidl_double__array_access_f(accVector, nativeVec,
$ lower, upper, stride, refindex)
do i = 0, m-1
y(i) = nativeVec(refindex + i)
do j = 0, n-1
y(i) = y(i) + alpha * A(i, j) * x(j)
end do
y(i) = y(i) + nativeVec(refindex + i)
nativeVec(refindex + i) = y(i)
end do
Accesssing entries in a normal SIDL array can also be done
through accessor subroutine calls. In the case of
arrays of SIDL type double, the accessor subroutines are
sidl_opaque__array_set1_f and
sidl_opaque__array_get1_f (for single dimensional
arrays).
if (accVector .eq. 0) then
call sidl_double__array_create1d_f(m, accVector)
call sidl_int__array_set1_f(intArray, 0, m)
call sidl_opaque__array_set1_f(stateArray, 2, accVector)
dblTmp = 0.0
do i = 0, m-1
call sidl_double__array_set1_f(accVector, i, dblTmp)
end do
else
. . .
![]() |
Note |
|---|---|
|
When implementing a method that has SIDL normal arrays as arguments, it
should not be assumed that the array is contiguous in memory (stride=1).
SIDL normal arrays allow for different strides in all dimensions. As
such, the correct code for vector addition in
do i = 0, m-1
nativeR(refindexR + i) = nativeVec(refindex + i) +
$ beta * nativeV(refindexV +i*strideV(1))
nativeVec(refindex + i) = nativeR(refindexR + i)
end do
No stride is used when accessing the array |
Code for the F90ArrayOp component can be found in the
directory , in
the $STUDENT_SRC/components/arrayOps/f90Impl
files arrayOps_F90ArrayOp_Impl.F90and
arrayOps_F90ArrayOp_Mod.F90. Private component state
is represented by the type arrayOps_F90ArrayOp_priv
in the file arrayOps_F90ArrayOp_Mod.F90
type arrayOps_F90ArrayOp_priv sequence ! DO-NOT-DELETE splicer.begin(arrayOps.F90ArrayOp.private_data) ! Handle to framework Services object type(gov_cca_Services_t) :: frameworkServices real (selected_real_kind(15, 307)), dimension(:), pointer :: myVectorP integer (selected_int_kind(9)) :: myVecLen ! DO-NOT-DELETE splicer.end(arrayOps.F90ArrayOp.private_data) end type arrayOps_F90ArrayOp_priv
The constructor subroutine arrayOps_F90ArrayOp__ctor_mi
contains the code for the allocation and initialization of the private data
associated with this component instance
type(arrayOps_F90ArrayOp_wrap) :: dataWrap type(arrayOps_F90ArrayOp_priv), pointer :: pd allocate(dataWrap%d_private_data) pd => dataWrap%d_private_data ! Allocate memory and initialize call set_null(pd%frameworkServices) pd%myVectorP => NULL() pd%myVecLen = 0 call arrayOps_F90ArrayOp__set_data_m(self, dataWrap)
Note that private data is accessed through the pointer
pd, accessed through the variable
dataWrap of type
arrayOps_F90ArrayOp_wrap. The call to the
built-in method
arrayOps_F90ArrayOp__set_data_m associates the newly
created structure pointed to via pd with this instance
of the component. The corresponding method
arrayOps_F90ArrayOp__get_data_m is used to retrieve this
private data for further processing.
The subroutine that implements the mulMatVec method
uses SIDL raw arrays (note that the name of this subroutine is altered by
Babel to accomodate F90 identifier length restrictions as outlined in
Section 3.3, “Implementation of the F90Driver in
Fortran 90”). SIDL raw arrays manifest
themselves in F90 implementations as regular F90 arrays that use zero-based
indexing.
real (selected_real_kind(15, 307)), dimension(0:m-1, 0:n-1) :: A ! in real (selected_real_kind(15, 307)), dimension(0:n-1) :: x ! in real (selected_real_kind(15, 307)), dimension(0:m-1) :: y ! inout
The subroutine that implements the addVec method uses
SIDl normal arrays. SIDL normal arrays are represented as user defined
types, with a pointer data member
(d_datathat points to an F90 array built on top of
the underlying SIDL array memory. While access to SIDL normal array
entries can be achieved via accessor subroutines (set
and get - defined for all native SIDL types and user
defined classes and interfaces), it is more convenient (and efficient) to
access those entries directly via the d_data pointer.
vdata => v%d_data rdata => r%d_data rdata = pd%myVectorP + beta * vdata pd%myVectorP = rdata
![]() |
Note |
|---|---|
|
When implementing a method that has SIDL normal arrays as arguments, it should not be assumed that the array is contiguous in memory (stride=1). SIDL normal arrays allow for different strides in all dimensions. The Babel runtime build the correct F90 array descriptor (dope vector) that correctly reflects the strides used to create the SIDL array. |