You can instruct the compiler to insert calls to the tracing procedures that you have defined to aid in debugging or timing the execution of other procedures.
To trace procedures in your program, you must specify which procedures to trace. You must also provide your own tracing procedures. If you enable tracing without providing tracing procedures, you will get linker errors about undefined symbols called __func_trace_enter, __func_trace_exit, and possibly __func_trace_catch.
The -qfunctrace compiler option controls tracing for all non-inlined user-defined procedures and all outlined compiler-generated procedures in your program. If you are interested in tracing specific external or modules procedures, you can use the -qfunctrace+ and -qfunctrace- compiler options. You can also specify the NOFUNCTRACE directive to disable the tracing of entire modules, external procedures, module procedures, or internal procedures.
Tracing applies to programs, external procedures, non-intrinsic module procedures, and internal procedures.
Compiler-generated procedures are not traced unless they were generated for outlined user code, such as an OpenMP program. In those cases, the name of the outlined procedure contains the name of the original user procedure as a prefix.
Inlined procedures and statement functions cannot be traced because they do not exist in the executable.
To avoid infinite recursion, user-defined tracing procedures cannot be traced. Similarly, tracing must be disabled for procedures called from user-defined tracing procedures.
You can implement the tracing procedures in Fortran, C, or C++.
SUBROUTINE routine_name(procedure_name, file_name, line_number, id)
USE, INTRINSIC :: iso_c_binding
CHARACTER(*), INTENT(IN) :: procedure_name
CHARACTER(*), INTENT(IN) :: file_name
INTEGER(C_INT), INTENT(IN) :: line_number
TYPE(C_PTR), INTENT(INOUT) :: id
END SUBROUTINE
where routine_name is the
name of an external or module procedure.When you specify these options or directives, XL Fortran generates wrapper procedures called __func_trace_enter, __func_trace_exit, and __func_trace_catch that call your corresponding tracing procedure. These wrappers allow interoperability with C and C++ by converting the dummy arguments from the C prototype to the interface described earlier. routine_name must therefore not be named __func_trace_enter, __func_trace_exit, or __func_trace_catch. In addition, your program must not contain more than one of each of the tracing procedures.
XL Fortran inserts calls to your tracing procedures on procedure entry and exit. It passes the name of the procedure being traced, the name of the file containing the entry or exit point being traced, and the line number. It also passes the address of a static pointer that is initialized to C_NULL_PTR at the beginning of the program. This pointer allows you to store arbitrary data in the entry tracing procedure and access this data in the exit and catch procedures. See the Examples section for detail. Because this pointer resides in static memory, extra steps might be needed when tracing threaded or recursive procedures.
> cat helloworld.f
print *, 'hello world'
end
> cc -c /opt/IBM/xlf/15.1.0/samples/functrace/tracing_routines.c
> xlf95 helloworld.f -qfunctrace tracing_routines.o
** _main === End of Compilation 1 ===
1501-510 Compilation successful for file helloworld.f.
> ./a.out
{ _main (helloworld.f:1)
hello world
} _main (helloworld.f:2)
>
> cat recursive.f
integer function test()
test = 1
end function
integer test
print *, test() ! test must not have I/O on external unit
end
> xlf95 -c /opt/IBM/xlf/15.1.0/samples/functrace/tracing_routines.f90
** my__func_trace_enter === End of Compilation 1 ===
** my__func_trace_exit === End of Compilation 2 ===
** my__func_trace_catch === End of Compilation 3 ===
1501-510 Compilation successful for file tracing_routines.f90.
> xlf95 recursive.f tracing_routines.o -qfunctrace
** test === End of Compilation 1 ===
** _main === End of Compilation 2 ===
1501-510 Compilation successful for file recursive.f.
> ./a.out
{ _main (recursive.f:6)
XL Fortran (I/O initialization): I/O recursion detected.
IOT/Abort trap
>
> cat example.f
! Designate my_enter as a tracing procedure that should be called
! on procedure entry
!ibm* functrace_xlf_enter
subroutine my_enter(procedure_name, file_name, line_number, id)
use, intrinsic :: iso_c_binding
use, intrinsic :: xlfutility
character(*), intent(in) :: procedure_name, file_name
integer(c_int), intent(in) :: line_number
type(c_ptr), intent(inout) :: id
integer(kind=time_size), pointer :: enter_count
! Store the time we entered the procedure being traced into id.
if (.not. c_associated(id)) then
allocate(enter_count)
enter_count = time_()
id = c_loc(enter_count)
end if
print *, 'Entered procedure ', procedure_name, ' at ( ', &
file_name, ' :', line_number, ').'
end subroutine
! Designate my_exit as a tracing procedure that should be called
! on procedure exit
!ibm* functrace_xlf_exit
subroutine my_exit(procedure_name, file_name, line_number, id)
use, intrinsic :: iso_c_binding
use, intrinsic :: xlfutility
character(*), intent(in) :: procedure_name, file_name
integer(c_int), intent(in) :: line_number
type(c_ptr), intent(inout) :: id
integer(kind=time_size), pointer :: enter_count
integer(kind=time_size) exit_count, duration
! id should have been associated in my_enter with the time we
! entered the procedure being traced. Find the elapsed time.
if (c_associated(id)) then
exit_count = time_()
call c_f_pointer(id, enter_count)
duration = exit_count - enter_count
else
stop "error!"
endif
print *, 'Leaving procedure ', procedure_name, ' at ( ', &
file_name, ' :', line_number, ').'
print *, 'Spent', duration, 'seconds in ', procedure_name, '.'
end subroutine
! sub2 will be traced
subroutine sub2
call sleep_(3)
end subroutine
! sub1 will be traced
subroutine sub1
call sleep_(5)
call sub2
end subroutine
! Do not want to trace main_program
!ibm* nofunctrace
program main_program
call sub1
end program
> xlf95 example.f -qfunctrace
** my_enter === End of Compilation 1 ===
** my_exit === End of Compilation 2 ===
** sub2 === End of Compilation 3 ===
** sub1 === End of Compilation 4 ===
** main_program === End of Compilation 5 ===
1501-510 Compilation successful for file example.f.
> ./a.out
Entered procedure sub1 at ( example.f : 59 ).
Entered procedure sub2 at ( example.f : 54 ).
Leaving procedure sub2 at ( example.f : 55 ).
Spent 3 seconds in sub2.
Leaving procedure sub1 at ( example.f : 61 ).
Spent 8 seconds in sub1.
>