PureBasic speed test compared to this video

Everything else that doesn't fall into one of the other PB categories.
BarryG
Addict
Addict
Posts: 3292
Joined: Thu Apr 18, 2019 8:17 am

PureBasic speed test compared to this video

Post by BarryG »

Hi all, I'm a fan of Dave Plummer on YouTube (he wrote "Task Manager" on Windows, and lots of other Windows things) and he just posted a video about the speed of calculating prime numbers in Python, C#, and C++ (see the results here). He posted the source for the three languages on Github. My obvious question is: can someone convert one of those sources to PureBasic to compare the speed to his results? Would be very interesting to see. Make sure you post your code here to compare. Thanks!

[Edit] The test is done over 5 seconds, to compare properly with his results.
Last edited by BarryG on Thu Mar 25, 2021 4:59 pm, edited 1 time in total.
Axolotl
Enthusiast
Enthusiast
Posts: 435
Joined: Wed Dec 31, 2008 3:36 pm

Re: PureBasic speed test compared to this video

Post by Axolotl »

i will have a look to the codes. usually i am to slow on doing this... the professionals here will beat me with ther solutions i guess. :oops:
stay tuned.
Mostly running PureBasic <latest stable version and current alpha/beta> (x64) on Windows 11 Home
User avatar
NicTheQuick
Addict
Addict
Posts: 1223
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: PureBasic speed test compared to this video

Post by NicTheQuick »

Just translated it for you:

Code: Select all

EnableExplicit

Global Dim rawbits.a(0)
Global sieveSize.i

Procedure validateResults(actualCount.i)
	Protected count.i
	Select sieveSize
		Case 10: count = 1
		Case 100: count = 25
		Case 1000: count = 168
		Case 10000: count = 1229
		Case 100000: count = 9592
		Case 1000000: count = 78498
		Case 10000000: count = 664579
		Case 100000000: count = 5761455
		Default: ProcedureReturn #False
	EndSelect
	
	ProcedureReturn Bool(count = actualCount)
EndProcedure

Procedure GetBit(index.i)
	If index & 1
		index / 2
		ProcedureReturn rawbits(index / 8) & (1 << (index % 8))
	EndIf
	ProcedureReturn #False
EndProcedure

Procedure ClearBit(index.i)
	If index & 1
		index / 2
		rawbits(index / 8) & ~(1 << (index % 8))
	EndIf
EndProcedure

Procedure prime_sieve(n.i)
	sieveSize = n
	ReDim rawbits.a(n / 8)
	FillMemory(@rawbits(0), n / 8 + 1, $ff, #PB_Ascii)
EndProcedure

Procedure runSieve()
	Protected factor.i = 3
	Protected q = Sqr(sieveSize)
	Protected num.i
	
	While (factor < q)
		num = factor
		While num < sieveSize
			If GetBit(num)
				factor = num
				Break
			EndIf
			num + 1
		Wend
		num = factor * 3
		While num < sieveSize
			ClearBit(num)
			num + factor * 2
		Wend
		factor + 2
	Wend
EndProcedure

Procedure printResults(showResults.i, duration.d, passes.i)
	Protected num.i
	
	If showResults
		Print("2, ")
	EndIf
	
	Protected count.i = 1
	For num = 3 To sieveSize
		If GetBit(num)
			If showResults
				Print(Str(num) + ", ")
			EndIf
			count + 1
		EndIf
	Next
	
	If showResults
		PrintN("")
	EndIf
	
	PrintN("Passes: " + passes + 
	       ", Time: " + duration + " ms" +
	       ", Avg: " + StrD(duration / passes, 3) + " ms" +
	       ", Limit: " + sieveSize + 
	       ", Count: " + count + 
	       ", Valid: " + Str(validateResults(count)))
EndProcedure

Procedure main(limit.i = 1000000, duration.i = 10000)
	Protected passes.i = 0
	
	Protected tStart.i = ElapsedMilliseconds()
	
	While ElapsedMilliseconds() - tStart < duration
		prime_sieve(limit)
		runSieve()
		passes + 1
	Wend
	
	Protected tD.i = ElapsedMilliseconds() - tStart
	
	printResults(#False, tD, passes)
EndProcedure

OpenConsole()

main(1000000, 10000)
Input()
CloseConsole()
And this is the output on my old laptop:

Code: Select all

Passes: 246, Time: 10021 ms, Avg: 40.736 ms, Limit: 1000000, Count: 78498, Valid: 1
And in case you are curious, this is with debugger on:

Code: Select all

Passes: 30, Time: 10190 ms, Avg: 339.667 ms, Limit: 1000000, Count: 78498, Valid: 1
I also compiled the C++ code using g++ on Linux and got this result:

Code: Select all

Passes: 1741, Time: 10000 ms, Avg: 5.744, Limit: 1000000, Count: 78498, Valid: 1
As you can see it is nearly 7 times faster. I gues the main reason for that is automatic inlining of functions and better optimization for GetBit and ClearBit.
Last edited by NicTheQuick on Thu Mar 25, 2021 4:35 pm, edited 3 times in total.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
tft
User
User
Posts: 84
Joined: Mon Dec 29, 2008 9:34 am

Re: PureBasic speed test compared to this video

Post by tft »

on my maschine ....... Passes 329, Time 10004 ms, AVG= 30.407

and yet ???
TFT seid 1989
Aktuelles Projekte : Driving School Evergarden
YouTube : Pure Basic to go
FaceBook : Temuçin SourceMagic Games
DISCORD : SourceMagic
W10 , i9 9900K ,32 GB Ram , GTX Titan , 3 Monitore FHD
ARDUINO Freak :-)
BarryG
Addict
Addict
Posts: 3292
Joined: Thu Apr 18, 2019 8:17 am

Re: PureBasic speed test compared to this video

Post by BarryG »

The test is meant to be done over a 5-second period, not 10. My result over 5 seconds is:

Passes: 182, Time: 5001 ms, Avg: 27.478 ms, Limit: 1000000, Count: 78498, Valid: 1

(And thanks for the converted code, NicTheQuick!).
fluent
User
User
Posts: 68
Joined: Sun Jan 24, 2021 10:57 am

Re: PureBasic speed test compared to this video

Post by fluent »

PB 5.62 x86, debugger off:
Passes: 395, Time: 5009 ms, Avg: 12.681 ms, Limit: 1000000, Count: 78498, Valid: 1

PB 5.62 x64, debugger off:
Passes: 122, Time: 5039 ms, Avg: 41.303 ms, Limit: 1000000, Count: 78498, Valid: 1

Looks like 64-bit is slower??

(win 10 x64 - 5-year-old low-end ASUS laptop)
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: PureBasic speed test compared to this video

Post by skywalk »

Ha! This is quite timely with v6 approaching.

Please post your OS versions and whitelisting of PB app in use.
And there is no process priority applied to the test?
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
NicTheQuick
Addict
Addict
Posts: 1223
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: PureBasic speed test compared to this video

Post by NicTheQuick »

With macros and the avoidance of modulo you actually can make it pretty fast. And that is what a C compiler usually does automatically for you:

Code: Select all

EnableExplicit

Global Dim rawbits.a(0)
Global sieveSize.i

Procedure validateResults(actualCount.i)
	Protected count.i
	Select sieveSize
		Case 10: count = 1
		Case 100: count = 25
		Case 1000: count = 168
		Case 10000: count = 1229
		Case 100000: count = 9592
		Case 1000000: count = 78498
		Case 10000000: count = 664579
		Case 100000000: count = 5761455
		Default: ProcedureReturn #False
	EndSelect
	
	ProcedureReturn Bool(count = actualCount)
EndProcedure

Macro GetBit(index)
	((index & 1) And rawbits(index >> 4) & (1 << ((index & $f) >> 1)))
EndMacro

Macro ClearBit(index)
	rawbits(index >> 4) & ~(1 << ((index & $f) >> 1))
EndMacro

Procedure prime_sieve(n.i)
	sieveSize = n
	ReDim rawbits.a(n / 8)
	FillMemory(@rawbits(0), n / 8 + 1, $ff, #PB_Ascii)
EndProcedure

Procedure runSieve()
	Protected factor.i = 3
	Protected q = Sqr(sieveSize)
	Protected num.i
	
	While (factor < q)
		num = factor
		While num < sieveSize
			If GetBit(num)
				factor = num
				Break
			EndIf
			num + 1
		Wend
		num = factor * 3
		While num < sieveSize
			; We can be sure that num is always an odd number
			ClearBit(num)
			num + factor * 2
		Wend
		factor + 2
	Wend
EndProcedure

Procedure printResults(showResults.i, duration.d, passes.i)
	Protected num.i
	
	If showResults
		Print("2, ")
	EndIf
	
	Protected count.i = 1
	For num = 3 To sieveSize
		If GetBit(num)
			If showResults
				Print(Str(num) + ", ")
			EndIf
			count + 1
		EndIf
	Next
	
	If showResults
		PrintN("")
	EndIf
	
	PrintN("Passes: " + passes + 
	       ", Time: " + duration + " ms" +
	       ", Avg: " + StrD(duration / passes, 3) + " ms" +
	       ", Limit: " + sieveSize + 
	       ", Count: " + count + 
	       ", Valid: " + Str(validateResults(count)))
EndProcedure

Procedure main(limit.i = 1000000, duration.i = 5000)
	Protected passes.i = 0
	
	Protected tStart.i = ElapsedMilliseconds()
	
	While ElapsedMilliseconds() - tStart < duration
		prime_sieve(limit)
		runSieve()
		passes + 1
	Wend
	
	Protected tD.i = ElapsedMilliseconds() - tStart
	
	printResults(#False, tD, passes)
EndProcedure

OpenConsole()

main(1000000, 5000)
Input()
CloseConsole()
Old code over 5 seconds:

Code: Select all

Passes: 129, Time: 5001 ms, Avg: 38.767 ms, Limit: 1000000, Count: 78498, Valid: 1
New version over 5 seconds:

Code: Select all

Passes: 1690, Time: 5000 ms, Avg: 2.959 ms, Limit: 1000000, Count: 78498, Valid: 1
C-Code over 5 seconds on the same machine:

Code: Select all

Passes: 909, Time: 5000 ms, Avg: 5.501 ms, Limit: 1000000, Count: 78498, Valid: 1
C-Code over 5 seconds with -O3 flag for best optimization:

Code: Select all

Passes: 4431, Time: 5000 ms, Avg: 1.128 ms, Limit: 1000000, Count: 78498, Valid: 1
Btw my CPU: Intel(R) Core(TM) i7-3820QM CPU @ 2.70GHz with 8MB L3 cache.
It's a Thinkpad W530.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
Rinzwind
Enthusiast
Enthusiast
Posts: 636
Joined: Wed Mar 11, 2009 4:06 pm
Location: NL

Re: PureBasic speed test compared to this video

Post by Rinzwind »

PB needs inline procedures as manual option at least if the compiler is not smart enough to detect when to apply it.

Same as with easy byref parameters (way more BASIC than having to deal with pointers). I guess it is too much to ask for for current asm emitter logic? Too much old, sticky and cold spaghetti?

Anyway good to see that macro's saved PB's ass ;). They could also do with some practical extra's btw.
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: PureBasic speed test compared to this video

Post by skywalk »

Macro's are inlined code. :idea: :wink:
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
NicTheQuick
Addict
Addict
Posts: 1223
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: PureBasic speed test compared to this video

Post by NicTheQuick »

skywalk wrote:Macro's are inlined code. :idea: :wink:
Not really. Macros are more like generic programming in C(++).
For example you can not create Macros with a non trivial return value. This only works if the macro itself is a one liner. And then you also have the issue that parameters which are used multiple times were also evaluated multiple times. See here:

Code: Select all

Global counter = 0
Procedure count()
	counter + 1
	ProcedureReturn counter
EndProcedure

Macro tripleAMacro(a)
	((a) + (a) + (a))
EndMacro

Procedure tripleAProcedure(a)
	ProcedureReturn ((a) + (a) + (a))
EndProcedure

; Calls count() once
Debug tripleAProcedure(count())

counter = 0
; Calls count() three times
Debug tripleAMacro(count())
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
User avatar
skywalk
Addict
Addict
Posts: 3972
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: PureBasic speed test compared to this video

Post by skywalk »

I agree, but I was referring to your macro code in the speed test. l often inline code for speed at the expense of shorter procedures.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
NicTheQuick
Addict
Addict
Posts: 1223
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: PureBasic speed test compared to this video

Post by NicTheQuick »

skywalk wrote:I agree, but I was referring to your macro code in the speed test. l often inline code for speed at the expense of shorter procedures.
In this case the inlining doubled the speed. If I change GetBit and ClearBit back to a procedure I get this result:

Code: Select all

Passes: 876, Time: 5002 ms, Avg: 5.710 ms, Limit: 1000000, Count: 78498, Valid: 1
which is ~52% of the speed of the Macro version.
If I then replace the shifts back to division (">> 4" -> "/ 16") it makes a much bigger difference:

Code: Select all

Passes: 190, Time: 5010 ms, Avg: 26.368 ms, Limit: 1000000, Count: 78498, Valid: 1
Finally replacing the bitwise ANDs with modulo again ("& $f" -> "% 16") it gets even slower:

Code: Select all

Passes: 125, Time: 5013 ms, Avg: 40.104 ms, Limit: 1000000, Count: 78498, Valid: 1
I think Purebasic should do the optimization with the modulo and shifts automatically. Then you would not need to make it manually.

But if Purebasic evolves to a compiler for C-Code instead FASM, we do not longer care about that I guess.
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
Axolotl
Enthusiast
Enthusiast
Posts: 435
Joined: Wed Dec 31, 2008 3:36 pm

Re: PureBasic speed test compared to this video

Post by Axolotl »

@NicTheQuick:
if i understand you correctly, these are the fastest routines based on procedure, right? :oops:

Code: Select all

; Macro GetBit(index) 
;    ((index & 1) And rawbits(index >> 4) & (1 << ((index & $f) >> 1)))
; EndMacro

Procedure GetBit(index.i)
   If index & 1
      ProcedureReturn rawbits(index >> 4) & (1 << ((index & $f) >> 1))
   EndIf
   ProcedureReturn #False
;    If index & 1
;       index / 2
;       ProcedureReturn rawbits(index / 8) & (1 << (index % 8))
;    EndIf
;    ProcedureReturn #False
EndProcedure

; Macro ClearBit(index)
;    rawbits(index >> 4) & ~(1 << ((index & $f) >> 1))
; EndMacro

Procedure ClearBit(index.i)
  rawbits(index >> 4) & ~(1 << ((index & $f) >> 1))
;    If index & 1
;       index / 2
;       rawbits(index / 8) & ~(1 << (index % 8))
;    EndIf
EndProcedure
@BarryG: told you :oops: (my solution was very similar to NicTheQuick's, so i refrained from publishing it.)
Mostly running PureBasic <latest stable version and current alpha/beta> (x64) on Windows 11 Home
User avatar
NicTheQuick
Addict
Addict
Posts: 1223
Joined: Sun Jun 22, 2003 7:43 pm
Location: Germany, Saarbrücken
Contact:

Re: PureBasic speed test compared to this video

Post by NicTheQuick »

Axolotl wrote:@NicTheQuick:
if i understand you correctly, these are the fastest routines based on procedure, right? :oops:
The fastest should be these:

Code: Select all

Procedure GetBit(index)
	ProcedureReturn Bool((index & 1) And rawbits(index >> 4) & (1 << ((index & $f) >> 1)))
EndProcedure

Procedure ClearBit(index)
	rawbits(index >> 4) & ~(1 << ((index & $f) >> 1))
EndProcedure
They are branchless (best for optimization within the CPU itself) and do not use any division or modulo (which is a division by itself).
The english grammar is freeware, you can use it freely - But it's not Open Source, i.e. you can not change it or publish it in altered way.
Post Reply