【问题标题】:Problems with memory access/allocation when using LAPACK DSYEVR. Code used is FORTRAN使用 LAPACK DSYEVR 时的内存访问/分配问题。使用的代码是 FORTRAN
【发布时间】:2014-09-29 16:09:44
【问题描述】:

我一直在 FORTRAN 中编写代码,但在使用 lapack dsyevr 时遇到问题:

http://netlib.sandia.gov/lapack/double/dsyevr.f

我遇到的问题似乎与内存分配问题有关,特别是我认为与 dsyevr 生成的输出数组有关(包括作为输入和输出的 A)。

我尝试编写一个简化的代码来演示我遇到的问题。请让我知道是否需要澄清。代码名称为prof1.f90,调用dsyevr函数:

PROGRAM prog1

implicit none

real(kind=8), allocatable :: W(:) 
real(kind=8), allocatable :: Z(:,:) 
real(kind=8), allocatable :: A(:,:)
integer(kind=8) :: n, info, il, iu, m, lwork, liwork
integer(kind=8) :: i, k, p, q, nu
real(kind=8) :: abstol, vl, vu
real(kind=8), allocatable :: work(:)
integer, allocatable :: isuppz(:), iwork(:)

n = 3

allocate(W(3),Z(3,3),A(n,n),stat=info)
if (info .ne. 0) stop "error allocating arrays"

A(1,1)=3.78136524999999994E-003
A(1,2)=0.0000000000000000
A(1,3)=-7.92918150000000038E-004
A(2,1)=0.0000000000000000
A(2,2)=5.20293929999999984E-003
A(2,3)=0.0000000000000000
A(3,1)=-7.92918150000000038E-004
A(3,2)=0.0000000000000000
A(3,3)=3.78136524999999994E-003
vl = 1.06451084056294826E-313
vu = 0.0
il = 4294967297
iu = 8839891
m = 140733655445712
W(1) = 2.98844710000000001E-003  
W(2) = 4.57428340000000030E-003  
W(3) = 5.20293929999999984E-003
Z(1,1) = 8.65587596665713699E-317  
Z(1,2) = 8.65587596665713699E-317
Z(1,3) = 1.58101006669198894E-322  
Z(2,1) = 1.58101006669198894E-322   
Z(2,2) = 0.0000000000000000
Z(2,3) = 8.65569415049946741E-317  
Z(3,1) = 4.24400777097956191E-314  
Z(3,2) = 4.79243676466009148E-322
Z(3,3) = 3.51391740150311405E-316
lwork = -1
liwork = -1
abstol = 1d-5

allocate(work(1),iwork(1),isuppz(6))

call dsyevr('V','A','U',n,A,n,vl,vu,il,iu,abstol,m,W,Z,n,isuppz,work,lwork,iwork,liwork,info)
if (info .ne. 0) stop "error obtaining work array dimensions"

lwork = work(1)
liwork = iwork(1)
deallocate(work,iwork)
allocate(work(lwork),iwork(liwork),stat=info)

if (info .ne. 0) stop "error allocating work arrays"

call dsyevr('V','A','U',n,A,n,vl,vu,il,iu,abstol,m,W,Z,n,isuppz,work,lwork,iwork,liwork,info)
if (info .ne. 0) stop "error diagonalizing the hamiltonian"

deallocate(A,work,iwork,isuppz)

END PROGRAM prog1

在上面的代码中,dsyevr 函数被调用了两次,第一次只是为了获取工作的尺寸等...矩阵正确运行但是第二次调用它时返回以下错误

*** glibc detected *** ./PROGRAM: munmap_chunk(): invalid pointer: 0x000000000134cc20 ***

我还可以提供一个 Backtrace 和 MemoryMap。

如果有用的话,我一直在使用的 makefile 如下所示。该程序是使用以下行创建的:

make PROGRAM

生成文件:

FC = gfortran
FCFLAGS = -g -fbounds-check
FCFLAGS = -O2
FCFLAGS += -I/usr/include

%: %.o
    $(FC) $(FCFLAGS) -o $@ $^ $(LDFLAGS)

%.o: %.f90
    $(FC) $(FCFLAGS) -c $< -fno-range-check

%.o: %.F90
    $(FC) $(FCFLAGS) -c $<

.PHONY: clean veryclean

PROGRAM:        prog1.f90 prog1.o
    $(FC) $(FCFLAGS) -o $@ prog1.o $(LIBS)  -Wl,--start-group -L$(MKLROOT)/lib/intel64 -lmkl_gf_ilp64 -lmkl_core -lmkl_sequential -Wl,--end-group -lpthread


clean:
    rm -f *.o *.mod *.MOD

veryclean: clean
    rm -f *~ $(PROGRAM)

其中 $MKLROOT 是 /opt/intel/composer_xe_2011_sp1.8.273/mkl

如果有用的话我用过valgrind:

 valgrind --tool=memcheck --db-attach=yes ./PROGRAM

我发现了以下错误:

==31069== 
==31069== Invalid write of size 8
==31069==    at 0x57B9F92: mkl_lapack_dsyevr (in /opt/intel/composer_xe_2011_sp1.8.273    /mkl/lib/intel64/libmkl_core.so)
==31069==    by 0x4D9A580: DSYEVR (in /opt/intel/composer_xe_2011_sp1.8.273/mkl/lib    /intel64/libmkl_gf_ilp64.so)
==31069==    by 0x401163: MAIN__ (in /home/j/workbook/Test4/PROGRAM)
==31069==    by 0x401F09: main (in /home/j/workbook/Test4/PROGRAM)
==31069==  Address 0x6afe0b0 is 0 bytes inside a block of size 4 alloc'd
==31069==    at 0x4A069EE: malloc (vg_replace_malloc.c:270)
==31069==    by 0x400FE4: MAIN__ (in /home/j/workbook/Test4/PROGRAM)
==31069==    by 0x401F09: main (in /home/j/workbook/Test4/PROGRAM)
==31069== 

我不确定“Invalid write of size 8”是指某些整数或实数的大小(如 Jonathan Dursi 所述),还是指传递给 dsyevr 的数组的大小。

【问题讨论】:

  • Invalid write of size 8 表示写入 8 个字节的单个元素。它可以是整数或实数。
  • 我尝试将所有参数设置为 kind=4,但是当我这样做时,我收到一条错误消息:“MKL 错误:进入 DSYEVR 时参数 20 不正确”
  • 难怪你用lp64 MKL,整数必须是8字节。
  • 所以 MKL 要求所有 (?) 整数为 8 字节。但是 gfortran 编译器要求整数很长,即 4 字节(如 Jonathan Dursi 所述)。这是一个正确的。有没有办法解决这个问题?
  • 当然,使用 8 字节类型的整数。

标签: memory fortran lapack


【解决方案1】:

这在文档中并不明显,但必须分配 isuppz,即使对于 lwork = -1 的初始调用也是如此。如果您将 isuppz 分配移到第一次调用之前,您的代码将成功完成。

之后,由于您使用的是 MKL 的 ILP(8 字节整数)版本,例如具有 8 字节整数索引的 LAPACK,所有 LAPACK 例程的整数参数必须是相同的长类型,因此您需要

integer(kind=8), allocatable :: isuppz(:), iwork(:)

我会注意到,对于这两者和整数,kind=8 实际上是标准的一部分,您应该真正使用 selected_int/real_kind 或 iso_fortran_env 模块和 int64 等。

【讨论】:

  • 非常感谢您的帮助。我已经做出了这个更正(并更新了我的问题),但不幸的是我仍然看到同样的错误。
  • 我无法重现您现在遇到的错误 - 适用于我的 gfortran(或 ifort)+ MKL。
  • 这很奇怪,使用与我现在的问题完全相同的代码和makefile吗?你介意告诉我你的 $MKLROOT 是否和我的一样吗? (我自己也看到过这个函数在 ifort 上工作,但是它正在尝试用 gfortran 编译它,以便可以用一堆我认为不会在 ifort 上快速编译的其他代码编译它)
  • 还有一个问题(奇怪的是,ifort 没有表现出来?)——所有整数都必须是长整数。
  • 我将 valgrind 的一些输出添加到我的问题中,可能与此相关
猜你喜欢
  • 2015-03-27
  • 1970-01-01
  • 2021-01-23
  • 2016-05-18
  • 1970-01-01
  • 1970-01-01
  • 2012-04-18
  • 1970-01-01
  • 2011-06-27
相关资源
最近更新 更多