Martin Backschat, Michael Bernards, Arnd Beißner
Assembler
TIP 1
Bei vielen komplizierten Funktionen sollten Sie sich überlegen, diese zu berechnen und die Ergebnisse als Tabellen anzulegen. Ein Beispiel ist der Sinus. Hier empfiehlt es sich, anstatt aufwendigem Rechnen, den Wert schnell aus einer Tabelle auszulesen.
TIP 2
Stack reinigen: Benutzen Sie statt
ADDA.L #Bytes,A7 (14,6)
bei bis zu 8 Byte
ADDQ.L #Bytes,A7 (8,2)
sonst
LEA Bytes(A7),A7 (8,4)
TIP 3
Umrechnen vom Intel- ins Motorola-Format. Wort steht in Dß:
ROR.W#8,D0.
Langwort steht in D0:
ROR.W#8,D0,SWAP D0, ROR.W#8 D0.
TIP 4
Die PC-Relative Adressierung ist 20 bis 30 Prozent schneller und um den selben Faktor kompakter als die direkte Adressierung.
TIP 5
Da man die PC-Relative Addressierung nicht im Zieloperanden verwenden kann, laden Sie bei vielen Zugriffen die Adresse in ein Adressregister und adressieren relativ.
TIP 6
PEA Adresse (20,6)
ist schneller als
MOVE #Adresse,-(A7) (24,6).
TIP 7
LEA Adresse, An (12,6)
ist schneller als
MOVEA #Adresse,An (20,6).
TIP 8
Bei Sprüngen größer 32 KByte BRA und BSR statt JMP und JSR verwenden. Bei sehr kurzen Sprüngen (kleiner 128 Byte) BRA.S und BSR.S einsetzen.
TIP 9
Die Datenübergabe an Unterprogramme führen Sie schneller über Register statt über den Stack durch.
TIP 10
CMPI #0,<ea> ersetzen durch TST <ea>.
TIP 11
Datenbereiche, die nicht initialisiert werden müssen ( z.B. Sektorpuffer), sollten ins BSS-Segment gelegt werden. Dort benötigen sie zwar genausoviel Speicher, aber auf Diskette sind die Programme kürzer, lassen sich deshalb schneller laden und sparen Platz.
TIP 12
Die schnellste Speicherverschiebe-Routine bedient sich des MOVEM-Befehls. Bei 14 Registern lassen sich mit zwei Befehlen in 244 Taktzyklen so 56 Bytes verschieben. Die normale Routine benötigt dafür mehr als 400 Taktzyklen.
TIP 13
Vergleiche mit Konstanten kleiner gleich 8 Byte sind schneller mit einem SUBQ-Befehl (4,2) als mit CMPI (8,4).
TIP 14
Zahlen zwischen -128 und +127 lassen sich mit einem MOVEQ dreimal schneller in ein Datenregister laden als mit MOVE.
TIP 15
Um einen Wert zu einem Adreßregister zu zählen, verwenden Sie statt
add.l/sub.l #,Ax
für kleine Werte
addq.l/subq.l #,Ax
und für größere
lea.l #(Ax),Ax
TIP 16
Bei Aufrufen des TOS reicht es vollkommen aus, sich die Register D0,D1,A0,A1 zu merken. Der Rückgabewert wird immer in DO übergeben. Einen Fehler testen Sie folgendermaßen:
trap #.. ;TOS-Call
tst.l d0
bmi AnError
TIP 17
Zum Löschen von Datenregistern verwenden Sie den Befehl
moveq #0,Dx
statt
clr.l Dx
GFA-Basic 3.0
TIP 18
Im Interpreter sollten Sie FOR-NEXT-Schleifen vermeiden und durch REPEAT-UNTIL oder WHILE-WEND-Konstrukte ersetzen. FOR-NEXT-Schleifen arbeitet der Interpreter langsamer ab, als die anderen Schleifenarten. Für den Compiler ist dies allerdings ohne Bedeutung.
TIP 19
Integer-Variablen sollten Sie immer benutzen, wenn keine Fließkommazahlen nötig sind. Es ist unwichtig, ob Wort-Integer (Suffix &) oder Langwort-Integer (Suffix %) verwendet werden, da kaum ein Unterschied besteht.
TIP 20
Die neue Version von GFA-Basic, 3.0, bietet spezielle Arithmetikbefehle für Integerzahlen (SUB,ADD,etc.). Diese sind erheblich schneller als die normalen Operanden (+,-,etc.).
TIP 21
Zum Speichern und Laden von ASCII—Texten empfehlen sich die Befehle STORE und RECALL. Sie sind um ein Vielfaches schneller als die Befehle PRINT# und INPUT#.
TIP 22
In der neuen Version des GFA-Basic gibt es zum schnellen Zeichnen von Bezierkurven den »Curve«-Befehl. Dieser nimmt vier Punktkoordinaten als Parameter.
Für die anderen Sprachen finden Sie einen schnellen Algorithmus von Bezierkurven im Expertenforum der kommenden Ausgabe.
GEMDOS, BIOS, XBIOS, GEM
TIP 23
Statt eine Datei in kleinen Stücken zu laden, nehmen Sie größere Blöcke, die Sie im Speicher trennen, denn Dateizugriffe sind allgemein sehr langsam.
TIP 24
Wenn in eine Datei häufiger geschrieben oder aus ihr gelesen werden muß (z.B. Adressverwaltung) ist es besser, die Datei zu Beginn größer zu dimensionieren, um dann in die vorhandene Datei zu schreiben. Das GEMDOS vor der TOS-Version 1.4 sucht sehr lange nach freien Sektoren.
TIP 25
Wenn bei einem Fenster—Redraw Slider oder Pfeile betätigt werden, zeichnet man nicht das ganze Fenster neu, sondern verschiebt es mit der Copy-Raster—Funktion und zeichnet dann nur die neuerscheinenden Bereiche. Bei Fenstern, die viele Objekte enthalten, ist der Geschwindigkeitsgewinn beträchtlich.
TIP 26
Beim Lesen und Schreiben von Sektoren (Rwabs, Floprd, Flopwr) sparen Sie Zeit indem Sie darauf achten, daß die Pufferadresse gerade ist.
TIP 27
Die Zeichenausgabe unter BIOS (Bconout) ist erheblich schneller als die entsprechenden Routinen des GEMDOS (Cconout). Nachteil: Die BIOS—Routinen lassen sich nicht auf andere Geräte umleiten und erfordern deshalb eventuell mehr Programmieraufwand.
TIP 28
Gibt man Zeichenketten auf den Bildschirm aus, die ASCII-Code 0 enthalten, benutzt man Fwrite mit Handle 1, da Cconws bei dem Auftreten von ASCII 0 abbricht.
TIP 29
Um die schnellstmöglichen Grafikroutinen für die Grundfunktionen wie Linien, Kreise, Füllen, Speicherverschiebungen und Textausgaben zu nutzen, greifen Sie auf die Line—A-Routinen des Betriebsystems zu, statt über GDOS und dem VDI zu arbeiten. Bibliotheken zum Ansprechen der Routinen sollten für jede Sprache zur Verfügung stehen.
ST-Basic
TIP 30
Am besten eine andere Sprache benutzen.
C
TIP 31
Um eine Struktur mit vielen Flags kleiner und handlicher zu gestalten, bietet es sich an, mit Bitfeldern zu arbeiten.
struct beispiel {
char flag1,flag2,flag3;
int color;
/* Werte 0-7 */ };
kann auch als
struct beispiel
{
unsigned int flag1 : 1;
flag2 : 1;
flag3 : 1;
unsigned int color : 3;
};
geschrieben werden und belegt nur noch 2 statt vorher 5 Byte.
TIP 32
Variablen, Strukturen, Zeiger etc., die gedanklich zusammengehören, können Sie der Übersicht halber als Struktur zusammenfassen. Dies hat einen Riesenvorteil: Das Kopieren aller Komponenten an eine andere Stelle geschieht mit einem Befehl und wird vom Compiler höchst optimiert:
int datensatz_nr;
char *datensatz_text;
long seriennummer;
fassen Sie zusammen zu:
struct Datensatz
{ int datensatz_nr;
char *datensatz_text;
long seriennummer};
und können nun diese Struktur mit «datensatz2 = datensatz1» kopieren.
TIP 33
Wenn nicht unbedingt nötigt, auf PRINTF, SCANF und deren Verwandten verzichten, da die meisten Compiler bei diesen Routinen eine große Library in das Programm binden und die Routinen langsamer sind als die des TOS.
TIP 34
Bei einigen C-Compilern (z.B. Megamax 1.1) lohnt es sich, Bibliotheksroutinen, die zwar miteingebunden, aber nicht benötigt werden, durch Dummies zu ersetzen.
TIP 35
Verwendet man bei C die Standard-Dateiroutinen wie FOPEN, nimmt der Code um einiges an Umfang zu. Die Systemroutinen FOPEN etc. reichen oft aus.
TIP 36
Um bei einer Float—Integer-Wandlung den Rundungsfehler zu minimieren, gibt es einen Trick: »Aint = (int) (Afloat+0.5)«
TIP 37
In Kopierschleifen ersetzen Sic die Array Index-Adressierung (carray[i] = darray[j]) durch die direkte Adressierung (*carray++ = *darray++).
TIP 38
Um einen größeren Speicherblock in C zu verschieben, bietet es sich an, Strukturen zu kopieren. Dabei optimiert der C-Compiler automatisch. 1000*4 Byte lassen sich etwa folgendermaßen kopieren:
struct BYTE4000
{ long long4[1000] };
*src_block,*dest_block;
src_block =...;
dest_block = ...;
*dest_block = *src_block;
TIP 39
Bei zeitkritischen Routinen benutzen Sie Registervariable. Hierbei werden die C-Variablen in den Prozessorregistem abgelegt. Beispiel:
register char *adr_pointer;
register long long_value;
TIP 40
Um Kopierschleifen mit komplizierten Arrays zu optimieren, kopieren Sie statt mit den Arrays mit Zeigern auf diese. Beispiel:
src_ptr= &src_array[i][0];
dest_ptr = &dest_array[j][0];
*src_ptr++ =*dest_ptr++;
TIP 41
Bei vielen Zugriffen auf eine Datei verwenden Sie die gepufferten Dateifunktionen »fopen«, »fclose«, »fseek«, »fread«, »fwrite« und »fflush« etc. Damit wird Ihre Datei im Speicher gepuffert. Die Puffergröße stellen Sie mit der Funktion »setbuf« ein.
TIP 42
Zum schnellen Datensortieren verwenden Sie die Bibliotheksroutine »qsort«. Sie basiert auf dem schnellen Quicksort-Algorithmus.
TIP 43
Der Multiplikationsbefehl »mulu« benötigt viel Zeit. Multiplikationen mit kleinen Werten optimieren Sie durch »add« und »lsl«. Beispiele:
D0 x 2: lsl.l #1,d0
D0 x 3: move.l d0,d1
add.l d1,d1
add.l d1,d0
D0 x 4: lsl.l #2,d0
D0 x 5: move.l d0,d1
lsl.l #2,d1
add.l d1,d0
TIP 44
Um auch ohne die langsamen Gleitkommazahlen schnell aber genau zu rechnen, teilen Sie ein Langwort (32 Bit) in zwei 16 Bit-Worte auf (Hi- und Lo-Wort). Das Hi-Wort deklarieren Sie dabei als Vorkomma— und das Lo-Wort als Nachkommawert. Zwei Zahlen (1.0 und 5.5) addieren Sie beispielsweise folgendermaßen:
move.l #$00010000,d0 ; 1.0
add.l #$00058000,d0 ; +5.5
Runden können Sie die Zahl mit
add.l #$00008000,d0 ; +0.5
clr.w d0
swap d0 ; Vorkomma
TIP 45
Um eine Zahl durch eine Zweierpotenz zu dividieren, benutzen Sie die Bitschiebebefehle:
D0 / 2: lsr.l #1,d0
D0 / 4: lsr.l #2,d0
D0 / (2 ^ 17): clr.w d0
swap d0
lsr.w 01, d0
TIP 46
Um Routinen im Supervisor auszuführen, eignet sich die XBIOS—Routine »Supexec(void *prgptr)«. Damit sparen Sie sich den lästigen Moduswechsel mit »Super(stack)« und Zeit.
TIP 47
Bei verschachtelten FOR-NEXT-Schleifen plazieren Sie die größte Schleife als die innerste Schleife.
TIP 48
Um die Geschwindigkeit bei Berechnungen zu beschleunigen, sperren Sie mit »or.w #$700,sr« in Assembler oder »IPL 6« in Omikron-Basic alle Interrupts.
TIP 49
In Omikron-Basic ist die Integer-Division vorzuziehen (»\« statt»/«). Diese teilt zwei Integerwerte extrem schnell.
TIP 50
Bestimmte Rechenfunktionen bewirken automatisch, daß die gesamte Berechnung mit Fließkommazahlen durchgeführt wird. Um in das Integer-Format zurückzukehren, verwenden Sie den Befehl CINT. Beispiel:
A=CINT (SQR(I))+J-I*3
Ohne CINT würde die komplette Formel mit Fließkommazahlen berechnet und mehr Rechenzeit beanspruchen.