F #: why using an external version of a function is faster than a pass function as an argument

The version (calc1) using the direct external function takes about 1 s.

But the version (calc2) with the skip function as a function parameter takes about 2 s, which is 2 times slower. Why?

open System.Diagnostics open System.Numerics let width = 1920 let height = 1200 let xMin = -2.0 let xMax = 1.0 let yMin = -1.0 let yMax = 1.0 let scaleX x = float x * (xMax - xMin) / float width + xMin let scaleY y = float y * (yMax - yMin) / float height - yMax let fn (z:Complex) (c:Complex) = z * z + c let calc1 width height = let iterFn zc = let rec iterFn' (z:Complex) cn = if z.Magnitude > 2.0 || n >= 255 then n else iterFn' (fn zc) c (n + 1) iterFn' zc 0 Array.Parallel.init (width * height) (fun i -> let x, y = i % width, i / width let z, c = Complex.Zero, Complex(scaleX x, scaleY y) (x, y, iterFn zc) ) let calc2 width height fn = let iterFn zc = let rec iterFn' (z:Complex) cn = if z.Magnitude > 2.0 || n >= 255 then n else iterFn' (fn zc) c (n + 1) iterFn' zc 0 Array.Parallel.init (width * height) (fun i -> let x, y = i % width, i / width let z, c = Complex.Zero, Complex(scaleX x, scaleY y) (x, y, iterFn zc) ) 

Run in F # interactive to get the following results:

 > calc1 width height |> ignore Real: 00:00:00.943, CPU: 00:00:03.046, GC gen0: 10, gen1: 8, gen2: 2 val it : unit = () > calc2 width height fn |> ignore Real: 00:00:02.033, CPU: 00:00:07.484, GC gen0: 9, gen1: 8, gen2: 1 val it : unit = () 

F # 4.0.1, .NET 4.6.1

+5
source share
1 answer

I suspect that in the first case fn is inline.

Passing it as a parameter prevents this optimization, so it is slower

+1
source

Source: https://habr.com/ru/post/1240263/


All Articles