Performance-Frage zu Konstante und Literal

  • VB.NET

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Performance-Frage zu Konstante und Literal

    Hallo zusammen,
    was geht schneller?

    Data(i)*256UI*256UI*256UI
    oder
    Private Const _256_3 As UInt32 = 16777216UI und dann
    Data(i)*_256_3?

    Ich gehe davon aus, dass der Compiler den Wert der Konstante direkt einsetzt, also steht im Maschinencode Data(i)*16777216UI. Dann bleibt dennoch die Frage, ob er auch 256UI*256UI*256UI zu 16777216UI optimiert.
    Ist es performanter, eine Konstante zu nutzen?
    Viele Grüße
    Bartosz
    ILSpy sagt
    Spoiler anzeigen

    dass aus

    VB.NET-Quellcode

    1. Friend Class FrmMain
    2. Private Sub FrmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    3. Dim Data = 123
    4. Dim Data1 = Data * 256UI * 256UI * 256UI
    5. End Sub
    6. End Class

    das hier wird

    C#-Quellcode

    1. // WinFormsNetFxVB.FrmMain
    2. using System;
    3. private void FrmMain_Load(object sender, EventArgs e)
    4. {
    5. int Data = 123;
    6. checked
    7. {
    8. long Data2 = unchecked((long)Data) * 256L * 256 * 256;
    9. }
    10. }

    und aus dem hier

    VB.NET-Quellcode

    1. Friend Class FrmMain
    2. Private Const _256_3 As UInt32 = 16777216UI
    3. Private Sub FrmMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    4. Dim Data = 123
    5. Dim Data1 = Data * _256_3
    6. End Sub
    7. End Class

    das

    C#-Quellcode

    1. // WinFormsNetFxVB.FrmMain
    2. using System;
    3. private void FrmMain_Load(object sender, EventArgs e)
    4. {
    5. int Data = 123;
    6. checked
    7. {
    8. long Data2 = unchecked((long)Data) * 16777216L;
    9. }
    10. }


    Aber Performance … naja. leidiges Thema …
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    Bartosz schrieb:

    Es ist also nicht das Gleiche.

    Doch. Dir ist ja sicherlich bewusst, dass VB.NET und C# nicht direkt in Maschinencode, sondern in IL-Code übersetzten. Zur Laufzeit rennt dann ein JIT und übersetzt IL-Code in Maschinencode, der dann ausgeführt wird. ILSpy zeigt dir nur (wie der Namen schon sagt) den generierten IL-Code an. Daher kannst du nur daraus ableiten, dass zumindest im IL-Code die Konstanten noch nicht optimiert werden und wie im Programmcode beibehalten werden. Aber jetzt schau dir für

    VB.NET-Quellcode

    1. Dim Data = 123
    2. Dim Data1 = Data * 256UI * 256UI * 256UI

    den Maschinencode im Debug an:

    Ganz klar die einzelnen Variablen noch zu sehen, da der JIT im Debug-Modus fast nichts optimiert.

    Und jetzt im Release:

    Hier wird nichts gerechnet. Er lädt direkt das Ergebnis 2063597568. Der JIT hat das optimiert, nicht der VB.NET Compiler. Das gleiche wie die Konstante.

    Aber mein Fehler war oben in der ersten Antwort zu schreiben Kompilierzeit vor kalkuliert. Das stimmt anscheint nicht, wie VaporiZed gezeigt hat. Erst nach dem Jitten.
    Welches Tool verwendest Du für die Maschinencodeanzeige?
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Deine Frage lautet also: Was ist schneller: eine Konstante oder ein Literal?

    Du kriegst ein Bier von mir, wenn du mir ieinen praktischen Anwendungsfall aufzeigen kannst, wo das relevant ist.

    Oder anders: Es ist egal. Beides ist irrsinnig schnell - viel schneller als auch der simpelste Methoden-Aufruf.
    Folglich ist auf jeden Fall das einzige Kriterium: was ist lesbarer?
    @ErfinderDesRades: Ich habe circa 45 Mal im Code stehen

    VB.NET-Quellcode

    1. Data(i) * _256_3 + Data(i + 1) * _256_2 + Data(i + 2) * 256UI + Data(i + 3)

    also mittlerweile mit Nutzung von Konstanten.
    ––––––––––––––––––––––––––––––––––––––––––––––––––––––
    @all
    Ich habe in SharpLabIO einen Test durchgeführt.
    Dieser Code
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Friend NotInheritable Class A
    2. Friend Sub T1()
    3. Dim data as Byte() = System.io.File.ReadAllBytes("mein Pfad")
    4. Dim result as Uinteger = Data(0)*256ui*256ui*256ui+data(1)*256ui*256ui+data(2)*256ui+data(3)
    5. End Sub
    6. End Class

    führt zu
    Spoiler anzeigen

    Quellcode

    1. A.T1()
    2. L0000: push edi
    3. L0001: push esi
    4. L0002: push eax
    5. L0003: mov ecx, [0x8fcc430]
    6. L0009: call dword ptr [0xa227528]
    7. L000f: mov ecx, eax
    8. L0011: mov esi, [ecx+4]
    9. L0014: test esi, esi
    10. L0016: je short L0089
    11. L0018: movzx eax, byte ptr [ecx+8]
    12. L001c: mov edx, 0x100
    13. L0021: mul edx
    14. L0023: jb short L0083
    15. L0025: mov edx, 0x100
    16. L002a: mul edx
    17. L002c: jb short L0083
    18. L002e: mov edx, 0x100
    19. L0033: mul edx
    20. L0035: jb short L0083
    21. L0037: mov [esp], eax
    22. L003a: cmp esi, 1
    23. L003d: jbe short L0089
    24. L003f: movzx edx, byte ptr [ecx+9]
    25. L0043: mov edi, 0x100
    26. L0048: mov eax, edx
    27. L004a: mul edi
    28. L004c: jb short L0083
    29. L004e: mul edi
    30. L0050: jb short L0083
    31. L0052: mov edx, [esp]
    32. L0055: add eax, edx
    33. L0057: jb short L0083
    34. L0059: mov [esp], eax
    35. L005c: cmp esi, 2
    36. L005f: jbe short L0089
    37. L0061: movzx edx, byte ptr [ecx+0xa]
    38. L0065: mov eax, edx
    39. L0067: mul edi
    40. L0069: jb short L0083
    41. L006b: mov edx, [esp]
    42. L006e: add eax, edx
    43. L0070: jb short L0083
    44. L0072: cmp esi, 3
    45. L0075: jbe short L0089
    46. L0077: movzx edx, byte ptr [ecx+0xb]
    47. L007b: add eax, edx
    48. L007d: jb short L0083
    49. L007f: pop ecx
    50. L0080: pop esi
    51. L0081: pop edi
    52. L0082: ret
    53. L0083: call 0x72729cf0
    54. L0088: int3
    55. L0089: call 0x72729d60
    56. L008e: int3
    (56 Zeilen).

    Wohingegen dieser Code
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Friend NotInheritable Class B
    2. Private Const _256_3 As UInteger = 16777216UI
    3. Private Const _256_2 As UInteger = 65536UI
    4. Friend Sub T2()
    5. Dim data as Byte() = System.io.File.ReadAllBytes("mein Pfad")
    6. Dim result as Uinteger = Data(0)*_256_3+data(1)*_256_2+data(2)*256ui+data(3)
    7. End Sub
    8. End Class

    hierzu führt
    Spoiler anzeigen

    Quellcode

    1. B.T2()
    2. L0000: push edi
    3. L0001: push esi
    4. L0002: push eax
    5. L0003: mov ecx, [0x8fcc430]
    6. L0009: call dword ptr [0xa227528]
    7. L000f: mov ecx, eax
    8. L0011: mov esi, [ecx+4]
    9. L0014: test esi, esi
    10. L0016: je short L0078
    11. L0018: movzx eax, byte ptr [ecx+8]
    12. L001c: mov edx, 0x1000000
    13. L0021: mul edx
    14. L0023: jb short L0072
    15. L0025: mov [esp], eax
    16. L0028: cmp esi, 1
    17. L002b: jbe short L0078
    18. L002d: movzx edx, byte ptr [ecx+9]
    19. L0031: mov edi, 0x10000
    20. L0036: mov eax, edx
    21. L0038: mul edi
    22. L003a: jb short L0072
    23. L003c: mov edx, [esp]
    24. L003f: add eax, edx
    25. L0041: jb short L0072
    26. L0043: mov [esp], eax
    27. L0046: cmp esi, 2
    28. L0049: jbe short L0078
    29. L004b: movzx edx, byte ptr [ecx+0xa]
    30. L004f: mov edi, 0x100
    31. L0054: mov eax, edx
    32. L0056: mul edi
    33. L0058: jb short L0072
    34. L005a: mov edx, [esp]
    35. L005d: add eax, edx
    36. L005f: jb short L0072
    37. L0061: cmp esi, 3
    38. L0064: jbe short L0078
    39. L0066: movzx edx, byte ptr [ecx+0xb]
    40. L006a: add eax, edx
    41. L006c: jb short L0072
    42. L006e: pop ecx
    43. L006f: pop esi
    44. L0070: pop edi
    45. L0071: ret
    46. L0072: call 0x72729cf0
    47. L0077: int3
    48. L0078: call 0x72729d60
    49. L007d: int3
    (49 Zeilen).

    Meine Befürchtung ist, dass selbst beim Jitten* das *256ui*256ui*256ui nicht schon ausgerechnet wird.

    *Danke an Bluespide für die Erklärung