[futurebasic] Re: [FB] New instr (was "Whyfor this thou behavior? ")

Message: < previous - next > : Reply : Subscribe : Cleanse
Home   : April 2010 : Group Archive : Group : All Groups

From: Robert Purves <listrp@...>
Date: Thu, 29 Apr 2010 17:20:27 +1200
Jay Reeve wrote:

> I've continued to play with this, and I'm now convinced that instr can be accelerated even more by using a different routine when searching for longer strings.
> The new routine compares 8-byte chunks rather than chars, but it incurs some additional overhead.

I have a built-in distrust of code that performs misaligned loads. 
<http://en.wikipedia.org/wiki/Data_structure_alignment>
<http://msdn.microsoft.com/en-us/library/ms253548(v=VS.90).aspx>


> The speed boost for long needles appears to be significant on my old G4 (OS 10.4.11). I'm curious how it will fare on a modern machine.

Timings on a modern machine (Core i5). 
I converted your two versions of instr_new() to PSinstr() and put them in the C runtime, alongside our buggy old original. 
The timing test code is given below. It looks as though the misalignment kills performance of jay2 with long needles.

Times in s; smaller values are better.
 orig  jay1   jay2
 0.07  0.05   0.05     [len( needle ) == 1]
 0.12  0.10   0.08     [len( needle ) == 1]
 0.54  0.63   0.50     [len( needle ) == 3]
 4.58  0.60   0.94     [len( needle ) == 18]
 0.77  0.64   1.10     [len( needle ) == 48]


> BTW, is there yet a way to PEEK WIDE()? Using XREF was the only means I could find.


Yes. To dereference 1, 2, 4 and 8 byte signed integers: p.0`  p.0%  p.0&  p.0@. (For unsigned: p.0``  p.0%`  p.0&`  p.0@`).

Robert P.


'-----------------------
include "ConsoleWindow"
include "Tlbx Timer.incl"

local mode
local fn MyGetTime as double // system time in s
'~'1
dim as UnsignedWide us
dim as double       s

Microseconds( @us )
s = 4294967296.0 * us.hi + us.lo
end fn = s * 1e-6


dim as Str255  need, hay
dim as long    j, k
dim as double  t
_nLoop = 1000000

t = fn MyGetTime
need = "x"
hay = string$( 5, "a" ) + "x"
for j = 1 to _nLoop
k = instr( 0, hay, need )
next
t = fn MyGetTime - t
print using "##.##"; t

t = fn MyGetTime
need = "x"
hay = string$( 20, "a" ) + "x"
for j = 1 to _nLoop
k = instr( 0, hay, need )
next
t = fn MyGetTime - t
print using "##.##"; t

t = fn MyGetTime
need = "xxx"
hay = string$( 200, "a" ) + "xxx"
for j = 1 to _nLoop
k = instr( 0, hay, need )
next
t = fn MyGetTime - t
print using "##.##"; t

t = fn MyGetTime
need = "aaaaaaaaaaaaaaaxxx"
hay = string$( 200, "a" ) + "xxx"
for j = 1 to _nLoop
k = instr( 0, hay, need )
next
t = fn MyGetTime - t
print using "##.##"; t

t = fn MyGetTime
need = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
hay = string$( 250, "a" )
for j = 1 to _nLoop
k = instr( 0, hay, need )
next
t = fn MyGetTime - t
print using "##.##"; t
'-----------------------