Xojo is slower than Python

Not to go on a rant but I am really quite gobsmacked by the slow performance of Xojo.

As many of you know, I’ve been working on a Python-like programming language for a couple of years, written in Xojo. It started off as a tree-walking interpreter called Roo and currently it’s been renamed to Possum and uses a stack-based bytecode. I have finally got Possum to the stage that it can call functions and handle local and global variables.

Excitedly, I thought I would now test Possum’s speed against Roo with a simple (albeit heinously inefficient) fibonacci test:

function fib(n):
	if n < 2 then return n
	return fib(n - 1) + fib(n - 2)

print(fib(28))

For both implementations this prints the correct answer (9227465). What depressed me was that Roo took about 60 seconds and Possum about 50 seconds.

Whilst both of these implementations are really slow, I was surprised to see how little improvement Possum had made over Roo. Possum runs as close to the metal as I can get it.

Curious, I did a test to compare a barebones Xojo console application against Swift and Python to see how fast they are. Here’s the Xojo application code:

Function Fib(n As Integer) As Integer
  If n < 2 Then Return n
  Return Fib(n - 1) + Fib(n - 2)
End Function

In App.Run:

Print(Fib(35).ToString)

This takes 6 seconds as a compiled console application on a 2017 MacBook Pro.

Compare this to Swift (0.5 seconds) and Python (5 seconds).

How the f**k is Xojo slower than Python 3??

For completeness, here’s the Swift code:

import Foundation

func fib(_ n: Int) -> Int {
    if n < 2 {
        return n
    } else {
        return fib(n - 1) + fib(n - 2)
    }
}

print(fib(35))

and here’s the Python script:

from __future__ import print_function

def fib(n):
  if n < 2: return n
  return fib(n - 1) + fib(n - 2)

print(fib(35))

is this a console app in xojo ? if not make it one so you get rid of any interruptions for UI
did you compile with or without optimizations ? turn them to at least moderate if not aggressive
make sure you use all the pragmas

  #Pragma BackgroundTasks False
  #Pragma BoundsChecking False
  #Pragma BreakOnExceptions False
  #Pragma NilObjectChecking False
  #Pragma StackOverflowChecking False

that should get you closer to python

edit fwiw in rust this is .125 seconds :slight_smile:

It was compiled as a console app with moderate optimisation. No pragmas.

Huh … wouldnt expect the pragmas to make that big a difference though

Nor would I expect it to be that slow

Me neither. I’m genuinely surprised. Keep thinking I’ve goofed but the code is there to see.

Really weird. I did the test in my PC

Xojo: 1.22s
Xojo “optimized”: 1.21s
Pyton: 3.01s

Just for fun:
B4J: 0.028s :upside_down_face:

Note: Xojo 2018r3 as I didnt renew pro after that

@ivan That’s very curious. What PC are you running? I’m running macOS 10.15. Using the prerelease 2020 R1

FYI… my iMac running this in Swift did it in 0.145 seconds

func Fib(_ n: Int) -> Int {
    if n < 2 { return n }
    return Fib(n-1)+Fib(n-2)
}
   let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSSZZZZZ"
        print(formatter.string(from: Date()))
        print(Fib(35))
        print(formatter.string(from: Date()))
2020-05-29T08:52:44.143000-07:00
9227465
2020-05-29T08:52:44.288000-07:00

@Garry, a desktop one, i7-8700k.

Can you try with a Pre API 2.0 xojo ?

In Rust

use std::time::Instant;

fn fibonacci( n : i32 ) -> i32 {

    if n < 0 {
		0
    }
    else if n == 0 {
    	0
    }
    else if n == 1 {
    	1
    }
    else {
    	fibonacci(n - 1 ) + fibonacci(n -2)
    }
}

fn main() {
    let start = Instant::now();

	println!("fib(35) = {}", fibonacci(35) );

    let elapsed = start.elapsed();

    println!("Millis: {} ms", elapsed.as_millis());    
}

First I compile it (cargo build)
Then I run it with

perl -MTime::HiRes=time -e 'printf "%.9f\n", time' ; /Users/npalardy/RustProjects/fibonacci/target/debug/fibonacci ; perl -MTime::HiRes=time -e 'printf "%.9f\n", time'

1590771171.419712067
fib(35) = 9227465
Millis: 115 ms
1590771171.550776005

or .492 seconds total - only 115 msec to do fib(35) though
and this time includes start up and tear down by the OS to start the process

compiled a comparable xojo app aggressively and ran it the same way (just the perl portion)

1590771626.041557074
9227465
1590771626.853302002

so .811 sec which isnt shabby

Something weird is going on here for me.

I’ve cleared Xojo’s build cache and restarted my computer. I’m now seeing run times of 220 ms when compiled with aggressive optimisations and all of the pragma’s @npalardy suggested. Maybe I was suffering some cache bug??

In any regard, Swift is still faster. I’m running this code through the Elements compiler (using their Fire IDE) and getting run times of 45 ms with a release build. That’s fast!

import Foundation

func fib(_ n: Int) -> Int {
    if n < 2 {
        return n
    } else {
        return fib(n - 1) + fib(n - 2)
    }
}

let start = clock()

print(fib(35))

let diff = Double(clock() - start) / Double(CLOCKS_PER_SEC) * 1000
print(diff + " ms")

@DaveS: Have you checked out the free Elements Swift compiler by RemObjects? I think there has been discussion about it on the forum previously.

I had heard of it, but not looked into it…

It’s really good for non-UI based stuff

Not quite fitting to the topic, but I have made the experience that Xojo can be very, very fast with the right optimizations in the code. I am always amazed how performant arrays are, for example.

I think the point was that python (and others) can be even faster
They arent as “friendly” though

Also to get high performance you do often have to sacrifice some of the things that users pick Xojo for in the first place. For example, using pragmas to disable lots of framework safety assertions.

I’m currently porting a project from Xojo to C# and seeing substantial performance gains and still getting all the protections that the common language runtime provides.

well, you can’t really compare C/Swift to Xojo here.
The Xojo compiler always does maintenance there like stack checking, preparing exception and handling them.

The C/Swift compiler sees no exceptions can happen, so they will not do those setup things.

On the assembler output, the Xojo method is probably 10 times bigger than what C compiler produces. And probably most in registers in C vs. local stack variables in Xojo for each intermediate result.

right
even with aggressive optimization and all pragmas in a console app xojo has overhead that rust, python, c and swift dont
but it can be made to be pretty darn fast still

Like the IDE ? :stuck_out_tongue:

I’ll grant you there are lots of things where the speed differences wont be noticed
Thats very true

And for a LOT of tasks the speed differences wont be noticed

Until they are - and then its darned hard to do much to affect things in a big way since the compiler has done just about all it can for you and there are certain built in overheads you cannot work around

This is true in most languages but those points come at different times for different languages because of the things they do for you or dont do for you

Xojo gives you a lot of safety - and MOST times thats fine and doesnt cost you
But when it does its hard to get Xojo code to perform at the same level as C/Swift/Rust
But those languages let you blast your toes off much quicker :slight_smile:

Its all trade offs

EDIT : fixed typo “toes of” should be “toes off”