/* ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. This file is part of ChibiOS/RT. ChibiOS/RT is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. ChibiOS/RT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * @page article_jitter Response Time and Jitter * Response time jitter is one of the most sneaky source of problems when * designing a real time system. When using a RTOS like ChibiOS/RT one must * be aware of what the jitter is and how it can affect the performance of the * system. A good place to start is this * Wikipedia * article. * *

Interrupt handlers execution time

* The total execution time of an interrupt handler includes: * - Hardware interrupts latency, this parameter is pretty much fixed and * characteristic of the system. * - Fixed handler overhead, as example registers stacking/unstacking. * - Interrupt specific handler code execution time, as example, in a serial * driver, this is the time used by the handler to transfer data from/to * the UART. * - OS overhead. Any operating system requires to run some extra code * in interrupt handlers in order to handle correct preemption and Context * Switching. * . *

Interrupt Response Time

* The Interrupt Response Time is the time from an interrupt event and the * execution of the handler code. Unfortunately this time is not constant * in most cases, see the following graph: * * @dot digraph example { rankdir="LR"; node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.75", height="0.75"]; edge [fontname=Helvetica, fontsize=8]; int [label="Interrupt"]; busy [label="Busy"]; served [label="Interrupt\nServed"]; int -> served [label="Not Busy (minimum latency)"]; int -> busy [label="Not Ready"]; busy -> busy [label="Still Busy\n(added latency)"]; busy -> served [label="Finally Ready"]; } * @enddot * * In this scenario the jitter (busy state) is represented by the sum of: * - Higher or equal priority interrupt handlers execution time combined. * This time can go from zero to the maximum randomly. This value can be * guaranteed to be zero only if the interrupt has the highest priority in * the system. * - Highest execution time among lower priority handlers. This value is zero * on those architectures (Cortex-M3 as example) where interrupt handlers * can be preempted by higher priority sources. * - Longest time in a kernel lock zone that can delay interrupt servicing. * This value is zero for fast interrupt sources, see @ref system_states. * . *

Threads Flyback Time

* This is the time between an event, as example an interrupt, and the * execution of the thread that will process it. Imagine the following * graph as the continuation of the previous one. * * @dot digraph example { rankdir="LR"; node [shape=circle, fontname=Helvetica, fontsize=8, fixedsize="true", width="0.75", height="0.75"]; edge [fontname=Helvetica, fontsize=8]; served [label="Interrupt\nServed"]; busy [label="Busy"]; thread [label="Thread\nAwakened"]; served -> busy [label="Not highest Priority"]; busy -> busy [label="Higher priority Threads\n(added latency)"]; busy -> thread [label="Highest Priority"]; served -> thread [label="Highest Priority (minimum latency)"]; } * @enddot * * In this scenario all the jitter sources previously discussed are also * present and there is the added jitter caused by the activity of the * higher priority threads. * *

Jitter Mitigation

* For each of the previously described jitter sources there are possible * mitigation actions. * *

Interrupt handlers optimization

* An obvious mitigation action is to optimize the interrupt handler code as * much as possible for speed.
* Complex actions should never be performed in interrupt handlers. * An handler should just serve the interrupt and wakeup a dedicated thread in * order to handle the bulk of the work.
* Another possible mitigation action is to evaluate if a specific interrupt * handler really needs to interact with the OS, if the handler uses full * stand-alone code then it is possible to remove the OS related overhead.
* *

Kernel lock zones

* The OS kernel protects some critical internal data structure by disabling * (fully in simple architecture, to some extent in more advanced * microcontrollers) the interrupt sources. Because of this the kernel itself * is a jitter cause, a good OS design minimizes the jitter generated by the * kernel by using adequate data structures, algorithms and coding * practices.
* A good OS design is not the whole story, some OS primitives may generate * more or less jitter depending on the system state, as example the maximum * number of threads on a certain queue, the maximum number of nested mutexes * and so on. Some algorithms employed internally can have constant execution * time but others may have linear execution time or be even more complex. * *

Higher priority threads activity

* At thread level, the response time is affected by the interrupt-related * jitter but mainly by the activity of the higher priority threads and * contention on protected resources.
* It is possible to improve the system overall response time and reduce jitter * by carefully assigning priorities to the various threads and carefully * designing mutual exclusion zones.
* The use of the proper synchronization mechanism (semaphores, mutexes, events, * messages and so on) also helps to improve the overall system performance. * The use of the Priority Inheritance algorithm implemented in the mutexes * subsystem can improve the overall response time and reduce jitter but it is * not a magic wand, a proper system design comes first. */