From d76999710b6bbe378c7bb552a0baf86d685020b6 Mon Sep 17 00:00:00 2001 From: LKedward Date: Wed, 8 Jul 2020 14:47:55 +0100 Subject: [PATCH 1/5] Add: Fortran hex_string subroutine Replaces an inefficient internal write statement that was skewing the parse_int benchmark results. --- perf.f90 | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/perf.f90 b/perf.f90 index 1661cb7..ca0d33b 100644 --- a/perf.f90 +++ b/perf.f90 @@ -13,7 +13,7 @@ module utils implicit none private public trace, mean, std, init_random_seed, randn, assert, stop_error, & - sysclock2ms + sysclock2ms, hex_string contains @@ -143,6 +143,44 @@ function sysclock2ms(t) sysclock2ms = t * r end function sysclock2ms +! Convert an integer to a hex string +! +subroutine hex_string(dec,hexchar) + integer, intent(in) :: dec + character(*) :: hexchar + character(len(hexchar)) :: tempchar + + integer :: i + integer :: quotient, remainder + + character(len=1), parameter :: table(0:16) = & + [(char(i),i=48,57),(char(i),i=65,71)] + + quotient = dec + + hexchar(:) = ' ' + tempchar(:) = ' ' + + i = 1 + do while (quotient /= 0 .and. i <= len(hexchar)) + + remainder = modulo(quotient,16) + + tempchar(i:i) = table(remainder) + i = i+1 + + quotient = quotient/16 + + end do + + do i=1,len_trim(tempchar) + + hexchar(i:i) = tempchar(len_trim(tempchar)-i+1:len_trim(tempchar)-i+1) + + end do + +end subroutine hex_string + end module @@ -324,7 +362,7 @@ subroutine randmatmul(n, C) program perf use types, only: dp, i64 -use utils, only: assert, init_random_seed, sysclock2ms +use utils, only: assert, init_random_seed, sysclock2ms, hex_string use bench, only: fib, parse_int, printfd, quicksort, mandelperf, pisum, randmatstat, & randmatmul implicit none @@ -357,7 +395,7 @@ program perf do k = 1, 1000 call random_number(s1) n = int(s1*huge(n)) - write(s, '(z0)') n + call hex_string(n,s) m = parse_int(s(:len_trim(s)), 16) call assert(m == n) end do From 7f36466aeeca2bdeb4fb7a3f83874338d93ef88e Mon Sep 17 00:00:00 2001 From: LKedward Date: Wed, 8 Jul 2020 14:49:01 +0100 Subject: [PATCH 2/5] Update: Fortran parse_int with static table Replaces inefficient branching logic with a static lookup table. --- perf.f90 | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/perf.f90 b/perf.f90 index ca0d33b..c107baa 100644 --- a/perf.f90 +++ b/perf.f90 @@ -207,21 +207,23 @@ integer function parse_int(s, base) result(n) character(len=*), intent(in) :: s integer, intent(in) :: base integer :: i, d -character :: c + +integer, parameter :: table(0:127) = [integer::& +[(-1,i=1,48)], & +[(i,i=0,9)], & ! 0-9 +[(-1,i=1,7)], & +[(10+i,i=0,25)], & ! A-Z +[(-1,i=1,7)], & +[(10+i,i=0,25)], & ! a-z +[(-1,i=1,4)] & +] + n = 0 do i = 1, len(s) - c = s(i:i) - d = 0 - if (ichar(c) >= ichar('0') .and. ichar(c) <= ichar('9')) then - d = ichar(c) - ichar('0') - else if (ichar(c) >= ichar('A') .and. ichar(c) <= ichar('Z')) then - d = ichar(c) - ichar('A') + 10 - else if (ichar(c) >= ichar('a') .and. ichar(c) <= ichar('z')) then - d = ichar(c) - ichar('a') + 10 - else - call stop_error("parse_int 1") - end if + + d = table(iachar(s(i:i))) + if (d < 0 ) call stop_error("bench:parse_int - Illegal character in input") if (base <= d) call stop_error("parse_int 2") n = n*base + d end do From a393f0e9600c123938c8bbfaea19847d24dce585 Mon Sep 17 00:00:00 2001 From: LKedward Date: Thu, 9 Jul 2020 13:09:40 +0100 Subject: [PATCH 3/5] Revert "Update: Fortran parse_int with static table" This reverts commit 7f36466aeeca2bdeb4fb7a3f83874338d93ef88e. --- perf.f90 | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/perf.f90 b/perf.f90 index c107baa..ca0d33b 100644 --- a/perf.f90 +++ b/perf.f90 @@ -207,23 +207,21 @@ integer function parse_int(s, base) result(n) character(len=*), intent(in) :: s integer, intent(in) :: base integer :: i, d - -integer, parameter :: table(0:127) = [integer::& -[(-1,i=1,48)], & -[(i,i=0,9)], & ! 0-9 -[(-1,i=1,7)], & -[(10+i,i=0,25)], & ! A-Z -[(-1,i=1,7)], & -[(10+i,i=0,25)], & ! a-z -[(-1,i=1,4)] & -] - +character :: c n = 0 do i = 1, len(s) - - d = table(iachar(s(i:i))) + c = s(i:i) + d = 0 + if (ichar(c) >= ichar('0') .and. ichar(c) <= ichar('9')) then + d = ichar(c) - ichar('0') + else if (ichar(c) >= ichar('A') .and. ichar(c) <= ichar('Z')) then + d = ichar(c) - ichar('A') + 10 + else if (ichar(c) >= ichar('a') .and. ichar(c) <= ichar('z')) then + d = ichar(c) - ichar('a') + 10 + else + call stop_error("parse_int 1") + end if - if (d < 0 ) call stop_error("bench:parse_int - Illegal character in input") if (base <= d) call stop_error("parse_int 2") n = n*base + d end do From 7e011d948951890bba881d9f212f474541711ce8 Mon Sep 17 00:00:00 2001 From: LKedward Date: Thu, 9 Jul 2020 13:19:32 +0100 Subject: [PATCH 4/5] Remove magic numbers from fortran hex_string routine. Use explicit reference to character codes instead of hard-coded values. --- perf.f90 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/perf.f90 b/perf.f90 index ca0d33b..3acbba0 100644 --- a/perf.f90 +++ b/perf.f90 @@ -154,7 +154,7 @@ subroutine hex_string(dec,hexchar) integer :: quotient, remainder character(len=1), parameter :: table(0:16) = & - [(char(i),i=48,57),(char(i),i=65,71)] + [(char(i),i=ichar('0'),ichar('9')),(char(i),i=ichar('A'),ichar('G'))] quotient = dec From 4454e0f1d3ba8f4e8ba8aab55b2abac47ab834fb Mon Sep 17 00:00:00 2001 From: LKedward Date: Thu, 9 Jul 2020 13:46:25 +0100 Subject: [PATCH 5/5] Fix: off-by-one in fortran hex_string. --- perf.f90 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/perf.f90 b/perf.f90 index 3acbba0..a0af4d6 100644 --- a/perf.f90 +++ b/perf.f90 @@ -153,8 +153,8 @@ subroutine hex_string(dec,hexchar) integer :: i integer :: quotient, remainder - character(len=1), parameter :: table(0:16) = & - [(char(i),i=ichar('0'),ichar('9')),(char(i),i=ichar('A'),ichar('G'))] + character(len=1), parameter :: table(0:15) = & + [(char(i),i=ichar('0'),ichar('9')),(char(i),i=ichar('A'),ichar('F'))] quotient = dec