contents   index   previous   next



Accessing data with SafeArrayAccessData

 

A way to avoid the overhead associated with locking and unlocking a Safe Array is to use f90VB’s procedure SafeArrayAccessData [13]. This procedure puts a lock in the Safe Array and then maps the data-block of a Safe Array into a Fortran array, so your program accesses the Safe Array data in the same way it would do with a native Fortran array. Changes you make in the mapped Fortran array are automatically reflected in the Safe Array, because both objects are actually using the same memory locations. When your application has finished using the data-block of the Safe Array, it must call SafeArrayUnAccessData, which unlocks the data and destroys the mapping. The are two catches with this mechanism. First, your Fortran array only contains meaningful information from the moment you issue the call to SafeArrayAccessData to the moment you call SafeArrayUnAccessData. Remember that once a Safe Array is unlocked, the OS may relocate the memory location of the Safe Array’s data-block. Second, you must not explicitly DEALLOCATE the mapped Fortran arrays, even after you have called SafeArrayUnAccessData. The reason for this is that some Fortran compilers may attempt to release the memory of the mapped Fortran array to the operating system, which could result in an Access Violation error if the mapped Fortran array is sharing memory with a Safe Array that was allocated outside your Fortran program or subroutine (for example, an array created in Visual Basic and passed to a Fortran subroutine).

 

Example 2.5 illustrates the use of the two mechanisms to access Safe Array data explained in the previous sections. This example also shows a rough comparison of the performance of both mechanisms.

 

 

 

 

 

Example 2.5

 

program Example25

 

!This program compares the performance of 

!accessing Safe Array data using the 

!traditional method (SafeArrayGetElement)

!and SafeArrayAccessData

 

use f90VBDefs

use f90VBSafeArrays

implicit none

 

integer(SAFEARRAY_KIND)::SAHndl

 

integer(LONG_KIND)::i,j

integer(HRESULT_KIND)::iRet

real(REAL_KIND)::rValue

real(REAL_KIND),pointer::R4MappedMatrix(:,:)

integer,dimension(8)::StartTime,EndTime

 

!Allocate a Safe Array (100x100)

Call SafeArrayCreate(SAHndl,VT_R4, 1, 1000, 1, 1000)

 

!Set the values of the safe array to random numbers

call random_seed

 

print *, 'Filling a Safe Array using SafeArrayPutElement'

 

!Start timing for assignment loop

call date_and_time(values=StartTime)

 

do i=1,1000

    do j=1,1000

        call random_number(rValue)

        call SafeArrayPutElement(SAHndl,rValue,i,j,iRet)

    enddo

enddo 

 

!Stop timing

call date_and_time(values=EndTime)

 

!print the elapsed time

print *,'Assignment loop:'

write (*,'(a15,i2.2,a1,i2.2,a1,i2.2,a1,i3.3)') &

       'Starting time:',StartTime(5),':',StartTime(6),':', &

        StartTime(7),'.',StartTime(8)

write (*,'(a15,i2.2,a1,i2.2,a1,i2.2,a1,i3.3)') &

       'Ending time:  ',EndTime(5),':',EndTime(6),':', &

       EndTime(7),'.',EndTime(8)

 

print *,''

print *, 'Filling a Safe Array using SafeArrayPutAccessData'

 

!Start timing for mapping operation

call date_and_time(values=StartTime)

 

!Map matrix to Safe Array data-block

call SafeArrayAccessData(SAHndl,R4MappedMatrix,iRet)

 

!Stop timing

call date_and_time(values=EndTime)

 

!print the elapsed time

print *,'Mapping:'

write (*,'(a15,i2.2,a1,i2.2,a1,i2.2,a1,i3.3)') &

       'Starting time:',StartTime(5),':',StartTime(6),':', &

        StartTime(7),'.',StartTime(8)

write (*,'(a15,i2.2,a1,i2.2,a1,i2.2,a1,i3.3)') &

       'Ending time:  ',EndTime(5),':',EndTime(6),':', &

       EndTime(7),'.',EndTime(8)

 

!Start timing for assignment loop

call date_and_time(values=StartTime)

 

do i=1,1000

    do j=1,1000

        call random_number(rValue)

        R4MappedMatrix(i,j)=rValue

    enddo

enddo 

 

!Stop timing

call date_and_time(values=EndTime)

 

!print the elapsed time

print *,'Assignment loop:'

write (*,'(a15,i2.2,a1,i2.2,a1,i2.2,a1,i3.3)') &

       'Starting time:',StartTime(5),':',StartTime(6),':', &

        StartTime(7),'.',StartTime(8)

write (*,'(a15,i2.2,a1,i2.2,a1,i2.2,a1,i3.3)') &

       'Ending time:  ',EndTime(5),':',EndTime(6),':', &

       EndTime(7),'.',EndTime(8)

 

!Start timing for unmapping

call date_and_time(values=StartTime)

 

!Map matrix to Safe Array data-block

call SafeArrayUnAccessData(SAHndl,iRet)

 

!Stop timing

call date_and_time(values=EndTime)

 

!Stop timing

call date_and_time(values=EndTime)

 

!print the elapsed time

print *,'Unmapping:'

write (*,'(a15,i2.2,a1,i2.2,a1,i2.2,a1,i3.3)') &

       'Starting time:',StartTime(5),':',StartTime(6),':', &

        StartTime(7),'.',StartTime(8)

write (*,'(a15,i2.2,a1,i2.2,a1,i2.2,a1,i3.3)') &

       'Ending time:  ',EndTime(5),':',EndTime(6),':', &

       EndTime(7),'.',EndTime(8)

 

!Release memory used by the Safe Array

call SafeArrayDestroy(SAHndl, iRet)

 

stop

end

 

 

Figure 2.1 shows the results printed by Example 2.5 on a computer with a Pentium II – 400 MHz with Windows NT 4.0. Note that using SafeArrayPutElement required a total of 1.118 seconds to fill the array with random numbers. On the other hand, filling the Safe Array through the mapped Fortran array took only 0.256 seconds. The timing taken to map and un-map the Fortran array into the data-block of the safe array was negligible. In other words, using a mapped Fortran array to access the Safe Array data-block is more than 4 times faster than using SafeArrayGetElement or SafeArrayPutElement. This difference in performance, as explained before, is due to the overhead of internal locking and unlocking of the Safe Array each time SafeArrayGetElement or SafeArrayPutElement are called.