Call Matlab from Intel Fortran on Linux - linux

Editted:
This is building on my previous question.
With the answer, I am able to compile and run with gfortran however, I am still unable to run with ifort. The commands I am using to compile in tcsh are:
set PATH=${PATH}:${matlabroot}/bin/glnxa64/:${matlabroot}/bin
set LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${matlabroot}/bin/glnxa64/:${matlabroot}/sys/os/glnxa64/
${FC} ${matlabroot}/extern/examples/eng_mat/fengdemo.F -I${matlabroot}/extern/include/ -L${matlabroot}/bin/glnxa64/ -leng -lmx -cpp -o FEngDemo
Do I need to make changes to the libraries I use? To the Fortran code? Or to the Matlab code?
Any help would be appreciated.
The Fortran code is:
#include "fintrf.h"
C
#if 0
C
C fengdemo.F
C .F file need to be preprocessed to generate .for equivalent
C
#endif
C
C fengdemo.f
C
C This is a simple program that illustrates how to call the MATLAB
C Engine functions from a FORTRAN program.
C
C Copyright 1984-2011 The MathWorks, Inc.
C======================================================================
C
program main
C Declarations
implicit none
mwPointer engOpen, engGetVariable, mxCreateDoubleMatrix
mwPointer mxGetPr
mwPointer ep, T, D
double precision time(10), dist(10)
integer engPutVariable, engEvalString, engClose
integer temp, status
mwSize i
data time / 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 /
mwSize M, N
parameter(M=1)
parameter(N=10)
C
ep = engOpen('matlab ')
C
if (ep .eq. 0) then
write(6,*) 'Can''t start MATLAB engine'
stop
endif
C
T = mxCreateDoubleMatrix(M, N, 0)
call mxCopyReal8ToPtr(time, mxGetPr(T), N)
C
C
C Place the variable T into the MATLAB workspace
C
status = engPutVariable(ep, 'T', T)
C
if (status .ne. 0) then
write(6,*) 'engPutVariable failed'
stop
endif
C
C
C Evaluate a function of time, distance = (1/2)g.*t.^2
C (g is the acceleration due to gravity)
C
if (engEvalString(ep, 'D = .5.*(-9.8).*T.^2;') .ne. 0) then
write(6,*) 'engEvalString failed'
stop
endif
C
C
C Plot the result
C
if (engEvalString(ep, 'plot(T,D);') .ne. 0) then
write(6,*) 'engEvalString failed'
stop
endif
if (engEvalString(ep, 'title(''Position vs. Time'')') .ne. 0) then
write(6,*) 'engEvalString failed'
stop
endif
if (engEvalString(ep, 'xlabel(''Time (seconds)'')') .ne. 0) then
write(6,*) 'engEvalString failed'
stop
endif
if (engEvalString(ep, 'ylabel(''Position (meters)'')') .ne. 0)then
write(6,*) 'engEvalString failed'
stop
endif
C
C
C read from console to make sure that we pause long enough to be
C able to see the plot
C
print *, 'Type 0 <return> to Exit'
print *, 'Type 1 <return> to continue'
read(*,*) temp
C
if (temp.eq.0) then
print *, 'EXIT!'
status = engClose(ep)
if (status .ne. 0) then
write(6,*) 'engClose failed'
endif
stop
end if
C
if (engEvalString(ep, 'close;') .ne. 0) then
write(6,*) 'engEvalString failed'
stop
endif
C
D = engGetVariable(ep, 'D')
call mxCopyPtrToReal8(mxGetPr(D), dist, N)
print *, 'MATLAB computed the following distances:'
print *, ' time(s) distance(m)'
do 10 i=1,10
print 20, time(i), dist(i)
20 format(' ', G10.3, G10.3)
10 continue
C
C
call mxDestroyArray(T)
call mxDestroyArray(D)
status = engClose(ep)
C
if (status .ne. 0) then
write(6,*) 'engClose failed'
stop
endif
C
stop
end
With the -g and -traceback flags, the error I get at runtime is:
forrtl: severe (174): SIGSEGV, segmentation fault occurred
Image PC Routine Line Source
FEngDemo 0000000000477619 Unknown Unknown Unknown
FEngDemo 0000000000475EEE Unknown Unknown Unknown
FEngDemo 000000000044D8F2 Unknown Unknown Unknown
FEngDemo 0000000000431573 Unknown Unknown Unknown
FEngDemo 00000000004041FB Unknown Unknown Unknown
libpthread.so.0 0000003E1D80F790 Unknown Unknown Unknown
libmx.so 00007F5F077FCED7 Unknown Unknown Unknown
FEngDemo 00000000004032ED MAIN__ 46 fengdemo.F
FEngDemo 0000000000403186 Unknown Unknown Unknown
libc.so.6 0000003E1D01ED5D Unknown Unknown Unknown
FEngDemo 0000000000403009 Unknown Unknown Unknown

Related

Openmp: use of parallel do with omp_get_thread_num()

I'm splitting a do loop using parallel do and private clause. In this loop I add a variable to itself. Why do I get errors if I don't need a critical block or atomic statement in this case?
How can I fix it?
program trap
use omp_lib
implicit none
double precision::suma=0.d0 ! sum is a scalar
double precision:: h,x,lima,limb
integer::n,i, istart, iend, thread_num=4, total_threads, ppt
integer(kind=8):: tic, toc, rate
double precision:: time
double precision, dimension(4):: pi= 0.d0
call system_clock(count_rate = rate)
call system_clock(tic)
lima=0.0d0; limb=1.0d0; suma=0.0d0; n=100000000
h=(limb-lima)/n
suma=h*(f(lima)+f(limb))*0.5d0 !first and last points
ppt= n/total_threads
!$ call omp_set_num_threads(total_threads)
!$omp parallel do private (istart, iend, thread_num, i)
thread_num = omp_get_thread_num()
!$ istart = thread_num*ppt +1
!$ iend = min(thread_num*ppt + ppt, n)
do i=istart,iend ! this will control the loop in different threads
x=lima+i*h
suma=suma+f(x)
pi(thread_num+1)=suma
enddo
!$omp end parallel do
suma=sum(pi)
suma=suma*h
print *,"The value of pi is= ",suma ! print once from the first image
call system_clock(toc)
time = real(toc-tic)/real(rate)
print*, 'Time ', time, 's'
contains
double precision function f(y)
double precision:: y
f=4.0d0/(1.0d0+y*y)
end function f
end program trap
I get the following errors:
test.f90:23:35:
23 | thread_num = omp_get_thread_num()
Error: Unexpected assignment statement at (1)
test.f90:24:31:
24 | !$ istart = thread_num*ppt +1
Error: Unexpected assignment statement at (1)
test.f90:25:40:
25 | !$ iend = min(thread_num*ppt + ppt, n)
Error: Unexpected assignment statement at (1)
Compiled with:
gfortran -fopenmp -Wall -Wextra -O2 -Wall -o prog.exe test.f90
./prog.exe
I don't understand why you are manually splitting up the loop when the worksharing constructs in openmp, such as !$omp do, can do this automatically for you. Below is how I would do it
ian#eris:~/work/stack$ cat thread.f90
program trap
Use, Intrinsic :: iso_fortran_env, Only : wp => real64, li => int64
use omp_lib
implicit none
Real( wp ) ::suma=0.0_wp ! sum is a scalar
Real( wp ) :: h,x,lima,limb
integer(li):: tic, toc, rate
Real( wp ) :: time
Real( wp ) :: pi
Integer :: i, n
call system_clock(count_rate = rate)
call system_clock(tic)
lima=0.0_wp; limb=1.0_wp; suma=0.0_wp; n=100000000
h=(limb-lima)/n
suma=h*(f(lima)+f(limb))*0.5_wp !first and last points
pi = 0.0_wp
!$omp parallel default( None ) private( i, x, lima ) &
!$omp shared( pi, n, h )
!$omp do reduction( +:pi )
do i= 1, n
x = lima + i * h
pi = pi + f( x )
enddo
!$omp end do
!$omp end parallel
print *,"The value of pi is= ", pi / n
call system_clock(toc)
time = real(toc-tic)/real(rate)
print*, 'Time ', time, 's on ', omp_get_max_threads(), ' threads'
contains
function f(y)
Real( wp ) :: f
Real( wp ) :: y
f=4.0_wp/(1.0_wp+y*y)
end function f
end program trap
ian#eris:~/work/stack$ gfortran --version
GNU Fortran (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
ian#eris:~/work/stack$ export OMP_NUM_THREADS=1
ian#eris:~/work/stack$ ./a.out
The value of pi is= 3.1415926435902248
Time 1.8548842668533325 s on 1 threads
ian#eris:~/work/stack$ export OMP_NUM_THREADS=2
ian#eris:~/work/stack$ ./a.out
The value of pi is= 3.1415926435902120
Time 0.86763000488281250 s on 2 threads
ian#eris:~/work/stack$ export OMP_NUM_THREADS=4
ian#eris:~/work/stack$ ./a.out
The value of pi is= 3.1415926435898771
Time 0.54704123735427856 s on 4 threads
ian#eris:~/work/stack$
Instead of
!$omp parallel do private (istart, iend, thread_num, i)
thread_num = omp_get_thread_num()
!$ istart = thread_num*ppt +1
!$ iend = min(thread_num*ppt + ppt, n)
try the following:
!$omp parallel private (istart, iend, thread_num, i)
thread_num = omp_get_thread_num()
!$ istart = thread_num*ppt +1
!$ iend = min(thread_num*ppt + ppt, n)
....
!$omp end parallel

Printing members of parent type from an instance of an extended type

Scenario (see the code below): consider some Fortran module my_module which contains the definition of two derived types: test (parent) and sub_test (extends test, subclass). In addition to the two members a and b of the parent class, sub_test defines a new member c. Eventually, this module my_module is to used in some program my_program.
module my_module
implicit none
private
public :: test, sub_test
type :: test
integer :: a = 1
integer :: b = 2
end type test
type, extends(test) :: sub_test
integer :: c = 3
contains
procedure, public :: increment
end type sub_test
contains
subroutine increment (this)
class(sub_test) :: this
this % a = this % a + 1
write(*, *) "Incrementation complete!"
end subroutine increment
end module my_module
!---------------------------------------
program my_program
use my_module
implicit none
type(test) :: parent
type(sub_test) :: child
write(*, *) "Printing parent members"
write(*, *) parent % a, parent % b
write(*, *) "Printing child members"
write(*, *) child % a, child % b, child % c
call child % increment
end program my_program
Objective: When debugging, using gdb, we want to print the values of the parent members a and b of some variable of the child (extended) type sub_test. In sum, we're looking for a successful completion of something like:
(gdb) print child % a
yet, apparently, it is not that trivial.
Setup before trying to print:
Compile the program (here called test.f90) with the -g flag, convenient for the application of gdb with gfortran -g test.f90 -o a.out
Run the executable with gdb ./a.out
Insert a breakpoint a breakpoint in the last write(*, *) statement of the program and in the unique write(*, *) statement in subroutine increment and run the program
(gdb) break test.f90:41
Breakpoint 1 at 0xb12: file test.f90, line 41.
(gdb) break test.f90:24
Breakpoint 2 at 0x955: file test.f90, line 24.
(gdb) run
What I have (unsuccessfully) tried so far:
Print directly the members from the child variable (member c prints flawlessly)
Breakpoint 1, my_program () at test.f90:41
41 write(*, *) child % a, child % b, child % c
(gdb) p child%a
There is no member named a.
(gdb) p child%b
There is no member named b.
(gdb) p child%c
$1 = 3
Print the test (parent) member of the child variable, as gdb shows it exists
Print the so-wanted members from the test member of child
Breakpoint 1, my_program () at test.f90:41
41 write(*, *) child % a, child % b, child % c
(gdb) p child
$2 = ( test = ( a = 1, b = 2 ), c = 3 )
(gdb) p child%test
A syntax error in expression, near `test'.
(gdb) p child%test%a
A syntax error in expression, near `test%a'.
(gdb) p child%test%b
A syntax error in expression, near `test%b'.
The same steps above, but this time applied at the breakpoint inside the subroutine, therefore, trying to print the members of the dummy variable this. In this case, gdb clearly changes the pitch regarding the variable and, for instance, c can only be accessed through the hidden member _dat, yet a and b continue unreachable.
Breakpoint 2, my_module::increment (this=...) at test.f90:24
24 write(*, *) "Incrementation complete!"
(gdb) p this
$3 = ( _data = 0x555555756018 <child>, _vptr = 0x555555755d20 <__my_module_MOD___vtab_my_module_Sub_test> )
(gdb) p this%_data
$4 = (PTR TO -> ( Type sub_test )) 0x555555756018 <child>
(gdb) p this%_data%a
There is no member named a.
(gdb) p this%_data%b
There is no member named b.
(gdb) p this%_data%c
$5 = 3
(gdb) p this%_data%test%a
A syntax error in expression, near `test%a'.
(gdb) p this%_data%test%b
A syntax error in expression, near `test%b'.
Thank you for reading: I feel like reaching a dead-end in this regards, I deeply hope someone could lend me a hand. gdb seems incredible but, without being able to inspect this information, I sadly fear it won't suit my needs properly.
More information: I am using gdb-9.2 and gfortran 7.5.0.

No speedup with OpenMP when using Matlab MEX in Linux

I'm using OpenMP to speed up Fortran code in a Matlab MEX-file. However, I find that OpenMP seems not work on Linux, but actually works on Windows. I attach the code as follows:
1) Matlab Mex file:
clc; clear all; close all; tic
FLAG_SYS = 0; % 0 for Windows; 1 for Linux
%--------------------------------------------------------------------------
% Mex Fortran code
%--------------------------------------------------------------------------
if FLAG_SYS == 0
mex COMPFLAGS="-Qopenmp $COMPFLAGS"...
LINKFLAGS="/Qopenmp $LINKFLAGS"...
OPTIMFLAGS="/Qopenmp $OPTIMFLAGS"...
'-IC:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2017.5.267\windows\mkl\include'...
'-LC:\Program Files (x86)\IntelSWTools\compilers_and_libraries_2017.5.267\windows\mkl\lib\intel64'...
-lmkl_intel_ilp64.lib -lmkl_intel_thread.lib -lmkl_core.lib libiomp5md.lib...
Test_OpenMP_Mex.f90...
-output Test_OpenMP_Mex
elseif FLAG_SYS == 1
mex COMPFLAGS="-fopenmp $COMPFLAGS"...
LINKFLAGS="-fopenmp $LINKFLAGS"...
FFLAGS='$FFLAGS -fdec-math -cpp' ...
'-I${MKLROOT}/include'...
'-L${MKLROOT}/lib'...
-lmkl_avx2 -lmkl_gf_ilp64 -lmkl_core -lmkl_intel_thread -liomp5 -lpthread -lm -ldl...
Test_OpenMP_Mex.f90...
-output Test_OpenMP_Mex
end
Test_OpenMP_Mex;
2) Fortran code
#include "fintrf.h"
!GATEWAY ROUTINE
SUBROUTINE MEXFUNCTION(NLHS, PLHS, NRHS, PRHS)
!DECLARATIONS
IMPLICIT NONE
!MEXFUNCTION ARGUMENTS:
MWPOINTER PLHS(*), PRHS(*)
INTEGER NLHS, NRHS
!FUNCTION DECLARATIONS:
MWPOINTER MXCREATEDOUBLEMATRIX
MWPOINTER MXGETM, MXGETN
INTEGER MXISNUMERIC
!POINTERS TO INPUT MXARRAYS:
MWPOINTER MIV1, MIV2
!POINTERS TO OUTPUT MXARRAYS:
MWPOINTER MOV1, MOV2
!CALL FORTRAN CODE
CALL TEST_OPENMP
RETURN
END
!-----------------------------------------------------------------------
SUBROUTINE TEST_OPENMP
USE OMP_LIB
IMPLICIT NONE
INTEGER I, J, K, STEP
REAL*8 STARTTIME, ENDTIME,Y
OPEN(1,FILE='1.TXT')
!COUNT ELAPSED TIME START
STARTTIME = OMP_GET_WTIME()
DO I = 1,1000000
DO J = 1,50000
DO K = 1,1000
Y=(I+10)*J-SQRT(789.1)+SQRT(789.1)-(I+10)*J
END DO
END DO
END DO
ENDTIME = OMP_GET_WTIME()
WRITE(1,*) ENDTIME-STARTTIME
!COUNT ELAPSED TIME START
STARTTIME = OMP_GET_WTIME()
!$OMP PARALLEL
!$OMP DO PRIVATE(I,J)
DO I = 1,1000000
DO J = 1,50000
DO K = 1,1000
Y=(I+10)*J-SQRT(789.1)+SQRT(789.1)-(I+10)*J
END DO
END DO
END DO
!$OMP END DO
!$OMP END PARALLEL
ENDTIME = OMP_GET_WTIME()
WRITE(1,*) ENDTIME-STARTTIME
!$OMP PARALLEL
! GET THE NUMBER OF THREADS
WRITE(1,*) OMP_GET_THREAD_NUM(), OMP_GET_NUM_THREADS()
!$OMP END PARALLEL
CLOSE(1)
RETURN
END SUBROUTINE TEST_OPENMP
The output on Windows is:
1.09620520001044
4.50355500000296
0 6
1 6
3 6
5 6
2 6
4 6
and the output on Linux is:
0.0000
0.0000
0 1
It's obvious that OpenMP works on Windows, since the calculation time reduces from 4.5s to 1.0s. I can find that there are 6 threads being used for calculation. However, on Linux, no calculation seems to be executed, and there are only 2 threads (the number of threads on Linux is 36, but only 2 of them are used).
Any suggestions are welcome!
You can directly download code from this link:
https://www.dropbox.com/sh/crkuwhu22407sjs/AAAQrtzAvTmFOmAxv_jpTCBaa?dl=0
When compiling MEX-files under Linux (and MacOS) the COMPFLAGS variable is ignored. It is a Windows-specific environment variable. You need to use CFLAGS for C, CXXFLAGS for C++, or FFLAGS for Fortran, and LDFLAGS for the linker. These are the standard Unix environment variables to control compilation.
Your compile command will look like this:
mex LDFLAGS='-fopenmp $LDFLAGS'...
FFLAGS='-fopenmp -fdec-math -cpp $FFLAGS' ...
'-I${MKLROOT}/include'...
'-L${MKLROOT}/lib'...
-lmkl_avx2 -lmkl_gf_ilp64 -lmkl_core -lmkl_intel_thread -liomp5 -lpthread -lm -ldl...
Test_OpenMP_Mex.f90...
-output Test_OpenMP_Mex
Reference:
MATLAB documentation
GCC environment variables
There is one note you shouldn't miss when lining against intel mkl ilp64 versions of libs:
you need to add -I4 compiler option, otherwise, you may see some kind of an unexpected segfault... Please refer to the mkl linker adviser to see more details: https://software.intel.com/content/www/us/en/develop/articles/intel-mkl-link-line-advisor.html

get assert() failure message in android ndk sigaction crash handler

I am using sigaction() to install a crash handler in my app and print private version information.
In case of a failed assert() the abort message is super useful and I'd like my sigaction handler to print it. How can I get that string? Below is some analysis I've done thus far:
I noticed in ndk debuggerd/tombstone.c engrave_tombstone() that there is a argument uintptr_t abort_msg_address which contains the abort message, typically a failed assert. But no clue where that is fetched from. Noticing the default crash logs of android seem to run in a different process and debuggerd imples it's a daemon, I am not sure this is the right way to go.
I furthermore see in bionic libc/stdlib/assert.c there is just a call to __libc_android_log_print(ANDROID_LOG_FATAL, ...). Also not very helpful. But in bionic linker_main.cpp there is abort_msg_t* g_abort_message = nullptr; and other exciting stuff in android_set_abort_message.cpp. Again, not sure this is the right way, feels very hackish.
This is what the crash handler of android prints by default. Note how the first message in in the crashed pid/tid, but the others are some other random process (presumably, debuggerd?).
10-09 16:49:28.551 12084 12127 F libc : Fatal signal 6 (SIGABRT), code -6 (SI_TKILL) in tid 12127 (applyRouting), pid 12084 (com.android.nfc)
10-09 16:49:28.691 12203 12203 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
10-09 16:49:28.692 12203 12203 F DEBUG : Build fingerprint: 'Android/aosp_marlin/marlin:Q/OC-MR1/summit07191458:userdebug/test-keys'
10-09 16:49:28.692 12203 12203 F DEBUG : Revision: '0'
10-09 16:49:28.692 12203 12203 F DEBUG : ABI: 'arm64'
10-09 16:49:28.692 12203 12203 F DEBUG : pid: 12084, tid: 12127, name: applyRouting >>> com.android.nfc <<<
10-09 16:49:28.692 12203 12203 F DEBUG : signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
10-09 16:49:28.692 12203 12203 F DEBUG : Abort message: 'jni_internal.cc:622] JNI FatalError called: applyRouting'
10-09 16:49:28.692 12203 12203 F DEBUG : x0 0000000000000000 x1 0000000000002f5f x2 0000000000000006 x3 0000000000000008

Compile error: ` fatal error: gfc_todo: `

When I compile my code with
gfortran -O2 calpuff.for -o calpuff.exe
The following code:
REAL FUNCTION R1MACH (I)
C***BEGIN PROLOGUE R1MACH
C ...
real SMALL(2)
real LARGE(2)
real RIGHT(2)
real DIVER(2)
real LOG10(2)
c --- Set up for IBM PC: declare as reals ..........(DGS)
C
REAL RMACH(5)
SAVE RMACH
C
EQUIVALENCE (RMACH(1),SMALL(1))
EQUIVALENCE (RMACH(2),LARGE(1))
EQUIVALENCE (RMACH(3),RIGHT(1))
EQUIVALENCE (RMACH(4),DIVER(1))
EQUIVALENCE (RMACH(5),LOG10(1))
C ...
DATA SMALL(1) / 1.18E-38 /
DATA LARGE(1) / 3.40E+38 /
DATA RIGHT(1) / 0.595E-07 /
DATA DIVER(1) / 1.19E-07 /
DATA LOG10(1) / 0.30102999566 /
C ...
C***FIRST EXECUTABLE STATEMENT R1MACH
IF (I .LT. 1 .OR. I .GT. 5) CALL XERMSG ('SLATEC', 'R1MACH',
+ 'I OUT OF BOUNDS', 1, 2)
C
R1MACH = RMACH(I)
RETURN
C
END
Result shows in the following error:
calpuff.for: In function ‘r1mach’:
calpuff.for:58522: fatal error: gfc_todo: Not Implemented: Initialization of overlapping variables
compilation terminated.
Line 58522 corresponds to the first line of the code shown.
Why does this error occur?
Some information about my compiler: gcc version 4.1.2 20080704 (Red Hat 4.1.2-54)
This is a known compiler bug in gfortran, see here and here. This bug has been fixed in 2007.
Please update to a more recent version of gfortran.

Resources