Debugging
Displaying the exploration of the tree
New users of IRPF90 who are experienced Fortran programmers like to
display the exploration of the tree when they execute their first programs.
The -d
option of irpf90
prints a message when the program enters
or exits a function/provider/subroutine.
In the uvwt
example, the output is:
$ ./irp_example1
d1
1
d2
2
d3
3
d4
4
d5
5
t = 26
Activating the -d
option gives the following output:
$ ./irp_example1
0 : -> provide_t
0 : -> provide_u1
0 : -> provide_d1
0 : -> d1
d1
1
d2
2
d3
3
d4
4
d5
5
0 : <- d1 6.889999999999999E-004
0 : <- provide_d1 8.070000000000000E-004
0 : -> u1
0 : -> fu
0 : <- fu 9.999999999996990E-007
0 : <- u1 2.900000000000038E-005
0 : <- provide_u1 8.999999999999998E-004
0 : -> provide_v
0 : -> provide_w
0 : -> w
0 : <- w 1.000000000000133E-006
0 : <- provide_w 2.700000000000011E-005
0 : -> provide_u2
0 : -> u2
0 : -> fu
0 : <- fu 1.000000000000133E-006
0 : <- u2 2.015000000000000E-003
0 : <- provide_u2 2.026000000000000E-003
0 : -> v
0 : <- v 0.000000000000000E+000
0 : <- provide_v 2.089000000000000E-003
0 : -> t
0 : <- t 0.000000000000000E+000
0 : <- provide_t 3.033000000000000E-003
0 : -> irp_example1
t = 26
0 : <- irp_example1 0.000000000000000E+000
The floating point numbers given in the output are the CPU times, and the integer on the left of each line is the thread ID.
Compiler errors
When the Fortran compiler fails, it reports an error in the Fortran code.
This error is difficult for us to track because IRPF90 generated the Fortran
and we need to be able to do the mapping from the Fortran compiler's error
to the error in the *.irp.f
file. To achieve this goal, the generated
Fortran code has comments at the end of the lines which correspond to the
file names and line numbers of the original *.irp.f
file.
Let us introduce an error in the IRPF90 code (a missing closing parenthesis)
BEGIN_PROVIDER [ integer, u2 ]
implicit none
BEGIN_DOC
! This is u2 = u(d3,d4)
END_DOC
integer :: fu
u2 = fu(d3,d4
END_PROVIDER
The generated Fortran code in the IRPF90_temp/uvwt.irp.F90
file is
subroutine bld_u2
use uvwt_mod
use input_mod
implicit none ! uvwt.irp.f: 35
character*(2) :: irp_here = 'u2' ! uvwt.irp.f: 34
integer :: fu ! uvwt.irp.f: 39
u2 = fu(d3,d4 ! uvwt.irp.f: 40
end subroutine bld_u2
Running make
produces this error (with the Intel Fortran compiler)
ifort -I IRPF90_temp/ -O2 -c IRPF90_temp/uvwt.irp.F90 -o IRPF90_temp/uvwt.irp.o
IRPF90_temp/uvwt.irp.F90(71): error #5082: Syntax error, found END-OF-STATEMENT when expecting one of: ( * ) :: , . % + - [ : . ** / // .LT. < .LE. <= .EQ. == ...
u2 = fu(d3,d4 ! uvwt.irp.f: 40
----------------------------------------------------^
compilation aborted for IRPF90_temp/uvwt.irp.F90 (code 1)
make: *** [IRPF90_temp/uvwt.irp.o] Error 1
IRP_here
You can remark the presence of the irp_here
variable in the generated
bld_u2
generated subroutine. Every subroutine, function or provider has
a string local variable named irp_here
, which contains the name of the
current context. This variable is very helpful for users to print debug/error
messages:
print *, irp_here//' : a = ', a
Tracing memory allocations
When the memory used by a program becomes too large, one would like to
find the IRP entities that may be responsible. The -m
option will
display a message in the standard output when an array for an IRP entity is
allocated or deallocated (using the FREE
keyword).
Here is a real-world example (taken from the Quantum package IRPF90 code):
10 Allocating ci_electronic_energy(N_states_diag)
10 Allocating ci_eigenvectors(N_det,N_states_diag)
10 Allocating ci_eigenvectors_s2(N_states_diag)
128260 Allocating psi_det(N_int,2,psi_det_size)
...
Deallocating ci_eigenvectors
30600 Allocating ci_eigenvectors(N_det,N_states_diag)
6120 Allocating det_connections(N_con_int,N_det)
The integer at the beginning of the line is the number of elements in the array.
Debugging an embedded script
Embedded shell scripts may be difficult to debug. The --preprocess
option
helps the programmer to check the files IRPF90 will produce after executing
the scripts. For example, consider the file named test.irp.f
:
program test
BEGIN_SHELL [ /bin/bash ]
cat << EOF
print *, 'Compiled by `whoami` on `date`'
print *, '$PWD'
print *, '$(hostname)'
EOF
END_SHELL
end
The following command displays the produced Fortran file:
$ irpf90 --preprocess test.irp.f
program irp_program
call test
call irp_finalize_1624498827()
end program
subroutine test
character*(4) :: irp_here = 'test'
print *, 'Compiled by scemama on Mon Mar 9 18:41:50 CET 2015'
print *, '/dev/shm/tmp'
print *, 'lpqlx139'
end
Debugging TOUCH
statements
TOUCH
statements are particularly dangerous because they violate
the principle that one IRP entity can only be built by its builder, which
can only be called by its provider. To see what will be invalidated by a
TOUCH
statement can be useful to understand the consequences of a
dangerous modification. The -t
option displays which IRP entities will
be invalidated :
$ irpf90 -t psi_coef
Touching psi_coef invalidates the following entities:
- ci_electronic_energy
- ci_energy
- coef_hf_selector
- exc_degree_per_selectors
- n_det_generators
- n_det_selectors
- one_body_dm_mo
- psi_average_norm_contrib
- psi_det_sorted
- psi_generators
- psi_selectors
- s2_values