Section Arrays: Normalize Performance#
Adapted from: gjbex/Fortran-MOOC
This program tests the performance of various methods of performing matrix normalization in Fortran.#
program normalize_performance
use, intrinsic :: iso_fortran_env, only : error_unit, DP => REAL64
implicit none
integer :: matrix_size
real(kind=DP), dimension(:, :), allocatable :: matrix
real(kind=DP) :: row_norm
integer :: row, col, istat
real :: start_time, end_time
call get_arguments(matrix_size)
allocate (matrix(matrix_size, matrix_size), stat=istat)
! reinitialize the matrix to avoid cache effects
call random_number(matrix)
call cpu_time(start_time)
do row = 1, size(matrix, 1)
matrix(row, :) = matrix(row, :)/sum(matrix(row, :))
end do
call cpu_time(end_time)
print '(A, F10.6)', 'row-wise norm: ', end_time - start_time
if (.not. is_normed(matrix, abs_tol=1e-4_DP)) then
write (unit=error_unit, fmt='(A)') 'error: array is not normalized (row-wise)'
end if
! reinitialize the matrix to avoid cache effects
call random_number(matrix)
call cpu_time(start_time)
do concurrent (row = 1:size(matrix, 1))
row_norm = 1.0_DP/sum(matrix(row, :))
do concurrent (col = 1:size(matrix, 2))
matrix(row, col) = matrix(row, col)*row_norm
end do
end do
call cpu_time(end_time)
print '(A, F10.6)', 'do concurrent row-wise norm: ', end_time - start_time
if (.not. is_normed(matrix, abs_tol=1e-4_DP)) then
write (unit=error_unit, fmt='(A)') 'error: array is not normalized (row-wise)'
end if
! initialize the matrix
call random_number(matrix)
call cpu_time(start_time)
matrix = matrix/spread(sum(matrix, dim=2), 2, size(matrix, 2))
call cpu_time(end_time)
print '(A, F10.6)', 'norm using spread: ', end_time - start_time
if (.not. is_normed(matrix, abs_tol=1e-4_DP)) then
write (unit=error_unit, fmt='(A)') 'error: array is not normalized (spread)'
end if
deallocate (matrix)
contains
subroutine get_arguments(matrix_size)
implicit none
integer, intent(out) :: matrix_size
character(len=1024) :: buffer, msg
integer :: istat
if (command_argument_count() /= 1) then
write (unit=error_unit, fmt='(A)') 'error: expect matrix size as argument'
stop 1
end if
call get_command_argument(1, buffer)
read (buffer, fmt=*, iostat=istat, iomsg=msg) matrix_size
if (istat /= 0) then
write (unit=error_unit, fmt='(2A)') 'error: ', trim(msg)
stop 2
end if
end subroutine get_arguments
function is_normed(matrix, abs_tol) result(is_okay)
implicit none
real(kind=DP), dimension(:, :), intent(in) :: matrix
real(kind=DP), value :: abs_tol
logical :: is_okay
is_okay = all(sum(matrix, dim=2) - 1.0_DP < abs_tol)
end function is_normed
end program normalize_performance
The above program is compiled and run using Fortran Package Manager (fpm):
Build the Program using FPM (Fortran Package Manager)#
import os
root_dir = os.getcwd()
code_dir = root_dir + "/" + "Fortran_Code/Section_Arrays_Normalize_Performance"
os.chdir(code_dir)
build_status = os.system("fpm build 2>/dev/null")
Run the Program using FPM (Fortran Package Manager)#
exec_status = os.system("fpm run -- 10 2>/dev/null")
row-wise norm: 0.000001
do concurrent row-wise norm: 0.000014
norm using spread: 0.000005
exec_status = os.system("fpm run -- 100 2>/dev/null")
row-wise norm: 0.000020
do concurrent row-wise norm: 0.000033
norm using spread: 0.000098
exec_status = os.system("fpm run -- 1000 2>/dev/null")
row-wise norm: 0.002346
do concurrent row-wise norm: 0.009614
norm using spread: 0.009550
exec_status = os.system("fpm run -- 10000 2>/dev/null")
row-wise norm: 2.120497
do concurrent row-wise norm: 2.002749
norm using spread: 3.190369