Discussion:
Oh boy! This is slow.
(too old to reply)
Olav
2010-06-04 09:45:46 UTC
Permalink
Raw Message
It has always been said that Powerbasic is so fast, especially compared to
Visual Basic, but I think this no longer is true.

FUNCTION PBMAIN () AS LONG

LOCAL z,i AS SINGLE
REGISTER Counter&
REGISTER x##, y##
x## = 1
y## = 0.00001
i = TIMER
FOR Counter& = 1 TO 1000000000
x## = x## * y##
NEXT
z = TIMER - i
? STR$(z)
? "Press a key to end the program..."
WAITKEY$

END FUNCTION


//////////////////////Visual Basic 2010/////////////////////////////

Sub Main()

Dim start_time As DateTime

Dim stop_time As DateTime

Dim elapsed_time As TimeSpan

Dim Counter As Integer

Dim x, y As Double

x = 1

y = 0.00001

start_time = Now()

For Counter = 1 To 1000000000

x = x * y

Next

stop_time = Now()

elapsed_time = stop_time.Subtract(start_time)

Console.WriteLine(elapsed_time.TotalSeconds().ToString)

Console.Read() 'CTRL + F5 within the IDE halts the console

End Sub

/////////////////////////////Code
Ends//////////////////////////////////////////////////

And here are the results:

Debug mode No debugger

Powerbasic Unknown 2.76 secs

Visual Basic 10 secs 1 sec



Powerbasic result, while run in the debugger, is unknown because I canceled
the test after about 4 - FOUR- hours time. It was at that time still
running.

--

Olav

?
hutch--
2010-06-04 13:12:36 UTC
Permalink
Raw Message
Olav,

I ran your example in PBCC5 then stripped doewn the FOR loop into a
simpler form. Got the same timing on this quad.

This is the code generated after removing other variables.

! mov edx, 1000000000
#align 4
lbl0:
xx = xx * yy
! sub edx, 1
! jnz lbl0

This is that code disassembled.

0040119D BA00CA9A3B mov edx,3B9ACA00h
004011A2 90 nop
004011A3 90 nop
004011A4 loc_004011A4:
004011A4 D8C9 fmul st,st(1)
004011A6 83EA01 sub edx,1
004011A9 0F85F5FFFFFF jne loc_004011A4

Now the "xx = xx * yy" line is one line of assembler code in the
disassembly, "fmul st,st(1)".

Check what the VB code generated and see if it has simplified the FOR
loop to integer operations.

One FP instruction cannot be optimised so its probable that the VB
code has done something different.
Wolfgang Enzinger
2010-06-04 17:46:03 UTC
Permalink
Raw Message
Post by hutch--
Check what the VB code generated and see if it has simplified the FOR
loop to integer operations.
I wonder if that's possible at all. Olav said "VB" which is a bit
unprecise. His code though looks like VB.NET, which - as opposed to VB
"classic" - doesn't write a native code executable. Instead, an
intermediate language is written to disk and then JIT compiled (just in
time) at runtime. So while a .NET executable can be easily discompiled, I'm
not sure whether it can be disassembled. Not sayimg that it's impossible
though.
Olav
2010-06-05 06:39:23 UTC
Permalink
Raw Message
Post by hutch--
Olav,
I ran your example in PBCC5 then stripped doewn the FOR loop into a
simpler form. Got the same timing on this quad.
This is the code generated after removing other variables.
! mov edx, 1000000000
#align 4
xx = xx * yy
! sub edx, 1
! jnz lbl0
This is that code disassembled.
0040119D BA00CA9A3B mov edx,3B9ACA00h
004011A2 90 nop
004011A3 90 nop
004011A4 D8C9 fmul st,st(1)
004011A6 83EA01 sub edx,1
004011A9 0F85F5FFFFFF jne loc_004011A4
Now the "xx = xx * yy" line is one line of assembler code in the
disassembly, "fmul st,st(1)".
Check what the VB code generated and see if it has simplified the FOR
loop to integer operations.
My concern was more about the fact that VB is faster than PB and not so much
about how and why.
Post by hutch--
One FP instruction cannot be optimised so its probable that the VB
code has done something different.
I guess so. And VB2010 seems to do it better than PB, and this is even in an
area where it is said that PB is hand-optimized. FOR/NEXT loops in PB is
highly optimized; I have read.
And register variables is said to boost performance even more, but still VB
beats PB in such a loop.

And may I add; the debugger in PB is in practical terms completely useless.
--
Olav
hutch--
2010-06-05 07:44:09 UTC
Permalink
Raw Message
Olav,

Be that so the risk is that you are comparing chalk and cheese. One
floating point instruction in a loop cannot be further optimised so it
is evident that the VB code you posted is doing something else. With
the PB code you know for sure that it loops an 80 bit floating point
multiplication for the number of iterations in the loop.

Noting that VB apparently cannot do 80 bit FP and is restricted to 64
bit FP, try a benchmark that (a) you understand how it works, (b) you
are performing calculations that do not collapse down to one argument
being close to zero.
hutch--
2010-06-05 08:00:59 UTC
Permalink
Raw Message
Here is how to write a benchmark, instead of cooking the results to
get the slowest way to do something, try a direct comparison where the
programmer is in control, not the compiler. Done the fast way the PB
code is so fast that it does not get a timing.

4343 timing 1
22026.4633548315
0 timing 2
22026.4633548315
Press a key to end the program...

The test piece.

DECLARE FUNCTION GetTickCount LIB "KERNEL32.DLL" _
ALIAS "GetTickCount" () AS DWORD

FUNCTION PBMAIN () AS LONG

LOCAL xx as EXT
LOCAL yy as EXT
LOCAL counter as DWORD
LOCAL tc as DWORD

' ------------------------------------------

xx = 1.0
yy = 1.00000001

tc = GetTickCount

FOR counter = 1 TO 1000000000
xx = xx * yy
NEXT

tc = GetTickCount - tc
StdOut str$(tc)+" timing 1"

StdOut str$(xx)

' ------------------------------------------

xx = 1.0
yy = 1.00000001

tc = GetTickCount

xx = (xx * yy) ^ 1000000000

tc = GetTickCount - tc
StdOut str$(tc)+" timing 2"

StdOut str$(xx)

' ------------------------------------------

? "Press a key to end the program..."
WAITKEY$

END FUNCTION

Loading...