1 page.title=Avoiding Priority Inversion 2 @jd:body 3 4 <div id="qv-wrapper"> 5 <div id="qv"> 6 <h2>In this document</h2> 7 <ol id="auto-toc"> 8 </ol> 9 </div> 10 </div> 11 12 <p> 13 This article explains how the Android's audio system attempts to avoid 14 priority inversion, as of the Android 4.1 (Jellybean) release, 15 and highlights techniques that you can use too. 16 </p> 17 18 <p> 19 These techniques may be useful to developers of high-performance 20 audio apps, OEMs, and SoC providers who are implementing an audio 21 HAL. Please note that implementing these techniques is not 22 guaranteed to prevent glitches or other failures, particularly if 23 used outside of the audio context. 24 Your results may vary and you should conduct your own 25 evaluation and testing. 26 </p> 27 28 <h2 id="background">Background</h2> 29 30 <p> 31 The Android audio server "AudioFlinger" and AudioTrack/AudioRecord 32 client implementation are being re-architected to reduce latency. 33 This work started in Android 4.1 (Jellybean), continued in 4.2 34 (Jellybean MR1), and more improvements are likely in "K". 35 </p> 36 37 <p> 38 The lower latency needed many changes throughout the system. One 39 important change was to assign CPU resources to time-critical 40 threads with a more predictable scheduling policy. Reliable scheduling 41 allows the audio buffer sizes and counts to be reduced, while still 42 avoiding artifacts due to underruns. 43 </p> 44 45 <h2 id="priorityInversion">Priority Inversion</h2> 46 47 <p> 48 <a href="http://en.wikipedia.org/wiki/Priority_inversion">Priority inversion</a> 49 is a classic failure mode of real-time systems, 50 where a higher-priority task is blocked for an unbounded time waiting 51 for a lower-priority task to release a resource such as [shared 52 state protected by] a 53 <a href="http://en.wikipedia.org/wiki/Mutual_exclusion">mutex</a>. 54 </p> 55 56 <p> 57 In an audio system, priority inversion typically manifests as a 58 <a href="http://en.wikipedia.org/wiki/Glitch">glitch</a> 59 (click, pop, dropout), 60 <a href="http://en.wikipedia.org/wiki/Max_Headroom_(character)">repeated audio</a> 61 when circular buffers 62 are used, or delay in responding to a command. 63 </p> 64 65 <p> 66 In the Android audio implementation, priority inversion is most 67 likely to occur in these places, and so we focus attention here: 68 </p> 69 70 <ul> 71 72 <li> 73 between normal mixer thread and fast mixer thread in AudioFlinger 74 </li> 75 76 <li> 77 between application callback thread for a fast AudioTrack and 78 fast mixer thread (they both have elevated priority, but slightly 79 different priorities) 80 </li> 81 82 <li> 83 within the audio HAL implementation, e.g. for telephony or echo cancellation 84 </li> 85 86 <li> 87 within the audio driver in kernel 88 </li> 89 90 <li> 91 between AudioTrack callback thread and other app threads (this is out of our control) 92 </li> 93 94 </ul> 95 96 <p> 97 As of this writing, reduced latency for AudioRecord is planned but 98 not yet implemented. The likely priority inversion spots will be 99 similar to those for AudioTrack. 100 </p> 101 102 <h2 id="commonSolutions">Common Solutions</h2> 103 104 <p> 105 The typical solutions listed in the Wikipedia article include: 106 </p> 107 108 <ul> 109 110 <li> 111 disabling interrupts 112 </li> 113 114 <li> 115 priority inheritance mutexes 116 </li> 117 118 </ul> 119 120 <p> 121 Disabling interrupts is not feasible in Linux user space, and does 122 not work for SMP. 123 </p> 124 125 126 <p> 127 Priority inheritance 128 <a href="http://en.wikipedia.org/wiki/Futex">futexes</a> 129 (fast user-space mutexes) are available 130 in Linux kernel, but are not currently exposed by the Android C 131 runtime library 132 <a href="http://en.wikipedia.org/wiki/Bionic_(software)">Bionic</a>. 133 We chose not to use them in the audio system 134 because they are relatively heavyweight, and because they rely on 135 a trusted client. 136 </p> 137 138 <h2 id="androidTechniques">Techniques used by Android</h2> 139 140 <p> 141 We started with "try lock" and lock with timeout. These are 142 non-blocking and bounded blocking variants of the mutex lock 143 operation. Try lock and lock with timeout worked fairly well for 144 us, but were susceptible to a couple of obscure failure modes: the 145 server was not guaranteed to be able to access the shared state if 146 the client happened to be busy, and the cumulative timeout could 147 be too long if there was a long sequence of unrelated locks that 148 all timed out. 149 </p> 150 151 152 <p> 153 We also use 154 <a href="http://en.wikipedia.org/wiki/Linearizability">atomic operations</a> 155 such as: 156 </p> 157 158 <ul> 159 <li>increment</li> 160 <li>bitwise "or"</li> 161 <li>bitwise "and"</li> 162 </ul> 163 164 <p> 165 All of these return the previous value, and include the necessary 166 SMP barriers. The disadvantage is they can require unbounded retries. 167 In practice, we've found that the retries are not a problem. 168 </p> 169 170 <p> 171 Note: atomic operations and their interactions with memory barriers 172 are notoriously badly misunderstood and used incorrectly. We include 173 these here for completeness, but recommend you also read the article 174 <a href="https://developer.android.com/training/articles/smp.html"> 175 SMP Primer for Android</a> 176 for further information. 177 </p> 178 179 <p> 180 We still have and use most of the above tools, and have recently 181 added these techniques: 182 </p> 183 184 <ul> 185 186 <li> 187 Use non-blocking single-reader single-writer 188 <a href="http://en.wikipedia.org/wiki/Circular_buffer">FIFO queues</a> 189 for data. 190 </li> 191 192 <li> 193 Try to 194 <i>copy</i> 195 state rather than 196 <i>share</i> 197 state between high- and 198 low-priority modules. 199 </li> 200 201 <li> 202 When state does need to be shared, limit the state to the 203 maximum-size 204 <a href="http://en.wikipedia.org/wiki/Word_(computer_architecture)">word</a> 205 that can be accessed atomically in one bus operation 206 without retries. 207 </li> 208 209 <li> 210 For complex multi-word state, use a state queue. A state queue 211 is basically just a non-blocking single-reader single-writer FIFO 212 queue used for state rather than data, except the writer collapses 213 adjacent pushes into a single push. 214 </li> 215 216 <li> 217 Pay attention to 218 <a href="http://en.wikipedia.org/wiki/Memory_barrier">memory barriers</a> 219 for SMP correctness. 220 </li> 221 222 <li> 223 <a href="http://en.wikipedia.org/wiki/Trust,_but_verify">Trust, but verify</a>. 224 When sharing 225 <i>state</i> 226 between processes, don't 227 assume that the state is well-formed. For example, check that indices 228 are within bounds. This verification isn't needed between threads 229 in the same process, between mutual trusting processes (which 230 typically have the same UID). It's also unnecessary for shared 231 <i>data</i> 232 such as PCM audio where a corruption is inconsequential. 233 </li> 234 235 </ul> 236 237 <h2 id="nonBlockingAlgorithms">Non-Blocking Algorithms</h2> 238 239 <p> 240 <a href="http://en.wikipedia.org/wiki/Non-blocking_algorithm">Non-blocking algorithms</a> 241 have been a subject of much recent study. 242 But with the exception of single-reader single-writer FIFO queues, 243 we've found them to be complex and error-prone. 244 </p> 245 246 <p> 247 In Android 4.2 (Jellybean MR1), you can find our non-blocking, 248 single-reader/writer classes in these locations: 249 </p> 250 251 <ul> 252 253 <li> 254 frameworks/av/include/media/nbaio/ 255 </li> 256 257 <li> 258 frameworks/av/media/libnbaio/ 259 </li> 260 261 <li> 262 frameworks/av/services/audioflinger/StateQueue* 263 </li> 264 265 </ul> 266 267 <p> 268 These were designed specifically for AudioFlinger and are not 269 general-purpose. Non-blocking algorithms are notorious for being 270 difficult to debug. You can look at this code as a model, but be 271 aware there may be bugs, and the classes are not guaranteed to be 272 suitable for other purposes. 273 </p> 274 275 <p> 276 For developers, we may update some of the sample OpenSL ES application 277 code to use non-blocking, or referencing a non-Android open source 278 library. 279 </p> 280 281 <h2 id="tools">Tools</h2> 282 283 <p> 284 To the best of our knowledge, there are no automatic tools for 285 finding priority inversion, especially before it happens. Some 286 research static code analysis tools are capable of finding priority 287 inversions if able to access the entire codebase. Of course, if 288 arbitrary user code is involved (as it is here for the application) 289 or is a large codebase (as for the Linux kernel and device drivers), 290 static analysis may be impractical. The most important thing is to 291 read the code very carefully and get a good grasp on the entire 292 system and the interactions. Tools such as 293 <a href="http://developer.android.com/tools/help/systrace.html">systrace</a> 294 and 295 <code>ps -t -p</code> 296 are useful for seeing priority inversion after it occurs, but do 297 not tell you in advance. 298 </p> 299 300 <h2 id="aFinalWord">A Final Word</h2> 301 302 <p> 303 After all of this discussion, don't be afraid of mutexes. Mutexes 304 are your friend for ordinary use, when used and implemented correctly 305 in ordinary non-time-critical use cases. But between high- and 306 low-priority tasks and in time-sensitive systems mutexes are more 307 likely to cause trouble. 308 </p> 309 310