Unverified Commit ff13970b authored by Andreas Marek's avatar Andreas Marek
Browse files

Abort on error in QR-decomposition

If the QR-decomposition is used wrongly (matrix size is not a
multiple of block size) the the execution will abort, in
order to prevent the wrong results, discussed in a previous commit

Debug messages are now available by setting the environment variable
"ELPA_DEBUG_MESSAGES" to "yes".
parent 3d880b65
......@@ -9,7 +9,7 @@ AM_LDFLAGS = $(SCALAPACK_LDFLAGS)
lib_LTLIBRARIES = libelpa@SUFFIX@.la
libelpa@SUFFIX@_la_LINK = $(FCLINK) $(AM_LDFLAGS) -version-info $(ELPA_SO_VERSION) -lstdc++
libelpa@SUFFIX@_la_SOURCES = src/elpa1.F90 src/elpa2.F90
libelpa@SUFFIX@_la_SOURCES = src/elpa_utilities.F90 src/elpa1.F90 src/elpa2_utilities.F90 src/elpa2.F90
libelpa@SUFFIX@_la_SOURCES += src/elpa_qr/qr_utils.f90 \
src/elpa_qr/elpa_qrkernels.f90 \
src/elpa_qr/elpa_pdlarfb.f90 \
......
......@@ -170,7 +170,8 @@ am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
"$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(elpa_includedir)"
LTLIBRARIES = $(lib_LTLIBRARIES)
libelpa@SUFFIX@_la_LIBADD =
am__libelpa@SUFFIX@_la_SOURCES_DIST = src/elpa1.F90 src/elpa2.F90 \
am__libelpa@SUFFIX@_la_SOURCES_DIST = src/elpa_utilities.F90 \
src/elpa1.F90 src/elpa2_utilities.F90 src/elpa2.F90 \
src/elpa_qr/qr_utils.f90 src/elpa_qr/elpa_qrkernels.f90 \
src/elpa_qr/elpa_pdlarfb.f90 src/elpa_qr/elpa_pdgeqrf.f90 \
src/timer.F90 src/ftimings/ftimings.F90 \
......@@ -212,14 +213,14 @@ am__dirstamp = $(am__leading_dot)dirstamp
@WITH_REAL_AVX_BLOCK6_KERNEL_TRUE@am__objects_12 = src/elpa2_kernels/elpa2_kernels_real_sse-avx_6hv.lo
@WITH_COMPLEX_AVX_BLOCK1_KERNEL_TRUE@am__objects_13 = src/elpa2_kernels/elpa2_kernels_complex_sse-avx_1hv.lo
@WITH_COMPLEX_AVX_BLOCK2_KERNEL_TRUE@am__objects_14 = src/elpa2_kernels/elpa2_kernels_complex_sse-avx_2hv.lo
am_libelpa@SUFFIX@_la_OBJECTS = src/elpa1.lo src/elpa2.lo \
src/elpa_qr/qr_utils.lo src/elpa_qr/elpa_qrkernels.lo \
src/elpa_qr/elpa_pdlarfb.lo src/elpa_qr/elpa_pdgeqrf.lo \
$(am__objects_1) $(am__objects_2) $(am__objects_3) \
$(am__objects_4) $(am__objects_5) $(am__objects_6) \
$(am__objects_7) $(am__objects_8) $(am__objects_9) \
$(am__objects_10) $(am__objects_11) $(am__objects_12) \
$(am__objects_13) $(am__objects_14)
am_libelpa@SUFFIX@_la_OBJECTS = src/elpa_utilities.lo src/elpa1.lo \
src/elpa2_utilities.lo src/elpa2.lo src/elpa_qr/qr_utils.lo \
src/elpa_qr/elpa_qrkernels.lo src/elpa_qr/elpa_pdlarfb.lo \
src/elpa_qr/elpa_pdgeqrf.lo $(am__objects_1) $(am__objects_2) \
$(am__objects_3) $(am__objects_4) $(am__objects_5) \
$(am__objects_6) $(am__objects_7) $(am__objects_8) \
$(am__objects_9) $(am__objects_10) $(am__objects_11) \
$(am__objects_12) $(am__objects_13) $(am__objects_14)
libelpa@SUFFIX@_la_OBJECTS = $(am_libelpa@SUFFIX@_la_OBJECTS)
PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
am__elpa1_test_complex@SUFFIX@_SOURCES_DIST = test/test_complex.F90 \
......@@ -797,14 +798,14 @@ AM_LDFLAGS = $(SCALAPACK_LDFLAGS)
# libelpa
lib_LTLIBRARIES = libelpa@SUFFIX@.la
libelpa@SUFFIX@_la_LINK = $(FCLINK) $(AM_LDFLAGS) -version-info $(ELPA_SO_VERSION) -lstdc++
libelpa@SUFFIX@_la_SOURCES = src/elpa1.F90 src/elpa2.F90 \
src/elpa_qr/qr_utils.f90 src/elpa_qr/elpa_qrkernels.f90 \
src/elpa_qr/elpa_pdlarfb.f90 src/elpa_qr/elpa_pdgeqrf.f90 \
$(am__append_1) $(am__append_2) $(am__append_3) \
$(am__append_4) $(am__append_5) $(am__append_6) \
$(am__append_7) $(am__append_8) $(am__append_9) \
$(am__append_10) $(am__append_11) $(am__append_12) \
$(am__append_13) $(am__append_14)
libelpa@SUFFIX@_la_SOURCES = src/elpa_utilities.F90 src/elpa1.F90 \
src/elpa2_utilities.F90 src/elpa2.F90 src/elpa_qr/qr_utils.f90 \
src/elpa_qr/elpa_qrkernels.f90 src/elpa_qr/elpa_pdlarfb.f90 \
src/elpa_qr/elpa_pdgeqrf.f90 $(am__append_1) $(am__append_2) \
$(am__append_3) $(am__append_4) $(am__append_5) \
$(am__append_6) $(am__append_7) $(am__append_8) \
$(am__append_9) $(am__append_10) $(am__append_11) \
$(am__append_12) $(am__append_13) $(am__append_14)
#if WITH_AVX_SANDYBRIDGE
# libelpa@SUFFIX@_la_SOURCES += src/elpa2_kernels/elpa2_kernels_real_sse-avx_2hv.c \
......@@ -984,7 +985,11 @@ src/$(am__dirstamp):
src/$(DEPDIR)/$(am__dirstamp):
@$(MKDIR_P) src/$(DEPDIR)
@: > src/$(DEPDIR)/$(am__dirstamp)
src/elpa_utilities.lo: src/$(am__dirstamp) \
src/$(DEPDIR)/$(am__dirstamp)
src/elpa1.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
src/elpa2_utilities.lo: src/$(am__dirstamp) \
src/$(DEPDIR)/$(am__dirstamp)
src/elpa2.lo: src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
src/elpa_qr/$(am__dirstamp):
@$(MKDIR_P) src/elpa_qr
......
......@@ -5,19 +5,20 @@ This file contains the release notes for the ELPA 2015.02.001 version
What is new?
-------------
a)
a) ABI change
---------------------
Most importantly, the ABI of the ELPA libray changed!
A rebuild/relink of the user code using the ELPA library is mandatory!
b)
b) QR-decomposition
---------------------
The only major change (which results in point a) is in the ELPA-2
part of the library for real matrices:
the fully blocked QR decomposition has been moved from the development part
to the release! However, this is still experimental, since there is still
a bug. For some matrix sizes the results are wrong
to the release!
It is now possible to use this QR decomposition by either setting an
environment variable "ELPA_QR_DECOMPOSITION" to "yes", or to call the
......@@ -28,19 +29,33 @@ Note, that the environment variable always takes precedence over the setting in
the API call.
Furthernote, that if neither the environment variable or the API keyword are not
set, or set to "no" or ".false.", respectively, then no qr decomposition is used
set, or set to "no" or ".false.", respectively, then no QR-decomposition is used
(i.e. the previous behaviour is maintained).
The QR-decomposition fails, if the chosen matrix size is not a multiple of the
blocksize. The library will give a warning message if this happens and it will
abort.
c)
c) Debug messages
----------------------
By setting the environment variable "ELPA_DEBUG_MESSAGES" to "yes", ELPA will now
print more information if an error occurs.
d) Optimization flags
-----------------------
The configure procedure was adapted to be more consistent. No compiler omptimization
flags are set automatically anymore, this is up to the user at build time
d)
e) OpenMP check
----------------------
The checks for OpenMP in the configure have been improved
Any incompatibles to previous version?
---------------------------------------
......
This diff is collapsed.
This diff is collapsed.
! This file is part of ELPA.
!
! The ELPA library was originally created by the ELPA consortium,
! consisting of the following organizations:
!
! - Rechenzentrum Garching der Max-Planck-Gesellschaft (RZG),
! - Bergische Universität Wuppertal, Lehrstuhl für angewandte
! Informatik,
! - Technische Universität München, Lehrstuhl für Informatik mit
! Schwerpunkt Wissenschaftliches Rechnen ,
! - Fritz-Haber-Institut, Berlin, Abt. Theorie,
! - Max-Plack-Institut für Mathematik in den Naturwissenschaftrn,
! Leipzig, Abt. Komplexe Strukutren in Biologie und Kognition,
! and
! - IBM Deutschland GmbH
!
!
! More information can be found here:
! http://elpa.rzg.mpg.de/
!
! ELPA is free software: you can redistribute it and/or modify
! it under the terms of the version 3 of the license of the
! GNU Lesser General Public License as published by the Free
! Software Foundation.
!
! ELPA is distributed in the hope that it will be useful,
! but WITHOUT ANY WARRANTY; without even the implied warranty of
! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! GNU Lesser General Public License for more details.
!
! You should have received a copy of the GNU Lesser General Public License
! along with ELPA. If not, see <http://www.gnu.org/licenses/>
!
! ELPA reflects a substantial effort on the part of the original
! ELPA consortium, and we ask you to respect the spirit of the
! license that we chose: i.e., please contribute any changes you
! may have back to the original ELPA library distribution, and keep
! any derivatives of ELPA under the same license that we chose for
! the original distribution, the GNU Lesser General Public License.
!
!
! ELPA1 -- Faster replacements for ScaLAPACK symmetric eigenvalue routines
!
! Copyright of the original code rests with the authors inside the ELPA
! consortium. The copyright of any additional modifications shall rest
! with their original authors, but shall adhere to the licensing terms
! distributed along with the original code in the file "COPYING".
! ELPA2 -- 2-stage solver for ELPA
!
! Copyright of the original code rests with the authors inside the ELPA
! consortium. The copyright of any additional modifications shall rest
! with their original authors, but shall adhere to the licensing terms
! distributed along with the original code in the file "COPYING".
#include "config-f90.h"
module ELPA2_utilities
#ifdef HAVE_ISO_FORTRAN_ENV
use iso_fortran_env, only : error_unit
#endif
implicit none
PRIVATE ! By default, all routines contained are private
! The following routines are public:
public :: get_actual_real_kernel_name, get_actual_complex_kernel_name
public :: REAL_ELPA_KERNEL_GENERIC, REAL_ELPA_KERNEL_GENERIC_SIMPLE, &
REAL_ELPA_KERNEL_BGP, REAL_ELPA_KERNEL_BGQ, &
REAL_ELPA_KERNEL_SSE, REAL_ELPA_KERNEL_AVX_BLOCK2, &
REAL_ELPA_KERNEL_AVX_BLOCK4, REAL_ELPA_KERNEL_AVX_BLOCK6
public :: COMPLEX_ELPA_KERNEL_GENERIC, COMPLEX_ELPA_KERNEL_GENERIC_SIMPLE, &
COMPLEX_ELPA_KERNEL_BGP, COMPLEX_ELPA_KERNEL_BGQ, &
COMPLEX_ELPA_KERNEL_SSE, COMPLEX_ELPA_KERNEL_AVX_BLOCK1, &
COMPLEX_ELPA_KERNEL_AVX_BLOCK2
public :: REAL_ELPA_KERNEL_NAMES, COMPLEX_ELPA_KERNEL_NAMES
public :: get_actual_complex_kernel, get_actual_real_kernel
public :: check_allowed_complex_kernels, check_allowed_real_kernels
public :: AVAILABLE_COMPLEX_ELPA_KERNELS, AVAILABLE_REAL_ELPA_KERNELS
public :: print_available_real_kernels, print_available_complex_kernels
public :: qr_decomposition_via_environment_variable
#ifndef HAVE_ISO_FORTRAN_ENV
integer, parameter :: error_unit = 6
#endif
integer, parameter :: number_of_real_kernels = 8
integer, parameter :: REAL_ELPA_KERNEL_GENERIC = 1
integer, parameter :: REAL_ELPA_KERNEL_GENERIC_SIMPLE = 2
integer, parameter :: REAL_ELPA_KERNEL_BGP = 3
integer, parameter :: REAL_ELPA_KERNEL_BGQ = 4
integer, parameter :: REAL_ELPA_KERNEL_SSE = 5
integer, parameter :: REAL_ELPA_KERNEL_AVX_BLOCK2 = 6
integer, parameter :: REAL_ELPA_KERNEL_AVX_BLOCK4 = 7
integer, parameter :: REAL_ELPA_KERNEL_AVX_BLOCK6 = 8
#if defined(WITH_REAL_AVX_BLOCK2_KERNEL)
integer, parameter :: DEFAULT_REAL_ELPA_KERNEL = REAL_ELPA_KERNEL_GENERIC
#else
integer, parameter :: DEFAULT_REAL_ELPA_KERNEL = REAL_ELPA_KERNEL_GENERIC
#endif
character(35), parameter, dimension(number_of_real_kernels) :: &
REAL_ELPA_KERNEL_NAMES = (/"REAL_ELPA_KERNEL_GENERIC ", &
"REAL_ELPA_KERNEL_GENERIC_SIMPLE ", &
"REAL_ELPA_KERNEL_BGP ", &
"REAL_ELPA_KERNEL_BGQ ", &
"REAL_ELPA_KERNEL_SSE ", &
"REAL_ELPA_KERNEL_AVX_BLOCK2 ", &
"REAL_ELPA_KERNEL_AVX_BLOCK4 ", &
"REAL_ELPA_KERNEL_AVX_BLOCK6 "/)
integer, parameter :: number_of_complex_kernels = 7
integer, parameter :: COMPLEX_ELPA_KERNEL_GENERIC = 1
integer, parameter :: COMPLEX_ELPA_KERNEL_GENERIC_SIMPLE = 2
integer, parameter :: COMPLEX_ELPA_KERNEL_BGP = 3
integer, parameter :: COMPLEX_ELPA_KERNEL_BGQ = 4
integer, parameter :: COMPLEX_ELPA_KERNEL_SSE = 5
integer, parameter :: COMPLEX_ELPA_KERNEL_AVX_BLOCK1 = 6
integer, parameter :: COMPLEX_ELPA_KERNEL_AVX_BLOCK2 = 7
#if defined(WITH_COMPLEX_AVX_BLOCK1_KERNEL)
integer, parameter :: DEFAULT_COMPLEX_ELPA_KERNEL = COMPLEX_ELPA_KERNEL_GENERIC
#else
integer, parameter :: DEFAULT_COMPLEX_ELPA_KERNEL = COMPLEX_ELPA_KERNEL_GENERIC
#endif
character(35), parameter, dimension(number_of_complex_kernels) :: &
COMPLEX_ELPA_KERNEL_NAMES = (/"COMPLEX_ELPA_KERNEL_GENERIC ", &
"COMPLEX_ELPA_KERNEL_GENERIC_SIMPLE ", &
"COMPLEX_ELPA_KERNEL_BGP ", &
"COMPLEX_ELPA_KERNEL_BGQ ", &
"COMPLEX_ELPA_KERNEL_SSE ", &
"COMPLEX_ELPA_KERNEL_AVX_BLOCK1 ", &
"COMPLEX_ELPA_KERNEL_AVX_BLOCK2 "/)
integer, parameter :: &
AVAILABLE_REAL_ELPA_KERNELS(number_of_real_kernels) = &
(/ &
#if WITH_REAL_GENERIC_KERNEL
1 &
#else
0 &
#endif
#if WITH_REAL_GENERIC_SIMPLE_KERNEL
,1 &
#else
,0 &
#endif
#if WITH_REAL_BGP_KERNEL
,1 &
#else
,0 &
#endif
#if WITH_REAL_BGQ_KERNEL
,1 &
#else
,0 &
#endif
#if WITH_REAL_SSE_KERNEL
,1 &
#else
,0 &
#endif
#if WITH_REAL_AVX_BLOCK2_KERNEL
,1 &
#else
,0 &
#endif
#if WITH_REAL_AVX_BLOCK4_KERNEL
,1 &
#else
,0 &
#endif
#if WITH_REAL_AVX_BLOCK6_KERNEL
,1 &
#else
,0 &
#endif
/)
integer, parameter :: &
AVAILABLE_COMPLEX_ELPA_KERNELS(number_of_complex_kernels) = &
(/ &
#if WITH_COMPLEX_GENERIC_KERNEL
1 &
#else
0 &
#endif
#if WITH_COMPLEX_GENERIC_SIMPLE_KERNEL
,1 &
#else
,0 &
#endif
#if WITH_COMPLEX_BGP_KERNEL
,1 &
#else
,0 &
#endif
#if WITH_COMPLEX_BGQ_KERNEL
,1 &
#else
,0 &
#endif
#if WITH_COMPLEX_SSE_KERNEL
,1 &
#else
,0 &
#endif
#if WITH_COMPLEX_AVX_BLOCK1_KERNEL
,1 &
#else
,0 &
#endif
#if WITH_COMPLEX_AVX_BLOCK2_KERNEL
,1 &
#else
,0 &
#endif
/)
!******
contains
subroutine print_available_real_kernels
#ifdef HAVE_DETAILED_TIMINGS
use timings
#endif
implicit none
integer :: i
#ifdef HAVE_DETAILED_TIMINGS
call timer%start("print_available_real_kernels")
#endif
do i=1, number_of_real_kernels
if (AVAILABLE_REAL_ELPA_KERNELS(i) .eq. 1) then
write(error_unit,*) REAL_ELPA_KERNEL_NAMES(i)
endif
enddo
write(error_unit,*) " "
write(error_unit,*) " At the moment the following kernel would be choosen:"
write(error_unit,*) get_actual_real_kernel_name()
#ifdef HAVE_DETAILED_TIMINGS
call timer%stop("print_available_real_kernels")
#endif
end subroutine print_available_real_kernels
subroutine print_available_complex_kernels
#ifdef HAVE_DETAILED_TIMINGS
use timings
#endif
implicit none
integer :: i
#ifdef HAVE_DETAILED_TIMINGS
call timer%start("print_available_complex_kernels")
#endif
do i=1, number_of_complex_kernels
if (AVAILABLE_COMPLEX_ELPA_KERNELS(i) .eq. 1) then
write(error_unit,*) COMPLEX_ELPA_KERNEL_NAMES(i)
endif
enddo
write(error_unit,*) " "
write(error_unit,*) " At the moment the following kernel would be choosen:"
write(error_unit,*) get_actual_complex_kernel_name()
#ifdef HAVE_DETAILED_TIMINGS
call timer%stop("print_available_complex_kernels")
#endif
end subroutine print_available_complex_kernels
function get_actual_real_kernel() result(actual_kernel)
#ifdef HAVE_DETAILED_TIMINGS
use timings
#endif
implicit none
integer :: actual_kernel
#ifdef HAVE_DETAILED_TIMINGS
call timer%start("get_actual_real_kernel")
#endif
! if kernel is not choosen via api
! check whether set by environment variable
actual_kernel = real_kernel_via_environment_variable()
if (actual_kernel .eq. 0) then
! if not then set default kernel
actual_kernel = DEFAULT_REAL_ELPA_KERNEL
endif
#ifdef HAVE_DETAILED_TIMINGS
call timer%stop("get_actual_real_kernel")
#endif
end function get_actual_real_kernel
function get_actual_real_kernel_name() result(actual_kernel_name)
#ifdef HAVE_DETAILED_TIMINGS
use timings
#endif
implicit none
character(35) :: actual_kernel_name
integer :: actual_kernel
#ifdef HAVE_DETAILED_TIMINGS
call timer%start("get_actual_real_kernel_name")
#endif
actual_kernel = get_actual_real_kernel()
actual_kernel_name = REAL_ELPA_KERNEL_NAMES(actual_kernel)
#ifdef HAVE_DETAILED_TIMINGS
call timer%stop("get_actual_real_kernel_name")
#endif
end function get_actual_real_kernel_name
function get_actual_complex_kernel() result(actual_kernel)
#ifdef HAVE_DETAILED_TIMINGS
use timings
#endif
implicit none
integer :: actual_kernel
#ifdef HAVE_DETAILED_TIMINGS
call timer%start("get_actual_complex_kernel")
#endif
! if kernel is not choosen via api
! check whether set by environment variable
actual_kernel = complex_kernel_via_environment_variable()
if (actual_kernel .eq. 0) then
! if not then set default kernel
actual_kernel = DEFAULT_COMPLEX_ELPA_KERNEL
endif
#ifdef HAVE_DETAILED_TIMINGS
call timer%stop("get_actual_complex_kernel")
#endif
end function get_actual_complex_kernel
function get_actual_complex_kernel_name() result(actual_kernel_name)
#ifdef HAVE_DETAILED_TIMINGS
use timings
#endif
implicit none
character(35) :: actual_kernel_name
integer :: actual_kernel
#ifdef HAVE_DETAILED_TIMINGS
call timer%start("get_actual_complex_kernel_name")
#endif
actual_kernel = get_actual_complex_kernel()
actual_kernel_name = COMPLEX_ELPA_KERNEL_NAMES(actual_kernel)
#ifdef HAVE_DETAILED_TIMINGS
call timer%stop("get_actual_complex_kernel_name")
#endif
end function get_actual_complex_kernel_name
function check_allowed_real_kernels(THIS_REAL_ELPA_KERNEL) result(err)
#ifdef HAVE_DETAILED_TIMINGS
use timings
#endif
implicit none
integer, intent(in) :: THIS_REAL_ELPA_KERNEL
logical :: err
#ifdef HAVE_DETAILED_TIMINGS
call timer%start("check_allowed_real_kernels")
#endif
err = .false.
if (AVAILABLE_REAL_ELPA_KERNELS(THIS_REAL_ELPA_KERNEL) .ne. 1) err=.true.
#ifdef HAVE_DETAILED_TIMINGS
call timer%stop("check_allowed_real_kernels")
#endif
end function check_allowed_real_kernels
function check_allowed_complex_kernels(THIS_COMPLEX_ELPA_KERNEL) result(err)
#ifdef HAVE_DETAILED_TIMINGS
use timings
#endif
implicit none
integer, intent(in) :: THIS_COMPLEX_ELPA_KERNEL
logical :: err
#ifdef HAVE_DETAILED_TIMINGS
call timer%start("check_allowed_complex_kernels")
#endif
err = .false.
if (AVAILABLE_COMPLEX_ELPA_KERNELS(THIS_COMPLEX_ELPA_KERNEL) .ne. 1) err=.true.
#ifdef HAVE_DETAILED_TIMINGS
call timer%stop("check_allowed_complex_kernels")
#endif
end function check_allowed_complex_kernels
function qr_decomposition_via_environment_variable(useQR) result(isSet)
#ifdef HAVE_DETAILED_TIMINGS
use timings
#endif
implicit none
logical, intent(out) :: useQR
logical :: isSet
CHARACTER(len=255) :: ELPA_QR_DECOMPOSITION
#ifdef HAVE_DETAILED_TIMINGS
call timer%start("qr_decomposition_via_environment_variable")
#endif
isSet = .false.
#if defined(HAVE_ENVIRONMENT_CHECKING)
call get_environment_variable("ELPA_QR_DECOMPOSITION",ELPA_QR_DECOMPOSITION)
#endif
if (trim(ELPA_QR_DECOMPOSITION) .eq. "yes") then
useQR = .true.
isSet = .true.
endif
if (trim(ELPA_QR_DECOMPOSITION) .eq. "no") then
useQR = .false.
isSet = .true.
endif
#ifdef HAVE_DETAILED_TIMINGS
call timer%stop("qr_decomposition_via_environment_variable")
#endif
end function qr_decomposition_via_environment_variable
function real_kernel_via_environment_variable() result(kernel)
#ifdef HAVE_DETAILED_TIMINGS
use timings
#endif
implicit none
integer :: kernel
CHARACTER(len=255) :: REAL_KERNEL_ENVIRONMENT
integer :: i
#ifdef HAVE_DETAILED_TIMINGS
call timer%start("real_kernel_via_environment_variable")
#endif