For Loop optimisation in Julia

I am familiarizing myself with programming languages.

Came across a video “Go vs BUN and Node speed test”

Tried to perform the speed comparison betwen Node.js, Bun and Julia.

For some reason For Loop in Julia turned out to be slower then in Node.js and Bun.

Code for Node.js and Bun:

console.time("test");

for (var i = 0; i < 1000000; ++i) console.log(i);

console.timeEnd("test");

Code for Julia:

i = 0

@time while i < 1000000
  println(i)
  global i += 1
end

(In ~/.profile specified “export JULIA_NUM_THREADS=4”.)

Results:

Node.js

  1. 14.409s
  2. 14.709s
  3. 14.709s

Bun

  1. 6.44s
  2. 6.75s
  3. 6.78s

Julia

  1. 19.546201 seconds (9.10 M allocations: 269.540 MiB, 0.19% gc time, 0.14% compilation time)
  2. 19.605892 seconds (9.08 M allocations: 268.285 MiB, 0.15% gc time)
  3. 20.677104 seconds (9.08 M allocations: 268.285 MiB, 0.49% gc time)

Without “export JULIA_NUM_THREADS=4” speed also slow.

How to improve results in Julia?
Thanks.

Julia is moderately bad at dealing with global variables: Performance Tips · The Julia Language. The solution is to not use a global variable and put the code inside a function. With

function main()
    i = 0
    while i < 1000000
        println(i)
        i += 1
    end
    return i
end

@time main()

I get

  8.606004 seconds (8.10 M allocations: 253.779 MiB, 0.43% gc time, 0.28% compilation time)

However with Julia v1.8 it’s possible to get non-horribly-slow global variables by type-annotating them. Now, with

i::Int = 0

@time while i < 1000000
  println(i)
  global i += 1
end

I get

  8.125404 seconds (9.09 M allocations: 261.307 MiB, 0.48% gc time, 0.46% compilation time)

And if you remove side effects from the function, like printing to screen, then you get real optimisation:

julia> function main()
           i = 0
           while i < 1000000
               # println(i)
               i += 1
           end
           return i
       end
main (generic function with 1 method)

julia> @code_llvm main()
;  @ REPL[6]:1 within `main`
define i64 @julia_main_225() #0 {
top:
;  @ REPL[6]:7 within `main`
  ret i64 1000000
}

julia> @code_native main()
        .text
; ┌ @ REPL[6]:7 within `main`
        movl    $1000000, %eax                  # imm = 0xF4240
        retq
        nopw    %cs:(%rax,%rax)
; └

The compiler computes the result of this function at compile-time, and it automatically returns a constant.

11 Likes