Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Targeted for x64 would sometimes result in very bad performance than for anycpu

Tags:

f#

These are 2 functions, fun1 takes 1 parameter, fun2 takes 4 extra useless parameters. When I targeted for x64, fun1 takes 4s but fun2 takes less than 1s. If I targeted for anycpu, then both take less than 1s.

There is a similar question I asked here why Seq.iter is 2x faster than for loop if target is for x64?

It is compiled in .Net 4.5 Visual Studio 2012, F# 3.0, run in windows 7 x64

open System
open System.Diagnostics

type Position =
    {
        a: int
        b: int
    }

[<EntryPoint>]
let main argv = 

    let fun1 (pos: Position[]) =  //<<<<<<<< here
        let functionB x y z = 4

        Array.fold2 (fun acc x y -> acc + int64 (functionB x x y)) 0L pos pos

    let fun2 (pos: Position[]) u v w x =  //<<<<<<<< here
        let functionB x y z = 4

        Array.fold2 (fun acc x y -> acc + int64 (functionB x x y)) 0L pos pos



    let s = {a=2;b=3}
    let pool = [|s;s;s|]

    let test1 n =
        let mutable x = 0L
        for i in 1 .. n do
            x <- fun1 pool

    let test2 n =
        let mutable x = 0L
        for i in 1 .. n do
            x <- fun2 pool 1 2 3 4

    let sw = new Stopwatch()
    sw.Start()
    test2 10000000
    sw.Stop()
    Console.WriteLine(sw.Elapsed)

    sw.Restart()
    test1 10000000
    sw.Stop()
    Console.WriteLine(sw.Elapsed)


    0 // return an integer exit code
like image 494
colinfang Avatar asked Oct 05 '12 22:10

colinfang


1 Answers

This isn't a complete answer, it is first diagnostics of the problem.

I can reproduce the behaviour with the same configuration. If you turn on F# Interactive 64-bit in Tools -> Options -> F# Tools -> F# Interactive, you can observe the same behaviour there.

Diferrent from the other question, x64 jitter isn't a problem. It turns out "Generate tail calls" option in Project property causes considerable slowdown of test1 compared to test2. If you turn off that option, two cases are at similar speeds.

On the other hand, you can use inline keyword on fun1 so that tail call isn't needed. Two examples are comparable in execution time again no matter fun2 is inlined or not.

That said, it is weird that adding tail. opcode to fun1 makes it much slower than (doing the same with) fun2. You may contact F# team for further investigation.

like image 61
pad Avatar answered Nov 16 '22 08:11

pad