UDVIKLING/EMBEDDED Sikker ydelse i RTOS-applikationer Et multi-threaded real-time operativsystem kan gøre et embedded system mere effektivt, men der er mange hensyn at tage undervejs Figur 1: Grundlæggende kodeeksempel med to RTOS-tasks. Af dr. Johan Kraft, CEO og grundlægger, Percepio AB Brugen af real-time operativ- systemer (RTOS) i embeddede designs er et stadig mere popu- lært valg for systemdesignere. Når mikrocontrollerne bliver kraftigere, giver RTOS’erne flere fordele. Et RTOS tillader mul- tithreading og dermed mere modulære systemer, som ekse- kverer flere mindre program- mer. De kan hver især være ansvarlige for enkeltfunktioner som USB, display, TCP/IP eller Bluetooth. Det gør det lettere at forstå og vedligeholde koderne – og korrekt udført er det også en mere effektiv metode. Multithreading giver dog også nye udfordringer inden for soft- waredesign, debugging og test, og det kræver nye softwareud- viklingsstrategier. Problemerne omfatter omvendte prioriteter, memory-interferens, race-con- ditions, deadlocks, live-locks og starvation. Den statiske kode giver ikke altid hele billedet af den dy- namiske runtime-behaviour. I multithreadede systemer på- virkes runtime-behaviour af interferensen mellem tasks og timing-variationer. Det betyder, at egenskaber, som dukker op, ikke er synlige i source-koden, men kun viser sig under ek- sekvering. De forhold kan op- fanges med avancerede trace- værktøjer, der highlighter såvel driften af de enkelte tasks og deres interaktion over tid. Det kan vise, hvor tasks blokerer hin- anden eller dræner ressourcer. Mens visse tasks tilsyneladende er uafhængige, så kan de kræve adgang til globale ressourcer som datastrukturer eller hard- wareinterfaces, hvorved glo- bale events pludselig får betyd- ning. Variationer i, hvordan de enkelte tasks får adgang til disse ressourcer, kan forårsage race- tilstande og sporadiske fejl, som kan være svære at finde i sour- ce-koden. Brugen af et trace- værktøj gør det derfor lettere at identificere race-conditions, deadlocks og prioriterings(mis) forhold. Grundlæggende eksempel Et grundlæggende eksempel kunne anvende to RTOS-tasks (figur 1) . Koden kan oprindeligt være et single-loop design, som designerne derefter har porte- ret til en applikation for at bruge et RTOS, dog uden helt at forstå fordelene ved en RTOS-kerne. Vi kan med det samme se i koden, at der kører to tasks med den samme prioritet, så hvis begge tasks er aktive samtidig, vil de alternere med en opløsning svarende til operativsystemets tick-interrupt. Vi ser også en delay-funktion i TaskB_Periodic. Denne task skal øjensynligt køre hvert 10. millisekund. Figur 2 er en visuel trace af ko- dens runtime-behavior i Per- cepio Tracealyzer. Til venstre er et scheduling-trace med en lodret, nedadgående tidslinje, mens der øverst til højre er en graf over CPU-belastningen – et overblik over, hvordan pro- cessorens tid er distribueret mellem de to tasks. Diagram- met har en vandret orientering, så tiden løber fra venstre mod højre. Læg mærke til, at TaskB_Pe- riodic kører 50 procent af tiden. Hvorfor? Vi behøver jo kun at køre denne task hver 10ms, og koden har et delay til dét for- mål. Det viser sig, at den brugte delay-funktion, HAL_Delay, ikke er en del af RTOS-kernen, og derfor udsætter funktion i rea- liteten ikke den kørende task. Den blokerer kun task’en i en optaget wait-loop i en specifice- ret tid. Så med den implemen- tering spilder man rundt regnet 50 procent af processorens tid. For at fikse dét, ændrer vi koden i TaskB til at bruge vTaskDelay, som RTOS’en kan levere. Vi løf- ter samtidig prioriteten af TaskB, Figur 2: En simpel trace af to RTOS-tasks. så den kan gå foran TaskA, så snart den udsættes for et wake- up. På den måde sikrer vi os, at TaskB kan begynde eksekvering direkte efter et call for vTask- Delay. Som en konsekvens eksekverer TaskB nu hvert 10. millisekund – og kun så længe, det er nød- vendigt. Der er ingen ”busy- loop” wait-tilstande. Det giver plads til, at TaskA kan eksekvere næsten hele tiden, så ydelsen er næsten fordoblet for appli- kationen ved at ændre bare to linjer kode. Det er let at udføre, når man oplever, hvad der sker i runtime. I modsat fald havde man måske ikke opdaget mu- ligheden – især hvis de aktuelle kodelinjer er spredt langt inde i en stor kodebase. Det er selvfølgelig et simpelt eksempel. Men det er generelt sandt for RTOS-baserede appli- kationer, at softwaretiming skal være så stabile og deterministi- ske som muligt – hvilket kræver minimering af timingvariatio- nerne. Berømt klassiker Et berømt eksempel fra 1980’erne er den computer- styrede Therac-25 strålingste- rapimaskine. Den havde flere softwarefejl herunder race-con- ditions, som i hvert fald i seks tilfælde gav massive overdoser af stråling. Det er selvfølgelig et ekstremt eksempel, men selv et veldesignet system kan under visse omstændigheder trigge utestede eksekveringsmønstre og give fejl, der er noget nær umulige at reproducere med statisk kodeanalyse. Vi kan se på en anden dynamisk runtime-error, der ville være umulig at opdage med kode- inspektion. Det er en af RTOS’ fundamentale egenskaber, at tasks med højere prioritet ek- sekverer før tasks med lavere 30 nr. 9 | september 2021 - NASA’s Pathfinder-mission til Mars i 1997 sloges med prioritetsinvertering. (Foto: NASA).
Download PDF fil
Cookiepolitik
Se arkivet med udgivelser af Aktuel Elektronik her
TechMedias mange andre fagblade kan læses her