View Full Version : [QOD] Challenge: Beat these times!
ReneMiner
29-04-2013, 19:54
This time it's not a poll nor question here. But some challenge!
Imagine we have some Long or Dword we get passed from somewhere and have to split this into 3 Bytes...
The idea is from Maxer73's test-script- he wants to parse some parameters he receives from midi- and he wants it real fast. Now we got a few different attempts to split a number from Long to 3 Bytes (RBG-Reverse-Function). See this demonstration script (by Maxer73) - run it, read to see what it does - not much: splits up a few variables different ways - all the same result but different execution-times...
Which - you guess is the fastest way?
Method 1: Shifting the Bytes?
Method 2: Division?
Method 3: Peeking the bytes from memory at varptr?
Method 4: MKL$ from Value and Peek Bytes from StrPtr ?
Method 5: MKL$ and place virtual variable of adequate Type over it?
Uses "Console"
%MAX_Tests = 75000
Type data
byte0 As Byte
byte1 As Byte
byte2 As Byte
End Type
Dim Midi As data
Long MidiWord
Double tStart,tEnd,tTime 'for obtain elapsed time
'---------------------------------------------------------------------
PrintL "MidiWord conversion speed test" + Str$(%Max_Tests) + " of executions:"
PrintL
PrintL "Press a Key to start method Midi_Decode_Max"
WaitKey
tStart = Timer
For MidiWord = 1 To %Max_Tests
Midi_Decode_Max (MidiWord)
PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = Timer : tTime = (tEnd-tStart)
PrintL CRLF & "Executed in " & tTime & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene1"
WaitKey
tStart = Timer
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene1(MidiWord)
PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = Timer : tTime = (tEnd-tStart)
PrintL CRLF & "Executed in " & tTime & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene2"
WaitKey
tStart = Timer
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene2(MidiWord)
PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = Timer : tTime = (tEnd-tStart)
PrintL CRLF & "Executed in " & tTime & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene3"
WaitKey
tStart = Timer
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene3(MKL$(MidiWord))
PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = Timer : tTime = (tEnd-tStart)
PrintL CRLF & "Executed in " & tTime & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene4"
WaitKey
tStart = Timer
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene4(MKL$(MidiWord))
PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = Timer : tTime = (tEnd-tStart)
PrintL CRLF & "Executed in " & tTime & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to exit"
WaitKey
Sub Midi_Decode_Max (ByVal nVal As Long)
Dim temp0,temp1,temp2 As Long = nVal
Midi.byte0 = temp0 And 255
Midi.byte1 = (SHIFT SIGNED RIGHT temp1, 8) And 255
Midi.byte2 = (SHIFT SIGNED RIGHT temp2, 16) And 255
End Sub
Sub Midi_Decode_Rene1(ByVal anyValue As Long)
Midi.byte2 = Int(anyValue / &H10000)
Midi.byte1 = Int((anyValue - &H10000 * Midi.byte2)/ &H100)
Midi.byte0 = anyValue - Midi.byte2 * &H10000 - Midi.byte1 * &H100
End Sub
Sub Midi_Decode_Rene2(ByRef someVal As Long)
Midi.byte0 = Peek(Byte,VarPtr(someVal))
Midi.byte1 = Peek(Byte,VarPtr(someVal)+ 1)
Midi.byte2 = Peek(Byte,Varptr(someVal)+ 2)
End Sub
Sub Midi_Decode_Rene3(ByVal someVal As String)
Midi.byte0 = Peek(Byte,StrPtr(someVal))
Midi.byte1 = Peek(Byte,StrPtr(someVal)+ 1)
Midi.byte2 = Peek(Byte,StrPtr(someVal)+ 2)
End Sub
Sub Midi_Decode_Rene4(ByVal someVal As String)
Local lByte As data At StrPtr(someVal)
Midi = lByte
End Sub
You know any faster method?
for comparison reasons (see image), comment lines 22, 33, 44, 55, 66 and set CONST %MAX_TESTS = 1000000
Petr Schreiber
29-04-2013, 22:27
I did a minor modification to the code. The Timer function is very approximate, for benchmarks it is better to use HiResTimer. After the modification, the script looks like:
Uses "Console"
%MAX_Tests = 1000000
Type data
byte0 As Byte
byte1 As Byte
byte2 As Byte
End Type
Dim Midi As data
Long MidiWord
Quad tStart,tEnd
Double tTime 'for obtain elapsed time
' -- Initialize high precision timer
HiResTimer_Init
'---------------------------------------------------------------------
PrintL "MidiWord conversion speed test" + Str$(%Max_Tests) + " of executions:"
PrintL
PrintL "Press a Key to start method Midi_Decode_Max"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Max (MidiWord)
''PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene1"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene1(MidiWord)
''PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene2"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene2(MidiWord)
''PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene3"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene3(MKL$(MidiWord))
'' PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene4"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene4(MKL$(MidiWord))
'' PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to exit"
WaitKey
Sub Midi_Decode_Max (ByVal nVal As Long)
Dim temp0,temp1,temp2 As Long = nVal
Midi.byte0 = temp0 And 255
Midi.byte1 = (SHIFT SIGNED RIGHT temp1, 8) And 255
Midi.byte2 = (SHIFT SIGNED RIGHT temp2, 16) And 255
End Sub
Sub Midi_Decode_Rene1(ByVal anyValue As Long)
Midi.byte2 = Int(anyValue / &H10000)
Midi.byte1 = Int((anyValue - &H10000 * Midi.byte2)/ &H100)
Midi.byte0 = anyValue - Midi.byte2 * &H10000 - Midi.byte1 * &H100
End Sub
Sub Midi_Decode_Rene2(ByRef someVal As Long)
Midi.byte0 = Peek(Byte,VarPtr(someVal))
Midi.byte1 = Peek(Byte,VarPtr(someVal)+ 1)
Midi.byte2 = Peek(Byte,VarPtr(someVal)+ 2)
End Sub
Sub Midi_Decode_Rene3(ByVal someVal As String)
Midi.byte0 = Peek(Byte,StrPtr(someVal))
Midi.byte1 = Peek(Byte,StrPtr(someVal)+ 1)
Midi.byte2 = Peek(Byte,StrPtr(someVal)+ 2)
End Sub
Sub Midi_Decode_Rene4(ByVal someVal As String)
Local lByte As data At StrPtr(someVal)
Midi = lByte
End Sub
... and the results on my precious Core i5-3350P are the following:
MidiWord conversion speed test 1000000 of executions:
Press a Key to start method Midi_Decode_Max
Executed in 7.38 seconds
Press a Key to start method Midi_Decode_Rene1
Executed in 3.36 seconds
Press a Key to start method Midi_Decode_Rene2
Executed in 3.01 seconds
Press a Key to start method Midi_Decode_Rene3
Executed in 3.91 seconds
Press a Key to start method Midi_Decode_Rene4
Executed in 4.58 seconds
Press a Key to exit
Petr
Hi Petr....
Thanks for your reply, the script work very well with HiRes Timer
and is more precise.:D
ErosOlmi
30-04-2013, 07:29
Here is my method.
Hoping data is correct ... It seems I got a nice speed improvement: 8 to 20 times faster than any other method.
It uses a UNION data structure in order to directly assign a LONG and have it split into needed part automatically.
This method avoid to call a SUB/FUNCTION and instead assign the LONG directly to data and UNION automagically split it into relevant part.
Calling SUB/FUNCTION requires a lot of time if there are local variables or parameters due to local stack allocation.
MidiWord conversion speed test 1000000 of executions:
Press a Key to start method Midi_Decode_Max
Executed in 9.40 seconds
Press a Key to start method Midi_Decode_Rene1
Executed in 4.06 seconds
Press a Key to start method Midi_Decode_Rene2
Executed in 3.75 seconds
Press a Key to start method Midi_Decode_Rene3
Executed in 4.66 seconds
Press a Key to start method Midi_Decode_Rene4
Executed in 5.88 seconds
Press a Key to start method Midi_Decode_Eros1
Executed in 0.40 seconds
Press a Key to exit
Uses "Console"
%MAX_Tests = 1000000
Type data
byte0 As Byte
byte1 As Byte
byte2 As Byte
End Type
Union uData
AsByte As data
AsLong As Long
End Union
Type tData
Element As uData
End Type
Dim Midi As data
Long MidiWord
Quad tStart,tEnd
Double tTime 'for obtain elapsed time
' -- Initialize high precision timer
HiResTimer_Init
'---------------------------------------------------------------------
PrintL "MidiWord conversion speed test" + Str$(%Max_Tests) + " of executions:"
PrintL
PrintL "Press a Key to start method Midi_Decode_Max"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Max (MidiWord)
''PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene1"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene1(MidiWord)
''PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene2"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene2(MidiWord)
''PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene3"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene3(MKL$(MidiWord))
'' PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene4"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene4(MKL$(MidiWord))
'' PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Eros1"
WaitKey
tStart = HiResTimer_Get
Dim lData As tData
For MidiWord = 1 To %Max_Tests
lData.Element.AsLong = MidiWord
'PrintL lData.Element.AsByte.byte0 & $TAB & lData.Element.AsByte.byte1 & $TAB & lData.Element.AsByte.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to exit"
WaitKey
Sub Midi_Decode_Max (ByVal nVal As Long)
Dim temp0,temp1,temp2 As Long = nVal
Midi.byte0 = temp0 And 255
Midi.byte1 = (SHIFT SIGNED RIGHT temp1, 8) And 255
Midi.byte2 = (SHIFT SIGNED RIGHT temp2, 16) And 255
End Sub
Sub Midi_Decode_Rene1(ByVal anyValue As Long)
Midi.byte2 = Int(anyValue / &H10000)
Midi.byte1 = Int((anyValue - &H10000 * Midi.byte2)/ &H100)
Midi.byte0 = anyValue - Midi.byte2 * &H10000 - Midi.byte1 * &H100
End Sub
Sub Midi_Decode_Rene2(ByRef someVal As Long)
Midi.byte0 = Peek(Byte,VarPtr(someVal))
Midi.byte1 = Peek(Byte,VarPtr(someVal)+ 1)
Midi.byte2 = Peek(Byte,VarPtr(someVal)+ 2)
End Sub
Sub Midi_Decode_Rene3(ByVal someVal As String)
Midi.byte0 = Peek(Byte,StrPtr(someVal))
Midi.byte1 = Peek(Byte,StrPtr(someVal)+ 1)
Midi.byte2 = Peek(Byte,StrPtr(someVal)+ 2)
End Sub
Sub Midi_Decode_Rene4(ByVal someVal As String)
Local lByte As data At StrPtr(someVal)
Midi = lByte
End Sub
Petr Schreiber
30-04-2013, 08:36
I got inspired by Eros and used SetAt instead, the result is sometimes liiiiiitle bit faster :P
Test this time on Intel Core 2 Duo T6600 @ 2.2GHz:
MidiWord conversion speed test 1000000 of executions:
Press a Key to start method Midi_Decode_Max
Executed in 22.21 seconds
Press a Key to start method Midi_Decode_Rene1
Executed in 10.07 seconds
Press a Key to start method Midi_Decode_Rene2
Executed in 8.12 seconds
Press a Key to start method Midi_Decode_Rene3
Executed in 11.36 seconds
Press a Key to start method Midi_Decode_Rene4
Executed in 13.69 seconds
Press a Key to start method Midi_Decode_Eros1
Executed in 0.83 seconds
Press a Key to start method Midi_Decode_Petr1
Executed in 0.82 seconds
Press a Key to exit
Code:
Uses "Console"
%MAX_Tests = 1000000
Type data
byte0 As Byte
byte1 As Byte
byte2 As Byte
End Type
Union uData
AsByte As data
AsLong As Long
End Union
Type tData
Element As uData
End Type
Dim Midi As data
Long MidiWord
Quad tStart,tEnd
Double tTime 'for obtain elapsed time
' -- Initialize high precision timer
HiResTimer_Init
'---------------------------------------------------------------------
PrintL "MidiWord conversion speed test" + Str$(%Max_Tests) + " of executions:"
PrintL
PrintL "Press a Key to start method Midi_Decode_Max"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Max (MidiWord)
''PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene1"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene1(MidiWord)
''PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene2"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene2(MidiWord)
''PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene3"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene3(MKL$(MidiWord))
'' PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene4"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene4(MKL$(MidiWord))
'' PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Eros1"
WaitKey
tStart = HiResTimer_Get
Dim lData As tData
For MidiWord = 1 To %Max_Tests
lData.Element.AsLong = MidiWord
'PrintL lData.Element.AsByte.byte0 & $TAB & lData.Element.AsByte.byte1 & $TAB & lData.Element.AsByte.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Petr1"
WaitKey
tStart = HiResTimer_Get
Dim petr1Data As data At 0
For MidiWord = 1 To %Max_Tests
SetAt(petr1Data, VarPtr(midiWord))
''PrintL petr1Data.byte0 & $TAB & petr1Data.byte1 & $TAB & petr1Data.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to exit"
WaitKey
Sub Midi_Decode_Max (ByVal nVal As Long)
Dim temp0,temp1,temp2 As Long = nVal
Midi.byte0 = temp0 And 255
Midi.byte1 = (SHIFT SIGNED RIGHT temp1, 8) And 255
Midi.byte2 = (SHIFT SIGNED RIGHT temp2, 16) And 255
End Sub
Sub Midi_Decode_Rene1(ByVal anyValue As Long)
Midi.byte2 = Int(anyValue / &H10000)
Midi.byte1 = Int((anyValue - &H10000 * Midi.byte2)/ &H100)
Midi.byte0 = anyValue - Midi.byte2 * &H10000 - Midi.byte1 * &H100
End Sub
Sub Midi_Decode_Rene2(ByRef someVal As Long)
Midi.byte0 = Peek(Byte,VarPtr(someVal))
Midi.byte1 = Peek(Byte,VarPtr(someVal)+ 1)
Midi.byte2 = Peek(Byte,VarPtr(someVal)+ 2)
End Sub
Sub Midi_Decode_Rene3(ByVal someVal As String)
Midi.byte0 = Peek(Byte,StrPtr(someVal))
Midi.byte1 = Peek(Byte,StrPtr(someVal)+ 1)
Midi.byte2 = Peek(Byte,StrPtr(someVal)+ 2)
End Sub
Sub Midi_Decode_Rene4(ByVal someVal As String)
Local lByte As data At StrPtr(someVal)
Midi = lByte
End Sub
Petr
ReneMiner
30-04-2013, 13:37
Pretty fast methods- but Max wants to have the values stored to "midi"-variable instantly - and he does not want to change anything about the data-type.
So it has to print out this:
PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
but your both ways don't show the expected numbers if I insert this line. So there is some conversion in your code needed as
"Midi = ..."
which you have not timed in your test ;--)
How about this:
'...
PrintL "Press a Key to start method Midi_Decode_Rene5"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Poke$(VarPtr(midi), LEFT$(MKL$(MidiWord),3))
'PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
Petr Schreiber
30-04-2013, 14:34
You are right. Then...
Poke$? That is soooo 80's BASIC ;)
Lets see what new ThinBASIC offers, it's time to release the Kraken... or Memory_Copy!:
Uses "Console"
%MAX_Tests = 1000000
Type data
byte0 As Byte
byte1 As Byte
byte2 As Byte
End Type
Union uData
AsByte As data
AsLong As Long
End Union
Type tData
Element As uData
End Type
Dim Midi As data
Long MidiWord
Quad tStart,tEnd
Double tTime 'for obtain elapsed time
' -- Initialize high precision timer
HiResTimer_Init
'---------------------------------------------------------------------
PrintL "MidiWord conversion speed test" + Str$(%Max_Tests) + " of executions:"
PrintL
PrintL "Press a Key to start method Midi_Decode_Max"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Max (MidiWord)
''PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene1"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene1(MidiWord)
''PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene2"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene2(MidiWord)
''PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene3"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene3(MKL$(MidiWord))
'' PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Rene4"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Midi_Decode_Rene4(MKL$(MidiWord))
'' PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Eros1"
WaitKey
tStart = HiResTimer_Get
Dim lData As tData
For MidiWord = 1 To %Max_Tests
lData.Element.AsLong = MidiWord
''PrintL lData.Element.AsByte.byte0 & $TAB & lData.Element.AsByte.byte1 & $TAB & lData.Element.AsByte.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to start method Midi_Decode_Petr1 Tuned"
WaitKey
tStart = HiResTimer_Get
For MidiWord = 1 To %Max_Tests
Memory_Copy(VarPtr(MidiWord), VarPtr(Midi), SizeOf(Midi))
''PrintL Midi.byte0 & $TAB & Midi.byte1 & $TAB & Midi.byte2
Next
tEnd = HiResTimer_Get : tTime = (tEnd-tStart)/1000000
PrintL CRLF & "Executed in " & Format$(tTime, "#.00") & " seconds" & CRLF
'---------------------------------------------------------------------
PrintL "Press a Key to exit"
WaitKey
Sub Midi_Decode_Max (ByVal nVal As Long)
Dim temp0,temp1,temp2 As Long = nVal
Midi.byte0 = temp0 And 255
Midi.byte1 = (SHIFT SIGNED RIGHT temp1, 8) And 255
Midi.byte2 = (SHIFT SIGNED RIGHT temp2, 16) And 255
End Sub
Sub Midi_Decode_Rene1(ByVal anyValue As Long)
Midi.byte2 = Int(anyValue / &H10000)
Midi.byte1 = Int((anyValue - &H10000 * Midi.byte2)/ &H100)
Midi.byte0 = anyValue - Midi.byte2 * &H10000 - Midi.byte1 * &H100
End Sub
Sub Midi_Decode_Rene2(ByRef someVal As Long)
Midi.byte0 = Peek(Byte,VarPtr(someVal))
Midi.byte1 = Peek(Byte,VarPtr(someVal)+ 1)
Midi.byte2 = Peek(Byte,VarPtr(someVal)+ 2)
End Sub
Sub Midi_Decode_Rene3(ByVal someVal As String)
Midi.byte0 = Peek(Byte,StrPtr(someVal))
Midi.byte1 = Peek(Byte,StrPtr(someVal)+ 1)
Midi.byte2 = Peek(Byte,StrPtr(someVal)+ 2)
End Sub
Sub Midi_Decode_Rene4(ByVal someVal As String)
Local lByte As data At StrPtr(someVal)
Midi = lByte
End Sub
Petr