Android Tutorial byref mimic and performances

Hi all,
I've found and interesting article posted by Erel inside the "bugs & wishlist" section that deserves to be post in this section (and maybe as evidence article inside tutorials"). It deals about an interesting technique proposed to mimic references. This is the link http://www.b4x.com/forum/bugs-wishlist/8379-byref-parameter-android.html. I have investigated about the performances and I have discovered that references objects seem to be accessed in a faster way than primitive values. This is my profiling code. I got 3611 ticks with int variables and 3306 ticks with a reference object.
B4X:
Sub Globals
   Dim a,k,m,n As Int : a=1
   Dim start , Endt, diff As Int
   Type brint (val As Int)
   Dim b As brint : b.val=1
   S2(a) ' call passing an int
   S3(b) ' call passing and object containing an int
End Sub
Sub S2(x As Int )
   start=DateTime.Now
   For n=1 To 1000
      For k=1 To 1000
         m=x/2 ' direct use of x
      Next   
   Next   
    diff=DateTime.Now-start
   Log("by value " &diff) 
End Sub

Sub S3(x As brint )
   start=DateTime.Now
   For n=1 To 1000
      For k=1 To 1000
         m=x.val/2 'indirect use of the value through the Object
      Next
   Next
   diff=DateTime.Now-start
   Log("by ref " & diff) 
End Sub

>>>> this is the log output ater two tests:

** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
by value 3611
by ref 3306

** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
by value 3612
by ref 3576

I'm preparing a tutorial about references (now that I've understood how do the work - thanks to Erel and Agraham) sprites and easy linked gui-s
 

agraham

Expert
Licensed User
Longtime User
I have discovered that references objects seem to be accessed in a faster way than primitive values.
You need to be careful in drawing conclusions like this from simplistic tests. Accessing a local primitive requires one memory access to get the value, accessing a member of a type requires two memory accesses, one to get the reference and another to use that reference to get the value.

What is likely here is that there is some compiler optimisation going on (and maybe runtime JIT optimisation if you are on Android 2.2 or later) that is detecting that the reference is only read but not written so it is only doing the dereference once and caching the value. In real code you would probably see the difference in access times.
 

acorrias

Member
Licensed User
Longtime User
new tests

Hi Agraham
I agree with you and that's way I did that test. I has been very surprised for the results. But after you replay, I changed my program modifing the inner assignement of S2 and S3 in order to write and not to read the int and the byrefint object. The result seems the same.
- by value 6897
- by ref 1252
But to be sure i did another new and more complex test in order to prevent caching: now I pass an array entry whose index is provided by a random generator. I think that this technique allows to have no caching because the index of the array entry is unpredicible. This is the code:
B4X:
Sub Globals
   Dim i,k,m,n As Int 
   Dim start , Endt, diff As Int
   Type brint (val As Int)
   Dim a(1000)  As Int
   Dim b(1000)  As brint
   For i=0 To 999
      a(i)=Rnd(0,10): b(i).val=Rnd(0,10)
   Next
   Log(">>>>>INIT TEST")
   start=DateTime.Now
   For n=1 To 100 : For k=1 To 100
         m=Rnd(0,999)
         S2(a(m),k,m) ' call passing an int
      Next : Next   
    diff=DateTime.Now-start
   Log("by value " &diff) 
   
   start=DateTime.Now
   For n=1 To 100 : For k=1 To 100
         m=Rnd(0,999)
         S3(b(m),k,m) ' call passing an object
      Next: Next   
    diff=DateTime.Now-start
   Log("by ref " &diff) 
   Log(">>>>>END TEST")
End Sub
Sub S2(x,kf,mf As Int )
   x=x*kf/2 ' direct use of x
End Sub
Sub S3(x As brint, kf,mf As Int )
   x.val=x.val*kf/2 'indirect use of the value through the Object
End Sub

I repeated the test three times and these are my results:
1° test
  • by value 6897
  • by ref 1252
2° test
  • by value 6883
  • by ref 1211
3° test
  • by value 7800
  • by ref 1486

Please, give me some suggestion about this new test. I'm very surprised. I tought too about two memory access instead of one would be slower.

Anyway, I am sure about a fact: I can use references using Erel's suggestion since I have understood how to proceed. You promise a new post about this hint: I am very interested in that.

cheers
alex
 

agraham

Expert
Licensed User
Longtime User
The problem is here

Sub S2(x,kf,mf As Int )
Sub S3(x As brint, kf,mf As Int )

x and kf are being declared by default as Strings so there is a lot of string conversion happening. The Sub declarations should be

Sub S2(x As Int,kf As Int,mf As Int )
Sub S3(x As brint, kf As Int ,mf As Int )


Changing that and moving the code from Sub Globals (which is not a good place) into a button click event I get

B4X:
>>>>>INIT TEST
by value 11
by ref 12
>>>>>END TEST

>>>>>INIT TEST
by value 8
by ref 8
>>>>>END TEST

>>>>>INIT TEST
by value 15
by ref 12
>>>>>END TEST
The amount of other code is, together with the measurement uncertainty due to the OS task switching, as I would expect swamping any difference in the two access methods.
 

acorrias

Member
Licensed User
Longtime User
default param type

Hi
I'm improving my b4a knowledge every day. I've discovered why some my apps were slow: I used a compact form od subroutine formal declaration which gave a lot of overhead due to string type conversion.

I wrote this piece of code:
B4X:
Sub Globals
   Dim a, b, c As Int
End Sub

Sub Activity_Create(FirstTime As Boolean)
   a=1: b=2
   c=foo(a,b)
End Sub
Sub foo(x, y As Int)
   Return x+y
End Sub
and I gave a look at the java generated code. I was surprised to discover that, as Agraham pointed out, DIM X, Y as int corresponds to a string and a integer and not to two integer as in VB6.
B4X:
 //BA.debugLineNum = 9;BA.debugLine="c=foo(a,b)";
' this is the sub call
_c = (int)(Double.parseDouble(_foo(BA.NumberToString(_a),_b))); 
'and this is the sub definition
public static String  _foo(String _x,int _y) throws Exception{

Thanks a lot for this warning. But I could not find this important information inside the documentation. Did I miss some page? Again. I'm curious about the B4a > java transcoding: is it a bug or there is some reason to manage as unspecificed parameter as int?
cheers
alex
 
Last edited:

klaus

Expert
Licensed User
Longtime User
From the help of the Dim keyword:
Declare multiple variables. All variables will be of the specified type.
Dim variable1, variable2, ..., [As type]
Note that the shorthand syntax only applies to Dim keyword.
So
Dim a, b, c As Int
is equivalent to
Dim b As Int
Dim c As Int
Dim a As Int

But
Sub Test(a, b, c As Int)
is NOT equivalent to
Sub Test(a As Int, b As Int, c As Int)
but is equivalent to
Sub Test(a As String, b As String, c As Int)

Best regards.
 

agraham

Expert
Licensed User
Longtime User
I remember discussing this with Erel during the early development of Basic4android and suggested that he change it. The interchange went

It's a bit non-intuitive ...

I agree.
The shorthand syntax only applies to "dim" lines.


>I agree.
But you are not about to change it :)

Lets say that I don't plan to do it for now. But I agree that there is a
delicate point here. I will add a comment about the shorthand syntax in Dim.
I guess he has good reason (as he always seems have to whenever I raise something with him!)
 

ukimiku

Active Member
Licensed User
Longtime User
Sub Test(a, b, c As Int)
is NOT equivalent to
Sub Test(a As Int, b As Int, c As Int)

That's - interesting - news to me. Thanks.

Regards,
 

ivan.tellez

Active Member
Licensed User
Longtime User
Actually, it's incorrect in VB6

Hi
I was surprised to discover that, as Agraham pointed out, DIM X, Y as int corresponds to a string and a integer and not to two integer as in VB6.

In VB6; DIM X, Y as Integer, corresponds to a VARIANT and a integer and not to two integers.

So, there is also lots of convertions in there.
 
Top