54 use,
intrinsic :: iso_fortran_env
81 integer,
parameter :: &
82 LABEL_LENGTH = 40, & !< Max. number of characters of tag label.
87 character(LABEL_LENGTH) :: label
88 real(real64) :: entry_time
89 real(real64) :: total_time
90 real(real64) :: min_time
91 real(real64) :: self_time
92 real(real64) :: op_count_current
93 real(real64) :: op_count
94 real(real64) :: op_count_child
95 real(real64) :: op_count_child_current
96 real(real64) :: tr_count_current
97 real(real64) :: tr_count
98 real(real64) :: tr_count_child
99 real(real64) :: tr_count_child_current
100 type(profile_t),
pointer :: parent
102 logical :: initialized = .false.
103 logical :: active = .false.
107 logical :: has_child(MAX_PROFILES)
108 real(real64) :: timings(MAX_PROFILES)
113 type(profile_t),
pointer :: p
141 integer,
parameter,
public :: &
142 PROFILING_TIME = 1, &
148 integer,
parameter :: MAX_MEMORY_VARS = 25
152 integer,
public ::
mode
154 type(profile_pointer_t) :: current
156 integer :: last_profile
158 integer(int64) :: alloc_count
159 integer(int64) :: dealloc_count
161 integer(int64) :: memory_limit = -1
162 integer(int64) :: total_memory
163 integer(int64) :: max_memory
164 character(len=256) :: max_memory_location
166 integer(int64) :: large_vars_size(max_memory_vars)
167 character(len=256) :: large_vars(max_memory_vars)
169 real(real64) :: start_time
172 character(len=256) :: output_dir
173 character(len=6) :: file_number
177 logical :: output_yaml
178 logical :: output_tree
180 character(LABEL_LENGTH),
allocatable :: likwid_regions(:)
185 type(sphash_t),
save :: profiling_map
192 type(namespace_t),
intent(in) :: namespace
196 character(len=256) :: label
282 prof_vars%memory_limit = int(ii, int64)*1024
290 namespace, action=
'write')
291 write(
prof_vars%mem_iunit,
'(5a16,a70)')
'Elapsed Time',
'Alloc/Dealloc',
'Size (words)',
'Prof Mem', &
292 'Sys Mem',
'Variable Name(Filename:Line)'
312 if (
parse_block(namespace,
'LikwidRegions', blk) == 0)
then
317 if (len_trim(label) > label_length)
then
318 message(1) =
"LikwidRegions: label " // trim(label) //
" is too long"
324 message(1) =
"LikwidRegions is ignored because ProfilingMode does not include likwid."
332 call likwid_markerinit()
385 real(real64),
parameter :: megabyte = 1048576.0_real64
387 integer(int64) :: io_open_count_red, io_close_count_red
396 prof_vars%profile_list(ii)%p%initialized = .false.
400 safe_deallocate_a(
prof_vars%likwid_regions)
404 write(
message(1),
'(a,i10)')
'Number of allocations = ',
prof_vars%alloc_count
405 write(
message(2),
'(a,i10)')
'Number of deallocations = ',
prof_vars%dealloc_count
406 write(
message(3),
'(a,f18.3,a)')
'Maximum total memory allocated = ',
prof_vars%max_memory/megabyte,
' Mbytes'
411 message(2) =
'Largest variables allocated:'
413 do ii = 1, max_memory_vars
421 write(
message(1),
'(a,i10,a,i10,a)')
"Not all memory was deallocated: ",
prof_vars%alloc_count, &
422 ' allocations and ',
prof_vars%dealloc_count,
' deallocations'
426 write(
message(1),
'(a,f18.3,a,f18.3,a)')
"Remaining allocated memory: ",
prof_vars%total_memory/megabyte, &
427 ' Mbytes (out of maximum ',
prof_vars%max_memory/megabyte,
' Mbytes)'
438 call likwid_markerclose()
450 write(
message(3),
'(a,i10)')
'Global number of file open = ', io_open_count_red
451 write(
message(4),
'(a,i10)')
'Global number of file close = ', io_close_count_red
463 type(
profile_t),
target,
intent(out) :: this
464 character(*),
intent(in) :: label
470 if(len_trim(label) > label_length)
then
471 message(1) =
"Label " // trim(label) //
" is too long for the internal profiler"
479 this%entry_time = huge(this%entry_time)
481 this%op_count_current =
m_zero
483 this%op_count_child =
m_zero
484 this%tr_count_current =
m_zero
486 this%tr_count_child =
m_zero
487 this%active = .false.
489 this%has_child = .false.
492 this%likwid = .false.
505 this%initialized = .
true.
508 if (
allocated(
prof_vars%likwid_regions))
then
509 this%likwid = any(
prof_vars%likwid_regions == this%label)
516 do iprofile = 1,
prof_vars%last_profile - 1
517 if (
prof_vars%profile_list(iprofile)%p%label == this%label)
then
518 message(1) =
"Label "//label//
" used more than once."
532 character(*),
intent(in) :: label
533 logical,
optional,
intent(in) :: exclude
537 class(*),
pointer :: profile_p
540 character(len=len(label)) :: label_
548 profile_p =>
sphash_lookup(profiling_map, trim(label_), found)
549 if (.not. found)
then
553 profile_p =>
sphash_lookup(profiling_map, trim(label_), found)
555 select type(this => profile_p)
557 if (.not. this%initialized)
then
561 if (this%active)
then
562 message(1) =
" The region with label "//trim(label)//
" is already active."
563 message(2) =
" This is likely caused by a missing or incorrect profiling_out call."
566 assert(.not. this%active)
571 if (
associated(
prof_vars%current%p))
then
574 this%parent%has_child(this%index) = .
true.
580 this%op_count_current =
m_zero
581 this%tr_count_current =
m_zero
582 this%op_count_child_current =
m_zero
583 this%tr_count_child_current =
m_zero
586 this%entry_time = now
590#if defined(HAVE_NVTX) || (defined(HAVE_HIP) && defined(__HIP_PLATFORM_AMD__))
595 if (this%likwid)
call likwid_markerstartregion(trim(label_))
607 character(*),
intent(in) :: label
609 real(real64) :: now, time_spent
610 class(*),
pointer :: profile_p
619 if (.not. found)
then
620 message(1) =
" No profiling region with label "//trim(label)//
" found."
621 message(2) =
" This is likely caused by a missing or incorrect profiling_in call."
626 select type(this => profile_p)
628 assert(this%initialized)
630 this%active = .false.
633 time_spent = now - this%entry_time
634 this%total_time = this%total_time + time_spent
635 this%self_time = this%self_time + time_spent
636 this%count = this%count + 1
637 if (time_spent < this%min_time)
then
638 this%min_time = time_spent
641 this%op_count = this%op_count + this%op_count_current
642 this%tr_count = this%tr_count + this%tr_count_current
643 this%op_count_child = this%op_count_child + this%op_count_child_current
644 this%tr_count_child = this%tr_count_child + this%tr_count_child_current
646 if (
associated(this%parent))
then
648 this%parent%self_time = this%parent%self_time - time_spent
649 if (this%exclude) this%parent%total_time = this%parent%total_time - time_spent
652 this%parent%op_count_child_current = this%parent%op_count_child_current &
653 + this%op_count_current + this%op_count_child_current
654 this%parent%tr_count_child_current = this%parent%tr_count_child_current &
655 + this%tr_count_current + this%tr_count_child_current
657 this%parent%timings(this%index) = this%parent%timings(this%index) + time_spent
667 if (this%likwid)
call likwid_markerstopregion(trim(this%label))
671#if defined(HAVE_NVTX) || (defined(HAVE_HIP) && defined(__HIP_PLATFORM_AMD__))
681 integer,
intent(in) :: ops
686 prof_vars%current%p%op_count_current =
prof_vars%current%p%op_count_current + real(ops, real64)
693 real(4),
intent(in) :: ops
698 prof_vars%current%p%op_count_current =
prof_vars%current%p%op_count_current + real(ops, real64)
705 real(real64),
intent(in) :: ops
718 integer(int64),
intent(in) :: trf
719 integer,
intent(in) :: type
724 prof_vars%current%p%tr_count_current =
prof_vars%current%p%tr_count_current + 4*real(trf, real64)
731 integer(int64),
intent(in) :: trf
732 integer(int64),
intent(in) :: type
737 prof_vars%current%p%tr_count_current =
prof_vars%current%p%tr_count_current + 8*real(trf, real64)
744 integer(int64),
intent(in) :: trf
745 real(4),
intent(in) :: type
750 prof_vars%current%p%tr_count_current =
prof_vars%current%p%tr_count_current + 4*real(trf, real64)
758 integer(int64),
intent(in) :: trf
759 real(real64),
intent(in) :: type
764 prof_vars%current%p%tr_count_current =
prof_vars%current%p%tr_count_current + 8*real(trf, real64)
772 integer(int64),
intent(in) :: trf
773 complex(4),
intent(in) :: type
786 integer(int64),
intent(in) :: trf
787 complex(real64),
intent(in) :: type
792 prof_vars%current%p%tr_count_current =
prof_vars%current%p%tr_count_current + 16*real(trf, real64)
800 integer(int64),
intent(in) :: trf
801 type(
type_t),
intent(in) :: type
814 integer,
intent(in) :: trf
815 integer,
intent(in) :: type
820 prof_vars%current%p%tr_count_current =
prof_vars%current%p%tr_count_current + 4*real(trf, real64)
827 integer,
intent(in) :: trf
828 integer(int64),
intent(in) :: type
833 prof_vars%current%p%tr_count_current =
prof_vars%current%p%tr_count_current + 8*real(trf, real64)
840 integer,
intent(in) :: trf
841 real(4),
intent(in) :: type
854 integer,
intent(in) :: trf
855 real(real64),
intent(in) :: type
868 integer,
intent(in) :: trf
869 complex(4),
intent(in) :: type
882 integer,
intent(in) :: trf
883 complex(real64),
intent(in) :: type
888 prof_vars%current%p%tr_count_current =
prof_vars%current%p%tr_count_current + 16*real(trf, real64)
896 integer,
intent(in) :: trf
897 type(
type_t),
intent(in) :: type
907 real(real64) function profile_total_time(this)
910 push_sub(profile_total_time)
911 profile_total_time = this%total_time
913 pop_sub(profile_total_time)
918 real(real64) function profile_self_time(this)
929 real(real64) function profile_total_time_per_call(this)
940 real(real64) function profile_min_time(this)
951 real(real64) function profile_self_time_per_call(this)
962 real(real64) function profile_total_throughput(this)
965 push_sub(profile_throughput)
967 if (this%total_time > epsilon(this%total_time))
then
973 pop_sub(profile_throughput)
982 push_sub(profile_bandwidth)
984 if (this%total_time > epsilon(this%total_time))
then
990 pop_sub(profile_bandwidth)
998 push_sub(profile_throughput)
1000 if (this%self_time > epsilon(this%self_time))
then
1006 pop_sub(profile_throughput)
1014 push_sub(profile_bandwidth)
1016 if (this%self_time > epsilon(this%self_time))
then
1022 pop_sub(profile_bandwidth)
1056 type(namespace_t),
intent(in) :: namespace
1060 real(real64) :: total_time
1062 character(len=256) :: filename
1063 real(real64),
allocatable :: selftime(:)
1064 integer,
allocatable :: position(:)
1065 class(*),
pointer :: profile_p
1068 if (.not. in_profiling_mode)
return
1071 call mpi_world%barrier()
1073 if (.not.
prof_vars%all_nodes .and. .not. mpi_world%is_root())
then
1079 iunit = io_open(trim(filename), namespace, action=
'write', die=.false.)
1080 if (iunit == -1)
then
1081 message(1) =
'Failed to open file ' // trim(filename) //
' to write profiling results.'
1082 call messages_warning(1)
1087 write(iunit,
'(2a)') &
1088 ' CUMULATIVE TIME ', &
1090 write(iunit,
'(2a)') &
1091 ' ----------------------------------------------------------', &
1092 '----------------|-------------------------------------------------------------'
1093 write(iunit,
'(2a)') &
1094 'TAG NUM_CALLS TOTAL_TIME TIME_PER_CALL MIN_TIME ', &
1095 ' MFLOPS MBYTES/S %TIME | TOTAL_TIME TIME_PER_CALL MFLOPS MBYTES/S %TIME'
1096 write(iunit,
'(2a)') &
1097 '===================================================================================================', &
1098 '=================|============================================================='
1100 profile_p => sphash_lookup(
profiling_map,
"COMPLETE_RUN", found)
1102 select type(complete_run => profile_p)
1107 safe_allocate(selftime(1:
prof_vars%last_profile))
1108 safe_allocate(position(1:
prof_vars%last_profile))
1115 call sort(selftime, position)
1118 prof =>
prof_vars%profile_list(position(ii))%p
1119 if (.not. prof%initialized)
then
1120 write(message(1),
'(a,i6,a)')
"Internal error: Profile number ", position(ii),
" is not initialized."
1121 call messages_fatal(1)
1123 if (prof%active)
then
1124 write(message(1),
'(a)')
"Internal error: Profile '" // trim(
profile_label(prof)) // &
1125 "' is active, i.e. profiling_out was not called."
1126 call messages_warning(1)
1131 write(iunit,
'(a,i14,3f16.6,2f10.1,f8.1,a,2f16.6,2f10.1,f8.1)') &
1148 call io_close(iunit)
1152 iunit = io_open(trim(filename), namespace, action=
'write', die=.false.)
1153 if (iunit == -1)
then
1154 message(1) =
'Failed to open file ' // trim(filename) //
' to write profiling results.'
1155 call messages_warning(1)
1159 write(iunit,
'(2a)')
'schema: [num_calls, total_time, total_throughput, ', &
1160 'total_bandwidth, self_time, self_throughput, self_bandwidth]'
1161 write(iunit,
'(a)')
'data:'
1164 prof =>
prof_vars%profile_list(position(ii))%p
1166 write(iunit,
'(a,a,a,i6,a,e10.3,a,e10.3,a,e10.3,a,e10.3,a,e10.3,a,e10.3,a)') &
1177 call io_close(iunit)
1180 safe_deallocate_a(selftime)
1181 safe_deallocate_a(position)
1185 iunit = io_open(trim(filename), namespace, action=
'write', die=.false.)
1186 if (iunit == -1)
then
1187 message(1) =
'Failed to open file ' // trim(filename) //
' to write profiling results.'
1188 call messages_warning(1)
1192 write(iunit,
'(a40,a11,a11,a12)') &
1193 "Tree level, region ", &
1194 "% of total ",
"% of parent", &
1197 select type(complete_run => profile_p)
1200 write(iunit,
'(a,a25,a,f8.2,a,f8.2,a,f12.4)') &
1201 repeat(
'-', 0) //
'| ', &
1203 repeat(
' ', 15-0-2), &
1209 write(iunit,
'(a)')
"// modeline for vim to enable folding (put in ~/.vimrc: set modeline modelineexpr)"
1210 write(iunit,
'(a)')
"// vim: fdm=expr fde=getline(v\:lnum)=~'.*\|.*'?len(split(getline(v\:lnum))[0])-1\:0"
1211 call io_close(iunit)
1219 integer,
intent(in) :: level
1220 real(real64),
intent(in) :: total_time
1221 integer,
intent(in) :: iunit
1223 integer :: ichild, width
1229 if (profile%has_child(ichild))
then
1232 write(iunit,
'(a,a25,a,f8.2,a,f8.2,a,f12.4)') &
1233 repeat(
'-', level) //
'| ', &
1235 repeat(
' ', width-level-2), &
1236 profile%timings(ichild)/total_time * 100,
"% ", &
1237 profile%timings(ichild)/profile%total_time * 100,
"% ", &
1238 profile%timings(ichild)
1240 level+1, total_time, iunit)
1250 character(len=*),
intent(in) :: var
1251 character(len=*),
intent(in) :: file
1252 integer,
intent(in) :: line
1253 character(len=*),
intent(out) :: str
1255 integer :: ii, jj, nn
1260 if (var(jj:jj) ==
')')
then
1262 do ii = len(var)-1, 1, -1
1264 if (var(ii:ii) ==
')') nn = nn + 1
1265 if (var(ii:ii) ==
'(') nn = nn - 1
1269 message(1) =
"Internal Error in profiling_memory_log"
1270 call messages_fatal(1)
1273 ii = index(file,
'/', back=.
true.)+1
1275 write(str,
'(4a,i5,a)') var(1:jj),
"(", trim(file(ii:len(file))),
":", line,
")"
1283 character(len=*),
intent(in) :: type
1284 character(len=*),
intent(in) :: var
1285 character(len=*),
intent(in) :: file
1286 integer,
intent(in) :: line
1287 integer(int64),
intent(in) :: size
1289 character(len=256) :: str
1290 integer(int64) :: mem
1297 mem = loct_get_memory_usage()
1299 write(
prof_vars%mem_iunit,
'(f16.6,a16,3i16,a70)') loct_clock() -
prof_vars%start_time, &
1300 trim(type),
size,
prof_vars%total_memory, mem, trim(str)
1307 character(len=*),
intent(in) :: var
1308 character(len=*),
intent(in) :: file
1309 integer,
intent(in) :: line
1310 integer(int64),
intent(in) :: size_
1313 integer(int64) :: size
1314 character(len=256) :: str
1329 message(1) =
"Memory limit set in the input file was passed"
1330 call messages_fatal(1)
1344 if (
size >
prof_vars%large_vars_size(ii))
then
1361 if (
size >
prof_vars%large_vars_size(ii))
then
1378 character(len=*),
intent(in) :: var
1379 character(len=*),
intent(in) :: file
1380 integer,
intent(in) :: line
1381 integer(int64),
intent(in) :: size
1400 character(len=1),
intent(in) :: c_in
1401 character(len=1) :: c_out
1403 integer,
parameter :: difference=iachar(
'a')-iachar(
'A'), la=iachar(
'a'), lz=iachar(
'z')
1404 integer :: ascii_decimal
1407 ascii_decimal = iachar(c_in)
1408 if (ascii_decimal >= la .and. ascii_decimal <= lz)
then
1409 ascii_decimal = ascii_decimal - difference
1411 c_out = achar(ascii_decimal)
1415 pure function to_upper(string)
result(upper_string)
1416 character(len=*),
intent(in) :: string
1417 character(len=len(string)) :: upper_string
1422 do i = 1, len(string)
if write to the Free Software Franklin Fifth USA !If the compiler accepts long Fortran it is better to use that and build all the preprocessor definitions in one line In !this the debuggers will provide the right line numbers !If the compiler accepts line number then CARDINAL and ACARDINAL !will put them just a new line or a ampersand plus a new line !These macros should be used in macros that span several lines They should by !put immedialty before a line where a compilation error might occur and at the !end of the macro !Note that the cardinal and newline words are substituted by the program !preprocess pl by the ampersand and by a real new line just before compilation !The assertions are ignored if the code is compiled in not debug mode(NDEBUG ! is defined). Otherwise it is merely a logical assertion that
real(real64), parameter, public m_huge
real(real64), parameter, public m_zero
logical pure function, public not_in_openmp()
logical, public in_profiling_mode
Same for profiling mode.
integer(int64), save io_open_count
subroutine, public io_close(iunit, grp)
integer(int64) pure function, public io_get_close_count()
integer(int64), save io_close_count
subroutine, public io_mkdir(fname, namespace, parents)
integer(int64) pure function, public io_get_open_count()
integer function, public io_open(file, namespace, action, status, form, position, die, recl, grp)
System information (time, memory, sysname)
character(kind=c_char, len=1) function, dimension(len_trim(f_string)+1), private string_f_to_c(f_string)
convert a Fortran string to a C string
subroutine, public messages_print_with_emphasis(msg, iunit, namespace)
character(len=512), private msg
subroutine, public messages_warning(no_lines, all_nodes, namespace)
character(len=256), dimension(max_lines), public message
to be output by fatal, warning
subroutine, public messages_fatal(no_lines, only_root_writes, namespace)
subroutine, public messages_input_error(namespace, var, details, row, column)
subroutine, public messages_info(no_lines, iunit, debug_only, stress, all_nodes, namespace)
real(real64) function, public mpi_get_wtime()
. Returns an elapsed time on the calling processor.
type(mpi_grp_t), public mpi_world
subroutine, public parse_block_string(blk, l, c, res, convert_to_c)
integer function, public parse_block(namespace, name, blk, check_varinfo_)
subroutine profiling_count_tran_int(trf, type)
subroutine profiling_count_tran_int_8_l(trf, type)
subroutine, public profiling_end(namespace)
type(profile_vars_t), target, save, public prof_vars
real(real64) function profile_self_bandwidth(this)
real(real64) function profile_self_time(this)
pure character(len=1) function char_to_upper(c_in)
integer, parameter max_memory_vars
subroutine iprofiling_count_operations(ops)
integer, parameter, public profiling_memory
subroutine profiling_memory_log(type, var, file, line, size)
integer, parameter, public profiling_likwid
subroutine profiling_output(namespace)
Write profiling results of each node to profiling.NNN/profiling.nnn The format of each line is tag-la...
integer, parameter, public profiling_memory_full
subroutine profiling_count_tran_real_8(trf, type)
subroutine, public profiling_out(label)
Increment out counter and sum up difference between entry and exit time.
subroutine profiling_count_tran_real_8_l(trf, type)
subroutine profiling_count_tran_int_8(trf, type)
subroutine rprofiling_count_operations(ops)
integer, parameter, public profiling_io
real(real64) function profile_self_throughput(this)
subroutine profiling_count_tran_complex_8_l(trf, type)
subroutine profile_init(this, label)
Initialize a profile object and add it to the list.
subroutine, public profiling_in(label, exclude)
Increment in counter and save entry time.
real(real64) function profile_total_throughput(this)
subroutine, public profiling_init(namespace)
Create profiling subdirectory.
subroutine profiling_count_tran_real_4_l(trf, type)
subroutine dprofiling_count_operations(ops)
pure character(len=len(string)) function to_upper(string)
real(real64) function profile_total_time_per_call(this)
integer, parameter max_profiles
Max. number of tags.
subroutine profiling_count_tran_int_l(trf, type)
subroutine profiling_count_tran_complex_4_l(trf, type)
subroutine profiling_count_tran_real_4(trf, type)
type(sphash_t), save profiling_map
integer function profile_num_calls(this)
subroutine profiling_count_tran_type(trf, type)
real(real64) function profile_min_time(this)
subroutine, public profiling_memory_deallocate(var, file, line, size)
character(label_length) function profile_label(this)
real(real64) function profile_self_time_per_call(this)
subroutine, public profiling_memory_allocate(var, file, line, size_)
subroutine profiling_count_tran_type_l(trf, type)
subroutine profiling_make_position_str(var, file, line, str)
subroutine profiling_count_tran_complex_8(trf, type)
subroutine profiling_count_tran_complex_4(trf, type)
real(real64) function profile_total_bandwidth(this)
real(real64) function profile_total_time(this)
This module is intended to contain "only mathematical" functions and procedures.
This module implements a simple hash table for string valued keys and integer values using the C++ ST...
subroutine, public sphash_init(h)
Initialize a hash table h with size entries. Since we use separate chaining, the number of entries in...
subroutine, public sphash_insert(h, key, val, clone)
Insert a (key, val) pair into the hash table h. If clone=.true., the object will be copied.
subroutine, public sphash_end(h)
Free a hash table.
class(*) function, pointer, public sphash_lookup(h, key, found)
Look up a value in the hash table h. If found is present, it indicates if key could be found in the t...
integer pure function, public types_get_size(this)
subroutine get_output_dir()
recursive subroutine output_tree_level(profile, level, total_time, iunit)