Real-time operating systems (RTOS) are finding their way into more and more systems. Developers who are accustomed to bare-metal development or working with highly resource constrained systems will often complain about system performance or memory usage. Here are seven tips developers can follow to help optimize their RTOS for performance and code size.
1. Minimize Tasks in the Application
The ability to break an application up into separate tasks, “mini programs,” that appear to be running concurrently is extraordinarily beneficial. Developers who are new to RTOS development, though, can sometimes get a little overzealous and create more tasks than are required for the application. What’s the harm in a few extra tasks? Every task that is created in the application requires that a task control block (TCB) be created to manage the task. The TCB contains at least a few dozen different variables that are used to track the task. (An example TCB from uCOS/III can be seen here.) As one can imagine, the TCB doesn’t use a large amount of memory but as more and more tasks are added, the memory use can quickly balloon. For that reason, developers looking to minimize how much code space is used should be looking to minimize how many tasks are in the application.
2. Use Memory Block Pools over Byte Pools
A memory byte pool essentially is a heap. A developer can request memory dynamically during program execution just like they are using malloc. In many cases, using the heap or a byte pool can result in non-deterministic behavior that affects the real-time system performance. In order to ensure that the system runs in a timely manner, developers can use block pools instead which behave in a deterministic manner and also don’t have issues with fragmentation.
3. Don’t Create and Destroy Objects
Creating tasks, semaphores, message queues, and other RTOS objects usually results in memory being allocated dynamically. Creating and destroying RTOS objects will use malloc and free which once again are not deterministic and can result in performance issues. The overhead associated with creating and destroying objects especially if it is done often can be a system hindrance not to mention how it can increase the code complexity and make the program difficult to follow. When possible allocate all objects during the applications initialization and let them persist throughout the applications life. In this way, objects will behave as if they are being allocated statically rather than dynamically.
4. Consider Using Event Flags
Event flags can be used to synchronize tasks similar to the way that a semaphore is used to synchronize tasks. When comparing event flags and semaphores from a performance standpoint, event flags usually use less memory and execute faster. Developers should consider comparing the memory footprints and execution times for their RTOS to determine where they can squeeze a few extra bytes or microseconds from their application.
5. Minimize RTOS Objects
Most RTOS objects require a control block. The more tasks, semaphores, message queues, etc. that are in the application, the greater the memory usage will be. Memory usage can be minimized by limiting the number of RTOS objects that are created during run-time.
6. Optimize the Task Stacks
Task stacks are notorious for consuming the most memory in an application. Many developers just guess at a value rather than making a measurement. Many RTOSes will recommend a default stack size around 1 kB for a task. Is that too much? Too little? There is no way to tell without making a measurement so a developer will just guess. The result is way too much memory being allocated for stack space and wasted. Developers should utilize stack monitoring features associated with the RTOS to determine their min, max, and average stack usage. From the maximum, adding an extra 25% would be a safe rule of thumb to size the stack.
7. Turn Off Unused Features
RTOSes are extremely rich and complicated software systems. They include many features that won’t be utilized by every application or developer. Becoming familiar with the RTOSes configuration file can be very helpful in minimizing memory usage and code size. The configuration file allows developers to enable and disable features.
Using an RTOS doesn’t necessarily require a souped-up microcontroller or a plethora of memory. The way that a developer architects and uses their RTOS can make all the difference between whether it works well in a resource-constrained environment or is labeled bloat code. These seven tips are just a few to get you started in optimizing your RTOS.
What other tips can you think of to make sure that an RTOS runs efficiently in a small memory footprint? Share your ideas in the below comments section.
The questions is no longer "should I use an RTOS," but "how can I most effectively design a system using an RTOS." Technical session From Baremetal to Real-Time Operating Systems, held during ESC Boston 2017, May 3-4, will answer this question and more. Register today!
Jacob Beningo is an embedded software consultant who currently works with clients in more than a dozen countries to dramatically transform their businesses by improving product quality, cost and time to market. He has published more than 200 articles on embedded software development techniques, is a sought-after speaker and technical trainer and holds three degrees which include a Masters of Engineering from the University of Michigan. Feel free to contact him at [email protected], at his website www.beningo.com/, and sign-up for his monthly Embedded Bytes Newsletter.