# Improving Fortran Results in the Julia Micro-benchmarks

**URL:** <https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198>\
**Category:** Help\
**Created:** [July 8, 2020, 2:39pm UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198 "2020-07-08T14:39:56Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![lkedward](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/lkedward/32/72_2.png) [@lkedward](https://fortran-lang.discourse.group/u/lkedward)\
**Post date:** [April 12, 2022, 8:08pm UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/23 "2022-04-12T20:08:12Z")

</div>

My improvements to this Fortran benchmark have now been merged into the Julia benchmarks repository and the benchmarks page has been updated.

> <https://github.com/JuliaLang/Microbenchmarks/pull/54>
>
> Replaces an inefficient internal write statement that was skewing the parse\_int …benchmark results.
> 
> Squash of #41 to run on benchmark ci
> 
> Closes #41

Edit: as pointed out by Milan, it looks like the online results page has not actually been updated yet.

---

<div class="post-metadata">

**Author:** ![milancurcic](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/milancurcic/32/2_2.png) [@milancurcic](https://fortran-lang.discourse.group/u/milancurcic)\
**Post date:** [April 12, 2022, 8:48pm UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/24 "2022-04-12T20:48:45Z")

</div>

Great work, @lkedward! I suppose the update will eventually propagate to the [plot on the Julia website](https://julialang.org/benchmarks/) (I don’t think it has yet)?

---

<div class="post-metadata">

**Author:** ![jacobwilliams](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/jacobwilliams/32/10_2.png) [@jacobwilliams](https://fortran-lang.discourse.group/u/jacobwilliams)\
**Post date:** [April 12, 2022, 8:54pm UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/25 "2022-04-12T20:54:03Z")

</div>

Very disturbing… Fortran faster than Julia? What?? 😄

---

<div class="post-metadata">

**Author:** ![urbanjost](https://avatars.discourse-cdn.com/v4/letter/u/0ea827/32.png) [@urbanjost](https://fortran-lang.discourse.group/u/urbanjost)\
**Post date:** [April 13, 2022, 4:41am UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/26 "2022-04-13T04:41:51Z")

</div>

I need the functionality for a very low-volume niche need, so I am not sure if I ever timed them, but note there are several routines in M\_string (a registered fpm(1) package, so easy to access), some of which I do not even list in the man-pages that convert to and from anything from base 2 to base 36 using what I think is a classic algorithm:

```nohighlight
$@(#) M_strings::base(3f): convert whole number string in base [2-36] to string in alternate base [2-36]
$@(#) M_strings::decodebase(3f): convert whole number string in base [2-36] to base 10 number
$@(#) M_strings::codebase(3f): convert whole number in base 10 to string in base [2-36]
$@(#) M_strings::todecimal(3f): given string and base return decimal integer
$@(#) M_strings::todecimal(3f): given integer and base return string

```

that might be pertinent if looking to generalize base conversion for stdlib.

---

<div class="post-metadata">

**Author:** ![FortranFan](https://avatars.discourse-cdn.com/v4/letter/f/96bed5/32.png) [@FortranFan](https://fortran-lang.discourse.group/u/FortranFan)\
**Post date:** [April 30, 2022, 5:37pm UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/27 "2022-04-30T17:37:42Z")

</div>

It is interesting in this [**thread**](https://fortran-lang.discourse.group/t/why-is-my-code-compiled-with-gfortran-on-windows-slower-than-on-ubuntu/1666/30), @mecej4 writes:

> [@Why is my code compiled with GFortran on Windows slower than on Ubuntu?](https://fortran-lang.discourse.group/t/why-is-my-code-compiled-with-gfortran-on-windows-slower-than-on-ubuntu/1666/30):
>
> … Before joining this forum, I had barely heard of Julia. Some of the posts in fortran-lang.discourse named Julia as a threat to Fortran, so I searched and read some articles claiming that Julia was xxx times faster than Fortran, etc. I felt that the claims were not credible, and wanted to give Julia a test-drive. I downloaded the 1.7.2 distribution for Windows, and ran a few examples of nonlinear regression.
> 
> The Fortran version compiles and links in ~ 2 seconds, and the run takes less than a second. A second run of the EXE takes 0.04 s, since the DLLs are now cached. The Julia version took 25 seconds for the first run, of which 17 s were used to process the directive **using PyPlot**. A second run while staying within the Julia REPL took 0.4 s. What disappointed me was the inability to compile stable source code into object files, EXEs and libraries and the huge startup time for running any Julia program unless one stays inside the REPL.

I had a very similar experience a couple of years ago when this thread by @lkedward first caught my attention. I do feel good to know I am not the only one who came away with the same impression as @mecej4 on Julia.

I was aware of Julia as a possibly leading contender in the near future in the HPC domain but had not looked into it until this thread surfaced here.

In addition to the comments by @mecej4 , I felt many of the claims among the Julia crowd were based on the microbenchmarks that were setup by the ardent users of Julia. But so many of those microbenchmarks were highly questionable in my opinion, especially when it came to other languages used in their comparisons. Honestly, the codes used in the microbenchmarks are poorer than beginner level.

I personally don’t think [**code**](https://github.com/JuliaLang/Microbenchmarks/blob/master/perf.f90) such as the following to reveal anything useful, let alone be a measure for anything. But this is what the Julia folks use to claim that their “parse integers” test shows Julia faster than Fortran:

```fortran
    call system_clock(t1)
    do k2 = 1, NRUNS
        do k = 1, 1000
            call random_number(s1)
            n = int(s1*huge(n))
            call hex_string(n,s)
            m = parse_int(s(:len_trim(s)), 16)
            call assert(m == n)
        end do
    end do
    call system_clock(t2)

```

---

<div class="post-metadata">

**Author:** ![mecej4](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/mecej4/32/855_2.png) [@mecej4](https://fortran-lang.discourse.group/u/mecej4)\
**Post date:** [June 5, 2022, 10:24am UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/28 "2022-06-05T10:24:38Z")

</div>

The hex\_string subroutine in [perf.f90](https://github.com/JuliaLang/Microbenchmarks/blob/master/perf.f90) generates a hex representation of a 32-bit integer. The present implementation uses modulo() and integer divisions by 16 to generate the hex string, which is then used as the input for the parsing routine. The following replacement uses shifts and masks, instead, and on my PC reduced the parse\_integers microbenchmark time from 0.130 s to 0.047 s. I have offered this replacement code as an issue on the [Julia microbenchmarks Github](https://github.com/JuliaLang/Microbenchmarks/issues/67).

```auto
! Convert an integer to a hex string
!
subroutine hex_string(dec,hexchar)
  integer, intent(in) :: dec
  character(*) :: hexchar

  integer :: i, quotient

  character(len=1), parameter :: table(0:15) = &
  [(char(i),i=ichar('0'),ichar('9')),(char(i),i=ichar('A'),ichar('F'))]

  quotient = dec
  hexchar = '00000000'
  i = 8
  do while (quotient /= 0 .and. i > 0)
      hexchar(i:i) = table(iand(quotient,15))
      i = i-1
      quotient = ishft(quotient,-4)
  end do

end subroutine hex_string

```

---

<div class="post-metadata">

**Author:** ![PetrKryslUCSD](https://avatars.discourse-cdn.com/v4/letter/p/5f9b8f/32.png) [@PetrKryslUCSD](https://fortran-lang.discourse.group/u/PetrKryslUCSD)\
**Post date:** [June 6, 2022, 1:57pm UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/29 "2022-06-06T13:57:06Z")

</div>

The comparison of the benchmarks really makes sense only if all languages implement _the same_ algorithm. Otherwise we have comparison of apples and orangutans. Example: solving a system of equations with Gauss eliminations vs. Cramer’s rule.

---

<div class="post-metadata">

**Author:** ![mecej4](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/mecej4/32/855_2.png) [@mecej4](https://fortran-lang.discourse.group/u/mecej4)\
**Post date:** [June 6, 2022, 4:13pm UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/30 "2022-06-06T16:13:59Z")

</div>

I agree mostly, but we have to make allowances where one language does not provide means for implementing certain algorithms (for example, standard Fortran 77 did not provide bit manipulation intrinsics, but C did), and so workarounds have to be used and these may result in poor performance.

---

<div class="post-metadata">

**Author:** ![mecej4](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/mecej4/32/855_2.png) [@mecej4](https://fortran-lang.discourse.group/u/mecej4)\
**Post date:** [June 19, 2022, 9:21pm UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/31 "2022-06-19T21:21:16Z")

</div>

Thanks to @oscardssmith’s interest, initiative and help, these changes have been [accepted and merged](https://github.com/JuliaLang/Microbenchmarks/pull/68#issuecomment-1159461518) into the Julia microbenchmarks test suite. With these changes, Fortran is the fastest for the parse\_integer test among all the languages tested.

```auto
C 0.1635
Fortran 0.074126 (was 0.682692)
Go 0.097109
Java 0.275906
Julia 0.123103
Python 1.39308
Rust 0.155348

```

One should not put too much value on these timings, since the codes for the other languages can also benefit from similar changes. It is a quirk of the parse\_integer benchmark that the time for creating the test strings is included in the “parsing time” and, indeed, my improvements were confined to the lines of code for this preparatory task.

It is to be hoped that the [graph](https://julialang.org/benchmarks/) and [the CSV table](https://github.com/JuliaLang/Microbenchmarks/blob/a963d284b09d04b3e0374f6dd46ec4b039ed5569/bin/benchmarks.csv) will be updated soon to reflect this change.

---

<div class="post-metadata">

**Author:** ![CRquantum](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/crquantum/32/730_2.png) [@CRquantum](https://fortran-lang.discourse.group/u/CRquantum)\
**Post date:** [June 20, 2022, 5:37am UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/32 "2022-06-20T05:37:25Z")

</div>

My shallow opinion is that, believe it or not, it does not really matter what algorithms are used, because there will never really be (and no need to be) apple to apple comparisons.

Because at the end of the day, the real question is really extremely simple, that is,

To achieve the same result, what programming language is the fastest?

PS.

In your example, solving a system of equations, I personally think that, it does not matter one uses Gauss eliminations or Cramer’s rule or anything else. At the end, what really matters is just what language (it can use any algorithms it prefers) solves the system of equations the fastest. That is all.

I mean it is like soccer, in the World Cup, the goal is to win the World Cup. It does not matter what formation you use, 442, 343, 41212, 352, 532, …etc. It does not matter what strategy you used. You are the best if you are the champion.

---

<div class="post-metadata">

**Author:** ![fortran4r](https://avatars.discourse-cdn.com/v4/letter/f/9de0a6/32.png) [@fortran4r](https://fortran-lang.discourse.group/u/fortran4r)\
**Post date:** [June 21, 2022, 6:30am UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/33 "2022-06-21T06:30:39Z")

</div>

Why Fortran’s print\_to\_file is so slow in the Julia benchmark?

---

<div class="post-metadata">

**Author:** ![snano](https://avatars.discourse-cdn.com/v4/letter/s/fbc32d/32.png) [@snano](https://fortran-lang.discourse.group/u/snano)\
**Post date:** [June 21, 2022, 6:44am UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/34 "2022-06-21T06:44:58Z")

</div>

If you see in detail, the print\_to\_file is slow compared to many other counterparts such as c, go, jullia, lua, python, and rust. Really surprising.

---

<div class="post-metadata">

**Author:** ![mecej4](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/mecej4/32/855_2.png) [@mecej4](https://fortran-lang.discourse.group/u/mecej4)\
**Post date:** [June 21, 2022, 7:55am UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/35 "2022-06-21T07:55:20Z")

</div>

Try using different Fortran compilers and comparing. [Formatted writes have been noticeably slow](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78549) with some versions of Gfortran, especially on Windows.

---

<div class="post-metadata">

**Author:** ![snano](https://avatars.discourse-cdn.com/v4/letter/s/fbc32d/32.png) [@snano](https://fortran-lang.discourse.group/u/snano)\
**Post date:** [June 21, 2022, 8:21am UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/36 "2022-06-21T08:21:20Z")

</div>

the print\_to\_file uses the following Fortran file :  
(link:[Microbenchmarks/perf.f90 at a963d284b09d04b3e0374f6dd46ec4b039ed5569 · JuliaLang/Microbenchmarks · GitHub](https://github.com/JuliaLang/Microbenchmarks/blob/a963d284b09d04b3e0374f6dd46ec4b039ed5569/perf.f90#L231)):

```auto

subroutine printfd(n)
integer, intent(in) :: n
integer :: i , unit
open(unit=1, file="/dev/null")
do i = 1, n
    write(unit=1, fmt=*) i, i+1
end do
close(unit=1)
end subroutine

```

---

<div class="post-metadata">

**Author:** ![mecej4](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/mecej4/32/855_2.png) [@mecej4](https://fortran-lang.discourse.group/u/mecej4)\
**Post date:** [June 21, 2022, 8:36am UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/37 "2022-06-21T08:36:43Z")

</div>

For list-directed output of real type list items, the processor supplies its own values for w, d and e in Fw.d, Ew.dEe, etc. The format conversion has to be performed, nevertheless.

Your use of he phrase “free format” in the context of output rather than Fortran source code format can be a source of confusion.

---

<div class="post-metadata">

**Author:** ![snano](https://avatars.discourse-cdn.com/v4/letter/s/fbc32d/32.png) [@snano](https://fortran-lang.discourse.group/u/snano)\
**Post date:** [June 21, 2022, 8:50am UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/38 "2022-06-21T08:50:22Z")

</div>

Yes, I agree. The w,d, and e are provided by the processor itself and not by the user. I will update the my previous reply.

---

<div class="post-metadata">

**Author:** ![zoziha](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/zoziha/32/582_2.png) [@zoziha](https://fortran-lang.discourse.group/u/zoziha)\
**Post date:** [June 21, 2022, 2:26pm UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/39 "2022-06-21T14:26:53Z")

</div>

In addition to the topic of `print_to_file`, in the topic of `matrix_statistics`, I found that the `scale` function is used in that code ([`rnorm` function](https://github.com/JuliaLang/Microbenchmarks/blob/2f81eea6b6999e2480d42f8bde77a46b3c4b80e8/perf.f90#L82)):

```fortran
DO
    CALL RANDOM_NUMBER( u )
    CALL RANDOM_NUMBER( v )
    u = SCALE( u, 1 ) - one
    v = SCALE( v, 1 ) - one
    sum = u*u + v*v + vsmall ! vsmall added to prevent LOG(zero) / zero
    IF(sum < one) EXIT
  END DO
  sln = SQRT(- SCALE( LOG(sum), 1 ) / sum)
  fn_val = u*sln

```

As far as I know, simply using `2*u` to replace the code like `scale(u, 1)` can be ~~much~~ (a bit) faster:

```fortran
DO
    CALL RANDOM_NUMBER( u )
    CALL RANDOM_NUMBER( v )
    u = 2*u - one
    v = 2*v - one
    sum = u*u + v*v + vsmall ! vsmall added to prevent LOG(zero) / zero
    IF(sum < one) EXIT
  END DO
  sln = SQRT(- 2*LOG(sum) / sum)
  fn_val = u*sln

```

~~Simple example (Incorrect)~~:

> **Summary**
>
> ```fortran
> program main
> 
> real(8) :: t1, t2, x, y
> integer, parameter :: N = 100000000
> 
> print *, "x = ", x, "; y = ", y
> 
> call cpu_time(t1)
> do i = 1, N
> x = 2*y + i
> end do
> call cpu_time(t2)
> print *, "time for N = ", N, ", x = 2*y : ", t2 - t1, " s; x = ", x
> 
> call cpu_time(t1)
> do i = 1, N
> x = scale(y, 1) + i
> end do
> call cpu_time(t2)
> print *, "time for N = ", N, ", x = scale(y, 1): ", t2 - t1, " s; x = ", x
> 
> end program main
> 
> ```
> 
> Results:  
> (Compiler optimization options are not used, because with optimization, Fortran runs too fast, and the running time is 0)
> 
> ```auto
> # On WSL2-Debian gfortran 10.3
> >> gfortran main.f90 && ./a.out
> x = 9.8813129168249309E-324 ; y = 2.0000000000000000     
> time for N = 100000000 , x = 2*y : 0.16183899999999998 s; x = 100000004.00000000     
> time for N = 100000000 , x = scale(y, 1): 0.72182100000000005 s; x = 100000004.00000000
> # On MSYS2-ucrt64-gfortran 12.1
> >> gfortran main.f90 && ./a
> x = 6.9530460433855700E-310 ; y = 2.0000000000000000     
> time for N = 100000000 , x = 2*y : 0.15625000000000000 s; x = 100000004.00000000     
> time for N = 100000000 , x = scale(y, 1): 0.60937500000000000 s; x = 100000004.00000000  
> # Windows10-ifort 2021.6.0
> >> ifort main.f90 && ./main
> x = 0.000000000000000E+000 ; y = 2.00000000000000     
> time for N = 100000000 , x = 2*y : 0.000000000000000E+000 s; x =
> 100000004.000000
> time for N = 100000000 , x = scale(y, 1): 3.125000000000000E-002 s; x = 
> 100000004.000000
> 
> ```

Modified example:

```fortran
program main

    real(8) :: t1, t2, x, y = 2.0
    integer, parameter :: N = 100000000

    call cpu_time(t1)
    do i = 1, N
        call random_number(y)
        x = 2*y
    end do
    call cpu_time(t2)
    print *, "time for N = ", N, ", x = 2*y : ", t2 - t1, " s; x = ", x

    call cpu_time(t1)
    do i = 1, N
        call random_number(y)
        x = scale(y, 1)
    end do
    call cpu_time(t2)
    print *, "time for N = ", N, ", x = scale(y, 1): ", t2 - t1, " s; x = ", x

end program main

```

Results:

```nohighlight
# WSL2-Debian gfortran 10.3
>> gfortran -Ofast main.f90 && ./a
 time for N = 100000000 , x = 2*y : 0.78022399999999992 s; x = 1.1880948469991348     
 time for N = 100000000 , x = scale(y, 1): 1.4326160000000001 s; x = 1.6401134682038268
# MSYS2-ucrt64-gfortran 12.1
>> gfortran -Ofast main.f90 && ./a
 time for N = 100000000 , x = 2*y : 2.5156250000000000 s; x = 1.1728265567290517     
 time for N = 100000000 , x = scale(y, 1): 3.0625000000000000 s; x = 1.5269402525788756
# On Windows-ifort 2021.6.0
>> ifort /fast main.f90 && ./main
 time for N = 100000000 , x = 2*y : 0.437500000000000 s; x = 
   1.03704569309432
 time for N = 100000000 , x = scale(y, 1): 0.625000000000000 s; x = 
   1.14890448267426 

```

---

<div class="post-metadata">

**Author:** ![mecej4](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/mecej4/32/855_2.png) [@mecej4](https://fortran-lang.discourse.group/u/mecej4)\
**Post date:** [June 21, 2022, 8:35pm UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/40 "2022-06-21T20:35:59Z")

</div>

Whether you request optimization or not, the compiler may determine that an expression that is to be output may be calculated entirely at compile time, store that value in the EXE/a.out, and simply output that previously computed value.

Obviously, the result of the first loop is N+4, and it appears that the Intel compiler did not have to place code in the executable to calculate that result (elapsed time = 0).

We have seen an [extreme example](https://fortran-lang.discourse.group/t/computing-at-compile-time/3044/32) of such compile time calculation in a recent thread.

---

<div class="post-metadata">

**Author:** ![zoziha](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/zoziha/32/582_2.png) [@zoziha](https://fortran-lang.discourse.group/u/zoziha)\
**Post date:** [June 22, 2022, 1:50am UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/41 "2022-06-22T01:50:33Z")

</div>

You’re right, I modified the above example to use random numbers to avoid compiler compile-time optimizations, I don’t know if this really works.

All in all, I think `scale(u, 1)` is still slower than `2*u`, maybe not that significant.

---

<div class="post-metadata">

**Author:** ![Ali](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/ali/32/751_2.png) [@Ali](https://fortran-lang.discourse.group/u/Ali)\
**Post date:** [June 23, 2022, 6:29am UTC](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198/43 "2022-06-23T06:29:43Z")

</div>

To the topic `print_to_file`:

The use of implied DO-loops leads to a better performance: `fortran,print_to_file,8.043278`.  
However, the output will be transposed.

```auto
subroutine printfd(n)
integer, intent(in) :: n
integer :: i , unit
open(unit=1, file="/dev/null")
write(unit=1,fmt=*) (i,i=1,n)
write(unit=1,fmt=*) (i,i=2,n+1)
close(unit=1)
end subroutine

```

Previous version: `fortran,print_to_file,23.939606`

```auto
subroutine printfd(n)
integer, intent(in) :: n
integer :: i , unit
open(unit=1, file="/dev/null")
do i = 1, n
    write(unit=1,fmt=*) i, i+1
end do
close(unit=1)
end subroutine

```

[Previous page](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198.md?page=1)

[Next page](https://fortran-lang.discourse.group/t/improving-fortran-results-in-the-julia-micro-benchmarks/198.md?page=3)
