Seite 1 von 1
Interpreter beschleunigen
Verfasst: 01.07.2011 13:41
von Kevin
Hi,
ich möchte meinen Interpreter beschleunigen und hab dazu ein paar fragen.
So läuft es aktuell: (Codes sind nur zur Veranschaulichung funktionieren nicht)
Code: Alles auswählen
Repeat
Select ReadWord(File)
Case 1;+
;...
Case 2;-
....
Case 3;*
...
Case ...
...
...
case 200;extrem langsam da erst die anderen case' durchgegangen werden
...
EndSelect
Until ...
nur das Problem dabei ist um so mehr case' es gibt um so langsamer es wird.
deshalb hab ich das hier getestet:
Code: Alles auswählen
Procedure P01_Add()
; + ...
EndProcedure
Procedure P02_Sub()
; - ...
EndProcedure
Procedure P04_Div()
; * ...
EndProcedure
Procedure P200_Ka()
; * ...
EndProcedure
;...
Prototype Beispiel()
Structure ProzedurListe
Beispiel.Beispiel[4]
EndStructure
Define ProzedurListe.ProzedurListe
ProzedurListe\Beispiel[1] = @P01_Add()
ProzedurListe\Beispiel[2] = @P02_Sub()
ProzedurListe\Beispiel[2] = @P04_Div()
ProzedurListe\Beispiel[200] = @P200_Ka()
Repeat
ProzedurListe\Beispiel[ReadWord(File)]()
Until ...
hier ist zwar jeder Aufruf gleich schnell, aber alles insgesamt langsamer da jetzt immer eine procedure aufgerufen werden muss...
Meine frage jetzt gibt es noch eine Möglichkeit das ganze schneller zu machen ohne proceduren dabei zu verwenden?
Re: Interpreter beschleunigen
Verfasst: 01.07.2011 14:11
von TomS
Was hast du gegen Proceduren?
Also das Lesen geht sicherlich sehr viel schneller, wenn du den ganzen Dateiinhalt mit ReadData() einliest und dann mit
Select PeekW(*pointer)
und *pointer + SizeOf(Word)
arbeitest.
Re: Interpreter beschleunigen
Verfasst: 01.07.2011 14:27
von Kevin
TomS hat geschrieben:Was hast du gegen Proceduren?
ich habe nichts gegen Proceduren aber schon allein der Aufruf einer Procedure braucht Rechenleistung und ich suche eine noch schnellere Möglichkeit das ganze umzusetzen.
TomS hat geschrieben:Also das Lesen geht sicherlich sehr viel schneller, wenn du den ganzen Dateiinhalt mit ReadData() einliest und dann mit
Select PeekW(*pointer)
und *pointer + SizeOf(Word)
arbeitest.
so wird es aktuell schon gemacht der Code war nur da damit ihr euch grob vorstellen könnt wie das ganze abläuft.
Re: Interpreter beschleunigen
Verfasst: 01.07.2011 15:02
von TomS
Schneller geht's nicht. Außer du benutzt von Haus aus Integer, was aber die Scriptgröße vervierfacht.
Was du noch machen kannst (was du wahrscheinlich schon gemacht hast, nur nicht für nötig empfunden hast und mitzuteilen), ist das aufteilen deiner Befehle in Gruppen (Libraries).
Anstatt:
Code: Alles auswählen
Case 1 ;LibA
Select next
Case 1
;...
Case 255
EndSelect
Case 1 ;LibB
Select next
Case 1
;...
Case 255
EndSelect
Mal angenommen du hast 10 Libraries mit jeweils 10 Befehlen.
Dann musst du mit der linearen Methode 100 mal Case aufrufen.
Mit der neuen Methode nur maximal 20 mal.
Das ist also 5 mal schneller (~4.9 wegen bissal Overhead wegen erneutem Select)
Wenn du Byte nimmst anstatt Word bleibt dein Code gleich groß.
Falls du eine "Library" haben solltest die mehr als 254 Befehle hat, kannst du die ja aufteilen.
LibA1
LibA2
LibB
etc...
Re: Interpreter beschleunigen
Verfasst: 01.07.2011 15:09
von miscalculated
Soetwas war bei mir schneller als ein Select:
Code: Alles auswählen
; Springt zur nächsten Anweisung, muss hinter jeden Befehl
Macro NextInstruction()
TARGET = JumpTable(ReadWord(Dateibla))
; Weiß nicht ob das auf 64bit Systemen genauso funktionieren würde:
!JMP dword [p.v_TARGET]
EndMacro
Procedure Execute()
; Sprungtabelle mit allen Befehlen
Dim JumpTable(255)
JumpTable(0) = ?Add
JumpTable(0) = ?Sub
...
; alles ins rollen bringen:
NextInstruction()
?Add:
; addieren
NextInstruction()
?Sub:
; subtrahieren
NextInstruction()
...
EndProcedure
Eventuell sind bei dir auch noch Optimierungen in den Befehlen möglich, aber das musst du selbst wissen, wenn dass alles nicht hilft bleibt noch die Möglichkeit das Skript zu kompilieren.
PS: kannst auch das Konzept der Sprungtabelle nutzen und die Schleifenstruktur beibehalten:
Code: Alles auswählen
Procedure Execute()
; Sprungtabelle mit allen Befehlen
Dim JumpTable(255)
JumpTable(0) = ?Add
JumpTable(0) = ?Sub
...
; alles ins rollen bringen:
Repeat
; Zum passenden Befehl springen
TARGET = JumpTable(ReadWord(Dateibla))
; Weiß nicht ob das auf 64bit Systemen genauso funktionieren würde:
!JMP dword [p.v_TARGET]
?Add:
; addieren
Continue
?Sub:
; subtrahieren
Continue
...
ForEver
EndProcedure
Re: Interpreter beschleunigen
Verfasst: 01.07.2011 15:53
von Kevin
@TomS
genau das hätte ich auch noch einbauen können
@miscalculated
Super genau so was habe ich gesucht
Eventuell sind bei dir auch noch Optimierungen in den Befehlen möglich, aber das musst du selbst wissen, wenn dass alles nicht hilft bleibt noch die Möglichkeit das Skript zu kompilieren.
PS: kannst auch das Konzept der Sprungtabelle nutzen und die Schleifenstruktur beibehalten:
werde ich machen.
Vielen Dank euch beiden ihr habt mir sehr weitergeholfen.
Re: Interpreter beschleunigen
Verfasst: 01.07.2011 16:27
von STARGÅTE
Bei der Lösung von miscalculated hast du halt keine möglichkeit Parameter oder Rückgabewerte zu erhalten, weil du die ganze Zeit nur "springst".
Wenn du also selber eine Art Stack/Register schreibst, in dem die Sachen verarbeitet werden, ist das sicher schneller.
Allerdings benutze ich selber in meinem aktuellen Projekten, ausschließlich FunktionsBäume:
Code: Alles auswählen
Prototype.i Term_FunctionI(*Term)
Structure Term
FunctionI.Term_FunctionI
StructureUnion
Integer.i
*Term.Term[2]
EndStructureUnion
EndStructure
Procedure.i Term_GetI(*Term.Term)
ProcedureReturn *Term\Integer
EndProcedure
Procedure.i Term_Function_PlusI(*Term.Term)
ProcedureReturn *Term\Term[0]\FunctionI(*Term\Term[0]) + *Term\Term[1]\FunctionI(*Term\Term[1])
EndProcedure
Term1.Term
Term1\FunctionI = @Term_GetI()
Term1\Integer = 123
Term2.Term
Term2\FunctionI = @Term_GetI()
Term2\Integer = 456
Term3.Term
Term3\FunctionI = @Term_Function_PlusI()
Term3\Term[0] = @Term1
Term3\Term[1] = @Term2
Debug Term3\FunctionI(@Term3)
Bei mir verbraucht dieser Baum ca 33 Tackzyklen
Klar an 2 Tackzyklen die eine normale Addition verbraucht mit zwei Variablen kommt es natürlcih nicht ran.
Aber zum Vergleich: Str(1) benötig alleine nur weil es um Strings geht 50 Tackzyklen.
Von daher sind die "Bremser" woanders zu suchen.
@miscalculated
Wäre nett wenn du mal ein funktionierendes Beispiel posten würdest.
@ALL:
Hier im übrigen so messe ich das:
Anzahl der Tacktzyklen von Befehlen ermitteln
Re: Interpreter beschleunigen
Verfasst: 01.07.2011 19:25
von Kevin
STARGÅTE hat geschrieben:Bei der Lösung von miscalculated hast du halt keine möglichkeit Parameter oder Rückgabewerte zu erhalten, weil du die ganze Zeit nur "springst".
Wenn du also selber eine Art Stack/Register schreibst, in dem die Sachen verarbeitet werden, ist das sicher schneller.
Allerdings benutze ich selber in meinem aktuellen Projekten, ausschließlich FunktionsBäume:
Code: Alles auswählen
Prototype.i Term_FunctionI(*Term)
Structure Term
FunctionI.Term_FunctionI
StructureUnion
Integer.i
*Term.Term[2]
EndStructureUnion
EndStructure
Procedure.i Term_GetI(*Term.Term)
ProcedureReturn *Term\Integer
EndProcedure
Procedure.i Term_Function_PlusI(*Term.Term)
ProcedureReturn *Term\Term[0]\FunctionI(*Term\Term[0]) + *Term\Term[1]\FunctionI(*Term\Term[1])
EndProcedure
Term1.Term
Term1\FunctionI = @Term_GetI()
Term1\Integer = 123
Term2.Term
Term2\FunctionI = @Term_GetI()
Term2\Integer = 456
Term3.Term
Term3\FunctionI = @Term_Function_PlusI()
Term3\Term[0] = @Term1
Term3\Term[1] = @Term2
Debug Term3\FunctionI(@Term3)
Bei mir verbraucht dieser Baum ca 33 Tackzyklen
Klar an 2 Tackzyklen die eine normale Addition verbraucht mit zwei Variablen kommt es natürlcih nicht ran.
Aber zum Vergleich: Str(1) benötig alleine nur weil es um Strings geht 50 Tackzyklen.
Von daher sind die "Bremser" woanders zu suchen.
ich glaube du hast meinen erste post nicht gelesen oder falsch verstanden
mein Interpreter liest eine kette von Anweisungen die im Speicher stehen ungefähr so wie in meinem ersten Beispiel und das kann ich jetzt durch miscalculated' Beispiel optimieren.
mit miscalculated' Beispiel brauch ich keinen Rückgabewerte da ich es sofort berechnen kann
STARGÅTE hat geschrieben:
@miscalculated
Wäre nett wenn du mal ein funktionierendes Beispiel posten würdest.
Hier ein funktionierender code:
Code: Alles auswählen
Define TARGET.l
Macro NextInstruction(too)
TARGET = JumpTable(too)
!JMP [v_TARGET]
EndMacro
; Sprungtabelle mit allen Befehlen
Dim JumpTable(255)
JumpTable(1) = ?l1
JumpTable(2) = ?l2
JumpTable(3) = ?l3
NextInstruction(1);sprung zu l1
Debug "wird übersprungen"
l1:
Debug "start"
NextInstruction(3);sprung zu l3
l2:
Debug "wird übersprungen"
l3:
Debug "ende"
hab ich schon gesehen und werde es auch benutzen um meinen Interpreter zu optimieren.
