• Welcome to Powerbasic Museum 2020-B.
 

News:

Forum in repository mode. No new members allowed.

Main Menu

Searching for some ... speed

Started by Eros Olmi, March 12, 2009, 05:23:27 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Eros Olmi

Hi all.

I've a piece of code executed thousands of times per secs and I'm searching for some execution speed.
Code is mainly pushing inside stack some parameters before calling a function.

My PowerBasic code is the following:

                SELECT CASE LONG @lFunction.params(pCount).ParamSubType
           
                  CASE %ArrayType_Long
                    PushParam = @lFunction.params(pCount).DataValue.lLong
                    ! push PushParam

                  CASE %ArrayType_Single
                    PushParamSingle = @lFunction.params(pCount).DataValue.lSingle
                    ! push PushParamSingle

                  CASE %ArrayType_DWord
                    PushParam = @lFunction.params(pCount).DataValue.lDWord
                    ! push PushParam
         
                  Case %ArrayType_Double
                    PushParam = VarPtr(@lFunction.params(pCount).DataValue.lDouble)
                    !mov eax,PushParam  ;'point EAX TO the 8 BYTE variable
                    !mov edx,[eax+4]    ;'GET latest 4 bytes
                    !push edx           ;'push them
                    !mov edx,[eax]      ;'GET the 1st 4 bytes
                    !push edx           ;'push them
     
                  CASE %ArrayType_Quad
                    PushParam = VARPTR(@lFunction.params(pCount).DataValue.lQuad)
                    !mov eax,PushParam  ;'point EAX TO the 8 BYTE variable
                    !mov edx,[eax+4]    ;'GET latest 4 bytes
                    !push edx           ;'push them
                    !mov edx,[eax]      ;'GET the 1st 4 bytes
                    !push edx           ;'push them
   
                  CASE %ArrayType_Ext
                    PushParam = VARPTR(@lFunction.params(pCount).DataValue.lExt)
                    !mov eax,PushParam  ;'point EAX TO the 8 BYTE variable
                    !mov edx,[eax+8]    ;'GET latest 4 bytes
                    !push edx           ;'push them
                    !mov edx,[eax+4]    ;'GET mid    4 bytes
                    !push edx           ;'push them
                    !mov edx,[eax]      ;'GET the 1st 4 bytes
                    !push edx           ;'push them

                  CASE %ArrayType_Integer
                    PushParam = @lFunction.params(pCount).DataValue.lInteger
                    ! push PushParam
     
                  Case %ArrayType_Byte
                    PushParam = @lFunction.params(pCount).DataValue.lByte
                    ! push PushParam
     
                  Case %ArrayType_Word
                    PushParam = @lFunction.params(pCount).DataValue.lWord
                    ! push PushParam
 
                END SELECT


I have ZERO knowledge of ASM but it seems to me I'm making a useless assignment to PushParam variable, at least for parameters that are exactly 4 bytes long (DWORD, LONG, SINGLE). For example, is there a way to pass from:

                  CASE %ArrayType_Long
                    PushParam = @lFunction.params(pCount).DataValue.lLong
                    ! push PushParam

to something like:

                  CASE %ArrayType_Long
                    ! push @lFunction.params(pCount).DataValue.lLong

and avoid one assignment?

Thanks a lot
Eros
thinBasic Script Interpreter - www.thinbasic.com | www.thinbasic.com/community
Win7Pro 64bit - 8GB Ram - Intel i7 M620 2.67GHz - NVIDIA Quadro FX1800M 1GB

Patrice Terrier

Eros,

Perhaps you could speed it up a little, if using the ON GOTO statement instead of SELECT CASE LONG.

(nothing is faster than a direct jump)

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Eros Olmi

Thanks a lot Patrice.
Done but not able to note significantly changes:


                On @lFunction.params(pCount).ParamSubType GoTo _
                        goto_ArrayType_Byte           , _' 1&
                        goto_ArrayType_Integer        , _' 2&
                        goto_ArrayType_Word           , _' 3&
                        goto_ArrayType_DWord          , _' 4&
                        goto_ArrayType_Long           , _' 5&
                        goto_ArrayType_Quad           , _' 6&
                        goto_ArrayType_Single         , _' 7&
                        goto_ArrayType_Double         , _' 8&
                        goto_ArrayType_Currency       , _' 9&
                        goto_ArrayType_Ext               '10&

                  GoTo goto_End_Select

                  goto_ArrayType_Byte:
                    PushParam = @lFunction.params(pCount).DataValue.lByte
                    ! push PushParam
                    GoTo goto_End_Select
                  goto_ArrayType_Integer:
                    PushParam = @lFunction.params(pCount).DataValue.lInteger
                    ! push PushParam
                    GoTo goto_End_Select
                  goto_ArrayType_Word:
                    PushParam = @lFunction.params(pCount).DataValue.lWord
                    ! push PushParam
                    GoTo goto_End_Select
                  goto_ArrayType_DWord:
                    PushParam = @lFunction.params(pCount).DataValue.lDWord
                    ! push PushParam
                    GoTo goto_End_Select
                  goto_ArrayType_Long:
                    PushParam = @lFunction.params(pCount).DataValue.lLong
                    ! push PushParam
                    GoTo goto_End_Select
                  goto_ArrayType_Quad:
                    PushParam = VarPtr(@lFunction.params(pCount).DataValue.lQuad)
                    !mov eax,PushParam  ;'point EAX TO the 8 BYTE variable
                    !mov edx,[eax+4]    ;'GET latest 4 bytes
                    !push edx           ;'push them
                    !mov edx,[eax]      ;'GET the 1st 4 bytes
                    !push edx           ;'push them
                    GoTo goto_End_Select
                  goto_ArrayType_Single:
                    PushParamSingle = @lFunction.params(pCount).DataValue.lSingle
                    ! push PushParamSingle
                    GoTo goto_End_Select
                  goto_ArrayType_Double:
                    PushParam = VarPtr(@lFunction.params(pCount).DataValue.lDouble)
                    !mov eax,PushParam  ;'point EAX TO the 8 BYTE variable
                    !mov edx,[eax+4]    ;'GET latest 4 bytes
                    !push edx           ;'push them
                    !mov edx,[eax]      ;'GET the 1st 4 bytes
                    !push edx           ;'push them
                  goto_ArrayType_Currency:
                    GoTo goto_End_Select
     
   
                  goto_ArrayType_Ext:
                    PushParam = VarPtr(@lFunction.params(pCount).DataValue.lExt)
                    !mov eax,PushParam  ;'point EAX TO the 8 BYTE variable
                    !mov edx,[eax+8]    ;'GET latest 4 bytes
                    !push edx           ;'push them
                    !mov edx,[eax+4]    ;'GET mid    4 bytes
                    !push edx           ;'push them
                    !mov edx,[eax]      ;'GET the 1st 4 bytes
                    !push edx           ;'push them

                goto_End_Select:
thinBasic Script Interpreter - www.thinbasic.com | www.thinbasic.com/community
Win7Pro 64bit - 8GB Ram - Intel i7 M620 2.67GHz - NVIDIA Quadro FX1800M 1GB

Charles Pegge


Hi Eros,

Cases translate into very efficient machine code, but if you can avoid arrays in favour of pointering, there is some performance gain to be had. Translating an array index into an offset from the array base address is extra work for the CPU.

Patrice Terrier

REGISTER lpf AS LONG

lpf = @lFunction.params(pCount).ParamSubType

ON lpf GOTO


Try also to make the matching sub/function STATIC.

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Eros Olmi

Thanks.
I will try some pointers tricks and data pre-fetching
thinBasic Script Interpreter - www.thinbasic.com | www.thinbasic.com/community
Win7Pro 64bit - 8GB Ram - Intel i7 M620 2.67GHz - NVIDIA Quadro FX1800M 1GB

Theo Gottwald

Looking at this code, I think that you will hardly get significant speedups anyway from this code.
If its a lot (more the 110) CASES, and they are called randomly, you can try SELECT CASE AS CONST instead of OS LONG.
Replacing the CASE AS LONG with a Chain of IF's will not help you anyway here.
If you make Cache-Tricks, the result may differ from CPU to CPU.

If you really see speed problems, i guess there should be other places to look at.

Charles Pegge

Eros,

Do you encode thinBasic scripts into interprative tokens or do you execute directly from the script? You could embed function pointers as tokens, - patch them into scripts when and where they are needed.


Eros Olmi

#8
Yes, I'm already doing that.
All is tokenized and resolved once and before script execution is started. The rest are only pointers to data structures.
Only pointers to local variables data are redetermined at runtime because they change at every function execution.

I was hoping that could be a way to avoid assignment in
                  CASE %ArrayType_Long
                    PushParam = @lFunction.params(pCount).DataValue.lLong
                    ! push PushParam


and pass to something like:

                  CASE %ArrayType_Long
                    ! push @lFunction.params(pCount).DataValue.lLong


Thanks
Eros
thinBasic Script Interpreter - www.thinbasic.com | www.thinbasic.com/community
Win7Pro 64bit - 8GB Ram - Intel i7 M620 2.67GHz - NVIDIA Quadro FX1800M 1GB

Charles Pegge


Both of those expressions would involve the same steps being taken at CPU level:
The Assembler will only take variables that have been resolved to a specific address.

Typically: local variable address are offset from the ebp register

local a,b,c as long

A: [ebp-4]
B: [ebp-8]
C: [ebp-12]

the values contained in these can be pushed onto the stack directly
The equivalent of push A would be

push [ebp-4]

For passing byref, the adresses must first be resolved, using the lea instruction [load effective address]

lea eax,A
push eax

For an array element the index has to scaled and then added to the address before pushing

mov eax,i
imul eax,eax,s
lea ecx,A
add eax,ecx
push eax


Getting the value, at a pointer (VARPTR) is done like this:

mov eax,[eax]
Similarly STRPTR (load the first character of a dynamic string)

mov eax,[eax]
mov al,[eax]


I hope this gives you a rough idea of what is involved. :)



Theo Gottwald

Eros, you can onlysave time at a place where time is wasted.

PushParam = @lFunction.params(pCount).DataValue.lLong
                    ! push PushParam


this is a operation that can be performed millions of times in a second.

If you just execute it

"code executed thousands of times per secs " there will not be any significant speedup here even if you could double its speed.

Powerbasic has a nice feature, which is the "PROFILE" Command.
Use it to really find the sections in your code that need the amount of time which is significant.

A menmonic which does not significant CPU cycles or where the usage is heavily dependent on cpu architecture  is normaly not a good target for optimization.

This assignment mainly uses time for the memory access. Therefore the needed time will depend on cache architecture of the used cpu as well as on which code was executed before.