Tagesarchive: 9.1.2013

MPP4: Immer im Takt

Schneller, höher, weiter, lautet die Maxime im Sport. Schneller, bunter, klangvoller, könnte man das auf Computer übertragen. Für die Multiplattform-Programmierung kann sich das allerdings als (kleines) Problem erweisen, z.B. wenn man mit einfachen FOR-NEXT-Warteschleifen arbeitet. Der heutige Beitrag in dieser Reihe widmet sich dem „schneller“, wobei man sich in einem Irrtum befindet, wenn man meint, dass neuere 8-Bit-Rechner schneller als ältere gewesen sein müssen, und dem „Schleifenproblem“ (was uns wieder mit den spezifischen Eigenheiten der Rechner konfrontieren wird).

Die CPU: mal schnell, mal langsam

Grundsätzlich wird die Rechengeschwindigkeit durch den Takt des Prozessors (der CPU) bestimmt. Der ist je nach Rechnertyp mal schneller, mal langsamer. Vom C64 weiß man, dass schon zwischen einem NTSC- und einem PAL-Gerät merkliche Unterschiede bestehen. Ein Plus/4 taktet (scheinbar) schneller, ein C128 (ohne VIC-Bildschirmanzeige) ebenfalls. Doch der CPU-Takt ist nur die halbe Wahrheit und manchmal führt er uns auch an der Nase herum.

Tabelle 1: Vergleich der CPU-Taktraten der Commodore-Rechner:

Computer PET/CBM VC 20 P 500 C 64 Plus/4 C 128 1MHz C 128 2MHz
PAL 1 MHz 1,10 MHz 0,98 MHz 0,98 MHz 1,76 MHz 0,98 MHz 1,97 MHz
NTSC 1 MHz 1,02 MHz 1,02 MHz 1,02 MHz 1,79 MHz 1,02 MHz 2,04 MHz

Anmerkungen:
PET/CBM: der Takt ist unabhängig vom Videochip und daher gibt es kein PAL oder NTSC.
VC 20
: Kein Fehler! Die PAL-Version ist schneller.
P 500
: Die verfügbaren Quellen sprechen alle nur von 1 MHz; da jedoch ein VIC II verbaut wurde, ist zu vermuten, dass die gleichen Werte wie für den C64 gelten.
Plus/4: Die hohe Taktrate (hier gibt es aus unterschiedlichen Quellen leicht variierende Angaben) führt in die Irre. Im sichtbaren Bereich des Bildschirms wird auf halbe Taktrate zurückgeschaltet, da TED und CPU sich den Systemtakt teilen müssen. Die effektive mittlere Taktrate liegt wohl irgendwo bei 1 MHz. Wegen unterschiedlicher Anzahl von Bildern/Sekunde zeigt die mittlere Taktrate eine weitere Abhängigkeit von der jeweiligen Videonorm (PAL/NTSC).

BASIC: weniger ist manchmal mehr

Bei Multiplattform-Programmen ist die Geschwindigkeit des BASICs entscheidend. Diese ist von zusätzlichen Faktoren abhängig, die sich durchaus stärker als die Variatonen in der Taktrate auswirken können. Zum einen spielt die Komplexität des Interpreters eine gewichtige Rolle. Ein mächtigeres BASIC (wie beim C128 BASIC 7.0) verlangsamt die Ausführung, spezielle Implementierungen von Grundfunktionen wie die verbesserte Garbage Collection ab BASIC 4.0 beschleunigt Programme mit vielen Stringoperationen. Zum anderen spielt die Komplexität der Hardware eine Rolle. Beim C64 braucht sich der Interpreter nicht groß mit Bankswitching herumzuschlagen, beim C128 hat das jedoch durchaus einen spürbareren Einfluss. Auch beim P500 wirkt sich das komplizierte Bankswitching geschwindigkeitshemmend aus.

Für einen Praxistest verwenden wir folgendes Programm:

10 t1=ti:fori=1to10000:next:t2=ti
20 print (t2-t1)/60"sekunden"

Zur Erinnerung: Die reservierte Variable TI gibt die Zeit in sechzigstel Sekunden (1/60) an. Der Zähler für TI wird initialisiert (auf Null gesetzt), wenn der Rechner startet und auch jedesmal wenn man die Anweisung TI$="000000" ausführt. TI$ gibt die seit dem letzten Initialisieren vergangene Zeit in Stunden, Minuten und Sekunden an („hhmmss“).

Mir ist klar, dass eine einfache Schleife nicht die ganze Wahrheit über die Leistungsfähigkeit eines Rechners offenbart. Es handelt sich mit Absicht um einen simplen Vergleich. Ich tröste mich damit, dass er auf jeden Fall besser ist als ein Vergleich mit PRINT-Operationen, da dabei die zusätzlichen Berechnungen für das Setzen des Farbrams die Ergebnisse einseitig beeinflussen würden.

In Ermangelung der erforderlichen Hardwarevielfalt wurden alle Messungen mit dem Emulator VICE unter Win98 durchgeführt. Daher sind die Angaben mit Vorsicht zu genießen. Zudem zeigten sich in Einzelfällen Probleme mit dem Emulator, die einen eigenen Artikel wert sind.

Tabelle 2 und 3: Zeitverbrauch der FOR-NEXT-Schleife mit 10.000 Durchläufen:

Computer PET 2001 CBM 3032 CBM 4032 B CBM 4032 CBM 8032
Dauer [Sekunden] 9,25 s 9,22 s 9,45 s 10,83 s 11,40 s

Anmerkung: Die Messungen für PET 2001 und CBM 3032 mussten mit VICE 2.2 statt der aktuellen Version 2.4 durchgeführt werden, da VICE 2.4 bei diesen Rechnern eine Bildwiederholrate von 56 fps statt 50 fps anzeigt und folglich andere Berechnungszeiten als VICE 2.2 liefert.

Computer P 500 VC 20 C 64 Plus/4 C 128 (2 MHz)
PAL 15,4 s 9,38 s 11,20 s 13,55 s 15,92 s (7,62 s)
NTSC 10,20 s 10,87 s 17,98 s 15,52 s (7,33 s)

Anmerkung: Für den P 500 sind derzeit keine Angaben zu NTSC möglich, da die Umstellung auf NTSC unter VICE 2.4 dazu führt, dass der Emulator nur noch mit 87%iger Geschwindigkeit läuft, dies beeinträchtigt die Messung. Unter VICE 2.2 ist im Menü keine Auswahl zwischen PAL und NTSC vorhanden. Beim Plus/4 ist deutlich der Effekt der Videonorm zu erkennen. Durch die höhere Bildfrequenz (60 Hz) unter NTSC wirkt sich der Bremseffekt des TED stärker aus als unter PAL (50 Hz). Beim C128 ist zum Vergleich zusätzlich der Wert für den 2 MHz-Modus in Klammern angegeben.

Für Experten sei noch angemerkt, dass der C128 auch im 40-Zeichen-Modus mit ein paar Tricks auf ca. 1,3 MHz beschleunigt werden kann. Die Schleife braucht dann ca. 11,74 s (PAL). Man kann auch noch den BASIC-IRQ deaktivieren und weitere Millisekunden gewinnen, Aber das alles bringt den C128 nur in die Nähe der Geschwindigkeit eines C64.

Kurze Zwischenbilanz: Komplexität und verrotztes Design (Plus/4) lassen die neueren Rechner gegenüber den alten CBMs alt aussehen. Hier gilt: weniger ist mehr. Die Unterschiede in der Effektivgeschwindigkeit sind erheblich. Blinkeffekte oder Anzeigezeiten für Info-Texte sollte man daher nicht mit einer einfachen FOR-NEXT-Schleife lösen!

Der Turbo: schlimmer geht immer

Wer jetzt noch meint, man könne diese „leichten“ Variationen in der Geschwindigkeit ignorieren, der sollte bedenken, dass es noch andere Gründe gibt, es nicht zu tun. Die passenden Stichworte sind SuperCPU, Chameleon im Turbo-Mode und BASIC-Compiler!

Die Zeit: ein steter Fluss

Die Lösung des Warteschleifenproblems ist simpel (oder auch nicht, wie wir später sehen werden) und nicht neu! BASIC 2.0 liefert uns seit seinen Anfängen das Werkzeug, das wir dazu brauchen: TI

Beispiel 1: Eine simple Warteschleife, wie sie vielleicht für einen Blinkeffekt genutzt werden könnte:
for i=1 to 1000 : next i

Auf einem C64 erhalten wir eine Verzögerung von ca. einer Sekunde. Der C128 benötigt für die gleiche Schleife allerdings gute 1,5 Sekunden. Derartige Abweichungen sind, vorsichig ausgedrückt: „unschön“.

Immer exakt eine Sekunde liefert hingegen dieses Programmschnipsel:
10000 t=ti+59:fori=0to1:i=-(ti>t):next:return

Man kann das auch so schreiben:
10000 t=ti+60:fori=0to1:i=-(ti=>t):next:return

So geht’s noch eleganter:
10000 t=ti+60:fori=-1to0:i=ti<t:next:return

Für einen relativen Vergleich der Rechnergeschwindigkeiten kann man ermitteln, wie häufig eine Schleife durchlaufen wird. Dazu baut man einen Zähler ein. Integriert man weitere Elemente in die Schleife kann man so auch die verbleibenden Ressourcen abschätzen. Zur Demonstration mag sich die simple Schleife selbst genügen. Die nachstehende Tabelle basiert auf folgendem Programm:

10 x=0:t1=ti:t=ti+60:fori=-1to0:i=ti<t:x=x+1:next:t2=ti
20 print (t2-t1)/60"sekunden", x"loops"

Computer CBM 3032 CBM 4032 VC 20 C64 Plus/4 (NTSC) C128 (2 MHz)
Schleifen-durchläufe 162 140 157 131 124 (96) 102 (212)

Anmerkung: Die Zahlen gelten bei den farbfähigen Computern für die PAL-Geräte. Zum Vergleich ist beim Plus/4 zusätzlich der Wert für NTSC, beim C128 der für den 2 MHz-Modus, in Klammern angegeben.

Beispiel 2: Eine Warteschleife mit Abbruchoption, wie sie vielleicht für die Anzeige von Infotexten genutzt werden könnte. Das folgende Unterprogramm kombiniert elegant Zeitschleife und Tastaturabfrage:

10000 rem 10 sekunden textanzeige (weiter mit <taste>)
10010 t=ti+600:fori=-1to0:getg$:i=(ti<t)and(g$=""):next:return

Über TI läßt sich auch bei Spielen der zeitliche Verlauf steuern, indem (z.B.) Unterprogramme (nur) alle halbe Sekunde angesprungen werden und nicht, abhängig von anderen Operationen und dem jeweiligen Rechnertyp, häufiger. Der Schwierigkeitsgrad des Programms ist dann plattformunabhängig gleich. Wobei man zugeben muss: gleich schwach, denn der schwächste Rechner bestimmt dann das zulässige Tempo. Was nerven kann, wenn es sich um interpretiertes BASIC handelt.

Beabsichtigt man hingegen, die Programme zu compilieren (danach ist das jeweils compilierte Programm natürlich wieder systemspezifisch, aber man braucht es nur in einer Version zu pflegen), dann ist ein TI-gesteuertes Programm oft die einzige Möglichkeit es überhaupt noch spielen zu können.

Der Frust: Commodore ist eben Commodore!

Commodore wäre nicht Commodere, wenn sie nicht wieder die simpelsten Grundregeln mißachtet und Blödsinn fabriziert hätten. Zum Thema TI/TI$ muss es daher heißen: Achtung Falle! Man mag es sich nicht vorstellen, was in den Knallköpfen damals vorgegangen sein muss, als man sich entschloß die CBM II-Reihe mit einem BASIC auszustatten, dass die Systemvariable TI (TIME) nicht mehr kennt.

Zwar zeigt der P 500 ein BASIC 4.0 an (es ist allerdings Version 4.7), das zu BASIC 2.0 abwärtskompatibel sein soll, doch hilft das wenig. TI ist nicht verwendbar und TI$ (TIME$) erhielt (wohl als schwachen Ersatz) einen veränderten Wertebereich. Was die Sache noch schlimmer macht. In BASIC 2.0 ist TI$ sechsstellig (ti$=“000000″) im Format „hhmmss“ (Stunden, Minuten, Sekunden). Bei BASIC 4.7 kommt eine siebte Stelle hinzu. Diese steht für Zehntel Sekunden. Kürzere Zeiteinheiten sind in BASIC nicht mehr erfassbar.

Bei der im Abschnitt „BASIC: weniger ist manchmal mehr“ in Tabelle 3 angegebenen Rechenzeit habe ich daher gemogelt. Statt des oben angegebenen Programms habe ich das folgende verwenden müssen (und folgerichtig habe ich keine zweite Nachkommastelle angegeben, denn es gab hier nichts zu Runden):

10 ti$="0000000":fori=1to10000:next:t$=ti$
20 print val(right$(t$,3))/10+val(mid$(t$,3,2))*60"sekunden"

Doch was bedeutet das für die Multiplattform-Programmierung? Man muss entweder auf den hübschen TI-Trick verzichten, für den P 500 eine alternative „Schleife“ auf Basis von TI$ entwickeln oder den P 500 aus dem Kreis der unterstützten Rechner ausschließen (da waren’s nur noch vier: PET/CBM, C64, Plus/4, C128). Beim Verbreitungsgrad des P 500 fällt da im Zweifel die Entscheidung leicht. Doch ein Gutes hat die Sache: Spötter können die CBM II-Reihe jetzt als zweifelsfrei „zeitlos“ titulieren – und in Anbetracht des Designs, wäre in diesem Spruch sogar noch eine zweite Wahrheit verborgen.

Nachdem sich, sozusagen als Nebenprodukt dieses Beitrags, die erste der bereits angekündigten bösen Überraschungen offenbart hat, mag man erahnen, dass im nächten Teil weiteres Ungemach droht, wenn wir uns intensiver mit der Kompatibilität bezüglich BASIC 2.0 beschäftigen werden.

Veröffentlicht unter C128, C64, CBM, Soft | Schreib einen Kommentar