Mathews_M_J
Mathews_M_J

Reputation: 467

Level 3 complex BLAS functions throwing out illegal value error

I am writing a function which calls Fortran functions for complex matrix matrix multiplication. I am calling the CGEMM_ and ZGEMM_ functions for complex multiplication. Since all xGEMM_ functions are essentially the same I copied the code from SGEMM_ to CGEMM__ and ZGEMM_. The only change made were the respective data types. The SGEMM_ and DGEMM_ functions are working fine but CGEMM_ throws the error. All inputs are the same as well.

** On entry to CGEMM  parameter number  13 had an illegal value

and zgemm_ throws

 ** On entry to ZGEMM  parameter number  1 had an illegal value

I really have no idea what's going on. Is this some kind of bug in the liblapack package? I am using liblapack-dev package. I made a smaller version of my big code and i am still getting the same error with CGEMM_.

I am running a 32-bit system and was wondering if that was the problem.

Code:

#include<iostream>
using namespace std;
#include<stdlib.h>
#include<string.h>
#include<complex>

typedef complex<float> c_float;
extern "C"
{c_float cgemm_(char*,char*,int*,int*,int*,c_float*, c_float[0],int*,c_float[0],int*,c_float*,c_float[0],int*);//Single Complex Matrix Multiplication
}

c_float** allocate(int rows, int columns)
{
  c_float** data;

  // Allocate Space
  data = new c_float*[columns]; //Allocate memory for using multidimensional arrays in column major format.
  data[0] = new c_float[rows*columns];
  for (int i=0; i<columns; i++)
    {
      data[i] = data[0] + i*rows;
    }

  // Randomize input
  for (int i=0; i<columns; i++)  
    {for (int j=0; j<rows; j++)
        {
          data[j][i] =complex<double>(drand48()*10 +1,drand48()*10 +1); //Randomly generated matrix with values in the range [1 11)
          }
    }
  return(data);
}

// Destructor
void dest(c_float** data)
{
   delete [] data[0];
    delete [] data;
}

// Multiplication
void mult(int rowsA,int columnsA, int rowsB,int columnsB)
{
  c_float **matA,**matB,**matC;
  char transA, transB;
  int m,n,k,LDA,LDB,LDC;
  c_float *A,*B,*C;
  c_float alpha(1.0,0.0);
  c_float beta(0.0,0.0);

  matA = allocate(rowsA,columnsA);
  matB = allocate(rowsB,columnsB);
  matC = allocate(rowsA,columnsB);

  transA = 'N';
  transB = 'N';
  A = matA[0];
  B = matB[0];
  m = rowsA;
  n = columnsB;
  C = matC[0];
  k = columnsA;
  LDA = m;
  LDB = k;
  LDC = m;
  cout<<"Matrix A"<<endl;
  for (int i=0; i<rowsA; i++)  
    {for (int j=0; j<columnsA; j++)
        {
          cout<<matA[i][j];
          cout<<" ";
        }cout<<endl;
    }
  cout<<"Matrix B"<<endl;
  for (int i=0; i<rowsB; i++)  
    {for (int j=0; j<columnsB; j++)
        {
          cout<<matB[i][j];
          cout<<" ";
        }cout<<endl;
    }

  cgemm_(&transA,&transB,&m,&n,&k,&alpha,A,&LDA,B,&LDB,&beta,C,&LDC);
  cout<<"Matrix A*B"<<endl;
  for (int i=0; i<rowsA; i++)  
    {for (int j=0; j<columnsB; j++)
        {
          cout<<matC[i][j];
          cout<<"";
        }
      cout<<endl;
    }
  dest(matA);
  dest(matB);
  dest(matC);
}



main()
{
  mult (2,2,2,2);
}

The output and valgrind report are as follows:

-----------------------------------------
Compilation using g++ -g -o matrix Matrix_multiplication.cpp -lblas -llapack -lgfortran
./matrix gives
Matrix A
(1.00985,1) (1.91331,4.64602)
(2.76643,1.41631) (5.87217,1.92298)
Matrix B
(5.54433,6.2675) (6.6806,10.3173)
(9.31292,3.33178) (1.50832,6.56094)
 ** On entry to CGEMM  parameter number  1 had an illegal value

Valgrind output looks like

==4710== Memcheck, a memory error detector
==4710== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4710== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==4710== Command: ./o
==4710== Parent PID: 3337
==4710==
==4710== Conditional jump or move depends on uninitialised value(s)
==4710==    at 0x46E5096: lsame_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710==    by 0x46DD683: cgemm_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710==    by 0x8048C7E: mult(int, int, int, int) (Matrix_multiplication.cpp:83)
==4710==    by 0x8048D70: main (Matrix_multiplication.cpp:102)
==4710==  Uninitialised value was created by a stack allocation
==4710==    at 0x8048A18: mult(int, int, int, int) (Matrix_multiplication.cpp:43)
==4710==
==4710== Conditional jump or move depends on uninitialised value(s)
==4710==    at 0x46DD686: cgemm_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710==    by 0x8048C7E: mult(int, int, int, int) (Matrix_multiplication.cpp:83)
==4710==    by 0x8048D70: main (Matrix_multiplication.cpp:102)
==4710==  Uninitialised value was created by a stack allocation
==4710==    at 0x8048A18: mult(int, int, int, int) (Matrix_multiplication.cpp:43)
==4710==
==4710== Conditional jump or move depends on uninitialised value(s)
==4710==    at 0x46E5096: lsame_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710==    by 0x46DD7B1: cgemm_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710==    by 0x8048C7E: mult(int, int, int, int) (Matrix_multiplication.cpp:83)
==4710==    by 0x8048D70: main (Matrix_multiplication.cpp:102)
==4710==  Uninitialised value was created by a stack allocation
==4710==    at 0x8048A18: mult(int, int, int, int) (Matrix_multiplication.cpp:43)
==4710==
==4710== Conditional jump or move depends on uninitialised value(s)
==4710==    at 0x46DD7B4: cgemm_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710==    by 0x8048C7E: mult(int, int, int, int) (Matrix_multiplication.cpp:83)
==4710==    by 0x8048D70: main (Matrix_multiplication.cpp:102)
==4710==  Uninitialised value was created by a stack allocation
==4710==    at 0x8048A18: mult(int, int, int, int) (Matrix_multiplication.cpp:43)
==4710==
==4710== Conditional jump or move depends on uninitialised value(s)
==4710==    at 0x46E5096: lsame_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710==    by 0x46DD859: cgemm_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710==    by 0x8048C7E: mult(int, int, int, int) (Matrix_multiplication.cpp:83)
==4710==    by 0x8048D70: main (Matrix_multiplication.cpp:102)
==4710==  Uninitialised value was created by a stack allocation
==4710==    at 0x8048A18: mult(int, int, int, int) (Matrix_multiplication.cpp:43)
==4710==
==4710== Conditional jump or move depends on uninitialised value(s)
==4710==    at 0x46DD85C: cgemm_ (in /usr/lib/atlas-base/atlas/libblas.so.3.0)
==4710==    by 0x8048C7E: mult(int, int, int, int) (Matrix_multiplication.cpp:83)
==4710==    by 0x8048D70: main (Matrix_multiplication.cpp:102)
==4710==  Uninitialised value was created by a stack allocation
==4710==    at 0x8048A18: mult(int, int, int, int) (Matrix_multiplication.cpp:43)
==4710==
==4710==
==4710== HEAP SUMMARY:
==4710==     in use at exit: 120 bytes in 6 blocks
==4710==   total heap usage: 43 allocs, 37 frees, 13,897 bytes allocated
==4710==
==4710== LEAK SUMMARY:
==4710==    definitely lost: 0 bytes in 0 blocks
==4710==    indirectly lost: 0 bytes in 0 blocks
==4710==      possibly lost: 0 bytes in 0 blocks
==4710==    still reachable: 120 bytes in 6 blocks
==4710==         suppressed: 0 bytes in 0 blocks
==4710== Rerun with --leak-check=full to see details of leaked memory
==4710==
==4710== For counts of detected and suppressed errors, rerun with: -v
==4710== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0)

EDIT: The question was modified with a code that can be run. The problem remains the same and the nature of the question has not changed.

Upvotes: 1

Views: 503

Answers (2)

steabert
steabert

Reputation: 6878

The answer about the length of character variables in Fortran is essentially correct, but that is not your problem here. Fixed length character variables of functions inside the blas library will probably not read the length from a function argument. I checked this for a function and even at -O0 the length was a compile-time constant.

The cause of your particular problem is the definition c_float cgemm_(..., where you tell the compiler that cgemm_ returns a c_float. Normally, return values are put in a register, but when they are too large they can also go on the stack. In your case, on a 32bit system, this seems to be the case for the 8-byte c_float. Defining the function to be void cgemm_ (as it should be) or even int cgemm_ (which will use a register) solves the issue.

The take-home message is "don't do this", as this is a hackish way of calling and will cause headaches when dealing with different platforms/compilers. It is much better to use the cblas interface, or a C++ library for blas operations.

Upvotes: 1

MatCross
MatCross

Reputation: 389

I don't see the lengths of the transA or transB strings being passed to the xgemm_ call.

Character dummies in Fortran are accompanied by a 'hidden' length argument. The convention used by GCC 4.9.0, for example, for this is described more here:

https://gcc.gnu.org/onlinedocs/gcc-4.9.0/gfortran/Argument-passing-conventions.html.

The positioning of these hidden arguments in the argument list is platform dependent. On Linux they are placed after all the explicit arguments.

Consider s.f90

Subroutine s(c, r)
  Character (*), Intent (In) :: c
  Real, Intent (In) :: r
  Print '(3A,I0,A)', 'c = "', c, '", (len(c)=', len(c), ')'
  Print *, 'r = ', r
End Subroutine

and main.c

#include <string.h>
int main(void)
{
  char c[1+1];
  float r=4.2;
  strcpy(c,"A");
  s_(c,&r,1);
}

For running on Linux I am passing 1 as the (hidden in Fortran) third argument for s, representing the length of my string.

Compiling and running with gfortran gives me

> gfortran -g main.c s.f90 && ./a.out
c = "A", (len(c)=1)
 r =    4.19999981

So probably your xgemm_ calls should be ...,&LDC,1,1);?

Upvotes: 0

Related Questions