Migrating from RealBasic

I have an application that I developed several years ago in RB 2009, and it still works fine. However, I realize that I will need to upgrade to XOJO at some point. The question is whether this is the right project to do it with.
FYI, RB 2009 still runs just fine on my new MacBook Pro under OSX Yosemite, and I can make changes to the project and make new builds. My primary reason for migrating it to XOJO, other than just wanting to keep things current, is that the app does some heavy duty number crunching, and I thought that it would be a big advantage to build it as a 64 bit app. However, the first thing that I noticed after downloading the current version of XJ is that 64 bit is still “a work in progress”. I remember when Cocoa was “a work in progress” …for about a decade. That was one of the reasons why I gave up on updating RB (and its heir XJ).

Anyway, before I got remotely close to a 64 bit build with my legacy app, I ran afoul of the ThreadAccessingUIexception, and realize that I’m going to have to do a lot of major changes to the existing code before I can even think about testing it as a 64 bit app, and quite honestly, I don’t know if it will be worth the effort.

So, I would like to ask the question: Is 64 bit code turning out to be another Cocoa fiasco, or can I reasonably expect my code to run as a 64 bit app?

BTW, this isn’t going to be a commercial app; it’s only used in house in our business, and as such, we can tolerate some glitches that wouldn’t be acceptable for a commercial product.

For me there is no 64bit without a debugger.

Cocoa was a lot of work. For 64bit I think it shouldn’t be that much of an effort. As soon as all pieces are in place.

This is what I always found so painful with a different product called Corona when I was doing iOS apps.
Write the code, and test it by just compiling and running? Hello 1970’s…

That said, debugging in 32 bit, then compiling in 64 seems to be OK on the Mac.
Personally I cant report a noticeable speed increase with 64bit builds, and I have reverted to shipping 32 bit for the moment.

Thanks for your comments. One of my concerns was the lack of debugging in 64 bit mode.

Jeff, do your apps do any significant number crunching? When I run my app, the Mac Activity Monitor typically shows it using 100% of processor time. A single run of my app takes about 20 hours. So, if I can speed things up by even a few percent it would be very noticeable.

For many operations, the speedup can be dramatic. I’d encourage you to try, and please report the results back here.

Pure number crunching will be faster but in my case, it wasn’t what I’d hoped for.
I had more issues with some bugs (encoding join/splits) that are in 64-bit but not in 32-bit.

But 20 hours? You could share some slow routines on the forum to get some creative ideas on how to make things faster.

It’s a Monte Carlo double volume numerical integration (i.e., an integration in 6 dimensions). The inner loop executes about 3e10 times for one run. I’ve done as much optimization on this as I think is possible. It won’t get much faster. At least not in XOJO.

That could very well be, but we love a challenge. :slight_smile: And what do you have to lose?

Okay. Here you go. MonteHelix is the main routine which calls other routines (also shown).

There are some calls to some custom random number generator routines since I’ve found that the built-in random functions are not up to the task. If you want to see those, I can post them too.

[code]Function MonteHelix(n As int64,pitch As Double,r As Double,dw As Double,Maxerr As Double, Nmonte As int64) As double
'Monte carlo variables
dim sx,sy,sye,tx,ty,tye,montesumC,montesumU,ra,rb,y,yc,psi,cospsiinv,rra,rrb,p,LeftTermC,LeftTermU,L,Lc As Double
dim cIterTerm, uIterTerm, cSqSum,uSqSum As Double
dim ms As Double
dim iMonte,nupdate As Int64
dim tab As String
tab=chr(9)
nupdate=max(min(10000,Nmonte\1000),10)
SetRndSeed 'initialize random number generator
'calc pitch angle adjustments
psi= ATan(pitch/(pi2r))
cospsiinv=1/cos(psi)
OutText=OutText+EndOfLine+“psi factor: “+Format(cospsiinv,“0.0000000000”)
'outer montecarlo random filament generator loop
montesumU=0
montesumC=0
cSqSum=0
uSqSum=0
ms=Microseconds
for iMonte=1 to Nmonte
'Generate two random test points S and T
do
tx=rnd2-0.5
ty=rnd2-0.5
tye=sqrt(0.25-tx^2)
loop until (ty<=tye and ty>=-tye)
do
sx=rnd2-0.5
sy=rnd2-0.5
sye=sqrt(0.25-sx^2)
Loop Until (sy<=sye and sy>=-sye)
'calculate filament offset
y=(tx-sx)dw
yc=y
cospsiinv 'psi corrected version of axial offset
ra=r+sydw
rb=r+ty
dw
L=Msnow(n,pitch,ra,rb,y,MaxErr)
'Lc=Msnow(n,pitch,ra,rb,yc,MaxErr)
rra=rara
rrb=rb
rb
p=pitch/2/pi
LeftTermC=1e-7sqrt(rra+pp)sqrt(rrb+pp)/sqrt((1+pp/rra)(1+pp/rrb))
LeftTermU=1e-7
sqrt(rrarrb)/sqrt((1+pp/rra)(1+pp/rrb))
cIterTerm=LeftTermCL
uIterTerm=LeftTermU
L
montesumC=montesumC+cIterTerm
montesumU=montesumU+uIterTerm
cSqSum=cSqSum+cIterTermcIterTerm
uSqSum=uSqSum+uIterTerm
uIterTerm
if iMonte mod nupdate=0 then
OutText=OutText+EndOfLine+str(iMonte)+”, “+Format(montesumC/iMonte,”-#.############e”)+", “+Format(montesumU/iMonte,”-#.############e")
OutText=OutText+", “+Format(cSqSum/iMonte,”-#.############e")+", “+Format(uSqSum/iMonte,”-#.############e")
OutText=OutText+ “, “+ElapsedTime(ms)
end if
next
OutText=OutText+ EndOfLine+str(Nmonte)+tab+Format(montesumC/Nmonte,”-#.############e”)+tab+Format(montesumU/Nmonte,"-#.############e")
OutText=OutText+ tab+Format(cSqSum/Nmonte,"-#.############e")+tab+Format(uSqSum/Nmonte,"-#.############e")
return montesumC/Nmonte
End Function

Function Msnow(n As Double, pitch As Double, ra As Double, rb As Double, y As Double, Maxerr As Double) As Double
’ Uses xxxxx original xxxxx formula to calculate xxxxxx between
’ two xxxxxx of arbitrary radii and axial offset
’ with xxxxx offset radially and axially according to optimum xxxxx rotation angle
’ evaluated using Simpson’s rule, and xxxxxx
’ This is the inner function of the full integration
Dim nstr as string
Dim p,Ntp,rra,rrb,rab,a,b,grandtotal,dx As Double
Dim CurrentErr,Sum2,LastIntg,Sum,Integral,LeftTermC,LeftTermU As Double
Dim m,mtot,i As Int64
p=pitch/2/pi
Ntp=2piN
nstr=""
rra=rara
rrb=rb
rb
rab=rarb
LeftTermC=1e-7
sqrt(rra+pp)sqrt(rrb+pp)/sqrt((1+pp/rra)(1+pp/rrb))
LeftTermU=1e-7sqrt(rrarrb)/sqrt((1+pp/rra)(1+pp/rrb))
//Limits of integration are a (lower) and b (upper)
//The region 0…pi/2 is evaluated first because it may need the most subdivisions
a=0
b=pi/2
If b>Ntp then b=Ntp //ensure max value for b is Ntp
grandtotal=0
mtot=0
while a<Ntp // ensure ‘a’ never goes past upper limit
dx=b-a //range of integration
m=1
CurrentErr=2
MaxErr
Sum2=HlxIntgrndRad(1,-a,Ntp,p,rra,rrb,rab,y)+HlxIntgrndRad(1,-b,Ntp,p,rra,rrb,rab,y)+HlxIntgrndRad(-1,a,Ntp,p,rra,rrb,rab,y)+HlxIntgrndRad(-1,b,Ntp,p,rra,rrb,rab,y)
'Initialize LastResult to trapezoidal area for test purposes
LastIntg=Sum2/2dx
While CurrentErr>MaxErr or m<512
m=2
m
dx=dx/2
Sum=0
for i=1 to m step 2
Sum=Sum+HlxIntgrndRad(1,-idx-a,Ntp,p,rra,rrb,rab,y)+HlxIntgrndRad(-1,idx+a,Ntp,p,rra,rrb,rab,y)
next
Integral=(4Sum+Sum2)dx/3
CurrentErr=Abs((Integral)/(LastIntg)-1)
LastIntg=Integral
Sum2=Sum2+Sum
2
wend
grandtotal=grandtotal+Integral
a=b
b=b
2
If b>Ntp then b=Ntp
'nstr=nstr+str(m)+" "
mtot=mtot+m+1
wend
return grandtotal
End Function

Function HlxIntgrndRad(sn As Integer,phi As Double,N as Double,p As Double,rra As Double,rrb As Double,rab As Double,y As Double) As Double
return (N+snphi)(cos(phi)+pp/rab)/sqrt(rra+rrb-(2rabcos(phi))+(y+pphi)^2)
End Function
[/code]

Great, I’ll look in the morning.

In the meantime, I timed this code:

  dim one as Int64 = 1
  dim target as Int64 = 3 * 10 ^ 10
  dim i as Int64
  do
    i = i + one
  loop until i >= target

That takes about 2 minutes in 32-bit and 1 minute in 64-bit, for what that’s worth.

Say, how large is OutText by the time this code runs its course? About how many lines?

It’s less than 80k. It only adds one line of text after every 1000 iterations, so 1000 lines total after the usual run of 1000,000 iterations. In Realbasic I was using the outfield.appendtext method to add the text directly to a text field in the UI, but I changed that because the thread isn’t allowed to access the UI. So OutText is a global Property.

[quote=265471:@Kem Tekinay]Great, I’ll look in the morning.

In the meantime, I timed this code:

That takes about 2 minutes in 32-bit and 1 minute in 64-bit, for what that’s worth.[/quote]
Thanks, that’s promising.

BTW, in the code that I posted above, the innermost code is the Msnow function. It has a loop that typically executes about 32000 times, but may vary depending on that values of the data. So it is the routine that is most critical.

There is still room there for an optimization. Instead of concatenating the string (a progressively slow operation), append each new segment to an array and join the array into OutText at the end. Something like this…

dim outArr() as string
for …
  // operations
  if …
    out.Arr.Append "Format …"
    outArr.Append nextChunk
    outArr.Append EndOfLine
  end if
next

OutText = join( outArr, "" )

The text handling Kem pointed out I think may be the biggest speed up.

Some other ideas.

Cos and Sqrt are costly.

In HlxIntgrndRad there are 2 Cos(phi). Precompute it once and there may be a smidgen speed up if this method is called alot.

You can also precompute /2/pi and 2*pi

In this loop and the sx/sy one…

do tx=rnd2-0.5 ty=rnd2-0.5 tye=sqrt(0.25-tx^2) loop until (ty<=tye and ty>=-tye)

…I believe the Sqrt can be taken out like this. (since tye isn’t used later on)

do tx=rnd2-0.5 ty=rnd2-0.5 ty2 = ty*ty tye=0.25-tx^2 loop until (ty2<=tye and ty2>=-tye)

Again these are all probably tiny gains, if anything at all. But some pragmas in each method might make a difference

//#pragma DisableBackgroundTasks #pragma DisableBoundsChecking #pragma StackOverflowChecking false

I’m unsure about DisableBackgroundTasks, that might lock up the app until the method finishes.

If you’re running this in a thread then I assume it has a really high priority to get 100% CPU. Would running this in a dedicated app over IPC help?

Would a plugin or dylib help? I’m using a dylib for some number crunching and in one place it’s 3x faster and another is 10x. There’s no threading with a dylib though and the workaround I use for one case is complicated and only works when the equation can be called in separate small pieces. I can’t tell if your equation is like that. Plugins can yield for threads but I don’t know much more about plugins (That’s why I’m using dylibs)

Can you supply some sample parameters for MonteHelix(n As int64, pitch As Double, r As Double, dw As Double, Maxerr As Double, Nmonte As int64) that makes it run 20 hours?

Robert:

just in case you do not know:

if you can run your project in the IDE, you can download the last Xojo (2016r1.1) and run a copy of your project and see by yourself what happens…

FOR FREE ! I forgot the most important point I wanted to add !

You have to pay when you want to build the application. For testings, the IDE is free.

Another small one, these lines…

LeftTermC=1e-7*sqrt(rra+p*p)*sqrt(rrb+p*p)/sqrt((1+p*p/rra)*(1+p*p/rrb)) LeftTermU=1e-7*sqrt(rra*rrb)/sqrt((1+p*p/rra)*(1+p*p/rrb))

…might be faster as

p2 = p*p p2a = p2/rra p2b = p2/rrb LeftTermC=1e-7*sqrt(rra+p2)*sqrt(rrb+p2)/sqrt((1+p2a)*(1+p2b)) LeftTermU=1e-7*sqrt(rra*rrb)/sqrt((1+p2a)*(1+p2b))

And at one point XojoScript executed faster than regular code, is that still true?

Would inlining HlxIntgrndRad help any?

I just tested my suggestion, and while it makes a difference, it’s only in percentage. For about 80 K, the difference in concatenation vs. Join is 17 ms vs. 4.5 ms. Whatever’s taking 20 hours, that ain’t it. :slight_smile:

Maybe he has a really really slow computer? :wink: