Are you, by chance, running this from Visual Studio? Keep in mind that the default settings for that is to disable all JIT optimizations, specifically including inlining.

Otherwise, I'm pretty sure that 32-bit JIT at least will happily inline trivial property accessors, so it should be exactly as fast as a property access. I've just tested it on my local machine - sure enough, the difference is 5x when I run from VS (with optimizations suppressed), but it's exactly the same, to millisecond precision, when the compiled binary is just run from command line.

By on 6/2/2009 11:55 PM ()

I am aware of the debugger issue but when I run it outside of VS or run without debugging CTRL+F5 or timed from within FSI with all optimization flags on, implicit immutable structs are consistently 2 times slower.

For example:
Inspired by the following links
[link:metamatix.org]
[link:www.reddit.com]
[link:www.reddit.com]

I made the following F# versions to compare and the only version that matches the No Abstraction version is the Explicit Struct version at the bottom, it is as fast as the C++ version btw.
The Implicit Struct version that is commented out is 2 times slower than the Explicit Struct version.

</i><b>Update:</b><i> Don pointed me to the Implicit .ctor that generated a needless local ref to the this pointer before initializing the fields, and this will be fixed. So properties are not the issue and are indeed optimized out. I commented out the non-properties operators of the explicit version so you can compare. The other versions that are allocated on the heap are like 10 times slower than the No Abstraction version. I also commented out and replaced the recursive loops with a while loops to get a little extra performance. </i><b>[No Abstraction]</b><i> <code lang=fsharp> let resolution = 5000 //let iters maxIter xc yc = // let rec aux count x y = // if count = maxIter then maxIter // elif x * x + y * y >= 4.0 then count // else aux (count + 1) (x * x - y * y + xc) (2.0 * x * y + yc) // aux 0 xc yc let iters maxIter xc yc = let mutable x = xc let mutable y = yc let mutable ret = maxIter let mutable ns = true let mutable count = 0 while count < maxIter && ns do if x * x + y * y >= 4.0 then ns <- false; ret <- count let tmp = (x * x - y * y + xc) y <- (2.0 * x * y + yc) x <- tmp count <- count + 1 ret let main () = let maxVal = resolution / 2 let minVal = -maxVal let mul = 2.0 / float maxVal let count = ref 0 //let mutable count = 0 for i = minVal to maxVal do for j = minVal to maxVal do let x = float i * mul let y = float j * mul count := !count + iters 100 x y //count <- count + iters 100 x y printf "result: %d\n" !count //printf "result: %d\n" count ;; main ()</code> </i><b>[Record Abstraction]</b><i> <code lang=fsharp> let resolution = 5000 type Complex = { x : float; y : float } member c.NormSquare = c.x * c.x + c.y * c.y static member (+) (l : Complex, r : Complex) = { x = l.x + r.x; y = l.y + r.y } static member (*) (l : Complex, r : Complex) = { x = l.x * r.x - l.y * r.y; y = l.x * r.y + l.y * r.x } //let iters maxIter xc yc = // let c = { x = xc; y = yc } // let rec aux count (z : Complex) = // if count >= maxIter then maxIter // elif z.NormSquare >= 4.0 then count // else aux (count + 1) ((z * z) + c) // aux 0 c let iters maxIter xc yc = let c = { x = xc; y = yc } let mutable z = { x = xc; y = yc } let mutable ret = maxIter let mutable ns = true let mutable count = 0 while count < maxIter && ns do if z.NormSquare >= 4.0 then ns <- false; ret <- count z <- z * z + c; count <- count + 1 ret let main () = let maxVal = resolution / 2 let minVal = -maxVal let mul = 2.0 / float maxVal let count = ref 0 //let mutable count = 0 for i = minVal to maxVal do for j = minVal to maxVal do let x = float i * mul let y = float j * mul count := !count + iters 100 x y //count <- count + iters 100 x y printf "result: %d\n" !count //printf "result: %d\n" count ;; main ()</code> </i><b>[DU Abstraction]</b><i> <code lang=fsharp> let resolution = 5000 type Complex = | Complex of float * float member c.NormSquare = let (Complex (x, y)) = c in x * x + y * y static member (+) (Complex (lx, ly), Complex (rx, ry)) = Complex (lx + rx, ly + ry) static member (*) (Complex (lx, ly), Complex (rx, ry)) = Complex (lx * rx - ly * ry, lx * ry + ly * rx) //let iters maxIter xc yc = // let c = Complex (xc, yc) // let rec aux count (z : Complex) = // if count >= maxIter then maxIter // elif z.NormSquare >= 4.0 then count // else aux (count + 1) ((z * z) + c) // aux 0 c let iters maxIter xc yc = let c = Complex (xc, yc) let mutable z = Complex (xc, yc) let mutable ret = maxIter let mutable ns = true let mutable count = 0 while count < maxIter && ns do if z.NormSquare >= 4.0 then ns <- false; ret <- count z <- z * z + c; count <- count + 1 ret let main () = let maxVal = resolution / 2 let minVal = -maxVal let mul = 2.0 / float maxVal let count = ref 0 //let mutable count = 0 for i = minVal to maxVal do for j = minVal to maxVal do let x = float i * mul let y = float j * mul count := !count + iters 100 x y //count <- count + iters 100 x y printf "result: %d\n" !count //printf "result: %d\n" count ;; main ()</code> </i><b>[Explicit/Implicit Class/Struct Abstraction]</b><i> <code lang=fsharp> let resolution = 5000 [<Struct>] type Complex = val X : float val Y : float member c.NormSquare = c.X * c.X + c.Y * c.Y static member (+) (l : Complex, r : Complex) = Complex (l.X + r.X, l.Y + r.Y) static member (*) (l : Complex, r : Complex) = Complex (l.X * r.X - l.Y * r.Y, l.X * r.Y + l.Y * r.X) new (x, y) = { X = x; Y = y } //[<Struct>] //type Complex (x : float, y : float) = // member c.X = x // member c.Y = y // member c.NormSquare = x * x + y * y // static member (+) (l : Complex, r : Complex) = Complex (l.X + r.X, l.Y + r.Y) // static member (*) (l : Complex, r : Complex) = Complex (l.X * r.X - l.Y * r.Y, l.X * r.Y + l.Y * r.X) //let iters maxIter xc yc = // let c = new Complex (xc, yc) // let rec aux count (z : Complex) = // if count >= maxIter then maxIter // elif z.NormSquare >= 4.0 then count // else aux (count + 1) ((z * z) + c) // aux 0 c let iters maxIter xc yc = let c = new Complex (xc, yc) let mutable z = new Complex (xc, yc) let mutable ret = maxIter let mutable ns = true let mutable count = 0 while count < maxIter && ns do if z.NormSquare >= 4.0 then ns <- false; ret <- count z <- z * z + c; count <- count + 1 ret let main () = let maxVal = resolution / 2 let minVal = -maxVal let mul = 2.0 / float maxVal let count = ref 0 //let mutable count = 0 for i = minVal to maxVal do for j = minVal to maxVal do let x = float i * mul let y = float j * mul count := !count + iters 100 x y //count <- count + iters 100 x y printf "result: %d\n" !count //printf "result: %d\n" count ;; main ()</code>

By on 6/3/2009 11:30 AM ()

Hi there

What's the extent of the perf difference you're seeing, and on what platform, and what optimization settings?

Thanks

don

By on 8/18/2008 12:51 PM ()

Right now the implicit vesrion generates code with properties and are like 2 times slower than the explicit version when using structs, exactly the other way around now.
If I remember correctly it was all ok in the Sept CTP but I am not 100% sure.
Also why are the static operator members allowed to access explicit private fields like "val private x : float" while not being able to access implicit and let bound fields?

By on 6/2/2009 2:13 PM ()

Same issue with records and also with the slowdown.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
type Vector =
    {x : float; y : float}


    member a.X = a.x


    member a.Y = a.y


    static member Create (x, y) =


        {x = x; y = y}  


    static member ( + ) (l : Vector, r : Vector) =


        {x = l.x + r.x; y = l.y + r.y} // Generates (l.get_x() + r.get_x(), l.get_y() + r.get_y())
By on 8/21/2008 2:35 PM ()

Hi there

What's the extent of the perf difference you're seeing, and on what platform, and what optimization settings?

Thanks

don

Thanks for the quick reply

I fixed a little typo in the second snippet.

I get 1.5x difference as a class and 1.3x as a struct in this particular case, on Win-XP 32-bit .NET and O3 settings.

By on 8/18/2008 2:24 PM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper