Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.

Intel Visual Fortran code works in Debug mode but gets stuck in infinite loop in Release mode

Singh__Amit
Beginner
1,249 Views

Hi all. I have a C++ code that calls a Fortran subroutine which internally makes a call to the Fortran function dpmeps().  I use CMake to compile the Fortran code into a library that I link to my C++ executables. (CMakelist.txt files are attached). My code compiles without errors in both Debug and Release configurations. But it works as expected only in Debug configuration. In Release configuration it gets stuck in an infinite loop in the Fortran function dpmeps() (code files attached) at the code-block after label 10. I suspect that compiler optimization flags are somehow responsible for this. Any ideas how to fix this? <!--break-->

I have Visual Studio Community edition with Intel Parallel Studio XE 2017 with latest Intel C++ and Intel Visual Fortran compilers. This code is part of a bigger project which compiles and runs fine and quick with GCC compilers on Linux. We want the project to be portable to Windows and hence I am trying to get it working with Intel Compilers as well. Although with the Debug configuration flags the code works, it is much slower than GCC so it is not acceptable. Since, I have Intel i7 Skylake processors I was hoping Intel compilers to give a faster performance than GCC.

Please let me know if you need any more information. I have attached the Visual Studio Solution and project files in ZIP as well.

Regards,
Amit

0 Kudos
1 Solution
mecej4
Honored Contributor III
1,248 Views

The code DPMEPS(), and many others from the 1970s and 1980s, perform tricks to determine the machine epsilon. As compiler optimizations improve, these tricks will be defeated one by one.

To protect yourself from unexpected failures of your software when you recompile after an update your compiler, replace calls to dpmeps() by EPSILON(0d0). If this replacement is too troublesome, replace the body of dpmeps by "dpmeps = epsilon(0d0)" or "dpmeps = epsilon(dpmeps)".

Intrinsics such as EPSILON() are provided in modern Fortran precisely for this purpose.

 

View solution in original post

0 Kudos
6 Replies
Xiaoping_D_Intel
Employee
1,248 Views

The code ran into infinite loop because in release mode compiler will make aggressive optimizations on floating-point calculations and optimize the expression "(temp1 - one .eq. zero) " into "true" at compilation time so that there will be no comparison at runtime inside the loop.

You may change it by setting compiler option "-fp-model" with value other than the default "fast".

 

Thanks,

Xiaoping Duan

Intel Customer Support

 

 

0 Kudos
Les_Neilson
Valued Contributor II
1,248 Views

Xiaoping D. (Intel) wrote:

The code ran into infinite loop because in release mode compiler will make aggressive optimizations on floating-point calculations and optimize the expression "(temp1 - one .eq. zero) " into "true" at compilation time so that there will be no comparison at runtime inside the loop.

You may change it by setting compiler option "-fp-model" with value other than the default "fast".

 

Thanks,

Xiaoping Duan

Intel Customer Support

 

 

Another option is to use an appropriate tolerance e.g.   (Temp1 - one < tolerance)

Les 

0 Kudos
Singh__Amit
Beginner
1,248 Views

Thanks Xiaoping and Les for your answers. I think I will have to go the way Xiaoping suggests. The code is part of ome other library that i am using and the particular function dpmeps() is meant to  induce floating point arithmetic errors to determine the machine precision. So using a tolerance kind of defeats the purpose. 

0 Kudos
TimP
Honored Contributor III
1,248 Views

ifort also provides options -assume:protect_parens or (supposedly equivalent) -Qprotect-parens which may work with such source code when the source is split down to 1 procedure per source file.  This is a part of /standard-semantics (the documented option for compliance with F2003 in cases which don't require /fp:strict).  Unless you are targeting 1st generation Intel(r) Xeon Phi(tm), setting one of these options is usually a good idea.

The usual work-around for this specific issue is to replace the function with the corresponding Fortran intrinsic EPSILON(1_REAL64).  It seems the developers of ifort expect you to undertake such modernization.

I've wondered aloud why the compiler doesn't recognize when it has created an infinite loop by removing the exit condition (as well as submitting an IPS issue about why protect_parens is ignored under interprocedural "optimization").  By the way, lowering /fp: level doesn't necessarily work when there are multiple procedures in a source file (although it seems to do so with the "companion C processor" ICL).

The other problem I have with setting /fp:source is that it requires changing loops to !$omp simd reduction form where that is appropriate for optimization.  Not everyone is happy with the directive based optimization facility where you turn off all simd optimization except where specified by directive (so compile with -Qvec- -Qopenmp-simd).

gfortran likewise has problems with such code at "unsafe" optimization levels (-ffast-math) but you don't get that unless you ask for it.   I'm sure the ifort developers don't appreciate the implication that ifort default is "unsafe" besides being documented as not F2003 compliant (and in more than 1 case not F95 compliant).
 

0 Kudos
mecej4
Honored Contributor III
1,249 Views

The code DPMEPS(), and many others from the 1970s and 1980s, perform tricks to determine the machine epsilon. As compiler optimizations improve, these tricks will be defeated one by one.

To protect yourself from unexpected failures of your software when you recompile after an update your compiler, replace calls to dpmeps() by EPSILON(0d0). If this replacement is too troublesome, replace the body of dpmeps by "dpmeps = epsilon(0d0)" or "dpmeps = epsilon(dpmeps)".

Intrinsics such as EPSILON() are provided in modern Fortran precisely for this purpose.

 

0 Kudos
Singh__Amit
Beginner
1,248 Views

Thanks Tim for elaborating more on the compiler flags. And thanks both you and mecej4 for the EPSILON() intrinsic work-around. I tried it and in one of my application's execution reduced from 65 seconds to 45 seconds as well. All the replies have been helpful and I wish I could mark more than one of them as the best reply. But I think I will go with finally what helped me bring down the execution time which is using the EPSILON() intrinsic.

0 Kudos
Reply