Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"nested if" versus "if and" performance using F#

The following code results in slow1 = 1323 ms, slow2 = 1311 ms and fast = 897 ms. How is that possible?

Here: Nested or not nested if-blocks? they mention that

Any modern compiler, and by that I mean anything built in the past 20 years, will compile these to the same code.

let s = System.Diagnostics.Stopwatch()
let mutable a = 1
s.Start()

for i in 0 .. 1000000000 do
  if i < 0 then
    if i < 0 then
      a <- 4

printfn "fast = %d" s.ElapsedMilliseconds

s.Restart()

for i in 0 .. 1000000000 do
  if i < 0 && i < 0 then
    a <- 4

printfn "slow1 = %d" s.ElapsedMilliseconds

s.Restart()

for i in 0 .. 1000000000 do
  if i < 0 & i < 0 then
    a <- 4

printfn "slow2 = %d" s.ElapsedMilliseconds
like image 217
Oldrich Svec Avatar asked Apr 16 '13 12:04

Oldrich Svec


1 Answers

I've got hold of the MSIL from ildasm, which I'll post here for someone to elaborate on (no time) - it's community wiki time:

Fast (just the i comparison lines as the rest are identical):

//000030:   if i < 1000 then
  IL_001f:  ldloc.0
  IL_0020:  ldc.i4     0x3e8
  IL_0025:  bge.s      IL_003b
//000031:     if i < 1000 then
  IL_0027:  ldloc.0
  IL_0028:  ldc.i4     0x3e8
  IL_002d:  bge.s      IL_0038

Slow:

//000039:   if i < 1000 && i < 1000 then
  IL_0084:  ldloc.0
  IL_0085:  ldc.i4     0x3e8
  IL_008a:  bge.s      IL_0097
  IL_008c:  ldloc.0
  IL_008d:  ldc.i4     0x3e8
  IL_0092:  clt
  IL_0094:  nop
  IL_0095:  br.s       IL_0099
  IL_0097:  ldc.i4.0
  IL_0098:  nop
  IL_0099:  brfalse.s  IL_00a4

On a side note, C# version of the same has the same timing for both versions.

One thing I noticed in the disassembly was that the F# variables were Program.i and Program.a, so I'm not sure if there's some object interference in F# that isn't there in C#.

like image 141
2 revs Avatar answered Sep 28 '22 08:09

2 revs