performanceoptimizationf#

Terrific performance difference between almost equal methods


while working on a project I accidentally noticed that the same method with only one additional (unused) argument manages to run even ten times faster than the other one, with optimizations enabled.

type Stream () =
    static member private write (x, o, a : byte[]) = (for i = 0 to 3 do a.[o + i] <- byte((x >>> 24 - i * 8) % 256)); 4
    static member private format f x l = Array.zeroCreate l |> fun a -> (f(x, 0, a) |> ignore; a)
    static member private format1 f x l o = Array.zeroCreate l |> fun a -> (f(x, 0, a) |> ignore; a)
    static member Format (value : int) =  Stream.format (fun (x: int, i, a) -> Stream.write(x, i, a)) value 4
    static member Format1 (value : int) =  Stream.format1 (fun (x: int, i, a) -> Stream.write(x, i, a)) value 4

When tested, Stream.Format1 runs much faster than Stream.Format, although the only difference between the private members Stream.format and Stream.format1 is just the o argument, which moreover is unused by the method itself.

How does the compiler treat in so different ways two almost identical methods?

EDIT: thanks for the explanation and sorry for the ignorance.


Solution

  • The problem is that when you call Format1 with just a single argument, it only returns a function. It doesn't do the actual formatting yet. This means that if you compare the performance of:

    Stream.Format 42
    Stream.Format1 42
    

    ... then you're actually comparing the performance of actual formatting (that creates the array and writes something in it) in the first case and the performance of code that simply returns a function value without doing anything.

    If you're not using the o parameter of format1 for anything, then you can just pass in some dummy value, to actually evaluate the function and get the result. Then you should get similar performance:

    Stream.Format 42
    Stream.Format1 42 ()