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:
Case 2:
;...
Case 9999999:

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 :allright:
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"
STARGÅTE hat geschrieben:@ALL:

Hier im übrigen so messe ich das: Anzahl der Tacktzyklen von Befehlen ermitteln
hab ich schon gesehen und werde es auch benutzen um meinen Interpreter zu optimieren. :allright: