Сложные функции BLAS уровня 3, выдающие недопустимую ошибку значения

0

Я пишу функцию, которая вызывает функции Фортрана для умножения матричной матрицы. Я вызываю функции CGEMM_ и ZGEMM_ для комплексного умножения. Поскольку все функции xGEMM_ по существу одинаковы, я скопировал код из SGEMM_ в CGEMM__ и ZGEMM_. Единственным изменением были соответствующие типы данных. Функции SGEMM_ и DGEMM_ работают нормально, но CGEMM_ выдает ошибку. Все входы одинаковы.

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

и zgemm_ бросает

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

Я действительно не знаю, что происходит. Это какая-то ошибка в пакете liblapack? Я использую пакет liblapack-dev. Я сделал небольшую версию моего большого кода, и я все еще получаю ту же ошибку с CGEMM_.

Я запускаю 32-битную систему и задавался вопросом, была ли эта проблема.

Код:

#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);
}

Отчет о выходе и valgrind выглядит следующим образом:

-----------------------------------------
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: вопрос был изменен с помощью кода, который можно запустить. Проблема остается прежней, и характер вопроса не изменился.

  • 1
    Вы можете добавить полный пример, который можно скомпилировать. Также покажи, кого ты компилируешь и связываешь, это интерфейс cblas?
  • 0
    Я сделал уменьшенную версию своей программы, и ее можно найти здесь . Теперь я получаю ошибки valgrind, говорящие о том, что у меня есть неинициализированные значения, и я уверен, что я все инициализировал - ', и я компилирую так g ++ -g -o объектный файл.cpp -lgblas -llapack -lgfortran
Показать ещё 3 комментария
Теги:
fortran
lapack
blas

2 ответа

1

Ответ на длину символьных переменных в Fortran, по сути, правильный, но это не ваша проблема. Символьные переменные фиксированной длины функций внутри библиотеки blas, вероятно, не будут считывать длину из аргумента функции. Я проверил это для функции, и даже в -O0 длина была константой времени компиляции.

Причиной вашей конкретной проблемы является определение c_float cgemm_(..., где вы сообщаете компилятору, что cgemm_ возвращает c_float. Обычно возвращаемые значения помещаются в регистр, но когда они слишком велики, они также могут идти в стек В вашем случае в 32-битной системе это похоже на 8-байтный c_float. Определение функции, которая должна быть void cgemm_ (как и должно быть), или даже int cgemm_ (которая будет использовать регистр) решает проблему,

Сообщение о возврате - "не делай этого", так как это хакерский способ вызова и вызовет головные боли при работе с разными платформами/компиляторами. Гораздо лучше использовать интерфейс cblas или библиотеку C++ для операций blas.

  • 0
    Спасибо за ответ. Это на самом деле имеет большой смысл
0

Я не вижу длины transB строк transA или transB на вызов xgemm_.

Character манекены в Фортране сопровождаются аргументом "скрытой" длины. Соглашение, используемое GCC 4.9.0, например, для этого описано здесь более подробно:

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

Позиционирование этих скрытых аргументов в списке аргументов зависит от платформы. В Linux они размещаются после всех явных аргументов.

Рассмотрим 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

и main.c

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

Для работы в Linux я передаю 1 как третий (для скрытого в Fortran) аргумент для s, представляющий длину моей строки.

Компиляция и работа с gfortran дает мне

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

Поэтому, вероятно, ваши вызовы xgemm_ должны быть ...,&LDC,1,1); ?

Ещё вопросы

Сообщество Overcoder
Наверх
Меню