3. PowerBASIC and the CoProcessor

Deutsch


3.1. Does PowerBASIC support a CoProcessor?
3.2. Which Floatingpointlibrary is the right one?
3.3. Does the CoProcessor work with $FLOAT PROCEDURE, too?
3.4. Which PowerBASIC-Functions are affected?
3.5. Possible reasons for the CoProcessor-Effect
3.6. PowerBASIC-Benchmark Source

3.1. Does PowerBASIC support a CoProcessor?

The answer is simply YES. The Compileroptions already have the possibility to choose three different Floatingpointlibraries. There are some Hooks when working with the CoPorcessor under PowerBASIC, which will be shown here so that you can develop faster hopefully only cleanly running programs.

3.2. Which Floatingpointlibrary is the right one?

PowerBASIC has a total of three Floatingpointlibraries:

3.3. Does the CoProcessor work with $FLOAT PROCEDURE, too?

The answer here is YES, too. Even if PowerBASIC did not implement the CoProcessorsupportroutines, the Source below proves that it does. The riddles answer lies in the PowerBASIC-Runtime-Library, which supports the i87 from beginning on. That is why the speed advantages can't be generalized.

3.4. Which PowerBASIC-Routines are affected?

The following internal PowerBASIC-Functions are affected. Measures have shown that SELECT CASE needs 5 seconds with the i87. Under the same cirumstances (but without i87) SELECT CASE can need 200 seconds ($FLOAT EMULATE). The can be an extreme speedup with $FLOAT PROCEDURE (only 35 seconds).
All in one you can say: SELECT CASE should not be used in time critical routines!
Same, even if not as bad, is the PRINT-Output of numerical Values.

3.5. Possible reasons for the CoProcessor-Effect

As I see it this effect has natural causes, because all effected commands have to work with the new 80-Number-System. It seems that the programmers of PowerBASIC tried to compensate the additionally needed time by using the CoProcessor. And it seems that it worked quite good for them when a CoProcessor is available. On the other side there is the question why the Compiler doesn't optimize it further when only the normal 16/32-Bit numbers are used.

3.6. PowerBASIC-Benchmark Source

This source shall show you the connection between the previous paragraphs. It is best if you just compile it and then try around a bit.
    Source:
        REM *****************************************************************
        REM
        REM   PBBENCH.EXE - Performance-Measuringprogram for PowerBASIC
        REM
        REM   To test the differences in speed of different
        REM   PowerBASIC-Commands in connection with used Floatingpoint-
        REM   libraries when using or not using a CoProcessor
        REM
        REM   Copyright: Thomas Gohel & Andras Hoeffken         Version 2.10
        REM   All rights reserved
        REM
        REM -----------------------------------------------------------------
        REM
        REM   Important Notice:
        REM   For reliable Maesures the Porcessor must be in REAL-Mode.
        REM   There may not be any TSRs, no KEYB.COM, SMARTDRV.EXE or
        REM   other.
        REM   Important:
        REM   For reliable Measures the program will have to be started
        REM   more than once and an avergae must be built.
        REM
        REM   Users of 486/586 or 286/386 Processors with CoProcessor can
        REM   turn the x87 CoPro off in PowerBASIC with the in this Source
        REM   implemented listing.
        REM
        REM   ***************************************************************
        REM
        $COMPILE EXE "PBBENCH.EXE"
        $CPU 80386
        $LIB ALL OFF
        REM $FLOAT NPX              ' for Computers with CoProzessor
                                    ' (fastest)
        REM $FLOAT PROCEDURE        ' for Computers without CoProzessor
                                    ' (not recommended)
        REM $FLOAT EMULATE          ' Automatic aupport (Extremly slow
                                    ' without CoProcessor)
        REM $DEBUG MAP OFF

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

        REM Zc1! fuer 5000000-Schleifen   ; To take out the time for the
        REM Zc2! fuer 2000000-Schleifen   ; FOR/NEXT-Loops
        REM Zc3! fuer 100000-Schleifen
        REM Zc4! fuer 2000-Schleifen

        IF pbvnpx > 0 THEN
            PRINT "CoProcessor " + CHR$(pbvnpx+48) + "87 found!"
            PRINT
            PRINT "Shoulod the CoProcessor be turned of for next";
            PRINT "measure (Y/N)?"
            BEEP
            A$ = UCASE$(INPUT$(1))
            IF A$ = "Y" THEN CoPro "AUS"
        ELSE
            PRINT "no CoProcessor found!"
            PRINT
            PRINT "Should the CoProcessor be turned on for the next";
            PRINT "measure (Y/N)?"
            PRINT
            PRINT "Note: Turning on a not existing CoProcessor";
            PRINT "will cause a crash!"
            BEEP
            A$ = UCASE$(INPUT$(1))
            IF A$ = "Y" THEN CoPro "EIN"
        END IF

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

        '***********************************************
        '  Get the Timeconstants for the different tests
        '***********************************************

        HoleZeitKonstanten:
        PRINT "Messung der Zeitkonstanten ";

        t1! = TIMER
        FOR i& = 1 TO 2000           ' Time for 2000-Loops
        NEXT i&
        t2! = TIMER
        Zc4! = t2! - t1!

        PRINT ".";
        t1! = TIMER
        FOR i& = 1 TO 5000000        ' Time for 5-Mio-Loops
        NEXT i&
        t2! = TIMER
        Zc1! = t2! - t1!

        PRINT ".";
        t1! = TIMER
        FOR i& = 1 TO 100000         ' Time for 100000-Loops
        NEXT i&
        t2! = TIMER
        Zc3! = t2! - t1!

        PRINT "."
        t1! = TIMER
        FOR i& = 1 TO 2000000        ' Time for 2-Mio-Loops
        NEXT i&
        t2! = TIMER
        Zc2! = t2! - t1!
        RETURN

        MesseFORNEXT:
            PRINT "Testing FOR/NEXT   : ";
            t1! = TIMER
            FOR i& = 1 TO 5000000        'Get 5-Millions-Loop
            NEXT i&                      'i = long integer
            t2! = TIMER
            PRINT t2! - t1!; "sec "
            RETURN

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

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

        MesseMATHEMATIK:
            PRINT "Testing MATHEMATIC : ";
            t1! = TIMER
            FOR i& = 1 TO 2000000
                i% = i% + 100            'extremly simple Calculations
                e& = e& * 2
                e& = e& \ 2
                i% = i% - 100
            NEXT i&
            t2! = TIMER
            PRINT t2! - t1! - Zc2!; "sec "
            RETURN

        MesseSTRING:
            PRINT "Testing 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 "Testing NUM-PRINT's  ";
            t1! = TIMER
            FOR i& = 1 TO 100000
                LOCATE , 1
                PRINT "Testing NUM-PRINT's: "; i&;
            NEXT i&
            t2! = TIMER
            LOCATE , 20
            PRINT t2! - t1! - Zc3!; "sec "
            RETURN

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

        '**********************************************
        ' Here is a routine to turn off the CoProcessor
        '**********************************************

        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) 1996/2007 by Thomas Gohel, All rights and bugs reserved
(c) 1996/1997 by Thomas Geiger, english version