带有零开销的编译时检查的类型缩写

时间:2013-12-29 18:26:06

标签: performance f#

有可能吗?我的小黑客工作了吗?

[<StructLayout(LayoutKind.Explicit,Size=8)>]
type Slice = 
    struct
        [<FieldOffset(0)>]val mutable Address: int64
    end

let incSlice (slice: Slice) = slice.Address + 1L

let incInt64 (address: int64) = address + 1L

incSliceincInt64是否编译为相同的汇编代码?

时间几乎相同,但我不是100%肯定

3 个答案:

答案 0 :(得分:4)

这里的问题是尝试在不影响运行时性能的情况下为函数添加编译时安全性。虽然只有一个字段的结构可能有用,但很难预测。

相反,更好的解决方案是Units of measure

您可以使用

定义度量类型
[<Measure>] type Address

然后功能变为

let slice (t:int64<Address>)= t+1L<Address>

编译器将完全优化测量类型,同时提供类型安全性。

答案 1 :(得分:3)

琐碎基准的问题在于优化器总是会造成混乱。但是,我尝试通过在Release模式下构建exe并查看调试器中的反汇编来进行简单的测试。

看起来Slice仍有比int64版本更多的地址计算工作:

        let v1 = incSlice sl1
00000066  lea         edi,[ebp-1Ch] 
00000069  lea         esi,[ebp-14h] 
0000006c  movq        xmm0,mmword ptr [esi] 
00000070  movq        mmword ptr [edi],xmm0 
00000074  mov         eax,dword ptr [ebp-1Ch] 
00000077  mov         edx,dword ptr [ebp-18h] 
0000007a  mov         ecx,1 
0000007f  xor         ebx,ebx 
00000081  add         eax,ecx 
00000083  adc         edx,ebx 
00000085  mov         dword ptr [ebp-24h],eax 
00000088  mov         dword ptr [ebp-20h],edx 

        let v2 = incInt64 n
0000008b  mov         eax,dword ptr [ebp+8] 
0000008e  mov         edx,dword ptr [ebp+0Ch] 
00000091  mov         ecx,1 
00000096  xor         ebx,ebx 
00000098  add         eax,ecx 
0000009a  adc         edx,ebx 
0000009c  mov         dword ptr [ebp-2Ch],eax 
0000009f  mov         dword ptr [ebp-28h],edx 

在另一个测试中,我直接使用文字值,发现int64版本已针对结果进行了优化,而Slice版本没有 - 即它的存在似乎打败了优化者更多案例。

编辑:请注意,这是32位。根据越南的答案,64位通常看起来更好。

事实证明,只有在调试器下运行程序才会开始。如果在方法运行后附加调试器,则代码看起来非常相似,并且对于int64Slice个案,具有文字值的变量将保持不变。

答案 2 :(得分:1)

现在看起来非常相同

let test1(s: Slice) = 
    printfn "%d" 10
    let x = s.address + 1
    printfn "%d" x

产生

000000c1  mov         rax,qword ptr [rsp+000000A0h] 
000000c9  inc         rax 
000000cc  mov         qword ptr [rsp+28h],rax 

似乎已经过优化

并在内联的帮助下

let inline incSlice(s: Slice) = s.address + 1

let test2 (s: Slice) =
    printfn "%d" 10
    let x = incSlice s

产生

000000be  mov         rax,qword ptr [rsp+000000A0h] 
000000c6  mov         qword ptr [rsp+30h],rax 
000000cb  mov         rax,qword ptr [rsp+30h] 
000000d0  inc         rax 
000000d3  mov         qword ptr [rsp+28h],rax 

test1

几乎相同

有趣的汇编代码:D,rax四处移动 - 我不认为调试器中的反汇编被优化的原因