调用 lapacke hesv 例程后释放 MKL 指针时出现分段错误
Segmentation fault when free MKL pointer after called lapacke hesv routine
我正在开发代码以使用 C 语言的 lapacke 接口来反转矩阵。我使用了 intel mkl 库来完成这样的工作。然而,当我尝试简单的测试来反转可变大小 N 的矩阵时,当我释放矩阵的指针时,我得到了一个未定义的行为。奇怪的是,如果 N = 3 但停止使用 N >= 4 它会起作用,例如,如果我不释放指针,则代码 运行s 完全适用于 N 的任何值。该函数需要的其他指针我可以毫无困难地自由。有什么想法吗?
附加信息:我正在使用可以求解多个线性系统的 zhesv 函数。 API 可在以下位置找到:https://software.intel.com/en-us/node/520994
我正在尝试的代码 运行:
/*
* compile with intel mkl installation:
*
* gcc -o test exe/lapack_inversion_test.c -L${MKLROOT}/lib/intel64 -Wl,--no-as- needed -lmkl_intel_ilp64 -lmkl_gnu_thread -lmkl_core -lgomp -lm -ldl
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <mkl.h>
#include <math.h>
#define PI 3.141592653589793 // to define matrix entries
#define LAPACK_ROW_MAJOR 101
#define LAPACK_COL_MAJOR 102
int main(int argc, char * argv[])
{
int j, // counter
i, // counter
N, // The size of the Matrix
k;
double arg;
sscanf(argv[1], "%d", &N);
int * ipiv = (int *) malloc(N * sizeof(int));
MKL_Complex16 x; x.real = 0; x.imag = 0;
MKL_Complex16 * A = malloc(N * N * sizeof(MKL_Complex16));
MKL_Complex16 * Acopy = malloc(N * N * sizeof(MKL_Complex16));
MKL_Complex16 * Id = malloc(N * N * sizeof(MKL_Complex16));
for (i = 0; i < N; i++)
{ // Row major storage
A[i * N + i].real = 1.5 + sin( 3 * PI * i / N );
A[i * N + i].imag = 0;
Acopy[i * N + i].real = 1.5 + sin( 3 * PI * i / N );
Acopy[i * N + i].imag = 0;
Id[i * N + i].real = 1;
Id[i * N + i].imag = 0;
for (j = 0; j < i; j++)
{
arg = 10 * PI * ((double) i * j) / (N * N);
A[i * N + j].real = 2 * sin(arg) + 2;
A[i * N + j].imag = 3 * cos(arg);
A[j * N + i].real = 0; // Does not matter the upper tirangular
A[j * N + i].imag = 0; // when call lapack routine with 'L'
Acopy[i * N + j].real = 2 * sin(arg) + 2;
Acopy[i * N + j].imag = 3 * cos(arg);
Acopy[j * N + i].real = Acopy[i * N + j].real;
Acopy[j * N + i].imag = - Acopy[i * N + j].imag;
Id[i * N + j].real = 0; // Identity
Id[i * N + j].imag = 0;
Id[j * N + i].real = 0;
Id[j * N + i].imag = 0;
}
}
i = LAPACKE_zhesv(LAPACK_ROW_MAJOR, 'L', N, N, A, N, ipiv, Id, N);
printf("\n\nLapacke returned : %d\n", i);
printf("\n\nIf there was any problem print identity: \n");
for (i = 0; i < N; i++)
{
printf("\n\t|");
for (j = 0; j < N; j++)
{
x.real = 0;
x.imag = 0;
for (k = 0; k < N; k++)
{
x.real += Id[i*N + k].real * Acopy[k*N + j].real;
x.real -= Id[i*N + k].imag * Acopy[k*N + j].imag;
x.imag += Id[i*N + k].real * Acopy[k*N + j].imag;
x.imag += Id[i*N + k].imag * Acopy[k*N + j].real;
}
printf(" (%6.3lf,%6.3lf) |", x.real, x.imag);
}
}
// free(A); if one try to free does not work with N >= 4 !!!!
free(Id);
free(ipiv);
printf("\n\n");
return 0;
}
如果我们让代码自由 (A)(取消注释)它会:
$./测试 3
拉帕克返回:0
如果打印身份有任何问题:
| ( 1.000,-0.000) | ( 0.000,-0.000) | (-0.000,-0.000) |
| ( 0.000, 0.000) | ( 1.000, 0.000) | ( 0.000, 0.000) |
| (-0.000,-0.000) | (-0.000, 0.000) | ( 1.000, 0.000) |
$./测试 4
拉帕克返回:0
如果打印身份有任何问题:
| ( 1.000,-0.000) | ( 0.000,-0.000) | ( 0.000, 0.000) | (-0.000, 0.000) |
| (-0.000, 0.000) | ( 1.000, 0.000) | ( 0.000, 0.000) | (-0.000, 0.000) |
| (-0.000, 0.000) | (-0.000, 0.000) | ( 1.000,-0.000) | (-0.000,-0.000) |
分段错误(核心已转储)
让我们看一下LAPACKE_zhesv
的声明:
lapack_int LAPACKE_zhesv(int matrix_layout, char uplo, lapack_int n, lapack_int nrhs, lapack_complex_double* a, lapack_int lda, lapack_int* ipiv, lapack_complex_double* b , lapack_int ldb);
具体来说,它想要lapack_int* ipiv
,但你声明它是int* ipiv
。然后你 link 你的程序 mkl_intel_ilp64
和 do not define MKL_ILP64
。您的程序和 MKL 最终使用不兼容的整数类型:sizeof(int) = 4
,而 sizeof(lapack_int) = 8
.
快速修复是 link 和 mkl_intel_lp64
。但是您应该重写您的代码以使用 lapack_int
而不是 int
,然后它将与 LP64
和 ILP64
.
一起正常工作
我正在开发代码以使用 C 语言的 lapacke 接口来反转矩阵。我使用了 intel mkl 库来完成这样的工作。然而,当我尝试简单的测试来反转可变大小 N 的矩阵时,当我释放矩阵的指针时,我得到了一个未定义的行为。奇怪的是,如果 N = 3 但停止使用 N >= 4 它会起作用,例如,如果我不释放指针,则代码 运行s 完全适用于 N 的任何值。该函数需要的其他指针我可以毫无困难地自由。有什么想法吗?
附加信息:我正在使用可以求解多个线性系统的 zhesv 函数。 API 可在以下位置找到:https://software.intel.com/en-us/node/520994
我正在尝试的代码 运行:
/*
* compile with intel mkl installation:
*
* gcc -o test exe/lapack_inversion_test.c -L${MKLROOT}/lib/intel64 -Wl,--no-as- needed -lmkl_intel_ilp64 -lmkl_gnu_thread -lmkl_core -lgomp -lm -ldl
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <mkl.h>
#include <math.h>
#define PI 3.141592653589793 // to define matrix entries
#define LAPACK_ROW_MAJOR 101
#define LAPACK_COL_MAJOR 102
int main(int argc, char * argv[])
{
int j, // counter
i, // counter
N, // The size of the Matrix
k;
double arg;
sscanf(argv[1], "%d", &N);
int * ipiv = (int *) malloc(N * sizeof(int));
MKL_Complex16 x; x.real = 0; x.imag = 0;
MKL_Complex16 * A = malloc(N * N * sizeof(MKL_Complex16));
MKL_Complex16 * Acopy = malloc(N * N * sizeof(MKL_Complex16));
MKL_Complex16 * Id = malloc(N * N * sizeof(MKL_Complex16));
for (i = 0; i < N; i++)
{ // Row major storage
A[i * N + i].real = 1.5 + sin( 3 * PI * i / N );
A[i * N + i].imag = 0;
Acopy[i * N + i].real = 1.5 + sin( 3 * PI * i / N );
Acopy[i * N + i].imag = 0;
Id[i * N + i].real = 1;
Id[i * N + i].imag = 0;
for (j = 0; j < i; j++)
{
arg = 10 * PI * ((double) i * j) / (N * N);
A[i * N + j].real = 2 * sin(arg) + 2;
A[i * N + j].imag = 3 * cos(arg);
A[j * N + i].real = 0; // Does not matter the upper tirangular
A[j * N + i].imag = 0; // when call lapack routine with 'L'
Acopy[i * N + j].real = 2 * sin(arg) + 2;
Acopy[i * N + j].imag = 3 * cos(arg);
Acopy[j * N + i].real = Acopy[i * N + j].real;
Acopy[j * N + i].imag = - Acopy[i * N + j].imag;
Id[i * N + j].real = 0; // Identity
Id[i * N + j].imag = 0;
Id[j * N + i].real = 0;
Id[j * N + i].imag = 0;
}
}
i = LAPACKE_zhesv(LAPACK_ROW_MAJOR, 'L', N, N, A, N, ipiv, Id, N);
printf("\n\nLapacke returned : %d\n", i);
printf("\n\nIf there was any problem print identity: \n");
for (i = 0; i < N; i++)
{
printf("\n\t|");
for (j = 0; j < N; j++)
{
x.real = 0;
x.imag = 0;
for (k = 0; k < N; k++)
{
x.real += Id[i*N + k].real * Acopy[k*N + j].real;
x.real -= Id[i*N + k].imag * Acopy[k*N + j].imag;
x.imag += Id[i*N + k].real * Acopy[k*N + j].imag;
x.imag += Id[i*N + k].imag * Acopy[k*N + j].real;
}
printf(" (%6.3lf,%6.3lf) |", x.real, x.imag);
}
}
// free(A); if one try to free does not work with N >= 4 !!!!
free(Id);
free(ipiv);
printf("\n\n");
return 0;
}
如果我们让代码自由 (A)(取消注释)它会:
$./测试 3
拉帕克返回:0
如果打印身份有任何问题:
| ( 1.000,-0.000) | ( 0.000,-0.000) | (-0.000,-0.000) |
| ( 0.000, 0.000) | ( 1.000, 0.000) | ( 0.000, 0.000) |
| (-0.000,-0.000) | (-0.000, 0.000) | ( 1.000, 0.000) |
$./测试 4
拉帕克返回:0
如果打印身份有任何问题:
| ( 1.000,-0.000) | ( 0.000,-0.000) | ( 0.000, 0.000) | (-0.000, 0.000) |
| (-0.000, 0.000) | ( 1.000, 0.000) | ( 0.000, 0.000) | (-0.000, 0.000) |
| (-0.000, 0.000) | (-0.000, 0.000) | ( 1.000,-0.000) | (-0.000,-0.000) |
分段错误(核心已转储)
让我们看一下LAPACKE_zhesv
的声明:
lapack_int LAPACKE_zhesv(int matrix_layout, char uplo, lapack_int n, lapack_int nrhs, lapack_complex_double* a, lapack_int lda, lapack_int* ipiv, lapack_complex_double* b , lapack_int ldb);
具体来说,它想要lapack_int* ipiv
,但你声明它是int* ipiv
。然后你 link 你的程序 mkl_intel_ilp64
和 do not define MKL_ILP64
。您的程序和 MKL 最终使用不兼容的整数类型:sizeof(int) = 4
,而 sizeof(lapack_int) = 8
.
快速修复是 link 和 mkl_intel_lp64
。但是您应该重写您的代码以使用 lapack_int
而不是 int
,然后它将与 LP64
和 ILP64
.