Announcement

Collapse

Maintenance

The forum could be offline for 30-60 minutes in the very near future for maintenance (said 3pm Pacific). I was behind on getting this notice. I do apologize.
See more
See less

A tale of 2 algos.

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • A tale of 2 algos.

    Mike invited other programmers to do some direct comparison to the
    Microsoft VC6 C compiler to see if the claims made about the PowerBASIC
    compiler stood up to the test. I have bothered to make a pair of
    algorithms in both Microsoft C and PowerBASIC and clock them against each
    other.

    I have bothered to do this for a reason, its not a matter of polemic
    against Mike but to help assure PowerBASIC programmers that the compiler
    they area using can mix it in performance terms with the leading edge C
    compiler from Microsoft.

    Now I confess that my C is in a bad state of disrepair and its only going
    to get worse but I remember enough to write a comparison that involves
    direct loop optimisation comparison between the two compilers.

    Code:
    MICROSOFT C version 6
      
      // #######################################################################
      
      void TestProc()
      
          {
          DWORD counter1;
          counter1 = 0;
              while (counter1 < 1000000)
              {
              DWORD counter2;
              DWORD var1;
              DWORD var2;
              DWORD var3;
              DWORD var4;
              
              counter2 = 0;
                  while (counter2 < 1000)
                  {
                   var1 = 1;
                   var2 = 2;
                   var3 = 3;
                   var4 = 4;
                   counter2++;
                  }
              counter1++;
              }
          }
      
      // #######################################################################
      
      
      PowerBASIC version 6
      
      ' #########################################################################
      
      SUB TestProc()
      
          LOCAL var1  as DWORD
          LOCAL var2  as DWORD
      
          LOCAL item1 as DWORD
          LOCAL item2 as DWORD
          LOCAL item3 as DWORD
          LOCAL item4 as DWORD
      
          var1 = 0
          while var1 < 1000000
            var2 = 0
            while var2 < 1000
      
              item1 = 1
              item2 = 2
              item3 = 3
              item4 = 4
      
              var2 = var2 + 1
            wend
            var1 = var1 + 1
          wend
      
      END SUB
      
      ' #########################################################################
    With the C program that carried the test, I used the following compiler line,

    h:\msc6\bin\cl /c /G6 /GA /TC /FA /Fa project2.c >> build.txt

    I tried three compiler optimisations but two of them prevented the algorithm
    from running and the third did not change the time. ;/O2 /Ot /Og

    With the PowerBASIC program that carried the test piece, it ran the default
    compiler optimisation.

    On my PIII 600, I got the following results,

    MS C version 6 ==> 13.172 seconds

    PowerBASIC v 6 ==> 12.016 seconds

    These times may vary on different hardware but I think they speak for
    themselves, in terms of compiler produced loop optimisation, Bob Zale got
    it right the first time.

    The difference in complexity of the code is also obvious, the basic code
    is both easier and faster to write and get going.

    I think PowerBASIC programmers can safely work on the assumption that
    their code will run fast enough when they just get it going, it will
    probably run faster if they bother to do some more work on it and if all
    else fails and performance is still a problem, you can write some pure
    PowerBASIC inline assembler.

    Regards,

    [email protected]

    [This message has been edited by Steve Hutchesson (edited September 26, 2000).]
    hutch at movsd dot com
    The MASM Forum

    www.masm32.com

  • #2
    Good work Steve !

    To add to Steves comments above, the "Richness" of the PB command
    set gives programmers more tools to work with to find ways to
    optimize their code. It gives us more Power .


    ------------------
    Chris Boss
    Computer Workshop
    Developer of "EZGUI"
    http://cwsof.com
    http://twitter.com/EZGUIProGuy

    Comment


    • #3
      Steve


      hmmm - interesting - I tested the code on my PII 400 and came up
      with very different results:

      Background: I changed the code to main() in c and pbmain() in pb
      and added timing code. The c code was compiled using the free
      lcc-win32 compiler (which produces code which is not as fast as
      MSVC) and the pbcode was compiled with PBCC.

      The code in lcc-win32 was compiled for maximum speed, using
      Pentium Pro optmizations

      Compiled size C: 3104 bytes
      Compiled size PB: 10752 bytes
      Run time C: 13.339 seconds
      Run time PB: 18.617 seconds

      I used the code basically unchanged and did not make any optimizations
      in either PB or C.

      Here's the code I used:

      Code:
      // C code
      #include <time.h>
      #include <stdio.h>
       
      int main(void) {
      	unsigned int counter1 = 0;
      	unsigned int counter2;
      	unsigned int var1;
      	unsigned int var2;
      	unsigned int var3;
      	unsigned int var4;
       
      	clock_t start, finish;
      	double  duration;
      	start = clock();
       
      	while (counter1 < 1000000) {
      		counter2 = 0;
      		while (counter2 < 1000) {
      			var1 = 1;
      			var2 = 2;
      			var3 = 3;
      			var4 = 4;
      			counter2++;
      		}
      		counter1++;
      	}
       
      	finish = clock();
       
      	duration = (double)(finish - start) / CLOCKS_PER_SEC;
      	printf( "%2.8f seconds\n", duration );
       
      	return 0;
      }
       
      'PB code
      #COMPILE EXE
       
      FUNCTION PBMAIN() AS LONG
          LOCAL var1  AS DWORD
          LOCAL var2  AS DWORD
          LOCAL item1 AS DWORD
          LOCAL item2 AS DWORD
          LOCAL item3 AS DWORD
          LOCAL item4 AS DWORD
          LOCAL start AS DOUBLE, stop AS DOUBLE
       
          start = TIMER
       
            var1 = 0
            WHILE var1 < 1000000
              var2 = 0
              WHILE var2 < 1000
       
                item1 = 1
                item2 = 2
                item3 = 3
                item4 = 4
       
                INCR var2
              WEND
              INCR var1
            WEND
       
          stop = TIMER
          STDOUT FORMAT$(stop-start) + " seconds"
          
      END FUNCTION
      Cheers

      Florent



      [This message has been edited by Florent Heyworth (edited September 26, 2000).]

      Comment


      • #4
        Florent,

        Very interesting results, I did test them slightly differently in that
        I put both in a procedure to ensure that they both has the same stack
        overhead and I did the timing using GetTickCount() both sides of the
        SUB/function calls so that the timing code would not interfere with
        the internal workings of either proc.

        The GCC compiler looks like it is working fine as is but I would like
        to see the PB SUB put into its own space as a SUB.

        I did write one in ASM and it is fast enough but manually coding the
        asm made it very sensitive to alignment, I manually aligned it with NOP
        instructions before the executing code and it produced a speed
        improvement in the order of 35 - 40 % which brought it up to the speed
        of the PB "while" loop.

        I have a sneaking suspicion that alignment is responsible for the
        variations, if I am counting right, I added 8 NOP instructions to get
        the code to align on a 16 byte boundary. Under 8 slowed it down and more
        than 12 did as well so I think it has something to do with it. If I get
        time, I will do a test piece in masm using the align directive to see if
        that is the problem.

        Regards & Thanks for testing the algos.

        [email protected]

        ------------------
        hutch at movsd dot com
        The MASM Forum

        www.masm32.com

        Comment


        • #5
          Hi Steve

          good point about the alignement. I moved the PB test code to a sub
          and the c test code to a separate procedure. Additionally I used
          GetTickCount() to time the code in both C and PB.

          Moving the PB code to its own sub evened out the field a little:

          The results (using lcc-win32 compiler for C):
          Compiled size C: 3104 bytes
          Compiled size PB: 10752
          Run time C: 13.309 seconds
          Run time PB: 15.963 seconds


          Cheers


          Florent

          ------------------

          Comment


          • #6
            Well im getting absolutely vastly different numbers. VC++ wins
            no contest.

            P2 Celeron 266 w/ 128 megs ram
            PB = 53.6 seconds
            VC6 = 0.5 seconds (only with the debug build did it generate a 66 second score)

            Dual Pentium Pro 180 w/ 128 megs ram
            PB = 33.56 seconds
            VC6 = 0.5 seconds


            Here is the C code i used (DWORD didnt show up in MSVC++ 6.0 so
            i changed them to "unsigned long") Immediately following is
            the parameters for the build.

            /nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"Release/Text1.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c

            Code:
            #include <stdlib.h>
            #include <stdio.h>
            
            void main(void) {
                  unsigned long counter1;
            	  unsigned long counter2;
            
                  
            	  counter2 = 0;	
            	  counter1 = 0;
            	  printf("Test Begin\n");
                      while (counter1 < 1000000)
                      {
                      unsigned long counter2;
                      unsigned long var1;
                      unsigned long var2;
                      unsigned long var3;
                      unsigned long var4;
                      
                      counter2 = 0;
                          while (counter2 < 1000)
                          {
                           var1 = 1;
                           var2 = 2;
                           var3 = 3;
                           var4 = 4;
                           counter2++;
                          }
                      counter1++;
                      }
            		  printf("%d\n", counter1);
                  }
            Now the PB Code:

            Code:
              #COMPILE EXE
              #DIM ALL
              #INCLUDE "win32api.inc"
              
              FUNCTION PBMAIN()
            
                  LOCAL var1  AS DWORD
                  LOCAL var2  AS DWORD
            
                  LOCAL item1 AS DWORD
                  LOCAL item2 AS DWORD
                  LOCAL item3 AS DWORD
                  LOCAL item4 AS DWORD
                  LOCAL lTime AS LONG
                  
                  lTime = TimeGetTime
                  
                  var1 = 0
                  WHILE var1 < 1000000
                    var2 = 0
                    WHILE var2 < 1000
            
                      item1 = 1
                      item2 = 2
                      item3 = 3
                      item4 = 4
            
                      var2 = var2 + 1
                    WEND
                    var1 = var1 + 1
                  WEND
            
                    MSGBOX STR$(timegettime - ltime)
              END FUNCTION
            I've seen results like this with VC6 over and over again when
            using RELEASE build option (as opposed to DEBUG) under VC.

            -Mike


            ------------------

            Comment


            • #7
              Mike

              The optimizing MSVC 6 compiler probably optimizes the
              code by taking the loop invariants out of the code so that
              var1,var2,var3,var4 are assigned once outside of the loop.

              The optimizer probably unrolls the inner loop as well and
              probably does a wicked outer loop optimization. In effect
              it looks at what you wrote and is smart enough to factor out
              the unecessary steps - this results in you getting the expected
              results without having the code you wrote run at all. The only
              gripe that I have with optimizing compilers is that you have
              little control over what gets compiled apart from turning
              off all optimizations.

              Unrolling the inner loop in PB (grows code size to 20,000 bytes)
              makes the code run in 2.6 seconds. I could optimize it further
              but what's the point?

              In essence speed and size is always a compromise.

              Cheers

              Florent

              ------------------

              Comment


              • #8
                Florent, I agree with you 100% and I suspected some of the
                VC optimizations you mentioned were taking place. And yes, you
                can unwravel your own loops, but that starts to make your code
                look unweildly... not to mention it makes it difficult to
                use variable length loop counters.

                You commented on the lack of control with VC, but youve already
                stated that you can remove the command line options. In addition
                you can also switch between several pre-set configurations. VC
                shows the following optimization options from the Project
                Settings dialog:

                Default
                Disable(Debug)
                Maximum Speed
                Minimum Size
                Customize

                VC gives you just as much control, but also provides some very
                good optimizations for those who want to use it. Game programmers
                (least for your modern day 3d eye candy games) often want speed
                at the expense of size.

                But im not trying to paint PB in a bad light. PB is a great compiler
                and I use ive been using it predominantly for the past several months.
                PB is much easier to program and the time savings is huge. Its
                faster than VB, but most importantly to me, it creates stand
                alone EXE's and DLL's.

                All im saying is that i believe the people on this forum who say
                PB is the fastest compiler are wrong. Unless you are a guru
                and know asm, VC wins most of the time. Its nothing inherent
                about the language, its just VC has some wicked optimization
                capabilities.

                This makes VC more forgiving to the average programmer. We cant all
                be top echelon programmers, and we dont all mind if a 20kb PB exe
                churns in at 40kb in VC++. What I would like to see in PB, is
                more optimization options... the ability to select "fast" versus
                "size" options specifically.

                -Mike
                Because of VC's optimization capabilities, I believe that
                using OOP in VC++ can be fast as well. The use of objects (not
                taling about COM) does not automatically equal slow code. If
                VC can do it, so can a OO version of PB.

                And besides, in VC you dont need to use objects if you dont want
                to. I envision the same thing with an OO version of PB. Either
                that, or just create a seperate compiler altogether? Whats wrong
                with having a PowerBASIC 7.0 and a ObjectBASIC 1.0?


                ------------------

                Comment


                • #9
                  I did some benchmarking with VB 5.0 Professional (native code)
                  and PB 6.0 and I found some interesting things:

                  Since VB 5.0 uses a C compiler in the backend, the results are
                  very fast. In fact, when you use "simple" loops (For next, etc.)
                  VB 5.0 was faster than PB, But :

                  I found that the more complex the calculations inside the loops
                  were, then VB is slower and PB is faster.


                  My impressions are that the Microsoft compilers (VB and C) are
                  highly optimized for loops and hard to beat, but when you start
                  having more complex code the compiler can't optimize so well.

                  Real world code tends to be much more complex that many benchmarks.
                  A good benchmark really requires some very complex code.

                  Here is my PB Benchmark program (it could be made more complex too) :

                  Code:
                  ' *************************************************************
                  '       Code Generated by EZGUI Freeware Dialog Designer
                  ' *************************************************************
                  
                  #COMPILE EXE
                  #REGISTER NONE
                  #DEBUG ERROR OFF
                  #DIM ALL          '  This is helpful to prevent errors in coding
                  
                  
                   ' Remark out the Constants for Controls you Will use in your program !
                  
                   %NOANIMATE    = 1
                   %NOBUTTON     = 1
                   %NOCOMBO      = 1
                   %NODRAGLIST   = 1
                   %NOHEADER     = 1
                   %NOIMAGELIST  = 1
                   %NOLIST       = 1
                   '    %NOLISTVIEW   = 1
                   '    %NOSTATUSBAR  = 1
                   '    %NOTABCONTROL = 1
                   '    %NOTOOLBAR    = 1
                   '    %NOTOOLTIPS   = 1
                   %NOTRACKBAR   = 1
                   '    %NOTREEVIEW   = 1
                   '    %NOUPDOWN     = 1
                  #INCLUDE "win32api.inc"   ' Must come first before other include files !
                  #INCLUDE "commctrl.inc"  ' The Common Controls include file !
                  ' *************************************************************
                  
                  DECLARE SUB Proc1(BYVAL X&, BYVAL Y&)
                  DECLARE FUNCTION Proc2(BYVAL X&, BYVAL Y&) AS LONG
                  
                  
                  ' *************************************************************
                  '              EZGUI Library Constants and Declares
                  ' *************************************************************
                  
                  DECLARE SUB EZLIB_InitFonts()
                  DECLARE SUB EZLIB_DeleteFonts()
                  DECLARE SUB EZLIB_FixSize(BYVAL hDlg&, BYVAL Style&, BYVAL HasMenu&)
                  DECLARE FUNCTION EZLIB_IsTooltip(BYVAL lParam AS LONG) AS LONG
                  DECLARE FUNCTION EZLIB_TooltipID(BYVAL lParam AS LONG) AS LONG
                  DECLARE SUB EZLIB_SetTooltipText(BYVAL lParam AS LONG, TipText$)
                  DECLARE FUNCTION EZLIB_IsTab(BYVAL lParam AS LONG) AS LONG
                  DECLARE FUNCTION EZLIB_TabID(BYVAL lParam AS LONG) AS LONG
                  DECLARE FUNCTION EZLIB_TabNum(BYVAL lParam AS LONG) AS LONG
                  DECLARE SUB EZLIB_AddTabs(BYVAL hDlg AS LONG, BYVAL IDNum&, BYVAL TabText$)
                  DECLARE SUB EZLIB_DefColors()
                  DECLARE SUB EZLIB_DeleteBrushes()
                  DECLARE FUNCTION EZLIB_QBColor(N&) AS LONG
                  DECLARE SUB EZLIB_ShowControl(BYVAL hWnd&, BYVAL ID&, BYVAL SFlag&)
                  
                  ' *************************************************************
                  '              Application Constants and Declares
                  ' *************************************************************
                  
                  %FORM1_COMMAND1           = 100
                  %FORM1_TEXT1              = 105
                  %FORM1_COMMAND2           = 110
                  %FORM1_COMMAND3           = 115
                  %FORM1_COMMAND4           = 120
                  %FORM1_COMMAND5           = 125
                  ' --------------------------------------------------
                  DECLARE SUB ShowDialog_Form1(BYVAL hParent&)
                  DECLARE CALLBACK FUNCTION Form1_DLGPROC
                  ' --------------------------------------------------
                  ' ------------------------------------------------
                  
                  DECLARE CALLBACK FUNCTION CBF_FORM1_COMMAND1()
                  DECLARE CALLBACK FUNCTION CBF_FORM1_TEXT1()
                  DECLARE CALLBACK FUNCTION CBF_FORM1_COMMAND2()
                  DECLARE CALLBACK FUNCTION CBF_FORM1_COMMAND3()
                  DECLARE CALLBACK FUNCTION CBF_FORM1_COMMAND4()
                  DECLARE CALLBACK FUNCTION CBF_FORM1_COMMAND5()
                  
                  
                  ' (1) Put NEXT DIALOG Constant and Declare code after here :
                  
                  
                  ' *************************************************************
                  '            Application Global Variables and Types
                  ' *************************************************************
                  
                  GLOBAL App_Brush&()
                  GLOBAL App_Color&()
                  GLOBAL App_Font&()
                  
                  
                  GLOBAL hForm1&    ' Dialog handle
                  
                  
                  ' (2) Put NEXT DIALOG Globals code after here :
                  
                  ' *************************************************************
                  '                    Application Entrance
                  ' *************************************************************
                  
                  FUNCTION PBMAIN
                      LOCAL Count&
                      LOCAL CC1 AS INIT_COMMON_CONTROLSEX
                  
                      CC1.dwSize=SIZEOF(CC1)
                      CC1.dwICC=%ICC_WIN95_CLASSES
                      InitCommonControlsEX CC1
                      EZLIB_DefColors
                      EZLIB_InitFonts
                  
                      ShowDialog_Form1 0
                      DO
                          DIALOG DOEVENTS TO Count&
                      LOOP UNTIL Count&=0
                  
                  
                      EZLIB_DeleteBrushes
                      EZLIB_DeleteFonts
                  END FUNCTION
                  
                  
                  ' *************************************************************
                  '                    Application Dialogs
                  ' *************************************************************
                  
                  SUB ShowDialog_Form1(BYVAL hParent&)
                      LOCAL Style&, ExStyle&
                      LOCAL N&, CT&        '  Variables used for Reading Data in Arrays for Listbox and Combobox
                      '   hParent& = 0 if no parent Dialog
                      Style& = %WS_POPUP OR %DS_MODALFRAME OR %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU OR %DS_CENTER
                      ExStyle& = 0
                      DIALOG NEW hParent&, "Form1 - PB version", 0, 0,  331,  128, Style&, ExStyle& TO hForm1&
                      EZLIB_FixSize hForm1&, Style&, 0
                      ' Layer # 0
                      CONTROL ADD "Button", hForm1&,  %FORM1_COMMAND1,  "Test 1 - Simple", 9, 13, 99, 18, _
                          %WS_CHILD OR %WS_VISIBLE OR %BS_PUSHBUTTON OR %WS_TABSTOP CALL CBF_FORM1_COMMAND1
                      CONTROL ADD TEXTBOX, hForm1&,  %FORM1_TEXT1,  "", 121, 13, 206, 108, _
                          %WS_CHILD OR %WS_VISIBLE OR %ES_MULTILINE OR %ES_WANTRETURN OR %ES_LEFT OR %ES_AUTOVSCROLL OR %WS_VSCROLL , _
                          %WS_EX_CLIENTEDGE CALL CBF_FORM1_TEXT1
                      CONTROL ADD "Button", hForm1&,  %FORM1_COMMAND2,  "Test 2 - Singles", 9, 34, 99, 18, _
                          %WS_CHILD OR %WS_VISIBLE OR %BS_PUSHBUTTON OR %WS_TABSTOP CALL CBF_FORM1_COMMAND2
                      CONTROL ADD "Button", hForm1&,  %FORM1_COMMAND3,  "Test 3 - Geometry", 9, 56, 99, 18, _
                          %WS_CHILD OR %WS_VISIBLE OR %BS_PUSHBUTTON OR %WS_TABSTOP CALL CBF_FORM1_COMMAND3
                      DIALOG SHOW MODELESS hForm1& , CALL Form1_DLGPROC
                  END SUB
                  
                  ' *************************************************************
                  '                             Dialog Callback Procedure
                  '                             for Form Form1
                  '                             uses Global Handle - hForm1&
                  ' *************************************************************
                  
                  CALLBACK FUNCTION Form1_DLGPROC
                      SELECT CASE CBMSG
                          ' Common Windows Messages you may want to process
                          ' -----------------------------------------------
                          CASE %WM_TIMER
                          CASE %WM_HSCROLL
                          CASE %WM_VSCROLL
                          CASE %WM_SIZE
                          CASE %WM_CLOSE
                          CASE %WM_DESTROY
                          CASE %WM_SYSCOMMAND
                          CASE %WM_PAINT
                          ' -----------------------------------------------
                          CASE %WM_CTLCOLORMSGBOX , %WM_CTLCOLORBTN, %WM_CTLCOLOREDIT,_
                               %WM_CTLCOLORSTATIC, %WM_CTLCOLORSCROLLBAR, %WM_CTLCOLORLISTBOX
                              ' Control colors
                              SELECT CASE GetDlgCtrlID(CBLPARAM)
                                  CASE ELSE
                                      FUNCTION=0
                              END SELECT
                          CASE %WM_NOTIFY
                              IF EZLIB_IsTooltip(CBLPARAM) THEN
                                  SELECT CASE EZLIB_TooltipID(CBLPARAM)
                                      CASE  %FORM1_COMMAND1
                                          EZLIB_SetTooltipText CBLPARAM, "Control -  %FORM1_COMMAND1"
                                      CASE  %FORM1_COMMAND2
                                          EZLIB_SetTooltipText CBLPARAM, "Control -  %FORM1_COMMAND2"
                                      CASE  %FORM1_COMMAND3
                                          EZLIB_SetTooltipText CBLPARAM, "Control -  %FORM1_COMMAND3"
                                      CASE  %FORM1_COMMAND4
                                          EZLIB_SetTooltipText CBLPARAM, "Control -  %FORM1_COMMAND4"
                                      CASE  %FORM1_COMMAND5
                                          EZLIB_SetTooltipText CBLPARAM, "Control -  %FORM1_COMMAND5"
                                      CASE ELSE
                                  END SELECT
                              END IF
                              IF EZLIB_IsTab(CBLPARAM) THEN
                                  SELECT CASE EZLIB_TabID(CBLPARAM)
                                      CASE ELSE
                                  END SELECT
                              END IF
                          CASE %WM_COMMAND
                              ' Process Messages to Controls that have no Callback Function
                              ' and Process Messages to Menu Items
                              SELECT CASE CBCTL
                                  CASE ELSE
                              END SELECT
                          CASE ELSE
                      END SELECT
                  END FUNCTION
                  
                  
                  ' (3) Put NEXT DIALOG Creation / Dialog Procedure code after here :
                  
                  
                  ' *************************************************************
                  '              EZGUI Freeware Dialog Designer Library
                  '
                  '                   see web site at EZGUI.COM
                  '
                  ' Copyright (C) 2000, Christopher R. Boss , All Rights Reserved !
                  '
                  ' This code was Generated by the EZGUI Freeware Dialog Designer
                  ' and may be used ROYALTY FREE, as long as this Copyright notice
                  ' is kept with the source code.
                  ' The Author also gives you the right to post this code on a
                  ' web site and to distribute it to others.
                  ' *************************************************************
                  
                  SUB EZLIB_InitFonts()
                      REDIM App_Font(0 TO 5)
                      App_Font(0)=GetStockObject(%SYSTEM_FONT)
                      App_Font(1)=GetStockObject(%SYSTEM_FIXED_FONT)
                      App_Font(2)=GetStockObject(%ANSI_VAR_FONT)
                      App_Font(3)=GetStockObject(%ANSI_FIXED_FONT)
                      App_Font(4)=GetStockObject(%DEFAULT_GUI_FONT)    ' MS Sans Serif
                      App_Font(5)=GetStockObject(%OEM_FIXED_FONT)      ' Terminal Font
                      END SUB
                  
                  ' -------------------------------------------------------------
                  
                  SUB EZLIB_DeleteFonts()
                      LOCAL N&
                      ' Fonts 0 to 5 do not need to be deleted
                      FOR N&=6 TO UBOUND(App_Font)
                          IF App_Font(N&)<>0 THEN DeleteObject App_Font(N&)
                      NEXT N&
                      END SUB
                  
                  ' -------------------------------------------------------------
                  
                  SUB EZLIB_FixSize(BYVAL hDlg&, BYVAL Style&, BYVAL HasMenu&)
                      LOCAL X&, Y&, W&, H&, XX&, YY&
                      DIALOG GET SIZE hDlg& TO X&, Y&
                      IF (Style& AND %WS_CAPTION) = %WS_CAPTION THEN
                          IF HasMenu& THEN
                              H&=H&+GetSystemMetrics(%SM_CYCAPTION)
                          END IF
                      END IF
                      IF (Style& AND %WS_HSCROLL) = %WS_HSCROLL THEN
                          H&=H&+GetSystemMetrics(%SM_CYHSCROLL)
                      END IF
                      IF (Style& AND %WS_VSCROLL) = %WS_VSCROLL THEN
                          W&=W&+GetSystemMetrics(%SM_CYVSCROLL)
                      END IF
                      DIALOG PIXELS hDlg&, W&, H& TO UNITS XX&, YY&
                      X&=X&+XX&
                      Y&=Y&+YY&
                      DIALOG SET SIZE hDlg&, X&, Y&
                  END SUB
                  
                  ' -------------------------------------------------------------
                  
                  FUNCTION EZLIB_IsTooltip(BYVAL lParam AS LONG) AS LONG
                      LOCAL pNM AS NMHDR PTR
                      pNM=lParam
                      IF @pNM.code=%TTN_NEEDTEXT THEN FUNCTION=1 ELSE FUNCTION=0
                  END FUNCTION
                  
                  ' -------------------------------------------------------------
                  
                  FUNCTION EZLIB_TooltipID(BYVAL lParam AS LONG) AS LONG
                      LOCAL pNM AS NMHDR PTR, pTT AS TOOLTIPTEXT PTR
                      LOCAL IDNum&, UF&
                      IDNum&=0
                      pNM=lParam
                      IF @pNM.code=%TTN_NEEDTEXT THEN
                          ' Check for Tooltip message
                          pTT=lParam
                          UF&[email protected] AND %TTF_IDISHWND
                          IF UF&=%TTF_IDISHWND THEN
                              IDNum&=GetDlgCtrlID(@pTT.hdr.idfrom)
                          ELSE
                              IDNum&[email protected]
                          END IF
                      END IF
                      FUNCTION=IDNum&
                  END FUNCTION
                  
                  ' -------------------------------------------------------------
                  
                  SUB EZLIB_SetTooltipText(BYVAL lParam AS LONG, TipText$)
                      LOCAL pNM AS NMHDR PTR, pTT AS TOOLTIPTEXT PTR
                      pNM=lParam
                      IF @pNM.code=%TTN_NEEDTEXT THEN
                          ' Check for Tooltip message
                          pTT=lParam
                          IF TipText$<>"" THEN
                              @pTT.szText=LEFT$(TipText$, 79)+CHR$(0)
                          END IF
                      END IF
                  END SUB
                  
                  ' -------------------------------------------------------------
                  
                  FUNCTION EZLIB_IsTab(BYVAL lParam AS LONG) AS LONG
                      LOCAL pNM AS NMHDR PTR
                      pNM=lParam
                      IF @pNM.code=%TCN_SELCHANGE THEN FUNCTION=1 ELSE FUNCTION=0
                  END FUNCTION
                  
                  ' -------------------------------------------------------------
                  
                  FUNCTION EZLIB_TabID(BYVAL lParam AS LONG) AS LONG
                      LOCAL pNM AS NMHDR PTR
                      LOCAL IDNum&
                      pNM=lParam
                      IF @pNM.code=%TCN_SELCHANGE THEN
                          IDNum&[email protected]
                      END IF
                      FUNCTION=IDNum&
                  END FUNCTION
                  
                  ' -------------------------------------------------------------
                  
                  FUNCTION EZLIB_TabNum(BYVAL lParam AS LONG) AS LONG
                      LOCAL RV&, pNM AS NMHDR PTR
                      LOCAL hCtrl AS LONG
                      pNM=lParam
                      IF @pNM.code=%TCN_SELCHANGE THEN
                      [email protected]
                          RV&=SendMessage(hCtrl, %TCM_GETCURSEL, 0, 0)+1
                      END IF
                      FUNCTION=RV&
                  END FUNCTION
                  
                  ' -------------------------------------------------------------
                  
                  SUB EZLIB_AddTabs(BYVAL hDlg AS LONG, BYVAL IDNum&, BYVAL TabText$)
                      LOCAL pItem AS TC_ITEM, hCtrl&
                      LOCAL zText AS ASCIIZ*80
                      LOCAL D$, P&, TB&
                      IF IDNum&<>0 THEN
                          hCtrl&=GetDlgItem(hDlg,IDNum&)
                          IF hCtrl&<>0 THEN
                              TB&=0
                              DO
                                  IF TabText$="" THEN EXIT DO
                                  P&=INSTR(TabText$,"|")
                                  IF P&>0 THEN
                                      D$=LEFT$(TabText$,P&-1)
                                      TabText$=MID$(TabText$,P&+1)
                                  ELSE
                                      D$=TabText$
                                      IF TabText$="" THEN EXIT DO
                                      TabText$=""
                                  END IF
                                  pItem.Mask=%TCIF_TEXT
                                  zText=D$+CHR$(0)
                                  pItem.pszText=VARPTR(zText)
                                  SendMessage hCtrl&, %TCM_INSERTITEM, TB&, VARPTR(pItem)
                                  TB&=TB&+1
                              LOOP
                          END IF
                      END IF
                  END SUB
                  
                  ' -------------------------------------------------------------
                  
                  SUB EZLIB_DefColors()
                      LOCAL T&
                      REDIM App_Brush&(0 TO 31)
                      REDIM App_Color&(0 TO 31)
                      FOR T&=0 TO 31
                          App_Brush&(T&)=CreateSolidBrush(EZLIB_QBColor(T&))
                          App_Color&(T&)=EZLIB_QBColor(T&)
                      NEXT T&
                  END SUB
                  
                  ' -------------------------------------------------------------
                  
                  SUB EZLIB_DeleteBrushes()
                      LOCAL T&
                      FOR T&=0 TO 31
                          DeleteObject App_Brush&(T&)
                      NEXT T&
                  END SUB
                  
                  ' -------------------------------------------------------------
                  
                  FUNCTION EZLIB_QBColor(N&) AS LONG
                      LOCAL RV&
                      SELECT CASE N&
                          CASE 0
                          RV&=RGB(0,0,0)       ' Black
                      CASE 1
                          RV&=RGB(0,0,128)     ' Blue
                      CASE 2
                          RV&=RGB(0,128,0)     ' Green
                      CASE 3
                          RV&=RGB(0,128,128)   ' Cyan
                      CASE 4
                          RV&=RGB(196,0,0)     ' Red
                      CASE 5
                          RV&=RGB(128,0,128)   ' Magenta (Purple)
                      CASE 6
                          RV&=RGB(128,64,0)    ' Brown
                      CASE 7
                          RV&=RGB(196,196,196) ' White
                      CASE 8
                          RV&=RGB(128,128,128) ' Gray
                      CASE 9
                          RV&=RGB(0,0, 255)    ' Lt. Blue
                      CASE 10
                          RV&=RGB(0,255,0)     ' Lt. Green
                      CASE 11
                          RV&=RGB(0,255,255)   ' Lt. Cyan
                      CASE 12
                          RV&=RGB(255,0,0)     ' Lt. Red
                      CASE 13
                          RV&=RGB(255,0,255)   ' Lt. magenta (Purple)
                      CASE 14
                          RV&=RGB(255,255,0)   ' Yellow
                      CASE 15
                          RV&=RGB(255,255,255) ' Bright White
                      CASE 16   ' - Extended QB colors Pastel version -
                          RV&=RGB(164,164,164)
                      CASE 17
                          RV&=RGB(128,160,255)
                      CASE 18
                          RV&=RGB(160,255,160)
                      CASE 19
                          RV&=RGB(160,255,255)
                      CASE 20
                          RV&=RGB(255,160,160)
                      CASE 21
                          RV&=RGB(255,160,255)
                      CASE 22
                          RV&=RGB(255,255,160)
                      CASE 23
                          RV&=RGB(212,212,212)
                      CASE 24
                          RV&=RGB(180,180,180)
                      CASE 25
                          RV&=RGB(188,220,255)
                      CASE 26
                          RV&= RGB(220,255,220)
                      CASE 27
                          RV&=RGB(220,255,255)
                      CASE 28
                          RV&=RGB(255,220,220)
                      CASE 29
                          RV&=RGB(255,220,255)
                      CASE 30
                          RV&=RGB(255,255,220)
                      CASE 31
                          RV&=RGB(228,228,228)
                      CASE ELSE
                          RV&=RGB(0,0,0)
                      END SELECT
                      FUNCTION=RV&
                  END FUNCTION
                   ' -------------------------------------------------------------
                  SUB EZLIB_ShowControl(BYVAL hWnd&, BYVAL ID&, BYVAL SFlag&)
                      LOCAL hCtrl&
                      IF IsWindow(hWnd&) THEN
                          IF ID&<>0 THEN
                              hCtrl&=GetDlgItem(hWnd&,ID&)
                              IF SFlag&=0 THEN
                                  ShowWindow hCtrl&, %SW_HIDE
                              ELSE
                                  ShowWindow hCtrl&, %SW_SHOW
                              END IF
                          END IF
                      END IF
                  END SUB
                   ' -------------------------------------------------------------
                  ' *************************************************************
                  '             End of EZGUI Dynamic Dialogs Library
                  ' *************************************************************
                  
                  
                  ' *************************************************************
                  '  Application Callback Functions (or Procedures) for Controls
                  ' *************************************************************
                  
                  ' ------------------------------------------------
                  CALLBACK FUNCTION CBF_FORM1_COMMAND1
                  LOCAL CT!, D$, X&, Y&, U!, V!, A#, B#
                      IF CBCTLMSG=%BN_CLICKED THEN
                          CONTROL GET TEXT hForm1&, %FORM1_TEXT1 TO D$
                          D$=D$+ CHR$(13) + CHR$(10) + "Test 1:" + CHR$(13) + CHR$(10) + STRING$(30, "-") + CHR$(13) + CHR$(10)
                          CONTROL SET TEXT hForm1&, %FORM1_TEXT1, D$
                  
                          CT! = TIMER
                          FOR X& = 1 TO 100000
                              Y& = Y& + 1
                              Y& = Y& * 13
                              Y& = Y& / 13
                          NEXT X&
                          CT! = TIMER - CT!
                          CONTROL GET TEXT hForm1&, %FORM1_TEXT1 TO D$
                          D$=D$+ "Numeric Test (Longs) -   " + STR$(CT!) + " Seconds" + CHR$(13) + CHR$(10)
                          CONTROL SET TEXT hForm1&, %FORM1_TEXT1, D$
                  
                          CT! = TIMER
                          FOR U! = 1 TO 100000
                              V! = V! + 1
                              V! = V! * 13
                              V! = V! / 13
                          NEXT U!
                          CT! = TIMER - CT!
                          CONTROL GET TEXT hForm1&, %FORM1_TEXT1 TO D$
                          D$=D$+ "Numeric Test (Singles) -   " + STR$(CT!) + " Seconds" + CHR$(13) + CHR$(10)
                          CONTROL SET TEXT hForm1&, %FORM1_TEXT1, D$
                  
                          CT! = TIMER
                          FOR A# = 1 TO 100000
                              B# = COS(A#)
                              B# = TAN(A#)
                              B# = SIN(A#)
                          NEXT A#
                          CT! = TIMER - CT!
                          CONTROL GET TEXT hForm1&, %FORM1_TEXT1 TO D$
                          D$=D$+ "Numeric Test (Double Geometry) -   " + STR$(CT!) + " Seconds" + CHR$(13) + CHR$(10)
                          CONTROL SET TEXT hForm1&, %FORM1_TEXT1, D$
                  
                          CT! = TIMER
                          D$ = ""
                          FOR X& = 1 TO 100000
                              D$ = STRING$(10, " ") + STRING$(50, "x") + STRING$(10, " ")
                              D$ = LTRIM$(RTRIM$(D$))
                              D$ = MID$(D$, 10, 20)
                              D$ = ""
                          NEXT X&
                          CT! = TIMER - CT!
                          CONTROL GET TEXT hForm1&, %FORM1_TEXT1 TO D$
                          D$=D$+ "String Test -   " + STR$(CT!) + " Seconds" + CHR$(13) + CHR$(10)
                          CONTROL SET TEXT hForm1&, %FORM1_TEXT1, D$
                      END IF
                  END FUNCTION
                  ' ------------------------------------------------
                  
                  ' ------------------------------------------------
                  CALLBACK FUNCTION CBF_FORM1_TEXT1
                      IF CBCTLMSG=%EN_CHANGE THEN
                  
                      END IF
                      IF CBCTLMSG=%EN_SETFOCUS THEN
                  
                      END IF
                      IF CBCTLMSG=%EN_KILLFOCUS THEN
                  
                      END IF
                  END FUNCTION
                  ' ------------------------------------------------
                  
                  ' ------------------------------------------------
                  CALLBACK FUNCTION CBF_FORM1_COMMAND2
                      LOCAL CT!, D$, X&, Y&, U!, V!, A#, B#
                      IF CBCTLMSG=%BN_CLICKED THEN
                          CONTROL GET TEXT hForm1&, %FORM1_TEXT1 TO D$
                          D$=D$ + CHR$(13) + CHR$(10) + "Test 2:" + CHR$(13) + CHR$(10) + STRING$(30, "-") + CHR$(13) + CHR$(10)
                          CONTROL SET TEXT hForm1&, %FORM1_TEXT1, D$
                  
                          CT! = TIMER
                          FOR X& = 1 TO 100000 STEP 2
                              Y& = Y& + 1 + X& - 3
                              Y& = ((Y& / Y&) * 13) + 7
                              Y& = (Y& / 13) * 13
                          NEXT X&
                          CT! = TIMER - CT!
                          CONTROL GET TEXT hForm1&, %FORM1_TEXT1 TO D$
                          D$=D$+ "Numeric Test (Longs) -   " + STR$(CT!) + " Seconds" + CHR$(13) + CHR$(10)
                          CONTROL SET TEXT hForm1&, %FORM1_TEXT1, D$
                  
                          CT! = TIMER
                          FOR U! = 1 TO 100000 STEP 2.1001
                              V! = (V! / 99.1) + 1
                              V! = (V! * 13.011) * 1.02221 + 1.0766
                              V! = (V! / 13.011) * 13.011 + 2.0132
                          NEXT U!
                          CT! = TIMER - CT!
                          CONTROL GET TEXT hForm1&, %FORM1_TEXT1 TO D$
                          D$=D$ + "Numeric Test (Singles) -   " + STR$(CT!) + " Seconds" + CHR$(13) + CHR$(10)
                          CONTROL SET TEXT hForm1&, %FORM1_TEXT1, D$
                  
                          CT! = TIMER
                          FOR A# = 1 TO 100000 STEP 2.1001
                              B# = COS(A#) + TAN(A#) + SIN(A# + 1.01)
                              B# = TAN(A# + 0.5) + SIN(A# + 1.01) / 1.002
                              B# = (SIN(A# + 0.75) * 0.5) / 3.0032
                          NEXT A#
                          CT! = TIMER - CT!
                          CONTROL GET TEXT hForm1&, %FORM1_TEXT1 TO D$
                          D$=D$ + "Numeric Test (Double Geometry) -   " + STR$(CT!) + " Seconds" + CHR$(13) + CHR$(10)
                          CONTROL SET TEXT hForm1&, %FORM1_TEXT1, D$
                  
                          CT! = TIMER
                          D$ = ""
                          FOR X& = 1 TO 100000 STEP 2
                              D$ = "AB DEFG"
                              D$ = STRING$(10, MID$(D$, 3, 1)) + STRING$(50, "x") + STRING$(10, MID$(D$, 3, 1))
                              D$ = LTRIM$(RTRIM$(D$))
                              D$ = D$ + D$ + D$ + D$ + D$ + D$ + D$
                              D$ = MID$(D$, 10, 20) + MID$(D$, 10, 20) + MID$(D$, 10, 20) + MID$(D$, 10, 20)
                          NEXT X&
                          CT! = TIMER - CT!
                          CONTROL GET TEXT hForm1&, %FORM1_TEXT1 TO D$
                          D$=D$+ "String Test -   " + STR$(CT!) + " Seconds" + CHR$(13) + CHR$(10)
                          CONTROL SET TEXT hForm1&, %FORM1_TEXT1, D$
                  
                      END IF
                  END FUNCTION
                  ' ------------------------------------------------
                  
                  ' ------------------------------------------------
                  CALLBACK FUNCTION CBF_FORM1_COMMAND3
                      LOCAL CT!, D$, I&
                      REGISTER X##, Y##
                      IF CBCTLMSG=%BN_CLICKED THEN
                          CT! = TIMER
                          FOR X## = 1 TO 100000
                              Y## = COS(X##)
                              Y## = TAN(X##)
                              Y## = ATN(X##)
                              Y## = SIN(X##)
                          NEXT X##
                          CT! = TIMER - CT!
                          CONTROL GET TEXT hForm1&, %FORM1_TEXT1 TO D$
                          D$=D$ + CHR$(13) + CHR$(10) + "Test 3:" + CHR$(13) + CHR$(10) + STRING$(30, "-") + CHR$(13) + CHR$(10)
                          D$=D$+ "Numeric Test (Double Geometry) -   " + STR$(CT!) + " Seconds" + CHR$(13) + CHR$(10)
                          CONTROL SET TEXT hForm1&, %FORM1_TEXT1, D$
                      END IF
                  END FUNCTION
                  ' ------------------------------------------------
                  
                  
                  ' (4) Put NEXT DIALOG Callback / Subs code after here :
                  
                  ' *************************************************************
                  '                     Put Your Code Here
                  ' *************************************************************

                  ------------------
                  Chris Boss
                  Computer Workshop
                  Developer of "EZGUI"
                  http://cwsof.com
                  http://twitter.com/EZGUIProGuy

                  Comment


                  • #10
                    I have modified both test pieces to force both compilers to execute the
                    nested while loop instead of placing the 4 empty assignments outside of
                    the loop. This brings the test pieces more into line with how they can
                    be used in a code situation.

                    If the compiler optimisations still prevent the nested loop from being
                    executed, it is easy enough to add enough code to make the test pieces
                    more like real world examples so that the inner loop does get executed.

                    With the addition of some more code, the timings are now starting to
                    open up some,

                    PIII 600 512 meg ram

                    VC6 = 8.508 seconds
                    PB6 = 5.954 seconds

                    AMD K6 550 192 meg ram

                    VC6 = 10.946 seconds
                    PB6 = 7.307 seconds

                    PowerBASIC running on its default optimisation, Microsoft VC6 running with
                    the following CL command line,

                    h:\msc6\bin\cl /c /G6 /GA /TC /FA /Fa project2.c >> build.txt

                    Regards,

                    [email protected]

                    Code:
                    MICROSOFT VC 6
                      
                      // #######################################################################
                      
                      void TestProc()
                      
                          {
                          DWORD counter1;
                          counter1 = 0;
                              while (counter1 < 1000000)
                              {
                              DWORD counter2;
                              DWORD var1;
                              DWORD var2;
                              DWORD var3;
                              DWORD var4;
                      
                              var1 = 0;
                              var2 = 0;
                              var3 = 0;
                              var4 = 0;
                              
                              counter2 = 0;
                                  while (counter2 < 500)
                                  {
                                   var1++;
                                   var2++;
                                   var3++;
                                   var4++;
                      
                                   counter2++;
                                  }
                              counter1++;
                              }
                          }
                      
                      // #######################################################################
                      
                      PowerBASIC ver 6
                      
                      ' #########################################################################
                      
                      SUB TestProc2()
                      
                          LOCAL var1  as DWORD
                          LOCAL var2  as DWORD
                      
                          LOCAL item1 as DWORD
                          LOCAL item2 as DWORD
                          LOCAL item3 as DWORD
                          LOCAL item4 as DWORD
                      
                          var1 = 0
                          while var1 < 1000000
                      
                            item1 = 0
                            item2 = 0
                            item3 = 0
                            item4 = 0
                            var2  = 0
                      
                            while var2 < 500
                      
                              item1 = item1 + 1
                              item2 = item2 + 1
                              item3 = item3 + 1
                              item4 = item4 + 1
                      
                              var2 = var2 + 1
                            wend
                            var1 = var1 + 1
                          wend
                      
                      END SUB
                      
                      ' #########################################################################

                    [This message has been edited by Steve Hutchesson (edited September 26, 2000).]
                    hutch at movsd dot com
                    The MASM Forum

                    www.masm32.com

                    Comment


                    • #11
                      Steve

                      I would hazard that the results you're getting have to do with
                      the debug build not the release build. Look in the MSVC
                      Build|Set Active Configuration and make sure you've got the
                      release build selected. The code should run within 0.0100 seconds
                      in the MSVC release build.

                      Cheers

                      Florent



                      ------------------

                      Comment


                      • #12
                        These posts remind me of an application that I speeded up by
                        taking a division operation out of an integer-part operation. In
                        other words it was faster with that one-line in the loop becoming
                        two-of-the-lines in the loop.


                        Well here is a brute-force integration that runs in 14 seconds on
                        a 200Mhz chip in PB DOS:

                        c# = 1 / 4000000#

                        FOR i# = 1 TO 4000001#
                        y# = 4 / (1 + x#^2)
                        x# = x# + c#
                        yy# = yy# + y#
                        NEXT i#

                        ans# = (yy# / 4000000#) * 1
                        PRINT ans#
                        END



                        ------------------

                        Comment


                        • #13
                          Florent,

                          I actually built the VC6 file using a batch file to avoid such problems.

                          The C compiler optimisations that I tested did not deliver the correct
                          runtime performance so I could not use them,

                          /O2 maximize speed
                          /Ot favor code speed
                          /Og enable global optimization

                          When a compiler optimisation option produces runtime performance that is
                          different to the coding, it has not optimised the code, it has messed it
                          up. I think the older C compilers used to call it aggressive optimisation
                          but finding why correctly coded files don't work correctly is a joy to
                          behold in debugging term which involves either decompiling the code to see
                          what the messup is or finding a source code debugger that will run the
                          code in assembler format.

                          This is what I used because I could get it to work and run the inner loop.

                          h:\msc6\bin\cl /c /G6 /GA /TC /FA /Fa project2.c >> build.txt

                          /c compile only, no link
                          /G6 optimize for Pentium Pro
                          /GA optimize for Windows Application
                          /TC compile all files as .c
                          /Fa[file] name assembly listing file
                          /FA[sc] configure assembly listing

                          There is no debug code in this build and it runs the optimisations that
                          don't mess up the execution of the code so I think the comparison of the
                          two compilers is fair.

                          I know what Bob Zale's optimisation does when it restricts itself to
                          register variables and you have the option to turn it off if you need to
                          with the compiler directive #REGISTER NONE.

                          Here is the reason why there is a speed difference in the two compilers,

                          Code:
                            ===========================================================================
                            This is Bob Zale's default compiler performance,
                            ===========================================================================
                            
                            00401E57 C7C600000000           mov     esi,0
                            00401E5D                    loc_00401E5D:
                            00401E5D 81FE40420F00           cmp     esi,0F4240h
                            00401E63 0F8354000000           jnb     loc_00401EBD
                            00401E69 C7458000000000         mov     dword ptr [ebp-80h],0
                            00401E70 C7857CFFFFFF00000000   mov     dword ptr [ebp-84h],0
                            00401E7A C78578FFFFFF00000000   mov     dword ptr [ebp-88h],0
                            00401E84 C78574FFFFFF00000000   mov     dword ptr [ebp-8Ch],0
                            00401E8E C7C700000000           mov     edi,0
                            00401E94                    loc_00401E94:
                            00401E94 81FFF4010000           cmp     edi,1F4h
                            00401E9A 0F8319000000           jnb     loc_00401EB9
                            00401EA0 FF4580                 inc     dword ptr [ebp-80h]
                            00401EA3                    loc_00401EA3:
                            00401EA3 FF857CFFFFFF           inc     dword ptr [ebp-84h]
                            00401EA9 FF8578FFFFFF           inc     dword ptr [ebp-88h]
                            00401EAF FF8574FFFFFF           inc     dword ptr [ebp-8Ch]
                            00401EB5 FFC7                   inc     edi
                            00401EB7 EBDB                   jmp     loc_00401E94
                            00401EB9                    loc_00401EB9:
                            00401EB9 FFC6                   inc     esi
                            00401EBB EBA0                   jmp     loc_00401E5D
                            00401EBD                    loc_00401EBD:
                            
                            ===========================================================================
                          This is the assembler listing produced by the C compiler and I think it is
                          fair to say that it is garbage code in comparison. Its bigger but it
                          clearly is not faster.
                            ===========================================================================
                            
                            	mov	DWORD PTR _counter1$[ebp], 0
                            $L52565:
                            	cmp	DWORD PTR _counter1$[ebp], 1000000	; 000f4240H
                            	jae	SHORT $L52566
                            	mov	DWORD PTR _var1$52568[ebp], 0
                            	mov	DWORD PTR _var2$52569[ebp], 0
                            	mov	DWORD PTR _var3$52570[ebp], 0
                            	mov	DWORD PTR _var4$52571[ebp], 0
                            	mov	DWORD PTR _counter2$52567[ebp], 0
                            $L52573:
                            	cmp	DWORD PTR _counter2$52567[ebp], 500	; 000001f4H
                            	jae	SHORT $L52574
                            	mov	eax, DWORD PTR _var1$52568[ebp]
                            	add	eax, 1
                            	mov	DWORD PTR _var1$52568[ebp], eax
                            	mov	ecx, DWORD PTR _var2$52569[ebp]
                            	add	ecx, 1
                            	mov	DWORD PTR _var2$52569[ebp], ecx
                            	mov	edx, DWORD PTR _var3$52570[ebp]
                            	add	edx, 1
                            	mov	DWORD PTR _var3$52570[ebp], edx
                            	mov	eax, DWORD PTR _var4$52571[ebp]
                            	add	eax, 1
                            	mov	DWORD PTR _var4$52571[ebp], eax
                            	mov	ecx, DWORD PTR _counter2$52567[ebp]
                            	add	ecx, 1
                            	mov	DWORD PTR _counter2$52567[ebp], ecx
                            	jmp	SHORT $L52573
                            $L52574:
                            	mov	edx, DWORD PTR _counter1$[ebp]
                            	add	edx, 1
                            	mov	DWORD PTR _counter1$[ebp], edx
                            	jmp	SHORT $L52565
                            $L52566:
                            
                            ===========================================================================
                          What I would conclude is that programmers using PowerBASIC are getting
                          good compiler performance that is much simpler to use and no-where as
                          complex to set up and get going as the Microsoft C compiler. I suspect
                          that the GCC compiler Florent is using generates working code that appears
                          to be a lot better than this listing above.

                          Perhaps what surprises me the most is that I grew up with C compilers and
                          they used to be leading edge performers in terms of binary output. It has
                          been my experience of recent times that C programmers looking for real
                          performance write seperate modules in assembler and link them into their C
                          programs.

                          While Microsoft C will write inline asm reasonably well, it does not have
                          the flexibility to mix it line for line in the same manner as you can in
                          PowerBASIC so generally Microsoft C programmers who need real performance
                          end up writing their speed critical code as a module in MASM and link it
                          into the final build.

                          Regards,

                          [email protected]

                          ------------------
                          hutch at movsd dot com
                          The MASM Forum

                          www.masm32.com

                          Comment


                          • #14
                            Ive updated my C sample and its just as fast as before. ~0.5 seconds.
                            I've also moved the routine into a seperate sub just as you
                            have done.

                            Here are my compiler switches.
                            /nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"Release/Text1.pch" /YX /Fo"Release/"

                            And Steve, there is nothing remotely difficult about setting
                            up these switches in the IDE. Its all done for you. I simply
                            click Project\Settings\ then click the C\C++ tab and select
                            "maximize speed" in the drop down. *poof* that command line
                            is created for you. Im anything but a VC master and i found it
                            pathetically easy to do.

                            You can theorize about PB being faster under real world circulations
                            but that is just one mans theory which I dont happen to believe.
                            As for your asm theories, I know there are alot of
                            C/C++ programmers who feel that there is no need to use asm in
                            anything but the most speed intensive routines and even then, only
                            if you're a good asm programmer (which most arent). Besides,
                            this started off as a C versus PB speed comparison and not about
                            any other niceties. It goes without saying that PB is easier and
                            faster to code.

                            If ultimately you're going to fall back on these
                            types of statements without producing examples which prove your
                            theory, then I see no further use in trying to refute your results.

                            Code:
                            #include <stdlib.h>
                            #include <stdio.h>
                            
                            void test(void);
                            
                            void main(void) {
                            
                             test();
                            
                            }
                                 
                            void test(void) {
                            
                            	  unsigned long counter1;
                                  unsigned long counter2;
                            
                                  
                            	  counter2 = 0;	
                            	  counter1 = 0;
                            	  printf("uXORTest Begin\n");
                                      while (counter1 < 1000000)
                                      {
                                      unsigned long counter2;
                                      unsigned long var1;
                                      unsigned long var2;
                                      unsigned long var3;
                                      unsigned long var4;
                                      
                            		  var1 = 0;
                            		  var2 = 0;
                            		  var3 = 0;
                            		  var4 = 0;
                            					
                                      counter2 = 0;
                                          while (counter2 < 1000)
                                          {
                                           var1 = 1;
                                           var2 = 2;
                                           var3 = 3;
                                           var4 = 4;
                                           counter2++;
                                          }
                                      counter1++;
                                      }
                            		  printf("%d\n", counter1);
                                  }
                            Bottom line, VC produces compiled code which executes significantly
                            faster than PB. As for real world examples, I'll say it again...
                            my Blowfish algorithm which I wrote based on the C reference
                            implementation (you can find it at www.counterpane.com) when
                            encrypting a 2megabytes of data took ~7 seconds with PB and ~2
                            seconds with VC. It wasnt until i cheated and used inline asm
                            was I able to get the score down to 1.2 for PB. Most PB users
                            arent going to want or know how to use asm to speed up such a
                            algorithm. I needed a ton of help for that portion, otherwise
                            I could never have produced asm which would be _faster_ than
                            the current PB compiled results.

                            -Mike

                            ------------------

                            Comment


                            • #15
                              ODD Indeed!!!!

                              I ported the code from the first example done in PB on a PIII 600 into VB6 and on my PIII 450
                              I can run the code below in 4.6 seconds (rather than PB's 12)

                              Code:
                              Private Sub Command1_Click()
                              
                              Dim x As Single
                                 x = Timer
                              
                                 Dim var1 As Long
                                 Dim var2 As Long
                              
                                 Dim item1 As Long
                                 Dim item2 As Long
                                 Dim item3 As Long
                                 Dim item4 As Long
                              
                                 var1 = 0
                                 While var1 < 1000000
                                    var2 = 0
                                    While var2 < 1000
                              
                                       item1 = 1
                                       item2 = 2
                                       item3 = 3
                                       item4 = 4
                              
                                       var2 = var2 + 1
                                    Wend
                                    var1 = var1 + 1
                                 Wend
                              
                                 MsgBox Timer - x
                              
                              
                              End Sub
                              If I do a normal compile then PB is quicker but if I do an optimized for P Pro compile in VB with the checking turned off then VB kicks PB into the mud. I've tried heaps of these tests and I think what I'd like to see is a P Pro compile for PB. I like PB for lots of reasons and it's not slow but VB is quite fast these days "If you know what you're doing" I beleive someone said


                              ------------------


                              [This message has been edited by Paul Dwyer2 (edited September 27, 2000).]

                              Comment


                              • #16
                                Steve

                                okay I dug out a copy of MSVC 6 (I use the lovely lcc-win32
                                compiler - which produces tight, quality code - for my C work) so
                                I could see for myself what MSVC was generating.

                                I compiled the test code with the following options to see
                                what optimizations the compiler was producing.

                                I used the following switches:
                                cl /G6 /O2 /FAc speed.c
                                G6: Optimize for Pentium Pro
                                O2: Optimize for fast code (a real culprit!)
                                FAc: Assembly with machine code

                                I had a good laugh when I looked at the code. The optimizer
                                optimized the whole TestProc code away!

                                Have a look guys - the only thing that the code is doing in TestProc
                                is returning to caller!!

                                Code:
                                	TITLE	speed.c
                                	.386P
                                include listing.inc
                                if @Version gt 510
                                .model FLAT
                                else
                                _TEXT	SEGMENT PARA USE32 PUBLIC 'CODE'
                                _TEXT	ENDS
                                _DATA	SEGMENT DWORD USE32 PUBLIC 'DATA'
                                _DATA	ENDS
                                CONST	SEGMENT DWORD USE32 PUBLIC 'CONST'
                                CONST	ENDS
                                _BSS	SEGMENT DWORD USE32 PUBLIC 'BSS'
                                _BSS	ENDS
                                _TLS	SEGMENT DWORD USE32 PUBLIC 'TLS'
                                _TLS	ENDS
                                ;	COMDAT [email protected][email protected]@[email protected]
                                _DATA	SEGMENT DWORD USE32 PUBLIC 'DATA'
                                _DATA	ENDS
                                ;	COMDAT _TestProc
                                _TEXT	SEGMENT PARA USE32 PUBLIC 'CODE'
                                _TEXT	ENDS
                                ;	COMDAT _main
                                _TEXT	SEGMENT PARA USE32 PUBLIC 'CODE'
                                _TEXT	ENDS
                                FLAT	GROUP _DATA, CONST, _BSS
                                	ASSUME	CS: FLAT, DS: FLAT, SS: FLAT
                                endif
                                PUBLIC	_TestProc
                                ;	COMDAT _TestProc
                                _TEXT	SEGMENT
                                _TestProc PROC NEAR					; COMDAT
                                ; File speed.c
                                ; Line 34
                                  00000	c3		 ret	 0
                                _TestProc ENDP
                                _TEXT	ENDS
                                PUBLIC	_main
                                PUBLIC	[email protected][email protected]@[email protected]		; `string'
                                PUBLIC	[email protected]@3ff583126e978d4fe000
                                EXTRN	__fltused:NEAR
                                EXTRN	_printf:NEAR
                                EXTRN	[email protected]:NEAR
                                ;	COMDAT [email protected][email protected]@[email protected]
                                ; File speed.c
                                _DATA	SEGMENT
                                [email protected][email protected]@[email protected] DB '%2.8f seconds', 0aH, 00H ; `string'
                                _DATA	ENDS
                                ;	COMDAT [email protected]@3ff583126e978d4fe000
                                CONST	SEGMENT
                                [email protected]@3ff583126e978d4fe000 DQ 03f50624dd2f1a9fcr ; 0.001
                                CONST	ENDS
                                ;	COMDAT _main
                                _TEXT	SEGMENT
                                _duration$ = -8
                                _main	PROC NEAR					; COMDAT
                                ; File speed.c
                                ; Line 37
                                  00000	83 ec 08	 sub	 esp, 8
                                  00003	56		 push	 esi
                                ; Line 42
                                  00004	8b 35 00 00 00
                                	00		 mov	 esi, DWORD PTR [email protected]
                                  0000a	57		 push	 edi
                                  0000b	ff d6		 call	 esi
                                  0000d	8b f8		 mov	 edi, eax
                                ; Line 43
                                  0000f	e8 00 00 00 00	 call	 _TestProc
                                ; Line 44
                                  00014	ff d6		 call	 esi
                                ; Line 46
                                  00016	2b c7		 sub	 eax, edi
                                  00018	89 44 24 08	 mov	 DWORD PTR -8+[esp+16], eax
                                  0001c	c7 44 24 0c 00
                                	00 00 00	 mov	 DWORD PTR -8+[esp+20], 0
                                  00024	df 6c 24 08	 fild	 QWORD PTR -8+[esp+16]
                                  00028	dc 0d 00 00 00
                                	00		 fmul	 QWORD PTR [email protected]@3ff583126e978d4fe000
                                  0002e	dd 5c 24 08	 fstp	 QWORD PTR _duration$[esp+16]
                                ; Line 47
                                  00032	8b 44 24 0c	 mov	 eax, DWORD PTR _duration$[esp+20]
                                  00036	8b 4c 24 08	 mov	 ecx, DWORD PTR _duration$[esp+16]
                                  0003a	50		 push	 eax
                                  0003b	51		 push	 ecx
                                  0003c	68 00 00 00 00	 push	 OFFSET FLAT:[email protected][email protected]@[email protected] ; `string'
                                  00041	e8 00 00 00 00	 call	 _printf
                                  00046	83 c4 0c	 add	 esp, 12			; 0000000cH
                                  00049	5f		 pop	 edi
                                ; Line 48
                                  0004a	33 c0		 xor	 eax, eax
                                  0004c	5e		 pop	 esi
                                ; Line 49
                                  0004d	83 c4 08	 add	 esp, 8
                                  00050	c3		 ret	 0
                                _main	ENDP
                                _TEXT	ENDS
                                END
                                Steve, you mentioned aggressive optimization: this is like shaking
                                someone's hand only to find out that you just lost 2 fingers...

                                I owe you an apology, Steve - you're quite right - if we're going
                                to compare code output then let's compare equivalent code.

                                The real code produced by MSVC runs at a respectable 14.451 seconds
                                on my PII 400 which is a far cry from just printing a fantasy timing.

                                Mike,

                                Steve's right - the optimizer didn't even unroll the loop and cast
                                out the loop invariants: it clean got rid of everything in TestProc
                                because it couldn't see what possible use you could have for it.

                                In your test code you print out the value of counter1 - what the
                                optimizer does is clean the whole code away and places the value
                                1000000 in counter and prints that... Not what you wrote and not
                                what you meant...

                                In short, when you optimize, optimize once everything's running
                                and DO IT YOURSELF - it's the only way you can look your client
                                in the eyes and say you delivered. There's a saying in Swiss German
                                (I live in Zürich) which translates to: "everybody cooks with water"
                                which means everybody is bound by the same constraints - you'll rarely
                                get a free lunch.

                                Cheers

                                Florent




                                [This message has been edited by Florent Heyworth (edited September 27, 2000).]

                                Comment


                                • #17
                                  Florent,

                                  Thanks for finding out what was happening, I don't class my own C as being
                                  up to scratch any more as I have not seriously written in C for about 5
                                  years. I confess that I have never lost my liking for the C dialect, I grew
                                  up when C could be directly translated back to assembler and you could write
                                  some very fast code with it if you got it right.

                                  The optimisation technique used by the VC compiler is a very interesting one
                                  if you will forgive the humour, I think I could get some really rocket code
                                  going if all I had to do was return a fixed value without having to do all
                                  the normal dirty work to get it.

                                  I don't know if it would be much use but it sure would be fast, maybe someone
                                  could produce a benchmarking optimising compiler that replaced all of it
                                  functions with hard coded numbers. I am sure such a beast would win all the
                                  compiler benchmark competitions, even if you could not write useful code with
                                  it.

                                  Actually the LCC-32 compiler looks interesting, as it seems Microsoft are not
                                  willing to put the code quality in the VC6 C compiler any longer, if I can
                                  get the time, it sounds well worth having a look at.

                                  Regards & Thanks,

                                  [email protected]

                                  ------------------
                                  hutch at movsd dot com
                                  The MASM Forum

                                  www.masm32.com

                                  Comment


                                  • #18
                                    As far as I'm concerned, VC still wins. Why? Because this was
                                    a speed contest and nothing more. Who's to say how it should
                                    optimize if you set the option "maximize speed?" In a speed
                                    contest, the bottom line is all that matters.

                                    Florent, dont you think you're jumping to conclusions? A simple
                                    testproc which VC intelligently optimizes, why not expect (or at
                                    least desire the _option_ in future versions) that PowerBASIC
                                    should be able to do the same? Who's to say what VC might've done
                                    had it not been able to determine it could short circuit everything?

                                    In my book, with the current simplistic testproc, VC wins. 1 - 0
                                    Next algorithm please. Perhaps I will find one and post it...
                                    At a minimum, the test should work with real data. Perhaps I
                                    will take one of the encryption or compression algorithms
                                    posted in the source code forumn and try to translate it to C.
                                    Might take me a bit.

                                    -Mike



                                    ------------------

                                    Comment


                                    • #19
                                      Mike, you're pushing your luck. This thread will not be allowed to degenerate into compiler wars. Keep it civil and informative.

                                      ------------------
                                      Tom Hanlin
                                      PowerBASIC Staff

                                      Comment


                                      • #20
                                        FWIW, we are not at war with one another. If we have an enemy(?) it is not each other, but perhaps ourselves, due to our dealings with that frustrating machine called a computer.
                                        People will be people. We will always have our own opinions and points of view. Your "beliefs" will blind you to what someone else is trying to say. Misunderstandings cause wars. We are not trying to "browbeat" someone into accepting our own "beliefs". We should only be saying "Why" we hold to the ideas we have.
                                        A lot of what is being said in the Windows and Programming forums is "Philosophy of Programming" and not programming at all. Perhaps it might be useful to create a new Forum called "Philosophy of Programming". That way the current Topics would be used only to discuss coding, much the way the moderators have done with the Source Code Forum.

                                        In highest Regards,

                                        ------------------
                                        [email protected]
                                        :) IRC :)

                                        Comment

                                        Working...
                                        X