Inconsistency in calling convention of level1 blas functions

Open discussion regarding features, bugs, issues, vendors, etc.

Inconsistency in calling convention of level1 blas functions

Postby Klaas » Tue Dec 18, 2007 1:25 pm

Dear all,

I don't know if what I am writing here is already know or not, but this is something I stumbled upon lately and thought it was worth mentioning it.

There is an inconsistency in the calling convention of gfortran compiled level 1 blas functions returning a complex or doublecomplex datatype with those functions of other well known blas libraries like GotoBlas, Intel MKL, ACML and others.

All these libraries use the calling conventions which were used by g77, i.e. functions that return type default REAL actually return the C type double, and functions that return type COMPLEX return the values via an extra argument in the calling sequence that points to where to store the return value.

Since g77 is not under development anymore, most people start to compile their blas and lapack libraries using gfortran. The so called successor of g77. One of the changes that gfortran brought along is the much easier to use calling convention of complex functions which is now identical to those of functions returning REAL data, i.e. functions that return type COMPLEX return now a C struct resembling the complex value.

Although much easier, this makes it difficult to create a general FORTRAN, C or C++ code which call these level 1 blas functions and can be used together with any of the above mentioned blas libraries.

This can be seen with some examples. We use the testfile zblat1.f and compile it with gfortran and ifort and use the libraries blas_GFORTRAN.a and libgoto.a.

Code: Select all
$ gfortran zblat1.f blas_GFORTRAN.a
$ ./a.out
 Complex BLAS Test Program Results


 Test of subprogram number  1            ZDOTC
                                    ----- PASS -----

 Test of subprogram number  2            ZDOTU
                                    ----- PASS -----

 Test of subprogram number  3            ZAXPY
                                    ----- PASS -----

 Test of subprogram number  4            ZCOPY
                                    ----- PASS -----

 Test of subprogram number  5            ZSWAP
                                    ----- PASS -----

 Test of subprogram number  6            DZNRM2
                                    ----- PASS -----

 Test of subprogram number  7            DZASUM
                                    ----- PASS -----

 Test of subprogram number  8            ZSCAL
                                    ----- PASS -----

 Test of subprogram number  9            ZDSCAL
                                    ----- PASS -----

 Test of subprogram number 10            IZAMAX
                                    ----- PASS -----
$ ifort zblat1.f blas_GFORTRAN.a
$ ./a.out
 Complex BLAS Test Program Results


 Test of subprogram number  1            ZDOTC
                                       FAIL

 CASE  N INCX INCY MODE  I                             COMP(I)                             TRUE(I)  DIFFERENCE     SIZE(I)

    1  1    1    1 9999  1                      0.00000000D+00                      0.90000000D+00 -0.9000D+00  0.9000D+00
    1  1    1    1 9999  2                      0.00000000D+00                      0.60000000D-01 -0.6000D-01  0.9000D+00
    1  2    1    1 9999  1                      0.00000000D+00                      0.91000000D+00 -0.9100D+00  0.1630D+01
    1  2    1    1 9999  2                      0.00000000D+00                     -0.77000000D+00  0.7700D+00  0.1730D+01
    1  4    1    1 9999  1                      0.00000000D+00                      0.18000000D+01 -0.1800D+01  0.2900D+01
    1  4    1    1 9999  2                      0.00000000D+00                     -0.10000000D+00  0.1000D+00  0.2780D+01
    1  1    2   -2 9999  1                      0.00000000D+00                      0.90000000D+00 -0.9000D+00  0.9000D+00
    1  1    2   -2 9999  2                      0.00000000D+00                      0.60000000D-01 -0.6000D-01  0.9000D+00
    1  2    2   -2 9999  1                      0.00000000D+00                      0.14500000D+01 -0.1450D+01  0.1630D+01
    1  2    2   -2 9999  2                      0.00000000D+00                      0.74000000D+00 -0.7400D+00  0.1730D+01
    1  4    2   -2 9999  1                      0.00000000D+00                      0.20000000D+00 -0.2000D+00  0.2900D+01
    1  4    2   -2 9999  2                      0.00000000D+00                      0.90000000D+00 -0.9000D+00  0.2780D+01
    1  1   -2    1 9999  1                      0.00000000D+00                      0.90000000D+00 -0.9000D+00  0.9000D+00
    1  1   -2    1 9999  2                      0.00000000D+00                      0.60000000D-01 -0.6000D-01  0.9000D+00
    1  2   -2    1 9999  1                      0.00000000D+00                     -0.55000000D+00  0.5500D+00  0.1630D+01
    1  2   -2    1 9999  2                      0.00000000D+00                      0.23000000D+00 -0.2300D+00  0.1730D+01
    1  4   -2    1 9999  1                      0.00000000D+00                      0.83000000D+00 -0.8300D+00  0.2900D+01
    1  4   -2    1 9999  2                      0.00000000D+00                     -0.39000000D+00  0.3900D+00  0.2780D+01
    1  1   -1   -2 9999  1                      0.00000000D+00                      0.90000000D+00 -0.9000D+00  0.9000D+00
    1  1   -1   -2 9999  2                      0.00000000D+00                      0.60000000D-01 -0.6000D-01  0.9000D+00
    1  2   -1   -2 9999  1                      0.00000000D+00                      0.10400000D+01 -0.1040D+01  0.1630D+01
    1  2   -1   -2 9999  2                      0.00000000D+00                      0.79000000D+00 -0.7900D+00  0.1730D+01
    1  4   -1   -2 9999  1                      0.00000000D+00                      0.19500000D+01 -0.1950D+01  0.2900D+01
    1  4   -1   -2 9999  2                      0.00000000D+00                      0.12200000D+01 -0.1220D+01  0.2780D+01

 Test of subprogram number  2            ZDOTU
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image              PC                Routine            Line        Source
a.out              00000000004079C6  Unknown               Unknown  Unknown
a.out              000000000040374A  Unknown               Unknown  Unknown
a.out              00000000004028E2  Unknown               Unknown  Unknown
libc.so.6          00002B3BE46F0AE4  Unknown               Unknown  Unknown
a.out              0000000000402829  Unknown               Unknown  Unknown
[klaas@talvin10 blas]$ gfortran zblat1.f libgoto.a -lpthread
[klaas@talvin10 blas]$ ./a.out
 Complex BLAS Test Program Results


 Test of subprogram number  1            ZDOTC
Segmentation fault
$ ifort zblat1.f libgoto.a -lpthread
$ ./a.out
 Complex BLAS Test Program Results


 Test of subprogram number  1            ZDOTC
                                    ----- PASS -----

 Test of subprogram number  2            ZDOTU
                                    ----- PASS -----

 Test of subprogram number  3            ZAXPY
                                    ----- PASS -----

 Test of subprogram number  4            ZCOPY
                                    ----- PASS -----

 Test of subprogram number  5            ZSWAP
                                    ----- PASS -----

 Test of subprogram number  6            DZNRM2
                                    ----- PASS -----

 Test of subprogram number  7            DZASUM
                                    ----- PASS -----

 Test of subprogram number  8            ZSCAL
                                    ----- PASS -----

 Test of subprogram number  9            ZDSCAL
                                    ----- PASS -----

 Test of subprogram number 10            IZAMAX
                                    ----- PASS -----


Analogue problems can be found when calling the libraries from C or C++. The function definition from the above mentioned libraries should be of the form
Code: Select all
extern "C" {
void cdotc_(std::complex<float> *result, long *, std::complex<float> *, long *, std::complex<float> *, long *);
}


while for the gfortran compiled version you have to define it as
Code: Select all
extern "C" {
std::complex<float> cdotc_(long *, std::complex<float> *, long *, std::complex<float> *, long *);
}


and fails to work with any of the above libraries.

I don't really see immediately a solution to this problem, maybe some coding gurus know their way out of this. But I would keep the following rules in mind when using gfortran.

- If you are sure you will only use gfortran for your code without any external blas libraries, compile the libraries with gfortran as mentioned in the make.inc examples.
- If you have a fortran code and you would like to link it with other blas libraries, compile your code with ifort or gfortran -ff2c or any other fortran compiler that uses the g77 conventions.
- If you intend to write a portable code FORTRAN/C/C++ but have no access to other blas libraries, compile them with gfortran -ff2c
If you did the above and your code is fortran, always use the -ff2c flag.


One real solution I would see is changing the level 1 blas functions into subroutines. But since BLAS and LAPACK are already so well known and have been used for several years in programs which still run now, I don't think those developers would like the idea to checking their code to see if they use any of those 7 functions.

With kind regards
Klaas
Klaas
 
Posts: 22
Joined: Mon Feb 06, 2006 2:06 pm

Re: Inconsistency in calling convention of level1 blas funct

Postby ichowdhury » Thu Sep 09, 2010 6:29 am

Maybe this is a solution:

The MKLblas function zdotc is called from C++ directly there is a seg-fault. So a wrapper in gfortran is written around zdotc_ which has the output value as one of its arguments. Compile this fortran file with "-ff2c" flag to make it amenable to g77. And then if linked to MKL there is no seg fault .

!!!! Fortran zdotcwrapper.f , z is the return value -- to call MKL zdotc from C++ without segfault
INTEGER FUNCTION zdotcwrapper(n,xcompl,incx ,ycompl,incy,
& z )

IMPLICIT NONE
integer n , incx, incy

double complex x(n), y(n), ret, ZDOTC
double complex xcompl(n), ycompl(n), z
integer I

PRINT *, 'N ', n , ' incx ', incx, ' incy ', incy
DO I=1,n
PRINT *, 'X ', xcompl(I), ' Y ', ycompl(I)
ENDDO

z = ZDOTC( n, xcompl, incx, ycompl, incy )
PRINT *, 'Z ', z
zdotcwrapper = 0

END
!!!!!!!!!!!!!!!!!!

/////C++ file calling the wrapped

#include <stdio.h>
#include <complex>

using namespace std;

typedef std::complex<double> ComplexDouble;

extern "C"{
extern int zdotcwrapper_(const int &n, ComplexDouble *x, const int &incx, ComplexDouble *y, const int &incy, ComplexDouble *z);
}

int main()
{
int n, incx, incy;

n = 3;
incx = 1;
incy = 1;

ComplexDouble x[3];
ComplexDouble y[3], z(0,0);
for( int i = 0 ; i < 3; ++i )
{
ComplexDouble tempx(5+i/10,i-.9);
x[i] = tempx;
ComplexDouble tempy(1+i/20,i*0.6-.8);
y[i] = tempy;
}


zdotcwrapper_( n, x, incx, y, incy, &z );

printf(" \nZREAL %le ZIMAG %le\n", real(z), imag(z) );

}

////////////////////////////////////
Now complile as follows:

g++ -g -c mainZDotc.cc
gfortran -g -c -ff2c zdotcwrapper.f
g++ -ff2c -g zdotcwrapper.o mainZDotc.o -o testZDotc -lmkl

There was no seg-fault
ichowdhury
 
Posts: 2
Joined: Tue Aug 31, 2010 6:31 am


Return to User Discussion

Who is online

Users browsing this forum: Google [Bot], Yahoo [Bot] and 2 guests