Author Topic: Fast string Len() function  (Read 7572 times)

0 Members and 1 Guest are viewing this topic.

Offline va!n

  • Pentium
  • *****
  • Posts: 1435
  • Karma: 109
    • View Profile
    • http://www.secretly.de
Fast string Len() function
« on: February 29, 2008 »
hello out there...
i know there is the Win32 API command lstrlen() to get the length of a string. As we all know, Win32 API functions are not ever the fastest and so i did some research and come up with following speed optimized lstrlen() replacement (based on Win32 API only), which seems to be a lot faster as the original version.

Code: [Select]
Text.s = "What do you think about this?"

lResult =  HeapSize_( GetProcessHeap_(), 0, @Text ) - 5
MessageBox_( 0, Str( lResult ), "StringLen", 0 )

It seems this replacement is a nice way to speed things up, but is this way really a clean way or more like a dirty hack? What do you think about this code? Any risk to use this in prods?

PS: Seems to work with PB...
« Last Edit: February 29, 2008 by va!n »
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Offline taj

  • Bytes hurt
  • DBF Aficionado
  • ******
  • Posts: 4810
  • Karma: 189
  • Scene there, done that.
    • View Profile
Re: Fast string Len() function
« Reply #1 on: February 29, 2008 »
Va!n thats a great little bit of code! Karma++ for the post. It looks legitimate to me, judging by MSDN docs and dates. Only uses kernel32.dll so can even be used in tiny code productions.
Challenge Trophies Won:

Offline rain_storm

  • Here comes the Rain
  • DBF Aficionado
  • ******
  • Posts: 3088
  • Karma: 182
  • Rain never hurt nobody
    • View Profile
    • org_100h
Re: Fast string Len() function
« Reply #2 on: February 29, 2008 »
the fastest way to get the length of a zero terminated string in DOS, though its not win32 it can still be used in win32 as a macro or proceedure bypassing the api altogether (by the time those push and pops are done this code has already begin scanning the string for zero terminator):

Code: [Select]
  lea edi,address ; address of string
  mov ecx,-1 ; maximum string length = 0xFFFFFFFF
  xor eax,eax ; search for zero terminator
  repnz scasb ; find first zero terminator byte
  not ecx ; ecx was counting down so ecx inverted is string length

and the same thing for normal strings

Code: [Select]
  lea edi,address ; address of string
  mov ecx,-1 ; maximum string length = 0xFFFFFFFF
  mov ax,"$" ; search for string terminator
  repne scasb ; find first string terminator byte
  not ecx ; ecx was counting down so ecx inverted is string length
« Last Edit: February 29, 2008 by rain_storm »

Challenge Trophies Won:

Offline va!n

  • Pentium
  • *****
  • Posts: 1435
  • Karma: 109
    • View Profile
    • http://www.secretly.de
Re: Fast string Len() function
« Reply #3 on: February 29, 2008 »
thanks taj  :)


Speed comparsion between PB internal functions, Win32 API lstrlen() and my version:
Code: [Select]
; -------- Program by "Mr.Vain/Secretly!" aka Thorsten Will in 2008 --------

DisableDebugger

Text.s = InputRequester("Fast Len() routine by Mr.Vain/Secretly!", "Type a string of any size", "What do you think about this?")

start1 = ElapsedMilliseconds()
For i = 0 To 20000000
    lResult1 =  Len( Text.s )
Next
start1 = ElapsedMilliseconds() - start1


start2 = ElapsedMilliseconds()
For i = 0 To 20000000
    lResult2 =  MemoryStringLength( @Text ) * SizeOf( Character )
Next
start2 = ElapsedMilliseconds() - start2


start3 = ElapsedMilliseconds()
For i = 0 To 20000000
    lResult3 =  lstrlen_( @Text )
Next
start3 = ElapsedMilliseconds() - start3


start4 = ElapsedMilliseconds()
For i = 0 To 20000000
    lResult4 =  HeapSize_( GetProcessHeap_(), 0, @Text ) - 5
Next
start4 = ElapsedMilliseconds() - start4


Msg1.s =          "PB Len():"                + #TAB$ + #TAB$ + #TAB$ + Str( lResult1 ) + " len" +#LFCR$
Msg1.s = Msg1.s + "PB MemoryStringLenght():" + #TAB$                 + Str( lResult2 ) + " len"+ #LFCR$
Msg1.s = Msg1.s + "Win32 API - lstrlen():"   + #TAB$                 + Str( lResult3 ) + " len"+ #LFCR$
Msg1.s = Msg1.s + "My Version:"              + #TAB$ + #TAB$         + Str( lResult4 ) + " len"+ #LFCR$

Msg2.s =          "PB Len():"                + #TAB$ + #TAB$ + #TAB$ + Str( start1 ) + " ms" +#LFCR$
Msg2.s = Msg2.s + "PB MemoryStringLenght():" + #TAB$                 + Str( start2 ) + " ms"+ #LFCR$
Msg2.s = Msg2.s + "Win32 API - lstrlen():"   + #TAB$                 + Str( start3 ) + " ms"+ #LFCR$
Msg2.s = Msg2.s + "My Version:"              + #TAB$ + #TAB$         + Str( start4 ) + " ms"+ #LFCR$

MessageRequester( "Results:", Msg1.s, 0 )
MessageRequester( "Speed:"  , Msg2.s, 0 )


Executeable can be downloaded to see the speed improvement =) But i am still not really sure if this way works in and for all situations and if its a dirty hack (cheating) or correct coding.

[Edited]
Zip includes ascii and unicode test versions!
« Last Edit: February 29, 2008 by va!n »
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Offline va!n

  • Pentium
  • *****
  • Posts: 1435
  • Karma: 109
    • View Profile
    • http://www.secretly.de
Re: Fast string Len() function
« Reply #4 on: February 29, 2008 »
Here is a version, works with Unicode and Non-Unicode strings :)

Code: [Select]
; -------- Program by "Mr.Vain/Secretly!" aka Thorsten Will in 2008 --------

DisableDebugger

Text.s = InputRequester("Fast Len() routine by Mr.Vain/Secretly!", "Type a string of any size", "What do you think about this?")

start1 = ElapsedMilliseconds()
For i = 0 To 20000000
    lResult1 =  Len( Text.s )
Next
start1 = ElapsedMilliseconds() - start1


start2 = ElapsedMilliseconds()
For i = 0 To 20000000
    lResult2 =  MemoryStringLength( @Text ) * SizeOf( Character )
Next
start2 = ElapsedMilliseconds() - start2


start3 = ElapsedMilliseconds()
For i = 0 To 20000000
    lResult3 =  lstrlen_( @Text )
Next
start3 = ElapsedMilliseconds() - start3


start4 = ElapsedMilliseconds()


CompilerIf #PB_Compiler_Unicode
    lOffset = 10
CompilerElse
    lOffset =  5
CompilerEndIf

lCharType = SizeOf(character) >> 1


For i = 0 To 20000000
    lResult4 =  (HeapSize_( GetProcessHeap_(), 0, @Text )  - lOffSet ) >> lCharType
Next
start4 = ElapsedMilliseconds() - start4


Msg1.s =          "PB Len():"                + #TAB$ + #TAB$ + #TAB$ + Str( lResult1 ) + " len" +#LFCR$
Msg1.s = Msg1.s + "PB MemoryStringLenght():" + #TAB$                 + Str( lResult2 ) + " len"+ #LFCR$
Msg1.s = Msg1.s + "Win32 API - lstrlen():"   + #TAB$                 + Str( lResult3 ) + " len"+ #LFCR$
Msg1.s = Msg1.s + "My Version:"              + #TAB$ + #TAB$         + Str( lResult4 ) + " len"+ #LFCR$

Msg2.s =          "PB Len():"                + #TAB$ + #TAB$ + #TAB$ + Str( start1 ) + " ms" +#LFCR$
Msg2.s = Msg2.s + "PB MemoryStringLenght():" + #TAB$                 + Str( start2 ) + " ms"+ #LFCR$
Msg2.s = Msg2.s + "Win32 API - lstrlen():"   + #TAB$                 + Str( start3 ) + " ms"+ #LFCR$
Msg2.s = Msg2.s + "My Version:"              + #TAB$ + #TAB$         + Str( start4 ) + " ms"+ #LFCR$

MessageRequester( "Results:", Msg1.s, 0 )
MessageRequester( "Speed:"  , Msg2.s, 0 )
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Offline taj

  • Bytes hurt
  • DBF Aficionado
  • ******
  • Posts: 4810
  • Karma: 189
  • Scene there, done that.
    • View Profile
Re: Fast string Len() function
« Reply #5 on: February 29, 2008 »
Yours works fine here (XP, SP2) and its much much faster.

Taj
Challenge Trophies Won:

Offline rain_storm

  • Here comes the Rain
  • DBF Aficionado
  • ******
  • Posts: 3088
  • Karma: 182
  • Rain never hurt nobody
    • View Profile
    • org_100h
Re: Fast string Len() function
« Reply #6 on: February 29, 2008 »
Thats not bad about 1/4 the time to do the same work as the other routines not bad at all

Challenge Trophies Won:

Offline va!n

  • Pentium
  • *****
  • Posts: 1435
  • Karma: 109
    • View Profile
    • http://www.secretly.de
Re: Fast string Len() function
« Reply #7 on: February 29, 2008 »
Has someone tested it on Vista business? i got feedback on another forum:

Quote
Unfortunately it doesn't seem to work on my 4.2b2 Vista business setup.

I'm getting

pb len 29
pb memorystring 29
win32 29
my version 86173 Shocked

But it is fast!

and another member has posted a small example and saying its not good to use this technique, but i think its due fact of how he is using it. He is allocating a big memory block and just copy only the string (afaik without string end-terminater sign) to the big allocated memoryblock... i think i would never do such a thing in my actual project nor in future projects. So the questions are now: Does this methode works on Vista too and is this routine safe when just only giving the adress of a string instead following example by a member from another forum:

Quote
You shouldn't use this, because you check the size of the memory block that the string contains. This must not be the size of the string itself.

Code: [Select]
Text.s = "Hallo Test"
*Memory = AllocateMemory(10000000)
CopyMemory(@Text,*Memory,Len(Text)+SizeOf(Character))

CompilerIf #PB_Compiler_Unicode
   Offset = 10
CompilerElse
   Offset =  5
CompilerEndIf

CharType = SizeOf(Character) >> 1

Result4 =  (HeapSize_( GetProcessHeap_(), 0, *Memory )  - Offset ) >> CharType

[Info]
Added unicode executeable version to the zip archive!
« Last Edit: February 29, 2008 by va!n »
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Offline taj

  • Bytes hurt
  • DBF Aficionado
  • ******
  • Posts: 4810
  • Karma: 189
  • Scene there, done that.
    • View Profile
Re: Fast string Len() function
« Reply #8 on: February 29, 2008 »
He is allocating a big memory block and just copy only the string (afaik without string end-terminater sign) to the big allocated memoryblock...

And this years Darwin award for C programming goes to...
Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Fast string Len() function
« Reply #9 on: March 01, 2008 »
How do you know your string is going to be allocated on the heap?  What if it's a static string.  And how do you know that Windows or PB hasn't padded the allocation to the next multiple of 4 (or more bytes)?

The real question is why you need a fast string length anyway.  One thing you can do is use a Pascal style string where all the string manipulation functions keep a track of how long the string is.
eg. in C
struct
{ int len; char *string;} mystring;

I've been to a seminar where Microsoft claimed that win32 API memcpy,memcmp, strcpy etc would always be the *guaranteed* fastest way to do these things on your OS/CPU combination.  I've never put that to the test myself.

Jim
Challenge Trophies Won:

Offline taj

  • Bytes hurt
  • DBF Aficionado
  • ******
  • Posts: 4810
  • Karma: 189
  • Scene there, done that.
    • View Profile
Re: Fast string Len() function
« Reply #10 on: March 01, 2008 »
I guess what Microsoft mean, correct me if I am wrong, is that for any possible use of a string, these routines are  completely safe and optimal. Which is their job. I'm not sure that should also imply that in specific use cases they are non-optimal but it does seem to. So I guess the conclusion is Va!ns routine is not safe to put into a string dll. But it works fine for your own code.
Challenge Trophies Won:

Offline hellfire

  • Sponsor
  • Pentium
  • *******
  • Posts: 1294
  • Karma: 466
    • View Profile
    • my stuff
Re: Fast string Len() function
« Reply #11 on: March 01, 2008 »
I'm still wondering how long your strings are that you're actually in need of faster strlen-function ???
Ok, I remember once exporting 180mb of xml from an obscure software that refused to add newlines...
But have you really profiled your mainloop and found its spending most of the time doing strlen?
If yes: your code sucks ;)
Challenge Trophies Won:

Offline va!n

  • Pentium
  • *****
  • Posts: 1435
  • Karma: 109
    • View Profile
    • http://www.secretly.de
Re: Fast string Len() function
« Reply #12 on: March 01, 2008 »
To answer some questions i have to point out following....  i dont really need a faster Len() command but i am someone who like to optimize where its possible. Why should i use slower things when there are ways to speed things a lot up like Len() ?

But the mainreason is i am coding with PB and i dont want to include the PB lib, because most libs are in my eyes to big and to buggy. If you may ask why dont code in C/CPP... the answer is simply i dont know how and where to start (in other words i have problems to work with VCs IDE), else i would still try to code in CPP (VisualC). But i will try to learn coding with VC in the future to be independent from PB and having more flexibility and even speed ^^
 
- hp EliteBook 8540p, 4 GB RAM, Windows 8.1 x64
- Asus P5Q, Intel Q8200, 6 GB DDR2, Radeon 4870, Windows 8.1 x64
http://www.secretly.de
Challenge Trophies Won:

Offline Jim

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 5301
  • Karma: 402
    • View Profile
Re: Fast string Len() function
« Reply #13 on: March 03, 2008 »
Try using your function to do Len("banana")

Jim
Challenge Trophies Won: