3. PowerBASIC und der CoProzessor

English


3.1. Unterstützt PowerBASIC einen CoProzessor?
3.2. Welche Fließkommabibliothek ist für mich die optimale?
3.3. Macht sich der CoProzessor auch bei $FLOAT PROCEDURE bemerkbar?
3.4. Welche PowerBASIC-Funktionen sind betroffen?
3.5. mögliche Ursachen für den CoProzessor-Effekt
3.6. PowerBASIC-Benchmark Source

3.1. Unterstützt PowerBASIC einen CoProzessor?

Die Antwort lautet ganz einfach JA. Bereits in den Compiler-Optionen haben Sie die Möglichkeit drei verschiedene Fließkommabibliotheken auszuwählen. Aber mit dieser Unterstützung des CoProzessors sind unter PowerBASIC einige Haken verbunden, die es hier aufzuzeigen geht damit sie schnellere und hoffentlich nur sauber funktionierende Programme entwickeln.

3.2. Welche Fließkommabibliothek ist für mich die optimale?

PowerBASIC bietet insgesamt drei Fließkommabibliotheken an:

3.3. Macht sich der Coprozessor auch bei $FLOAT PROCEDURE bemerkbar?

Auch hier ist die Antwort ganz klar: JA. Obwohl PowerBASIC keine Coprozessorunterstützende Fließkommabibliothek eingebunden hat, läßt sich dies anhand der beiliegenden Source sehr deutlich beweisen.
Des Rätsels Ursache liegt in der PowerBASIC-Runtime-Bibliothek, diese unterstützt schon von Hause aus einen i87. Deshalb lassen sich auch die Geschwindigkeitsauswirkungen der verschiedenen Fließkommabibliotheken nicht verallgemeinern.

3.4. Welche PowerBASIC-Funktionen sind betroffen?

Als betroffende internen PowerBASIC-Funktionen wäre da vorallem SELECT CASE zu nennen. Messungen haben gezeigt das SELECT CASE mit i87 5 Sekunden braucht. Unter den gleichen Voraussetzungen (aber ohne i87) bis zu 200 Sekunden benötigen kann ($FLOAT EMULATE). Enorme Verbesserungen waren bereit mit $FLOAT PROCEDURE zu erreichen (jetzt nur noch 35 Sekunden).
Im allgemeinen kann gesagt werden: SELECT CASE hat nichts in zeitkritischen Routinen zu suchen.
Ebenso, aber bei weitem nicht so extrem, ist die PRINT-Ausgabe von nummerischen Ausdrücken betroffen.

3.5. mögliche Ursachen für den CoProzessor-Effekt

Meines Erachtens hat dieser Effekt recht natürliche Ursachen, da alle betroffenden Befehle mit dem neuen 80-stelligen Zahlensystem umgehen können müssen. Anscheinend haben die Programmierer von PowerBASIC versucht den zusätzlichen Rechenaufwand durch Einsatz des CoProzessors wieder wettzumachen. Wobei Ihnen dies bei vorhandenem CoProzessor auch recht gut gelungen ist.
Andererseits kann man sich fragen, warum der Compiler dies nicht besser optimiert sofern nur normale 16/32bit Zahlen eingesetzt werden.

3.6. PowerBASIC-Benchmark Source

Die hier beigefügte Source soll Ihnen die Zusammenhänge der vorherigen Abschnitte besser demonstrieren. Am besten Sie compilieren die Source und testen einfach ein wenig herum.
    Source:
        REM *****************************************************************
        REM
        REM   PBBENCH.EXE - Performance-Meáprogramm fr PowerBASIC
        REM
        REM   Zum Feststellen der Geschwindigkeitsunterschiede einzelner
        REM   PowerBASIC-Befehle in Verbindung der verwendeten Flieákomma-
        REM   bibiothek bei vorhanden bzw. nichtvorhandensein eines
        REM   Coprozessors.
        REM
        REM   Copyright: Thomas Gohel & Andras Hoeffken         Version 2.10
        REM   Alle Rechte vorbehalten
        REM
        REM -----------------------------------------------------------------
        REM
        REM   Wichtige Hinweise:
        REM   Fr halbwegs reale Meáungen muá sich der Prozessor im REAL-
        REM   Mode befinden. Es drfen keine TSR-Treiber installiert sein,
        REM   also kein KEYB.COM, SMARTDRV.EXE oder ähnliches.
        REM   Wichtig:
        REM   Fr eine halbwegs genaue Meáung muá das Programm mehrmals
        REM   aufgerufen und dann Mittelwerte gebildet werden.
        REM
        REM   Besitzer von 486'er/586'ern bzw. 286/386'ern mit
        REM   installiertem x87'er Prozessor k”nnen den CoProzessor fr
        REM   PowerBASIC mit dem in dieser Source beigefgtem Listing
        REM   Ein/Aus schalten. Das muá allerdings die IDE bzw. das fertige
        REM   EXE-File erneut gestartet werden!
        REM
        REM   *************************************************************
        REM
        $COMPILE EXE "PBBENCH.EXE"
        $CPU 80386
        $LIB ALL OFF
        REM $FLOAT NPX              ' fr Rechner mit CoProzeáor (am
                                    ' schnellsten)
        REM $FLOAT PROCEDURE        ' fr Rechner ohne CoProzeáor (von mir
                                    ' empfohlen)
        REM $FLOAT EMULATE          ' automatisch untersttzen (ohne
                                    ' Coprozessor extrem langsam!!
        REM $DEBUG MAP OFF

        PRINT
        PRINT "Performance-Messprogramm fuer PowerBASIC";:
        PRINT TAB(58); "(c) A.Hoeffken/Th.Gohel";:
        PRINT TAB(68); "Version 2.10";:
        PRINT STRING$(80,"-");
        PRINT
        a% = 1                           ' diverse Variablen
        i% = 1234                        '       -"-
        e& = 12345678                    '       -"-

        REM Zc1! fr 5000000-Schleifen   ; zum Herausrechnen der Zeiten
        REM Zc2! fr 2000000-Schleifen   ; fr die FOR/NEXT-Schleifen
        REM Zc3! fr 100000-Schleifen
        REM Zc4! fr 2000-Schleifen

        IF pbvnpx > 0 THEN
            PRINT "CoProzessor " + CHR$(pbvnpx+48) + "87 gefunden!"
            PRINT
            PRINT "Soll der CoProzessor fr die n„chste Messung ";
            PRINT "ausgeschaltet werden (J/N)?"
            BEEP
            A$ = UCASE$(INPUT$(1))
            IF A$ = "J" THEN CoPro "AUS"
        ELSE
            PRINT "kein CoProzessor gefunden!"
            PRINT
            PRINT "Soll der CoProzessor fr die n„chste Messung ";
            PRINT "wieder eingeschaltet werden (J/N)?"
            PRINT
            PRINT "Hinweis: Einschalten dieses Testes bei nicht ";
            PRINT "installiertem Coprozessor fhrt"
            PRINT "         zum Absturz!"
            BEEP
            A$ = UCASE$(INPUT$(1))
            IF A$ = "J" THEN CoPro "EIN"
        END IF

        PRINT
        GOSUB HoleZeitKonstanten
        GOSUB MesseFORNEXT
        GOSUB MesseIFTHEN
        GOSUB MesseSELECTCASE
        GOSUB MesseMATHEMATIK
        GOSUB MesseSTRING
        GOSUB MesseNUMPRINT
        GOSUB MesseSTRPRINT
        PRINT
        END

        '********************************************************************
        '  Holen der einzelen Zeitkonstanten fr die einzelnen Messungen
        '********************************************************************

        HoleZeitKonstanten:
        PRINT "Messung der Zeitkonstanten ";

        t1! = TIMER
        FOR i& = 1 TO 2000           ' Zeit fr 2000-Schleifen ausmessen
        NEXT i&
        t2! = TIMER
        Zc4! = t2! - t1!

        PRINT ".";
        t1! = TIMER
        FOR i& = 1 TO 5000000        ' Zeit fr 5-Mio-Schleifen ausmessen
        NEXT i&
        t2! = TIMER
        Zc1! = t2! - t1!

        PRINT ".";
        t1! = TIMER
        FOR i& = 1 TO 100000         ' Zeit fr 100000-Schleifen ausmessen
        NEXT i&
        t2! = TIMER
        Zc3! = t2! - t1!

        PRINT "."
        t1! = TIMER
        FOR i& = 1 TO 2000000        ' Zeit fr 2-Mio-Schleifen ausmessen
        NEXT i&
        t2! = TIMER
        Zc2! = t2! - t1!

        RETURN


        '********************************************************************
        '
        ' Hier nun die einzelnen Routinen zur Zeitmessung der einzelnen
        ' Befehle. Im Prinzip ist die Messung immer abh„ngig vom verwendeten
        ' Computersystem und dem installiertem Betriebssytem. Gerade aber in
        ' Verbindung mit PowerBASIC, der verwendeten Flieákommabibiliothek
        ' und dem Vorhandensein eines CoProzessors lassen sich erhebliche
        ' Unterschiede bei der Performance einzelner Befehle ermitteln.
        '
        '********************************************************************

        MesseFORNEXT:
            PRINT "Messe FOR/NEXT   : ";
            t1! = TIMER
            FOR i& = 1 TO 5000000        '5-Millionen-Schleife ausmessen,
            NEXT i&                      'i = long integer
            t2! = TIMER
            PRINT t2! - t1!; "sec "
            RETURN

        MesseIFTHEN:
            PRINT "Messe IF/THEN    : ";
            t1! = TIMER
            FOR i& = 1 TO 5000000
                IF a% = 0 THEN           'IF THEN Methode
                ELSEIF a% = 2 THEN
                ELSE
                END IF
            NEXT i&
            t2! = TIMER
            PRINT t2! - t1! - Zc1!; "sec "
            RETURN

        MesseSELECTCASE:
            PRINT "Messe SELECT CASE: ";
            t1! = TIMER
            FOR i& = 1 TO 2000000
                SELECT CASE A%           'SELECT CASE Methode
                    CASE 0
                    CASE 1
                    CASE ELSE
                END SELECT
            NEXT i&
            t2! = TIMER
            PRINT t2! - t1! - Zc2!; "sec "
            RETURN

        MesseMATHEMATIK:
            PRINT "Messe MATHEMATIK : ";
            t1! = TIMER
            FOR i& = 1 TO 2000000
                i% = i% + 100            'extrem einfache Aufgaben
                e& = e& * 2
                e& = e& \ 2
                i% = i% - 100
            NEXT i&
            t2! = TIMER
            PRINT t2! - t1! - Zc2!; "sec "
            RETURN

        MesseSTRING:
            PRINT "Messe STRING's   : ";
            t1! = TIMER
            FOR i& = 1 TO 2000
                A$ = STRING$(20000, 32)
                A$ = RIGHT$(A$, 10000) + "Test"
                e% = INSTR(A$, "Test")
               A$ = ""
            NEXT i&
            t2! = TIMER
            PRINT t2! - t1! - Zc4!; "sec "
            RETURN

        MesseNUMPRINT:
            PRINT "Messe NUM-PRINT's  ";
            t1! = TIMER
            FOR i& = 1 TO 100000
                LOCATE , 1
                PRINT "Messe NUM-PRINT's: "; i&
            NEXT i&
            t2! = TIMER
            LOCATE , 20
            PRINT t2! - t1! - Zc3!; "sec "
            RETURN

        MesseSTRPRINT:
            PRINT "Messe $$$-PRINT's  ";
            t1! = TIMER
            FOR i& = 1 TO 100000
                LOCATE , 1
                PRINT "Messe $$$-PRINT's: ";
            NEXT i&
            t2! = TIMER
            LOCATE , 20
            PRINT t2! - t1! - Zc3!; "sec "
            RETURN

        '*****************************************************************
        ' Hier nun die Routine zum Ausschalten des Coprozessors
        '************************************************************************

        SUB Copro(Switch$)
                SELECT CASE UCASE$(Switch$)
                     CASE "AUS", "OFF", "-"
                         ! mov ax, &h0040
                         ! mov es, ax
                         ! mov ax, word ptr es:[&h10]
                         ! and ax, &b1111111111111101
                         ! mov word ptr es:[&h10], ax
                     CASE "EIN", "ON", "+"
                         ! mov ax, &h0040
                         ! mov es, ax
                         ! mov ax, word ptr es:[&h10]
                         ! or  ax, &b0000000000000010
                         ! mov word ptr es:[&h10], ax
                END SELECT
        END SUB


(c) 1995/2007 by Thomas Gohel, All rights and bug's reserved