My app is extremely slow in 2025r2

In this case, it does.

You are complainig about that, threads now behaving as documented instead of not really
abiding by the slots assigned to them.

Well, Xojo has improved a lot in the last years.

I do remember several complaints about time slices and sleeps, at some point some “fix” may have changed some behavior.

No, I’m complaining - and have demonstrated - that threads are much slower than they used to be. There’s not a damn thing I can do to get that performance back. It basically means I can’t ever update the version of Xojo I use for my app. How am I supposed to sell such a slowdown to my users? “Oh hey, you get nothing new, but these tasks take at least twice as long! Yay!”

You say it’s working as intended, but then how do you explain a thread taking 40% longer than a thread with half the CPU time?

I’m not interested in arguing about this with you.

1 Like

Ok, I ran another batch of tests. I’ll chalk up the original 2025r2.1 10 priority test as being a fluke, as this time it came in less than the priority 5 as expected. These tests are all with aggressive optimization in a built (not IDE debug) app. I also included some preemptive tests at the same priorities, even though the priority shouldn’t really matter in this test, and the results confirm that. Times are in seconds.

Xojo 2023r4, Windows x64

Priority Time
1 77.89
5 24.48
10 20.41

Xojo 2023r4, macOS ARM64

Priority Time
1 13.92
5 13.56
10 13.65

Xojo 2025r2.1, Windows x64

Priority Time
1 coop 131.09
5 coop 32.79
10 coop 24.18
1 preempt 16.67
5 preempt 16.69
10 preempt 16.65

Xojo 2025r2.1, macOS ARM64

Priority Time
1 coop 14.03
5 coop 13.45
10 coop 13.37
1 preempt 14.37
5 preempt 13.50
10 preempt 13.46

macOS has nice consistent times. It’s clear the scheduler is not simply dividing cycles between the threads, but treating priority as a true priority. Windows scheduling, on the other hand, is happy to hand processor cycles to the main thread even when it doesn’t need them. But what’s also clear is cooperative threads are undeniably slower on Windows in 2025r2.1 vs 2023r4. The same work with the same division of cycles takes nearly twice as long in 2025r2.1. This performance loss is less noticeable at higher priorities, but is still present.

Both platforms, unsurprisingly, get great results with preemptive threads. And I’d absolutely love to use them. But my threads do not exist in a vacuum.

So… looking at your results, isn’t the solution to simply rejigger the thread priorities to get equivalent performance in 2025r2.1? Or am I missing something?

It’s not exactly possible. I could increase the priority of some of these background threads to match the main thread, but there’s still a performance hit. In the case of this synthetic test, yes 32 seconds at priority 5 in 2025r2.1 is better than 77 seconds at priority 1 in 2023r4. But this doesn’t necessarily mean this scaling will carry over to real-world code. In fact, I know it doesn’t. If you read back to My app is extremely slow in 2025r2 - #22 by Thom_McGrath, the process goes from 53 seconds at priority 1 in 2023r4 to 12 minutes at priority 5 in 2025r2.1. That’s still a monumental loss of performance and no amount of playing with the priority is going to get that back. It may be possible by starving the main thread, but then… what’s the point of using a thread?

Could it be the the OS itself is taking care of handling preemptive threads (maybe macOS does it more optimized compared to Windows) and Xojo Inc cannot do anything about it? Or am I wrong here?

EDIT: stupid question I guess … if it works fine on an older Xojo version it must be Xojo. :slight_smile:

It’s a bit of both. If Xojo were 100% in control, Mac and Windows would have similar performance characteristics, assuming identical hardware of course. But Mac has a clear performance advantage over Windows, so there’s definitely reliance on the system. But yes, since performance changed dramatically between versions, I believe it’s not purely the system scheduler to blame for the loss of performance.

Ug. This thread will never end.

So I figured I’d at least try to retrofit preemptive threading. Experience tells me this is a bad idea, but it seems like the solution… right?

Well… no. There’s still something wrong between Xojo versions. Using my Mac this time, where it’s already been established that performance is much more consistent, my write-intensive process is still dramatically slower:

2025r2.1 cooperative: 793 seconds
2025r2.1 preemptive: 249 seconds
2023r4 cooperative: 25 seconds

This is just not good…

If it helps, I recently discovered that running two concurrent pre-emptive threads can be 3-5x slower than running a single pre-emptive thread when creating objects is involved. This is on MacOS in a built app.

1 Like

Thanks. I’ve already noticed the same in other projects. In this case, it’s literally the first and only preemptive thread in the app.

Well I’m heading to bed. But before I sign off for the evening, Xcode Instruments tells me the issue is SQLite. Specifically SelectSQL. ExecuteSQL seems very fast.

The other 40% of the time is also SelectSQL, just a different path to it.

The SQLite database uses write-ahead logging and a yield interval of 75 instructions. Since this is now a preemptive thread, I figured I’d try 0 for that, but it made no difference.

I know how you feel. I’ve given up using a Mac compiling for Windows using 2025R2.1
Mac is fine but It produces an unstable and slow app for Windows.
If you are compiling for multiple platforms on a Mac try compiling for Windows on a Windows machine.
Made a huge difference for me.

Thanks for the tip, but I already do that.

Have you logged a bug about this as that seems wrong to me.

1 Like

goes the single core at 2025r2.1 near to 100% with this cooperative threads in your app?
(full use of cpu core and not idle.)

But they are not behaving as documented.

Where does it say “On Windows, a low priority thread will cause the app to use very little CPU, a new behavior which is different than macOS and was changed in Xojo 2025”.

It’s a bug.

Then we have 2 problems, threads and SelectSQL? or only one?

Either way, I hope you find whats wrong and it can be fixed.

Possibly not. The difference is macOS distributes work, Windows distributes time.

If you have 2 threads, 1 at priority 1 and 1 at priority 5, your total would be 6. 1/6 cycles will go to the priority 1 thread, and 5/6 cycles go to priority 5. So in this example, the most CPU the priority 1 thread can use is 16%. As @Odeyani_Lugardo said, it’s being very literal. While I’m not 100% certain, I believe this is by design because that’s just how Microsoft implemented it.

On macOS, the system is much more logical. Priority 1 can still use nearly all of the core, as long as it’s available.

You can see these effects in my most recent benchmarks.

The bug in all this is that Windows cooperative threads became much slower. The same work with the same distribution of CPU cycles takes longer to complete, sometimes by orders of magnitude.

And to make matters worse, there may also be a performance bug with SQLiteDatabase.SelectSQL, though I haven’t had time to do a deep dive on that.

Dropping in to say this is likely. I noticed extremely slow database queries with TPLM 2.0 and rewrote massive chunks to push work into SQLite. I hope you find the cause, because it makes ActiveRecord projects just unusable in Web 2.0.