FreeRTOS Task Scheduler & GCC Optimisation Levels

Good day

I have been using MCUXpresso (NXP’s Eclipse-based IDE) to write code for a FreeRTOS-based project.
So far, FreeRTOS has been a wonderfully stable OS for this project.
However, I need to increase the speed at which the code executes, so I looked into GCC’s compiler optimisations.
Up until this point, I had not used any optimisation (used ‘None’ -O0).

I have enough space for the code to grow in size, so I am only optimising for speed.
For this reason, I chose to build my project with the ‘Optimise most’ (-O3) optimisation level.

Unfortunately, since I’ve made this change (no other changes), the task scheduler seems to not respond in the way it did before.
Many of the tasks that used to execute do not respond to their semaphores and task notifications.

Can someone please advise me on using GCC optimisation with FreeRTOS?
Is there a way to make it work?

FreeRTOS code itself is very unlikely the cause of your issues since it’s verified and known to work even with high/aggressive optimization levels.
Activating the optimizer might reveal various coding bugs.
Common pitfall of 'my perfectly running application stopped working in release/optimized build is e.g. missing volatile qualifiers where needed.
Did you try a less aggressive optimization level like ‘-O2’ ?
Bare in mind when running code from rather slow flash less code (using ‘-Os’) might also speed up your application with the nice side effect dealing with smaller binaries.
Good luck !

Hi there D_TTSA,

I have isolated at least two bugs in GCC related to optimization, so what you are seeing may be the result of erratic code being generated only at certain optimization levels.

Also, on top of the right-on-spot remarks of Hartmut, I’d like to add that depending on the MCU in question, the tradeoff between speed and size may be dramatic up to unbelievable. For example, on Cortex-M machines, speed optimization may imply code unfolding that minimizes memory accesses outside the core (yielding potential performance gains in factors of several thousands) but may in return blow up the code by a factor of 4-10 or more.

Which GCC version are you using?

Hi @rtel
I am using v10.2.0

Hi @hs2
Thank you for your detailed response!
You were correct about me missing the volatile qualifier for one of my tasks, so adding that seemed to fix a few problems.
However, there are still some issues with tasks - I think it may be to do with some of NXP’s drivers, but I’m still looking into it.

I’ve been running our tests for a day now using arm-none-eabi-gcc version 10.2.1 20201103 and -O3 and not seen any failures.

1 Like

@rtel Thanks for testing !
I’m also using GCC10.2 since it was released on Cortex-M3/4 and didn’t encounter any related issue.
And this was the case since I started using FreeRTOS (core) with GCC7 at that time :+1:

1 Like

Thank you everyone for your help.
At this point, I’m quite certain it is to do with NXP’s drivers, or their autogenerated code.
I can apply O3 on my source files, just not on the whole project.

Hi,
I use GCC.

I don’t know if this helps, but what I do is leave global optimizations at -O0 and put:

//#pragma GCC optimize ("Ofast") /*  todo final testing */
//#pragma GCC optimize ("O3")     /* todo final testing */
#pragma GCC optimize ("O0")         /* todo debugging, development and initial testing*/ 

At the top of each code file.

When I start off I un-comment O0. After I am happy with the code I switch to O3 or Ofast.

I add these lines to the freeRTOS modules and generally set these to O3 or Ofast. I haven’t come across any trouble with this.

If there is a function in a code file that must be optimised then I use:

#pragma GCC push_options
#pragma GCC optimize ("Ofast")

void myFunction {

}
#pragma GCC pop_options

The advantage here is that instead of getting it all going with no optimization and then when optimization is turned on globally you may have some issue which you then have to find in code that you may not have looked at for a week or more.

The only time I have had an issue with O3 so far that has caused a failure is forgetting to make a variable volatile. I have never had any trouble with ST Micro’s HAL Drivers with O3 or Ofast, but of course I’ve only used about 20% of them.

Turning on optimization as you go has worked well for me.

At the end of the project I may just leave it with all the optimizations set to O3 or Ofast, or I might remove the individual pragmas and just turn on global. Of course my projects never end so you can guess what actually happens.

Regards
Rob

1 Like