C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[1]: 変数の種類によって構造体の速度が違う理由


(過去ログ 176 を表示中)

[トピック内 3 記事 (1 - 3 表示)]  << 0 >>

■101282 / inTopicNo.1)  変数の種類によって構造体の速度が違う理由
  
□投稿者/ ぼんど (1回)-(2023/01/29(Sun) 21:18:33)

分類:[.NET 全般] 

http://bbs.wankuma.com/index.cgi?mode=al2&namber=101278


このページにて、構造体を使った際に
プロパティよりもフィールドの方が高速であることを教えていただきました。

いろいろと試して気がついたのですが、

Public Structure PointF_3D

Property X As Single
Property Y As Single
Property Z As Single

End Structure

のように浮動小数点の変数の場合に大きな差異が得られるのですが、

Public Structure PointF_3D

Property X As Integer
Property Y As Integer
Property Z As Integer

End Structure

のように、整数の変数を定義した場合には全く違い見られないことが分かりました。

プロパティよりもフィールドの違いについては
https://programming.pc-note.net/csharp/property.html

このページにあるようにプロパティを使った場合に、
目に見えない形でGetやSetなどのアクセサが呼ばれるために
その分のオーバーヘッドが大きくなってしまうということだと思います。

それなら、変数の型の種類によらないと思うのですが、
なぜ整数型の場合には違いが見られなくなるのでしょうか?


引用返信 編集キー/
■101283 / inTopicNo.2)  Re[1]: 変数の種類によって構造体の速度が違う理由
□投稿者/ KOZ (387回)-(2023/01/29(Sun) 23:09:29)
No101282 (ぼんど  さん) に返信
> それなら、変数の型の種類によらないと思うのですが、
> なぜ整数型の場合には違いが見られなくなるのでしょうか?

検証コードが間違っているのでは?
手元でやってみましたが、2倍以上違います。

Module Module1

    Public Structure PointF_3DF
        Public X As Integer
        Public Y As Integer
        Public Z As Integer
    End Structure

    Public Structure PointF_3DP
        Property X As Integer
        Property Y As Integer
        Property Z As Integer
    End Structure

    Sub Main()
        Dim ss As New Stopwatch
        Dim hh As Integer = 100000000
        Dim aa(hh) As PointF_3DF
        Dim bb(hh) As PointF_3DP
        Dim RefVal1 As New PointF_3DF With {.X = 1, .Y = 2, .Z = 3}
        Dim RefVal2 As New PointF_3DP With {.X = 1, .Y = 2, .Z = 3}

        ss.Restart()
        For i = 0 To hh
            aa(i).X = RefVal1.X
            aa(i).Y = RefVal1.Y
            aa(i).Z = RefVal1.Z
        Next
        MsgBox(ss.ElapsedMilliseconds)

        ss.Restart()
        For i = 0 To hh
            bb(i).X = RefVal2.X
            bb(i).Y = RefVal2.Y
            bb(i).Z = RefVal2.Z
        Next
        MsgBox(ss.ElapsedMilliseconds)
    End Sub

End Module

引用返信 編集キー/
■101284 / inTopicNo.3)  Re[1]: 変数の種類によって構造体の速度が違う理由
□投稿者/ radian (105回)-(2023/01/30(Mon) 13:53:16)
2023/01/30(Mon) 15:41:14 編集(投稿者)
https://sharplab.io で、簡単な検証用ソースのアセンブリコードを比較してみました。

----------------
Imports System
Imports System.Diagnostics
Imports System.Runtime.CompilerServices

Module Module1

    Public Structure PointF_3DF
        Public X As Integer
        Public Y As Integer
        Public Z As Integer
        Public Function Sum() As Integer
            Return X + Y + Z
        End Function
    End Structure

    Public Structure PointF_3DP
        Property X As Integer
        Property Y As Integer
        Property Z As Integer
        Public Function Sum() As Integer
            Return X + Y + Z
        End Function
        <MethodImpl(MethodImplOptions.AggressiveInlining)>
        Public Function Sum2() As Integer
            Return X + Y + Z
        End Function
    End Structure

    Sub Calc1()
        Dim v = Create3DF()
        Console.WriteLine(v.Sum())
    End Sub

    Sub Calc2()
        Dim v = Create3DP()
        Console.WriteLine(v.Sum())
    End Sub

    Sub Calc3()
        Dim v = Create3DP()
        Console.WriteLine(v.Sum2())
    End Sub

    Function Create3DF() As PointF_3DF
        Static r As New Random
        Const Max = 100           
        Return New PointF_3DF() With {.X = r.Next(1, Max), .Y = r.Next(1, Max), .Z = r.Next(1, Max)}
    End Function

    Function Create3DP() As PointF_3DP
        Static r As New Random
        Const Max = 100           
        Return New PointF_3DP() With {.X = r.Next(1, Max), .Y = r.Next(1, Max), .Z = r.Next(1, Max)}
    End Function

End Module
----------------


[x64 Release]
; Core CLR 7.0.22.51805 on x64

Module1.Calc1()
    L0000: sub rsp, 0x38
    L0004: xor eax, eax
    L0006: mov [rsp+0x28], rax
    L000b: mov [rsp+0x30], rax
    L0010: lea rcx, [rsp+0x28]
    L0015: call 0x00007ff9b0ee0048
    L001a: mov ecx, [rsp+0x28]
    L001e: add ecx, [rsp+0x2c]
    L0022: jo short L003c
    L0024: add ecx, [rsp+0x30]
    L0028: jo short L003c
    L002a: mov rax, 0x7ff9644a9b70
    L0034: call qword ptr [rax]
    L0036: nop
    L0037: add rsp, 0x38
    L003b: ret
    L003c: call 0x00007ff9c30c8710
    L0041: int3

Module1.Calc2()
    L0000: sub rsp, 0x38
    L0004: xor eax, eax
    L0006: mov [rsp+0x28], rax
    L000b: mov [rsp+0x30], rax
    L0010: lea rcx, [rsp+0x28]
    L0015: call 0x00007ff9b0ee0060
    L001a: mov ecx, [rsp+0x28]
    L001e: add ecx, [rsp+0x2c]
    L0022: jo short L003c
    L0024: add ecx, [rsp+0x30]
    L0028: jo short L003c
    L002a: mov rax, 0x7ff9644a9b70
    L0034: call qword ptr [rax]
    L0036: nop
    L0037: add rsp, 0x38
    L003b: ret
    L003c: call 0x00007ff9c30c8710
    L0041: int3

Module1.Calc3()
    L0000: sub rsp, 0x38
    L0004: xor eax, eax
    L0006: mov [rsp+0x28], rax
    L000b: mov [rsp+0x30], rax
    L0010: lea rcx, [rsp+0x28]
    L0015: call 0x00007ff9b0ee0060
    L001a: mov ecx, [rsp+0x28]
    L001e: add ecx, [rsp+0x2c]
    L0022: jo short L003c
    L0024: add ecx, [rsp+0x30]
    L0028: jo short L003c
    L002a: mov rax, 0x7ff9644a9b70
    L0034: call qword ptr [rax]
    L0036: nop
    L0037: add rsp, 0x38
    L003b: ret
    L003c: call 0x00007ff9c30c8710
    L0041: int3


[.NET Framework x64 Release]
; Desktop CLR 4.8.4526.0 on amd64

Module1.Calc1()
    L0000: sub rsp, 0x38
    L0004: xor eax, eax
    L0006: mov [rsp+0x28], rax
    L000b: mov [rsp+0x30], rax
    L0010: lea rcx, [rsp+0x28]
    L0015: call Module1.Create3DF()
    L001a: mov ecx, [rsp+0x28]
    L001e: add ecx, [rsp+0x2c]
    L0022: jo L0035
    L0024: add ecx, [rsp+0x30]
    L0028: jo L0035
    L002a: call System.Console.WriteLine(Int32)
    L002f: nop
    L0030: add rsp, 0x38
    L0034: ret
    L0035: call 0x7ff9e6ae9090
    L003a: int3

Module1.Calc2()
    L0000: sub rsp, 0x38
    L0004: xor eax, eax
    L0006: mov [rsp+0x28], rax
    L000b: mov [rsp+0x30], rax
    L0010: lea rcx, [rsp+0x28]
    L0015: call Module1.Create3DP()
    L001a: lea rcx, [rsp+0x28]
    L001f: call Module1+PointF_3DP.Sum()
    L0024: mov ecx, eax
    L0026: call System.Console.WriteLine(Int32)
    L002b: nop
    L002c: add rsp, 0x38
    L0030: ret

Module1.Calc3()
    L0000: sub rsp, 0x38
    L0004: xor eax, eax
    L0006: mov [rsp+0x28], rax
    L000b: mov [rsp+0x30], rax
    L0010: lea rcx, [rsp+0x28]
    L0015: call Module1.Create3DP()
    L001a: mov ecx, [rsp+0x28]
    L001e: add ecx, [rsp+0x2c]
    L0022: jo L0035
    L0024: add ecx, [rsp+0x30]
    L0028: jo L0035
    L002a: call System.Console.WriteLine(Int32)
    L002f: nop
    L0030: add rsp, 0x38
    L0034: ret
    L0035: call 0x7ff9e6ae9090
    L003a: int3


.NET Frameworkだと、プロパティがインライン展開されていないですね。
その場合でも、AggressiveInlining指定で同じようなコードが出力されました。
このように、最適化はフレームワーク等の条件で変化する可能性もあるので、
動作環境や計測方法のソースを記述した方がよろしいかと思います。
理論上は遅くなりそうなソースでも、
実際は最適化によって殆ど変わらないというケースも十分ありえます。

引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -