11. Vikasietoisuus Vikasietoisuuden käsitteitä

Samankaltaiset tiedostot
11. Luento: Vikasietoisuus. Tommi Mikkonen,

Arto Salminen,

Ohjelmoinnin perusteet Y Python

Ohjelmistojen virheistä

TK Palvelinympäristö

Sisällys. 16. Ohjelmoinnin tekniikkaa. Aritmetiikkaa toisin merkiten. Aritmetiikkaa toisin merkiten

16. Ohjelmoinnin tekniikkaa 16.1

2 Konekieli, aliohjelmat, keskeytykset

Vikasietoisuus ja luotettavuus

OHJ-4301 Sulautettu Ohjelmointi

Algoritmit 2. Luento 13 Ti Timo Männikkö

Concurrency - Rinnakkaisuus. Group: 9 Joni Laine Juho Vähätalo

815338A Ohjelmointikielten periaatteet Harjoitus 3 vastaukset

811312A Tietorakenteet ja algoritmit , Harjoitus 2 ratkaisu

Sulautettujen järjestelmien vikadiagnostiikan kehittäminen ohjelmistopohjaisilla menetelmillä

16. Ohjelmoinnin tekniikkaa 16.1

Sisällys. 17. Ohjelmoinnin tekniikkaa. Aritmetiikkaa toisin merkiten. for-lause lyhemmin

11/20: Konepelti auki

Osoitin ja viittaus C++:ssa

UML -mallinnus TILAKAAVIO

Ohjelmoinnin perusteet, syksy 2006

TAITAJA 2007 ELEKTRONIIKKAFINAALI KILPAILIJAN TEHTÄVÄT. Kilpailijan nimi / Nro:

TT00AA Ohjelmoinnin jatko (TT10S1ECD)

Tietotekniikan valintakoe

Algoritmit 1. Luento 3 Ti Timo Männikkö

Algoritmit 1. Luento 11 Ti Timo Männikkö

Ohjelmoinnin perusteet Y Python

12. Javan toistorakenteet 12.1

815338A Ohjelmointikielten periaatteet Harjoitus 2 vastaukset

Kirjoita oma versio funktioista strcpy ja strcat, jotka saavat parametrinaan kaksi merkkiosoitinta.

5. Luento: Rinnakkaisuus ja reaaliaika. Tommi Mikkonen,

9. Luento: Ohjelmistotyö. Tommi Mikkonen,

Ohjelmiston testaus ja laatu. Testausmenetelmiä

11. Javan toistorakenteet 11.1

12. Javan toistorakenteet 12.1

Tällä ohjelmoitavalla laitteella saat hälytyksen, mikäli lämpötila nousee liian korkeaksi.

A11-02 Infrapunasuodinautomatiikka kameralle

Stabilointi. Marja Hassinen. p.1/48

Se mistä tilasta aloitetaan, merkitään tyhjästä tulevalla nuolella. Yllä olevassa esimerkissä aloitustila on A.

Yleistä turvareleistä

Palomuurit. Palomuuri. Teoriaa. Pakettitason palomuuri. Sovellustason palomuuri

Tehtävä 2: Tietoliikenneprotokolla

Ohjelmiston testaus ja laatu. Ohjelmistotekniikka elinkaarimallit

Kontrollipolkujen määrä

Ongelma(t): Miten tietokoneen komponentteja voi ohjata siten, että ne tekevät yhdessä jotakin järkevää? Voiko tietokonetta ohjata (ohjelmoida) siten,

4. Luento: Prosessit ja säikeets. Tommi Mikkonen,

Rekursiolause. Laskennan teorian opintopiiri. Sebastian Björkqvist. 23. helmikuuta Tiivistelmä

Eye Pal Solo. Käyttöohje

Zeon PDF Driver Trial

Vikasietoisuus ja luotettavuus

CEM DT-3353 Pihtimittari

Ohjelmassa muuttujalla on nimi ja arvo. Kääntäjä ja linkkeri varaavat muistilohkon, jonne muuttujan arvo talletetaan.

Harjoitustyön testaus. Juha Taina

13. Loogiset operaatiot 13.1

811120P Diskreetit rakenteet

Sulautettujen järjestelmien skaala on niin laaja, että on erittäin vaikea antaa yleispätevää kuvausta siitä millainen on sulautettu järjestelmä.

Ohjelmoinnin peruskurssi Y1

Konsensusongelma hajautetuissa järjestelmissä. Niko Välimäki Hajautetut algoritmit -seminaari

Agenda. Johdanto Ominaispiirteitä Kokonaisjärjestelmän määrittely Eri alojen edustajien roolit Sulautetut järjestelmät ja sulautettu ohjelmointi

815338A Ohjelmointikielten periaatteet Harjoitus 4 vastaukset

1 Kannat ja kannanvaihto

7.4 Sormenjälkitekniikka

Sisällys. 3. Muuttujat ja operaatiot. Muuttujat ja operaatiot. Muuttujat. Operaatiot. Imperatiivinen laskenta. Muuttujat. Esimerkkejä: Operaattorit.

Tiedonsiirto helposti navetta-automaation ja tuotosseurannan välillä

Matematiikan tukikurssi, kurssikerta 2

Tutoriaaliläsnäoloista

3. Muuttujat ja operaatiot 3.1

Satunnaisalgoritmit. Topi Paavilainen. Laskennan teorian opintopiiri HELSINGIN YLIOPISTO Tietojenkäsittelytieteen laitos

Tehtävä 2: Säännölliset lausekkeet

811120P Diskreetit rakenteet

Koodaamme uutta todellisuutta FM Maarit Savolainen

Algoritmit 2. Luento 12 To Timo Männikkö


812347A Olio-ohjelmointi, 2015 syksy 2. vsk. X Poikkeusten käsittelystä

Perusteet. Pasi Sarolahti Aalto University School of Electrical Engineering. C-ohjelmointi Kevät Pasi Sarolahti

Sisällys. 12. Näppäimistöltä lukeminen. Yleistä. Yleistä

AS Automaatio- ja systeemitekniikan projektityöt

Ohjelmoinnin perusteet Y Python

etunimi, sukunimi ja opiskelijanumero ja näillä

LUKUJA, DATAA KÄSITTELEVÄT FUNKTIOT JA NIIDEN KÄYTTÖ LOGIIKKAOHJAUKSESSA

Lisää pysähtymisaiheisia ongelmia

LOAD R1, =2 Sijoitetaan rekisteriin R1 arvo 2. LOAD R1, 100

Alkuarvot ja tyyppimuunnokset (1/5) Alkuarvot ja tyyppimuunnokset (2/5) Alkuarvot ja tyyppimuunnokset (3/5)

Tietueet. Tietueiden määrittely

Luku 8. Aluekyselyt. 8.1 Summataulukko

Sähköä, ruutia Lähettäjän työskentelyä

Ehto- ja toistolauseet

815338A Ohjelmointikielten periaatteet Harjoitus 6 Vastaukset

Yhtälönratkaisusta. Johanna Rämö, Helsingin yliopisto. 22. syyskuuta 2014

Tarjolla tänää: Ohjelmiston toteutuksesta. Kuinka tulla hyväksi ohjelmoijaksi? CRC-kortit. Testilähtöinen kehittäminen JOT2007. Uudelleenrakentaminen

Kilpailemaan valmentaminen - Huipputaidot Osa 2: Taitava kilpailija. Harjoite 12: Kilpailuanalyysi. Harjoitteiden tavoitteet.

Koottu lause; { ja } -merkkien väliin kirjoitetut lauseet muodostavat lohkon, jonka sisällä lauseet suoritetaan peräkkäin.

Algoritmit 1. Luento 10 Ke Timo Männikkö

Tietorakenteet ja algoritmit

Luku 6. Dynaaminen ohjelmointi. 6.1 Funktion muisti

Ohjelmointi 1. Kumppanit

AU Automaatiotekniikka. Toimilohko FB

TIEP114 Tietokoneen rakenne ja arkkitehtuuri, 3 op. Assembly ja konekieli

Ohjelmoinnin peruskurssi Y1

Ohjelmoinnin perusteet Y Python

Transkriptio:

180 Sulautettu ohjelmointi 11. Vikasietoisuus Sulautetut järjestelmät toimivat usein ilman ihmisen välitöntä ohjausta. Siksi järjestelmä ei vikaantuessaan saa luottaa siihen, että ihminen korjaisi ongelman, vaan järjestelmän tulee selvitä vikaantumisesta itse ainakin niin pitkälle, että vika ei aiheuta lisää vikoja. Käymme seuraavassa läpi joitakin vikasietoisen järjestelmän kehittämiseen liittyviä seikkoja. Lisäksi esittelemme lyhyesti turvallisuusvaatimuksia, jotka on usein otettava huomioon vikasietoisia sulautettuja järjestelmiä toteutettaessa. 11.1 Vikasietoisuuden käsitteitä Vikasietoisten järjestelmien osalta sanasto ei ole täysin vakiintunut. Tässä käytetään sanaa vika (fault) tarkoittamaan kaikkein matalimman tason poikkeuksellista tai viallista toimintaa. Virhe tai virhetila (error) on järjestelmän (poikkeuksellinen) tila, johon siirrytään, kun vika tapahtuu tai se havaitaan. Virhetoiminto (failure) taas on järjestelmän väärä toiminta virhetilanteessa. Järjestelmän toimintaa voidaan kuvata turvallisuus- ja elävyysominaisuuksien avulla. Turvallisuusominaisuus (safety property) tarkoittaa tässä sitä, että ohjelma (tai laite) ei tee mitään sellaista, mitä se ei saisi tehdä, eli se tekee vain haluttuja toimintoja tai ei mitään. Elävyysominaisuus (liveness property) tarkoittaa, että laite tekee jotain, eikä vain ole. Jos laitteen turvallisuusominaisuudet säilyvät, se on luonnollisesti turvallinen käyttää, mutta se voi pysähtyä, jos elävyysominaisuudet eivät säily. Jos taas vain elävyysominaisuudet säilyvät, laite tekee jotain, mutta voi olla vaaraksi itselleen tai ympäristölleen. Vian sattuessa järjestelmä siirtyy virhetilaan. Vikasietoisuus voidaankin määritellä sen avulla, miten tämä siirtymä näkyy järjestelmän toiminnassa elävyys- ja turvallisuusominaisuuksien säilymisessä (katso taulukko 11.1).

Vikasietoisuus 181 Taulukko 11.1: Vikasietoisuuden neljä muotoa elävyys säilyy elävyys ei säily turvallisuus säilyy peittävä vikaturvallinen turvallisuus ei säily ei-peittävä ei vikasietoisuutta On erittäin tärkeä tiedostaa, että vikasietoisuus määritellään jotain tiettyä ominaisuutta kohti. Koko järjestelmän kattavaa peittävää vikasietoisuutta ei ole, sillä järjestelmä voi toipua vain sellaisista vioista, joita se osaa odottaa. 11.1.1 Ei vikasietoisuutta Jos vikasietoisuutta jotain tapahtumaa kohti ei ole olemassa, on kyse siitä, että kyseistä tapahtumaa ei osata odottaa. Järjestelmän käyttäytyminen on tämän jälkeen täysin satunnaista. Käytännön sulautetuissa järjestelmissä tämä voi tarkoittaa laitteen pillastumista ja toimimista täysin kontrollin ulkopuolella tai täydellistä jumiutumista. Tavallisella yleistietokoneella tämä voi aiheuttaa ohjelman päättymisen tai koko käyttöjärjestelmän kaatumisen riippuen siitä, missä ja minkälainen vika on. Mutta voihan käydä niinkin, että vaikka asiaa ei ole ennakoitu, se hoituu sattumalta pois päiväjärjestyksestä, mutta tähänhän ei pidä luottaa. Taulukon 11.1 perusteella tällä tasolla ei säily elävyys eikä turvallisuus. Turvallisuuden puuttuminen tarkoittaa sitä, että voidaan tehdä asioita, mitä ei pitäisi tehdä. Elävyyden puuttuminen tarkoittaa sitä, että haluttuja asioita ei tehdä, mutta järjestelmä voi silti tehdä jotain. 11.1.2 Ei-peittävä vikasietoisuus Jos virhetilanteessa turvallisuusominaisuudet eivät säily, mutta elävyysominaisuudet säilyvät, järjestelmä on ei-peittävästi vikasietoinen (nonmasking fault tolerance). Elävyys takaa siis sen, että jotain haluttua tehdään, mutta tehdyt laskennat voivat antaa vääriä tuloksia. Koska turvallisuus ei säily, tämä tarkoittaa sitä, että järjestelmä reagoi virheen jälkeen jotenkin väärin. Aivan tällaisenaan ei-peittävä vikasietoisuus ei ole kovin houkutteleva, mutta sitä voidaan käyttää, mikäli järjestelmä on itsestään stabiloituva (self-stabilizing) eli viasta huolimatta järjestelmä ennen pitkää päätyy takaisin turvalliseen tilaan. Itsestabiloitumista on havainnol-

182 Sulautettu ohjelmointi Toteutunut laskenta Laskennan sallitut rajat Toipumisjakso Virhetilanne Kuva 11.1 Viasta toipuva laskenta Aika listettu kuvassa 11.1. Vaikka tämä vaikuttaa siltä, että viasta toivutaan täysin, kyseessä ei ole peittävä vikasietoisuus, koska laskenta rikkoo alkuperäisiä turvallisuusominaisuuksia jonkin aikaa. 11.1.3 Vikaturvallinen järjestelmä Jos virhetilassa vain turvallisuusominaisuudet säilyvät, järjestelmä on vikaturvallinen (fail safe). Tässä tilassa järjestelmä siis takaa, että mitään pahaa ei tapahdu, mutta ei lupaa, että mitään hyvääkään tapahtuisi. Esimerkiksi vioittunut ABS-jarrujärjestelmä toimii juuri näin: vian sattuessa jarrut toimivat (siis paha asia jarruttomuus on vältetty), mutta ABS:n hyötyjä ei saada esille (eli hyvä asia menetetään). Koska peittävä vikasietoisuus on hyvin vaikea saavuttaa, ja turvallisuusominaisuudet ovat tai niitä pidetään yleensä elävyysominaisuuksia tärkeämpänä, tämä on yleisin vikasietoisuuden muoto. Kuten edellisessä kohdassa, tässäkin on mahdollista toipua takaisin normaalitoimintaan. Tämäkään ei ole peittävästi vikasietoinen, koska osa järjestelmää on hetken toimimatta.

Vikasietoisuus 183 11.1.4 Peittävästi vikasietoinen järjestelmä Mikäli virhetilassa käyntiä ei voi käyttäytymisestä havaita, järjestelmä on kyseisen vian osalta peittävästi vikasietoinen (masking fault tolerance). Tällöin järjestelmä täyttää viasta huolimatta sekä turvallisuusettä elävyysominaisuudet. Käytännössä tämä vaatii toipumisrutiineita, mutta nämä voivat olla kätkettynä normaalin toiminnan ehdollisiin osiin. 11.2 Turvallisuuskäsite Turvallisuus tässä kohdassa viittaa englannin kielen termiin safety (kontrastina termi security, joka liittyy oikeudettoman käytön estämiseen). Yleisesti turvallisuus tarkoittaa siis sitä, että laite on turvallinen käyttää. Kohdassa 11.1 esitelty turvallisuusominaisuus on teknisempi, tarkemmin rajattu termi. Osa turvallisuusvaatimuksista on peräisin viranomaisilta, tyyppihyväksynnästä ja muilta vastaavilta instansseilta, jotka pyrkivät suojelemaan esimerkiksi ohikulkijoita tai laitteen käyttäjiä, mutta jotkut turvallisuusominaisuudet liittyvät laitteen toteutukseen, erityisesti siihen, että jonkun asian vikaantuessa laitteelle itselleen ei koidu vaaraa. Silloin, kun rakennetaan laitetta, johon liittyy todella tiukkoja turvallisuusvaatimuksia, on tavallista rakentaa turvallisuusjärjestelmä, joka on irrallinen muusta laitteen ohjausjärjestelmästä. Tämän riippumattomuuden avulla on mahdollista taata riittävällä todennäköisyydellä, että virhetoimintoja ei tapahdu. Lisäksi turvallisuusjärjestelmä perustuu usein kokonaan muuhun teknologiaan kuin varsinainen ohjausjärjestelmä, jolloin sen vaikutus ohjelmistovaatimusten kannalta voi olla vähäinen. Esimerkiksi hissin tapauksessa lienee riittävää, että on automaattinen pysäytysmekanismi, joka pysäyttää hissin sen nopeuden noustessa liian suureksi, tai että metsäkone pysähtyy, jos joku liikkuu sen toiminta- tai vaara-alueella. Toisaalta tilanne ei ole aina niin yksinkertainen, että voitaisiin rakentaa irrallinen pysäyttävä varajärjestelmä. Esimerkiksi maata radallaan kiertävän satelliitin tapauksessa tämä saattaa olla täysin mahdotonta, sillä laite saattaisi menettää ohjattavuutensa täysin, jos se sammuttaisi kaikkien ohjausjärjestelmiensä toiminnan jonkun ongelmatilanteen sattuessa. Sama pätee moneen muuhun autonomiseen sulautettuun järjestelmään. Luonnollisesti ongelma on myös aiempaa hissi- ja

184 Sulautettu ohjelmointi metsäkone-esimerkkiä suoraviivaisempi, sillä satelliitin tapauksessa ihmishenkiä ei varmaankaan olisi vaarassa, ainakaan välittömästi. 11.3 Vikasietoisuuden saavuttaminen Kohdassa 11.1 olleista vikasietoisuuden kuvauksista nähtiin, mitä mikin vikasietoisuuden muoto tarkoittaa. Mielenkiintoisempaa lienee tutkia sitä, miten vikasietoisuus saavutetaan. Jos vertaamme peittävästi vikasietoista järjestelmää järjestelmään, jossa ei ole lainkaan vikasietoisuutta, huomaamme niiden olevan lähes samanlaisia. Erona peittävästi vikasietoisella järjestelmällä ei-vikasietoiseen järjestelmään verrattuna on vain se, että vikaa osataan odottaa, ja sen tultua osataan toimia oikein. Tästä voimme päätellä, että välttämätön osa vikasietoisuutta on mahdollisen vian tunnistaminen ja sen tapahtumamahdollisuuden ottaminen huomioon. Tarvitaanko vian käsittelemiseen sitten erillisiä toimenpiteitä vai ei, onkin sitten jo tapauskohtaista. Tavallisesti tarvitaan jotain, joka hoitaa poikkeuksellisen tilanteen. Käytännön ohjelmoinnissa tämä tarkoittaa sitä, että ohjelmassa on vikaan liittyvä testi ja ehdollinen osa, joka huolehtii vikatilanteesta. Kyseessä on tällöin ohjelmakoodin redundanssi. Jotta voidaan testata jotain arvoa vian havaitsemiseksi, tulee osa arvoista olla sellaisia, jotka ilmaisevat vikatilanteen. Jos järjestelmässä käytettyjen muuttujien kaikki arvot eivät ole sallittuja, on kyseessä datan redundanssi. Yhteenveto perusperiaatteista: Vikasietoisuuden saavuttamisen välttämätön ehto on se, että vikaan on varauduttu ja että vikatilanne pystytään tunnistamaan. Tunnistamiseen tarvitaan joko ohjelmakoodin tai tiedon redundanssia, yleensä molempia. Tunnistamisen jälkeen voidaan tehdä korjaavia toimenpiteitä. 11.3.1 Datan redundanssi Määritelmänmukaisesti voidaan sanoa, että sellainen tieto, jota ei (suoranaisesti) käytetä koskaan normaalitoiminnan aikana, on redundanttista. Datan redundanssia käytetään yleisesti tietoliikenteessä siirtoteiden epäluotettavuuden takia. Käytännössä nämä ovat erilaisia pariteettijärjestelmiä, joilla voidaan tunnistaa, mikäli lähetetyn sanoman bitit ovat muuttuneet matkalla. Pariteettibitit eivät ole idioottivarmoja, koska tarpeeksi monen bitin muutos voi tehdä viestistä oikean näköisen, jolloin se hyväksytään, mutta tulkitaan väärin. Tässä, niin kuin aina

Vikasietoisuus 185 vikamahdollisuuksia tutkittaessa, täytyy ottaa huomioon, millaisissa tilanteissa bitit voivat muuttua, ja pyrkiä tekemään sellainen pariteettitarkistus, joka varmasti huomaa tyypilliset muutokset. Toisaalta epätyypilliset muutokset voivat jäädä huomaamatta. Vaikka tiedonsiirrossa pariteetit ovat yleisiä, ne eivät ole kovin yleisiä itse tiedon säilyttämisessä lukuunottamatta joitain koodiluonteisia tietokenttiä kuten henkilötunnus, pankkitilin numero ja pankkisiirron viitenumero. Tämän takia virheellistä tietoa ei yleensä pystytä tunnistamaan. Mikäli tiedon virheellinen muuttuminen on mahdollista, tulee siihen lisätä joko pariteettikenttiä tai tallettaa tieto moneen paikkaan vikatilanteen tunnistamiseksi. Mikäli tila-avaruuden kaikki tilat ovat sallittuja, tarkoittaa tämä sitä, että vikaa ei voi ilmetä tila-avaruudessa. Näin käy hyvinkin helposti, sillä jo yksinkertaiset aritmeettiset tehtävät johtavat siihen, että tilaavaruus on erittäin suuri, teoriassa ääretön. Olettaen, että voimme tunnistaa vian tila-avaruudessa, tämä ei vielä kerro, että järjestelmä toimii niin kuin pitääkin. Vika voi olla vaikkapa siinä, että laskennassa esiintyvät peräkkäin sellaiset tilat, joiden ei pitäisi voida esiintyä peräkkäin. Esimerkki: tähdätty ase laukeaa, vaikka hupaisinta ei ole painettu. Kumpikin tila tähtääminen ja laukaisu ovat sinänsä aseelle sallittuja. Jälkimmäinen vain ei saa tapahtua ilman liipaisua. 11.3.2 Ohjelmakoodin redundanssi Koodin redundanssi tarkoittaa sitä, että ohjelmassa on haaroja, joita ei koskaan suoriteta, mikäli vikaa ei ilmene. Tyypillinen tällainen haara on esimerkiksi lukuoperaation jälkeen tehty testi lukemisen onnistumisesta. Normaalitoiminnassa ei koskaan suoriteta koodia, jonka tehtävänä on ratkaista lukuvirheen jälkeinen ongelma. Seuraava esimerkki yrittää valaista asiaa. Oletetaan, että aliohjelma ali (ja vain tämä aliohjelma) päivittää muuttujaa x, joka voi saada arvot A, B ja C, ja jonka alkuarvo on A. Mikäli aliohjelma näyttää seuraavalta: enum { A, B, C } x = A; void ali (void) { if (x == A) x = B; else if (x == B) x = A; }

186 Sulautettu ohjelmointi se ei ole vikasietoinen. Näin sen takia, että vaikka x ei voi tämän mukaan olla koskaan C (alkuarvohan oli A, ja runko vain vaihtaa x:n arvoa A:n ja B:n välillä), virhetilanteessa sen arvo voi tulla C:ksi, koska muuttujan arvoalueeseen kuuluu arvo C. Niinpä seuraava versio olisikin vikasietoinen: void ali (void) { if (x == A) x = B; else if (x == B) x = A; else if (x == C) { // Joitain toipumisoperaatioita, ja arvon saattaminen // normaaliksi x = A; } } Toinen esimerkkiohjelma sisältää hieman erilaisen vikamahdollisuuden (edellisen lisäksi): int i = 0; while (1) { // tekee jotain i++; if ( i == 10) break; // tekee taas jotain } Vaikka ohjelma tällaisena toimiikin, ongelmia voi tulla, jos siihen myöhemmin lisätään muuttujaa i suoraan tai epäsuorasti päivittävä käsky tai muuttujan i arvo muuttuu jollain muulla tavoin virheellisesti. On itse asiassa yhdentekevää, kumpaan suuntaan muutos tapahtuu, koska jos i vähenee, silmukka pitenee aiottua pitemmäksi, ja jos i kasvaa, silmukka joko lyhenee tai siitä voi tulla ikuinen. Vaikka ei ratkaisekaan koko ongelmaa, parempi olisi, jos ehtolauseen ehto olisi muodossa i >= 10, sillä silloin ainakin ikuinen silmukka saadaan estettyä. Tässä tapahtuu siis itsestabiloituminen. Stabiloitumista saadaan siis käytännössä aikaan muun muassa siten, että rajaehdot eivät ole yhtäsuuruusehtoja, vaan pienempi tai suurempi kuin -operaattoreita. Näin vahingossa tapahtuvat rajojen ylitykset eivät räjäytä ohjelmaa silmille 26. Ohjelman redundanssi tarkoittaa siis sellaista osaa ohjelmasta, jota ei suoriteta kuin poikkeuksellisessa tilanteessa. Yksinkertaisimmillaan tämä on tavallinen ehtolause, jonka testin jälkeen suoritetaan vikatilanteen vaatima poikkeuksellinen toimenpide. Erityisesti tulisi

Vikasietoisuus 187 muistaa aina tarkistaa käyttöjärjestelmäpyyntöjen onnistuminen, sillä tavallisesti ohjelmalla ei ole mahdollisuutta etukäteen varmistua siitä, että kutsu onnistuu. Ilman ydintä toimivassa sulautetussa järjestelmässä vastaava asia on aina tarkistaa oheislaitteen tilarekisteristä, että edellinen toiminto on onnistunut. Toimivuustestien huono puoli on se, että ne rikkovat ainakin visuaalisesti ohjelman normaalin toiminnan rakenteet niin, että sitä on vaikea hahmottaa ohjelmakoodista. Osittain tämän takia on joissain ohjelmointikielissä poikkeusmekanismi vikatilanteiden hallintaan. Poikkeuskäsittelijöitä tulee käyttää harkitusti. On mietittävä, milloin on kyseessä varsinainen vika, joka toteutetaan poikkeuskäsittelijällä, ja milloin on kyseessä vain kielteinen vastaus, joka toteutetaan palauttamalla sopiva paluuarvo. Esimerkki koettaa valaista asiaa: Tietokantaan tehtävä kysely "hae nämä ehdot täyttävät tietueet" palauttaa tyhjän listan, jos yhtään tietuetta ei löydy. Tämä ei ole poikkeustilanne. Toisaalta tietokannassa oleva virheellinen tieto, esimerkiksi sisäinen viittaus olemattomaan komponenttiin, on taas selvästi vikatilanne ja voidaan ratkaista poikkeuksella. Poikkeuskäsittely on suhteellisen raskas operaatio. Normaali paluu aliohjelmasta voi olla 10000 kertaa nopeampi kuin paluu poikkeuskäsittelijän kautta. 11.3.3 Vikojen havaitsemista Edellä olevia redundansseja toteutetaan monin tavoin. Tähän on kerätty muutama esimerkki. Jos ohjelmiston koodi on fyysisesti talletettu haihtumattomaan muistiin, perinteinen, laajasti käytetty tapa on tallettaa muistiin myös tarkistussumma, jonka avulla nähdään, onko ohjelma muistissa siinä muodossa kuin pitääkin. Tätä voidaan toteuttaa myös ajon aikana: vikaantumista valvova rutiini laskee suoritettavan ohjelmiston tarkistussummaa ja vertaa sitä referenssiarvoon. Jos arvo muuttuu, voidaan päätellä että sovelluksen koodi muistissa on korruptoitunut, ja se pitää ladata uudelleen. Samanlaista tekniikkaa voidaan käyttää myös ohjelmistojen parametreille. Toinen melko usein käytetty tekniikka on käyttää 26. Kaikki eivät ole tätä mieltä. Vastakkaisen näkemyksen mukaan vika pitääkin saada näkyviin, jotta se saadaan korjattua. Tässä esitettyä näkemystä tukee se, että usein lievästi virheellinen on pienempi paha kuin se vaihtoehto, että tosivirhe pääsee esille.

188 Sulautettu ohjelmointi assertioita eli redundantteja ehtoja, ja kytkeä niiden virhetilanteiden käsittely toipumisrutiineihin. Lisäksi toiminnot, jotka pitää suorittaa toistuvasti järjestelmän tilan hallittuna pitämiseksi ovat tavallisia. Tämäntapaisia rutiineja, joissa ohjelmallisesti käydään ilmoittamassa että ohjelmisto on edelleen suorituksessa, kutsutaan esimerkiksi vahtikoiriksi (watchdog) tai pulssiksi (heartbeat). Joskus toteutuksissa näillä on erilainen logiikka, esimerkiksi toinen voi olla varattu ohjelman suorituksessa olon todentamiseen ja toinen varsinaisen laskennan etenemisen tai laitteen ohjaamisen varmentamiseen. 11.4 Ohjelmisto- ja laitteistovikasietoisuuden eroista Tarkastelemme tässä kohtaa hieman laitteisto- ja ohjelmistovikojen eroja. 11.4.1 Laitteistoviat Tyypillinen laitteistovika on transienttimainen, eli toiminto ei satunnaisesti onnistu, mutta itse laitteessa ei ole varsinaista vikaa. Transientti voi johtua ulkoisesta tekijästä (sähkömagneettinen häiriö kuten moottorin käynnistys tai sammutus, tärinä, lämpötila) tai se voi olla vain komponenttien epätäydellisyydestä johtuvaa satunnaista "kohinaa" (hyvä laitteistosuunnittelu kyllä sietää isojakin toleransseja). Yrittämällä uudestaan toiminto voi sitten jo onnistuakin. Tällaisen vian voi tunnistaa laitteisto itse, ja se saattaa myös itse tehdä automaattisen uusintayrityksen. Hyvin samankaltainen on monien tietoliikenneprotokollien ratkaisu lähettää viesti uudelleen, jos sitä ei kuitata. Vaikka protokollien kohdalla ratkaisu onkin tehty ohjelmistolla, on kyseessä laitteistotasolla tapahtuneen häiriön kiertäminen. Varsinainen laitteistoredundanssi tarkoittaa laitteiden monistamista tai niiden suunnittelua niin, että yksittäisen signaalin virhe ei aiheuta koko järjestelmän virhetoimintaa. Kumpikin tarkoittaa käytännössä sitä, että laitteiston toteuttamiseen käytetään enemmän komponentteja kuin mitä minimissään olisi pakko, jos niiden toimintaan voisi täysin luottaa. Laitteen monistamisessa ongelmana on yhä viallisen laitteen tunnistaminen jos kaksi laitetta tuottaa eri tuloksen, kumpi toimi oikein? Koska laitteistoviat ovat usein vain häiriöitä ilman varsinaista pysyvää vikaa, on tavallinen ratkaisu pakottaa laite yrittämään toimintoa uudestaan.

Vikasietoisuus 189 Toimilaitteiden monistaminen on suhteellisen harvinaista, mutta siihen on päädytty tilanteissa, joissa järjestelmältä vaaditaan suurta luotettavuutta. Tällaisia järjestelmiä ovat esimerkiksi puhelinkeskukset, joissa riippuen keskuksen tärkeysasteesta on joko monella identtisellä toimilaitteella yksi yhteinen varalaite tai jokaisella laitteella oma varalaite. Joissain järjestelmissä molemmat (tai kaikki) yksiköt tekevät jatkuvasti aktiivilaskentaa, ja vertailujärjestelmä huolehtii siitä, että virheelliset laskennat joko tehdään uudestaan tai virheellinen yksikkö suljetaan pois järjestelmästä. Ongelmaksi tulee tietenkin se, voiko vertailun tekevään järjestelmään luottaa. Mikäli monella toimilaitteella on yksi varalaite, ei varalaite voi olla valmiina ottamaan vastuuta laskennasta heti vian ilmettyä, koska ei tiedetä, minkä laitteen se tulee korvaamaan. Varalaite on silloin "kylmä", ja vian ilmettyä se pitää lämmittää, ennen kuin se voi ottaa täyden vastuun toiminnasta. Mikäli varsinaisen laitteen vika on tarpeeksi paha, tämä aiheuttaa katkon toiminnassa. Jos jokaisella laitteella on oma varalaite, se voi olla "lämpimänä" eli toisin sanoen sen ohjelmat ja tiedot vastaavat täysin "kuumana" olevan yksikön tietoja. Vian ilmetessä vaihto on nopea, eikä aiheuta katkoja toiminnassa; korkeintaan juuri vaihdon aikana tapahtuvat muutokset saattavat epäonnistua. Vaikka tietotekniikassa varalaite on yleensä identtinen varsinaisen laitteen kanssa, näin ei välttämättä tarvitse olla. 11.4.2 Ohjelmistoviat Laitteistoviat, joihin varaudutaan, ovat laitteeseen käytössä jostain syystä tulevia vikoja. Viastatoipuminen on joko uusi käyttöyritys, varalaitteen käyttöönotto tai laitteen toiminnan korvaaminen jollain toisella järjestelmällä. Ohjelmistossa vikasietoisuuteen varautuminen näkyy juuri tätä näkökohtaa vasten: testataan laitteiston toimintaa, ja pyritään toimimaan jonkin tapahtumalogiikan mukaan, jos vika ilmenee. Mutta tämä lähestymistapa ei varaudu itse ohjelmiston vikoihin, eikä sitä suoraan voida sellaisena ohjelmistoissa käyttää. Ohjelmiston vikasietoisuutta on redundanssin lisääminen niin kuin laitteistopuolellakin. Tämä voi tarkoittaa sitä, että jokin asia toteutetaan kahdella eri algoritmilla, joiden tuloksia verrataan. Poikkeavat tulokset kertovat virheen tapahtuneen, mutta eivät kerro, kumpi ratkaisuista on oikea. Päätöstä voidaan helpottaa laskemalla tulos kolmella eri algoritmilla, ja päättää tulos äänestämällä. Äänestämisessä on tietenkin ongelmana se, voidaanko äänestysrutiiniin luottaa, mutta jos itse al-

190 Sulautettu ohjelmointi Kuva 11.2 Suunnittelumenetelmien heikkoudet. Kuvassa on kolmen eri suunnittelumenetelmän heikkouksia kuvattu alueina. Mikäli järjestelmä toteutetaan kaikilla näillä, voidaan niiden osaalueiden osalta, joilla heikkouksia vain yhdessä menetelmässä, virheet korjata äänestämällä. Niillä alueilla, joilla heikkouksia on kahdella järjestelmällä, vika voidaan havaita, jos virheelliset laskennat tuottavat eri tulokset, muuten järjestelmä saattaa äänestää oikean laskennan kumoon. Jos kaikki järjestelmät epäonnistuvat, virhe havaitaan, mutta sitä ei voi korjata. Koska menetelmän heikkous ei välttämättä johda virheeseen, kuvaus on pessimistinen goritmi on hyvin monimutkainen verrattuna äänestysrutiiniin, järjestelmän luotettavuus kasvaa. Yleisesti ottaen varsinaisessa ohjelmistovikasietoisuudessa ei ole kyse toimivan laitteen vikaantumisesta, vaan suunnitteluvirheisiin varautumisesta. Eri suunnittelumenetelmillä tai algoritmin suunnittelun lähtökohdilla pyritään siihen, että menetelmien tai algoritmien heikkoudet kompensoisivat toisensa. Jos äänestyksen yksinkertaistamiseksi lähdemme siitä, että meillä on kolme eri versiota ohjelmistoista, pyritään ne valitsemaan niin, että niiden heikkoudet osuvat mahdollisimman pitkälle eri alueille (katso kuva 11.2). Montakaan versiota samasta järjestelmästä ei takaa, että vika aina löydettäisiin, sillä virhetoiminto voi olla sama kaikesta huolimatta. Tällainen ilmiö tuli vastaan aikoinaan Ada-kääntäjissä. Ada-kielen kääntäjät on validoitava, eli niiden täytyy tuottaa esimerkinmukainen

Vikasietoisuus 191 koodi annetusta Ada-kielisestä ohjelmasta. Validointisetissä oli virhe, joten kaikki validoidut, "oikein toimivat" kääntäjät toimivat väärin. 11.4.3 Ohjelmiston sisäisestä vikasietoisuudesta Yleensä sulautetut järjestelmät kannattaa suunnitella siten, että paitsi kattava testaus myös ajonaikainen diagnostiikka on mahdollista. Tällöin ohjelman virheellinen toiminta voidaan havaita ajoissa, toivottavasti jo ennen kuin mitään suurempaa vahinkoa pääsee tapahtumaan. Varsin kriittinen komponentti on myös kunnonvalvonnan kunnonvalvonta, eli se osa järjestelmää, joka tarkkailee diagnostiikan toimintoja. Ohjelmistosuunnittelussa kannattaa myös pyrkiä siihen, että diagnostiikan havaitsemat ongelmat raportoidaan riittävällä tasolla, jolloin varsinaisen ongelman lisäksi kannattaa kerätä tietoa myös muista käynnissä olevista tapahtumista ja esimerkiksi ympäristön tilasta (lämpötila, ajonopeus, ja niin edelleen). Ohjelmistojen sisäiseen vikasietoisuuteen (tai virheettömyyteen) on myös joitakin työkaluja. Ehkä kaikkein tunnetuin tapa toteuttaa sisäisesti vikasietoisia ohjelmistoja on defensiivinen ohjelmointi, ohjelmointityyli, jossa pyritään välttämään virheitä johdonmukaisesti toimien. Käytännön ohjelmistosuunnittelussa defensiivinen ohjelmointi kattaa ainakin kolme eri ulottuvuutta: Laatu yleensä. Defensiivisen ohjelmoinnin yhteydessä pyritään jo lähtökohtaisesti korkeaan laatuun, jossa ohjelmointivirheille ei jätetä tilaa. Yleensä tähän yhdistyy myös testaustyökalujen käyttö ja korkea testikattavuus. Ohjelmakoodin luettavuus. Pyrkimys luettavampaan ohjelmakoodiin mahdollistaa sen, että ohjelman toiminta pystytään varmentamaan helpommin esimerkiksi katselmoinnein. Tähän pyritään esimerkiksi rajoittamalla vaihtoehtoisten rakenteiden käyttöä tyylioppaiden avulla. Oletusten vähyys. Defensiivisessä ohjelmoinnissa pyritään varmistamaan, että ohjelma toimii oikein kaikilla syötearvoilla. Toisin sanoen oletukset, joiden varaan ohjelman toiminta rakentuu, pyritään minimoimaan. Kaikki oletukset kirjataan näkyviin esimerkiksi kommentteina ohjelmakoodiin tai muuhun dokumentointiin. Varsinaisen defensiivisen ohjelmoinnin lisäksi on mahdollista käyttää assertioita, toisin sanoen totuusarvoisia lausekkeita, joiden avulla voidaan löytää ohjelmista ajatusvirheitä.

192 Sulautettu ohjelmointi Joissakin ohjelmointikielissä, kuten esimerkiksi jälleen kerran Adassa, on lisäksi mahdollista käyttää niin sanottu alityypin käsitettä, jonka avulla voidaan muuttujien arvoaluetta rajoittaa ja sitä kautta hyödyntää tyyppijärjestelmän tarjoamia mahdollisuuksia löytää ongelmia. Luonnollisesti tämä vaatii ohjelmoijalta kurinalaisuutta käyttää alityyppejä (ja tarvittaessa edelleen niiden alityyppejä), jotka on sopivasti rajoitettu esimerkiksi valmiiden kokonaislukumuuttujien sijaan. Tällöin vääräntyyppiset parametrit on helppo löytää mahdollisesti jo käännösvaiheessa, kun taas esimerkiksi C:ssä usein käytetty tapa käyttää kokonaislukuja oikeastaan kaikkeen mahdollistaa sen, että ongelmiin törmätään vasta myöhemmin ja ongelman selvittämiseksi tarjolla on paljon vähemmän johtolankoja. Lisäksi käytettävissä ovat normaalit ohjelmistotuotannon hyvät käytännöt, kuten testiohjattu ohjelmistokehitys sekä mahdollisuuksien mukaan kattava regressiotestiaineisto, joka voidaan tuottaa esimerkiksi saman järjestelmän aiemmalla versiolla. On kuitenkin syytä pitää mielessä, että johtuen sulautettujen järjestelmien usein vaatimasta rinnakkaisuudesta ja aikakriittisyydestä on monien ongelmien löytäminen testaamalla oikeastaan mahdotonta. 11.5 Vika-analyysistä Kuten aiemmin on jo todettu, vikasietoisuutta on vain etukäteen tunnistettuja vikoja kohtaan. Yleisesti ottaen vikasietoisuutta toteutettaessa analysoidaan mahdolliset viat, miten niihin voidaan reagoida ja viasta toipua. Näin tehty analyysi voidaan esittää tapahtumalogiikkana, jossa kuvataan ongelma ja siihen tehtävät reaktiot. Tällainen tapahtumalogiikka siinä esimerkkitilanteessa, että suunnistuskilpailun ajanoton sähkönsyöttö katkeaa, on kuvassa 11.3. Tapahtumalogiikan eri haaroille voidaan arvioida todennäköisyydet, jolloin voidaan päätellä, millä todennäköisyydellä jokin vika aiheuttaa minkinlaista vahinkoa. Tapahtumalogiikoiden avulla voidaan hyvin arvoida erilaisten järjestelmien toimintavarmuutta, mikäli eri komponenttien luotettavuus tunnetaan. Tämän idean siirtäminen tietotekniikan laitteistovikojen kuvaamiseen onnistuu hyvinkin, mutta ohjelmistovikoihin analyysiä on vaikea ulottaa. Mikä on todennäköisyys sillä, että testauksesta selvinnyt ohjelma ei toimikaan oikein? Vastaus on niin monen tekijän funktio, että sen arvioiminen on lähes mahdotonta.

Vikasietoisuus 193 aggregaatti käynnistyy sähkönsyöttö katoaa akut kunnossa aggregaatti käynnistyy OK OK 30 min, jonka jälkeen käsiajanottoon Pieni katkos, ei ongelmia tuloksissa Tulokset viivästyvät, mutta ne saadaan siirrytään käsiajanottoon Tuloksia katoaa, kilpailu tai sarjoja hylätään Kuva 11.3 Tapahtumalogiikka: Sähköisen ajanoton sähkönsyöttö katoaa. Kuvassa on tapahtumalogiikka siinä tilanteessa, että suunnistuskilpailun ajanoton sähkönsyöttö jostain syystä lakkaa. Toipumisyrityksen (haarapisteen) jälkeen ylempi vaihtoehto tarkoittaa yrityksen onnistumista ja alempi epäonnistumista. Lisähuomio: Vikatilanteen hoitavan järjestelmän täytyy itsessään olla kyseiselle vialle vikasietoinen. Muuten tilanne on kuin eräässä tietokonekeskuksessa, jossa oli sähkökatkosten varalle dieselgeneraattori. Generaattori käynnistettiin kokeeksi kerran kuukaudessa, ja kaikki toimi hyvin. Kun oikea sähkökatko sitten tuli, generaattori ei käynnistynytkään. Syynä oli se, että sen käynnistysmoottori sai sähkönsä sähköverkosta eikä akustosta. Varajärjestelmä ei siis itsessään ollut vikasietoinen. 11.6 Esimerkkejä vikasietoisista järjestelmistä Avaruussukkula on yksi tunnetuimpia vikasietoisia järjestelmiä. Siinä on viisi tietokonetta, joissa on kahden eri valmistajan tekemät ohjelmat. Koneiden lukumäärällä koetetaan varautua laitteistovikoihin, ja eri valmistajien ohjelmistoilla suunnitteluvikoihin. Toinen kuuluisa esimerkki epäonnistumisen kautta on Ariane 5 -kantoraketti. Ensimmäinen Ariane 5 räjähti hieman lähtönsä jälkeen. Syynä oli itse asiassa ohjelmistomäärittelyn virhe, mutta tapausta voidaan tarkastella myös vikasietoisuuden kannalta. Vian aiheuttanut järjestelmä oli raketin maanopeutta laskevassa navigointiyksikössä. Laitteistovian varalta järjestelmässä oli tämä yksikkö kahdennettu. Kun

194 Sulautettu ohjelmointi kantoraketti laukaistiin, tapahtui laskennassa ylivuoto. Koska järjestelmää suunnitellessa oli päätelty, että ylivuoto on mahdoton, aiheutti tämä käsittelemättömän poikkeuksen ohjelmaa ajettaessa. Tämän tullessa ohjelmisto taas päätteli, että laitteistossa on tapahtunut virhe ja sulki navigointiyksikön pois käytöstä. Koska varalaite ajoi täsmälleen samaa ohjelmaa, myös se teki saman virheen ja sekin suljettiin pois käytöstä. Tämän jälkeen järjestelmä ei saanut mitään navigointitietoja ja joutui epästabiiliin tilaan, jonka taas itsetuhojärjestelmä tunnisti ja räjäytti raketin muiden vahinkojen välttämiseksi. Mikäli suunnitteluvaiheessa ei olisi tehty mainittua arviointivirhettä, olisi ylivuotoon varauduttu. Kahdella eri ohjelmistolla olisi saattanut olla sen verran erilainen laskenta, että toisessa ylivuotoa ei olisi tullut. Jos edelleen laitteistot olisivat olleet eri suorittimella varustettuja, tämäkin olisi saattanut estää vian. Itse asiassa tuhoutunut Ariane 5 oli vikasietoinen. Sen vikasietoisuus oli optimoitu turvalliseksi: Ensin vialliseksi päätellyn yksikön toiminta keskeytettiin (turvallisuus), sitten itsetuhomekanismi toimi, jotta jo tuhoontuomittu kantoraketti aiheuttaisi mahdollisimman vähän tuhoa ympäristölleen syöksyessään mereen. Edellisen kaltaisten tapausten takia on tärkeää, että kokonaisjärjestelmässä on mahdollisimman vähän tai ei ollenkaan sellaisia osajärjestelmiä, joissa luotetaan vain yhteen laitteeseen, suunnittelumentelmään, ohjelmaan (kääntäjät mukaanlukien!) ja niin edelleen. 11.7 Vikasietoisuuden luokittelua Vikasietoisuus on aina määritelty kutakin vikaa tai vikayhdistelmää kohti erikseen. Mikään järjestelmä ei voi olla kaikille mahdollisille vioille vikasietoinen. Järjestelmää määriteltäessä luodaan siis turvallisuusja elävyysvaatimukset. Näiden lisäksi määritellään ne viat, jotka johtavat siirtymiin sellaisiin vikatiloihin, joista toipuminen on suunniteltua. Kaikkien muiden vikojen osalta järjestelmä ei ole vikasietoinen. Seuraavassa hahmotellut vikasietoisuuden tasot kuvastavat juuri tätä: alimmalla tasolla varaudutaan pieneen alijoukkoon mahdollisia virhetilanteita ja tason kasvaessa katettujen vikojen määrä kasvaa. Tosin tasot kaksi ja kolme voivat olla myös toisin päin, riippuen siitä, säilyykö elävyys vai turvallisuus. Tasosta kolme ylöspäin tarkoitetaan lähinnä peittävää vikasietoisuutta, vaikka siihen ei kaikissa tapauksissa päästäisikään.

Vikasietoisuus 195 11.7.1 Taso 1, normaalin toiminnan virhetilanteet Normaalissa toiminnassa tapahtuu aina joitain virhetilanteita. Näihin pikkuvikoihin tulisi aina varautua, myös muissa kuin sulautetuissa järjestelmissä. Tyypillisiä tämän tason tilanteita ovat muun muassa levyn täyttyminen tai virhe pääte- tai muulla tietoliikenneyhteydellä. Ohjelman kirjoittaja ei ehkä aina huomaa, että virhe on mahdollinen. Esimerkiksi merkkijonoja päätteelle tulostavan ohjelman tekijä ei ole tullut ajatelleeksi, että tulostus voidaankin ohjata levylle, joka mahdollisesti täyttyy tai jolla oleva käyttäjälle varattu muistitila on liian pieni. Tällä tasolla hoidettavat laitteistotason viat ovat tyypillisesti niin sanottuja transientteja, eli vikoja, jotka sattuvat tapahtumaan, mutta eivät toistu kuin ani harvoin. Laite ei ole siis varsinaisesti viallinen, se vain ei ole täydellinen. Tällaisesta viasta selvitään usein vain yrittämällä toimenpidettä uudelleen. Tälle perustasolle kuuluu myös laitteiston diagnostiikkajärjestelmä: testiohjelmien tulee voida testata kaikki oheislaitteet. Käynnistysvaiheessa tehdään perustestit ainakin muisteille. 11.7.2 Taso 2, vikaturvallinen toipuminen Ulkoiset häiriöt ovat yllättäviä tapauksia kuten sähkön lyhytaikainen katkeaminen, lähistöllä oleva voimakas magneettikenttä, tai salaman isku lähistölle. Sähköinen tai magneettinen häiriö voi sotkea ohjelman toiminnan, jolloin kone saadaan järkiinsä vain alustuksella. Alustaminen vastaa aiemmin mainittua järjestelmän pysäyttämistä, jotta turvallisuusominaisuuksia ei loukattaisi. Mikäli laitetta ei voida alustaa (reset) milloin tahansa aiheuttamatta ympäristölle tai laitteistolle vaaraa, täytyy laite suojata näitä häiriöitä vastaan laitteistoratkaisuilla. Näitä voivat olla muun muassa käyttöjännitteen varasyöttö tai laitteen koteloiminen siten, että sähkömagneettinen häiriö ei enää haittaa toimintaa. Jotta alustus ja siis uudelleenkäynnistys on mahdollista, on ensin havaittava häiriö. Laitteistopuolella tähän voidaan käyttää käyttöjännitettä nuuskivaa piiriä, joka estää toiminnan, mikäli jännite ei ole sallituissa arvoissa, vahtikoiraa (watchdog), joka on "ulkoinen" laite, jota ohjelman tulee säännöllisesti käydä pitämässä tyytyväisenä, jotta se ei keskeyttäisi toimintaa, tai muuta ulkoista logiikkaa, joka huomaa suorittimen sekoamisen (esimerkiksi kirjoitusyritys ROM-muistiin tai käskyn haku muualta kuin ROM-muistista, muistinhallintayksiköllä myös muita tapauksia). Ohjelmistopuolella vika havaitaan kielletystä ti-

196 Sulautettu ohjelmointi latiedosta tai muusta sellaisesta, jonka jälkeen tehdään ohjelmallinen alustus. Toinen tähän luokkaan kuuluva ongelmaryhmä on esimerkiksi rikkoontuneet anturit. Esimerkiksi mekaanisen laitteen asentoa ei enää tunneta tarkkaan, joten sen toimintaa joudutaan rajoittamaan tai jopa sulkemaan. Yksi ratkaisu on kieltää automaattitoiminta, mutta sallia käsikäyttö, jolloin käyttäjän näköyhteys laitteeseen korvaa menetetyn anturitiedon. 11.7.3 Taso 3, ei-peittävä itsestabiloituva vikasietoisuus Esimerkki tämän tason viasta on vikaantuneen muistin hallinta. Perusratkaisu on jälleen laitteistopohjainen: virhe tunnistetaan pariteettikentästä. Yleisin ratkaisu on yksi pariteettibitti, jolloin voidaan havaita yhden bitin virhe muistipaikkaa kohti. Mikäli käytössä on useampia bittejä voidaan yhden bitin virhe korjata tai vaihtoehtoisesti havaita useamman bitin virhe. Näin tehdään jo itse asiassa tasolla yksi, jossa ongelma koetetaan ratkaista toistamalla epäonnistunut toiminto. Tällä tasolla poistetaan tarvittaessa vikaantunut muisti käytöstä. Jos laitteessa on muistinhallintayksikkö, voidaan vikaantuneella sivulla olleet tiedot kuvata toiseen paikkaan. Tätä ennen sivun tiedot kopioidaan mahdollisimman täydellisenä uuteen paikkaan. Kuvaus toiseen paikkaan voidaan tehdä heti ensimmäisen vian jälkeen tai vasta sitten, jos vika toistuu. Yksittäinen vika voi johtua erilaisista satunnaistekijöistä, jolloin yhden vian jälkeen tapahtuva kuvauksen muutos voi olla turhan kärkäs. Mikäli vika on lukumuistissa (ROM tai muu sellainen), voidaan sielläkin oleva vika hoitaa näin, mikäli vapaana on tarpeeksi luku-kirjoitusmuistia tallentamaan viallisen kohdan tiedot. Näin tehty korjaus voi olla pysyvä, mikäli laite on paikassa, johon siihen on erittäin vaikea päästä käsiksi (maata kiertävä rata). Jos mahdollista, laite ilmoittaa käyttäjälleen viasta, jotta se voidaan korjata lopullisesti huollossa. Muistin lisäksi tälle tasolle kuuluvat ohjelmalliset toipumiset ympäristön yllättävästä käytöksestä tai siitä, että laite ei totellut ohjausta juuri niin kuin oli tarkoitus. Nämä virhetilanteet ovat selvästi monimutkaisempia kuin tason yksi viat, mutta sen asemesta, että laite alustetaan uudestaan, kuten tasolla kaksi, vialle pyritään tekemään jotain. Tällä tasolla ei kuitenkaan ole käytettävissä laitteistopuolen varmennusta.

Vikasietoisuus 197 Luokittelun ongelmallisuutta kuvaa se, että edellisen tason viimeinen esimerkki sopii myös tälle tasolle: jos anturi on viallinen, turvallinen toiminta ei tarkkaan ottaen ole mahdollista, mutta voimme silti säilyttää elävyyden käsikäytöllä. 11.7.4 Taso 4, peittävä vikasietoisuus Tärkeimmät laitteet tai osa niistä voidaan monistaa. Osittaisessa monistuksessa varayksikkö on olemassa ja asennettu paikalleen, mutta se ei normaalioloissa tee mitään toimintoja. Vian sattuessa toimintoja siirretään varalaitteelle niin nopeasti ja huomaamattomasti kuin suinkin. Perusesimerkki tällaisesta toiminnasta on tietoliikenneyhteyksien monistaminen. Normaalireitin lisäksi on olemassa varareitti, jolle liikenne siirtyy vian sattuessa. Siirtyminen vie hetken aikaa, jonka jälkeen yhteydet toimivat lähes normaalisti. Siirron huomaamattomuuteen voivat vaikuttaa käytössä olevat protokollat. Toinen esimerkki on niin sanottu RAID-tekniikka (Redundant Array of Inexpensive Disks). Tässä tekniikassa ideana on vara- ja pariteettilevyn alulla mahdollistaa järjestelmän toiminta, vaikka yksi levyjärjestelmän levyistä rikkoutuisikin. Lisäksi levyt voidaan liittää kahteen koneeseen, jolloin yhden koneen rikkoutuminenkaan ei pysäytä levypalvelua. RAID-järjestelmässä on kuusi yleisesti määriteltyä tasoa, 0 5, joista laitteet tavallisesti osaavat tasot 0, 1 ja 5. Tasolla nolla ei ole varmistusta, vaan levyt muodostavat suuren loogisen levyn, jossa tiedonsiirtonopeutta on kasvatettu rinnakkain tapahtuvilla levyoperaatioilla (striping). Tasolla yksi on kaksi kopiota samasta tiedosta. Tällöin tarvitaan siis kaksinkertainen määrä levytilaa tiedon tallentamiseen, mutta järjestelmä toimii vikatilanteessakin yhtä nopeasti kuin normaalisti. Tasot 2-4 ovat erilaisia paritettijärjestelmiä, mutta tavallisesti toteutetaan taso viisi, koska se tarjoaa käytännössä parhaimman turvan pienimmällä määrällä pariteettilevyjä. Tasolla viisi on datalevypakkaa (esimerkiksi neljä levyä) kohti yksi pariteetti- ja yksi varalevy. Levyvian tullessa varalevylle generoidaan rikkoutuneen levyn tiedot pariteettilevyn avulla. Ennen kuin kopio on valmis, levy-yksikkö vastaa hitaammin kuin normaalitilassa. Mikäli toinenkin levy rikkoutuu, järjestelmä pystyy vielä toimimaan, mutta hitaammin kuin normaalitilassa. Myös keskusyksiköitä voi olla yksi varalla, jolloin viallisen yksikön toiminnot siirretään varayksikköön. Siirtäminen voi aiheuttaa ly-

198 Sulautettu ohjelmointi hyen käyttökatkon. Tilanteesta riippuen joitain keskeneräisiä asioita väkisinkin unohtuu, mutta katkos ei silti ole kovin pitkä. Kaikissa edellisissä tapauksissa ideaalitilanne on sellainen, jossa sovellus ei huomaa vian tapahtumista lainkaan, ja jopa käyttöjärjestelmältä voidaan vika piilottaa (RAID-levyt), ellei laite erityisesti ilmoita viasta. Tämän tason järjestelmiä löytyy kaikkialta, jossa suhteellisen suuri osa työstä on kiinni tietokoneiden toiminnasta. Vaikka tämä vikataso onkin kuvattu kovin laitteiston näkökulmasta, laitteiston monistaminen aiheuttaa aina myös ohjelmiston monistamista ja yleensäkin monistamisen ottamista huomioon. Kyseessä ei siis ole mikään vain laitteistolla toteutettava ratkaisu, vaan ohjelmistot ovat olennainen osa viastatoipumista. 11.7.5 Taso 5, korjaus konetta sammuttamatta Tämä taso on oikeastaan vain edellisen tason pieni parannus. Edellisessä tapauksessa viasta kyllä selvitään, mutta sen lopullinen korjaaminen vaatii laitteen pysäyttämisen hetkeksi. Laitteen korjaaminen sammuttamatta konetta vaatii laitteiston tukea, jotta kytkeminen ei aiheuttaisi häiriöitä tietokoneen väylillä ja sähkönsyötössä. Edelleen RAID-levyjä esimerkkinä käyttäen, on mahdollista, että RAID-järjestelmässä rikkonaisen levyn voi vaihtaa vauhdissa, ja uudelle levylle siirretään automaattisesti sen oikea sisältö, kun se saadaan paikalleen. Mikäli laitteessa on ylimääräinen suoritinyksikkö, viallisen yksikön vaihtaminen vauhdissa voi olla mahdollista, samoin kuin muistin. Jos laite on viasta huolimatta yhä käytössä, ennen vaihtoa voidaan siirtää sieltä toiminnat pois, jotta häiriö olisi mahdollisimman pieni. Mikäli toiminnot ovat jo siirretty varayksikölle, uudesta yksiköstä tulee automaattisesti varayksikkö, ellei ylläpitokomennoilla muuta määrätä. Kummassakin edelläolevassa esimerkissä laitteistopuolen valmius on siinä, että laite voidaan irrottaa ja kytkeä turvallisesti jänniteisenäkin. Uuden laitteen kytkennän jälkeen se saadaan lopullisesti toimintakuntoon ohjelmiston avulla. Tämä operaatio voi olla hyvinkin monimutkainen ja vaikea toteuttaa käytännössä. 11.7.6 Taso 6, Kaikkien laitteiden varmistus Tällaisessa koneessa on jokaisella toiminnan kannalta välttämättömällä laitteella varmistusyksikkö. Normaalisti tällaisessa järjestelmässä

Vikasietoisuus 199 varayksikkö on "lämpimänä" eli se seuraa laskennassa toimivaa yksikköä. Toisin sanoen se saa kaikki toimivan yksikön vastaanottamat viestit ja tiedot, ja se tekee samat päätelmät kuin pääyksikkökin. Ainoastaan sen generoimia viestejä tai muita ohjauksia ei välitetä eteenpäin. Vastuussa olevan yksikön vaurioituminen siirtää vastuun välittömästi lämpimänä odottavalle varayksikölle, joka jatkaa toimintaa ilman käyttökatkoa. Yksikköä vaihdettaessa voi pieniä virhetoimintoja esiintyä, mutta oikealla suunnittelulla tiedetään, mitkä virhetoiminnot ovat mahdollisia ja mikä niiden todennäköisyys on. Kun tällaisessa järjestelmässä vaihdetaan viallinen yksikkö toiseen, täytyy tämä vaihtoyksikkö "lämmittää", jotta se voisi tarvittaessa ottaa vastuun laskennasta. Tämä lämmittäminen voi olla hyvinkin vaikeaa, varsinkin, jos järjestelmän kuormitus on suuri. Vaikka varsinainen lämmitysoperaatio ei toimisikaan, vaihtoyksikkö saa väkisinkin ajan myötä kiinni juonesta, kun sellaisen yhä tarpeellisen historian osuus vähenee, jota se ei ole viesteistä voinut päätellä. Esimerkki tällaisesta laitteistosta on suurehko puhelinkeskus. Pienemmät puhelinkeskukset täyttävät tavallisesti kohtien 11.7.4 ja 11.7.5 kuvaamat ehdot. 11.7.7 Taso 7, Koneiden monistaminen Yksi ratkaisumalli on laittaa monta konetta laskemaan samaa asiaa. Jopa niin, että koneissa on eri yritysten tekemät ohjelmistot laskemassa samaa asiaa. Lopullinen tulos on äänestyksen tuote, mutta ongelmana on se, että miten voidaan varmistua, mikä koneista toimii väärin. Yksi mahdollisuus on, että koneet päättävät, että se kone, joka ei pysy muiden mukana laskennassa tai tuottaa muista selvästi poikkeavia tuloksia, suljetaan pois äänestyksistä. Mutta myös äänestystarkkailulaite voi mennä epäkuntoon. Äänestys voi tapahtua myös vasta elektroniikan tai mekaniikan tasolla. Monistetut koneet ovat harvinaisia. 11.8 Käynnistys ja uudellenkäynnistys Yksi hankalimpia erikoistilanteita on käynnistäminen, jolloin oheislaitteet eivät vielä ole toimivalmiudessa. Vaikka tämä ei suoraan liitykään vikasietoisuuteen, tilanteessa on samankaltaisia tekijöitä, jotka liittyvät voimakkaasti turvallisuuteen. Ongelma on ehkä helpoin selittää lähtemällä esimerkistä, jossa suorittimen rinnakkaisliityntä ohjaa suoraan ulkoista elektroniikkaa. Jännitteen kytkeminen alustaa suorittimen,

200 Sulautettu ohjelmointi jolloin rinnakkaisliityntä on ennen sen ohjelmallista alustamista niin sanotussa korkeaimpedanssisessa tilassa, joka käytännössä tarkoittaa sitä, että ohjausta ei ole. Tämän takia oheiselektroniikka saattaa tulkita tilan miksi tilaksi hyvänsä, sillä johtimissa voi olla hyvinkin satunnaisia jännitteitä. Tästä seuraa, että lähes mitä tahansa voi tapahtua. Tämänkaltainen ongelma voidaan korjata sopivalla elektroniikkasuunnittelulla, ohjelmallisesti sille ei voi tehdä mitään. Kaikki ongelmat eivät ole tällaisia, vaan laitteiden alustusjärjestystä tai yksittäisen laitteen alustussekvenssiä muuttamalla voidaan osa ongelmista ratkaista melko helpostikin. Esimerkiksi äskeisen rinnakkaisliitynnän ulostulo määräytyy datarekisterin arvosta, ja ohjausrekisterillä ohjataan liityntä pois korkeaimpedanssisesta tilasta (eli tuloliitynnästä) lähteväksi liitynnäksi. Alustuksessa tulee siis ensin asettaa ohjaavaan datarekisteriin järkevä arvo, ja vasta sitten määrätä liitynnän bittien suunnat. Käynnistyksen aikana ulkoisten liittymien tulee toimia turvallisesti, joten tarvitaan laitteistoratkaisu, jossa käynnistäminen ei aiheuta satunnaiskäyttäytymistä. Yleissääntöä turvalliseen käynnistämiseen ilman laitteiston tukea ei ole, mutta myös ohjelmoija voi aiheuttaa ongelmia väärillä alustusrutiineilla. Vastuu käynnistyksen toiminnasta on siis yhteinen. Kun järjestelmässä havaitaan vika, josta ei pystytä toipumaan, on yleinen tapa ratkaista tilanne käynnistämällä laite uudelleen (tästä oli enemmän kohdassa 11.7.2). Käynnistys auttaa ohjelmavirheisiin ja joihinkin oheislaiteongelmiin. Kuitenkin normaali käynnistäminen on aivan eri asia kuin käynnissä olevan laitteen uudelleenkäynnistys. Liikkuvaa laitetta ei voi aina edes pysäyttää rikkomatta sitä tai toiminta on muuten vaarallinen (ABSjarrujärjestelmässä vika, lyödäänkö jarrut kiinni?). Tämän takia uudelleenkäynnistystä tulisi välttää, tai sitä ennen ajaa järjestelmä sellaiseen tilaan, jossa käynnistys on turvallinen. Yleensäkin poikkeukselliset tilanteet muutkin kuin koko järjestelmän uudelleenkäynnistys tulisi käydä tarkkaan läpi yllätysten välttämiseksi. Tätä varten on tehtävä kohdassa 11.5 mainitut tapahtumalogiikat. Yksi ongelmatekijä lienee se, että mielenkiinto ja ohjelmointitavat eivät suosi yleensä varsin työläitä tarkistuksia. Milloin viimeksi kirjoittamasi ohjelma testasi, onnistuiko kirjoitus?

Vikasietoisuus 201 11.9 Ohjelmistotyö ja ylläpito ohjelman suorituksen aikana Koska sulautettu järjestelmä saattaa olla jatkuvasti suorituksessa, saatetaan järjestelmää joutua muokkaamaan myös sen suorituksen aikana. Tämä on luonnollisesti vaikeaa, ja vaatii muokkaamisen huomioimista ohjelman suunnittelun aikana. Ohjelman suorituksen aikana tapahtuvan muuntelun taso voi vaihdella. Yksinkertaisimmillaan kyseeseen tulevat jonkinlaiset parametrisoinnit, joiden avulla voidaan esimerkiksi ohjata erilaisten toimenpiteiden frekvenssiä. Tällöin esimerkiksi tietyn diagnostiikkatoiminnon suorittamisen ajaksi voidaan ohjelmasta kytkeä pois diagnostiikkaa mahdollisesti häiritsevät ominaisuudet. Toinen melko helposti rakennettava tuki ovat erilaiset paikkoohjelmistot (patch) sekä tietty muistialue, joka varataan paikko-ohjelmistojen lataamista varten. Tämän jälkeen ohjelmisto voidaan ajaa alas ja sitten ladata päivitykset muistiin ennen uudelleen käynnistämistä. Vaihtoehtoisesti, olettaen että kyseessä olevat päivitykset on ollut mahdollista testata huolellisesti ja että laitteen toimintoja on mahdollista kytkeä pois dynaamisesti siten että ohjelmakoodi ei varmasti ole suorituksessa, päivitykset saatetaan jopa ottaa käyttöön ilman uudelleenkäynnistystä. Vähän suuremmissa järjestelmissä myös kirjastoja voidaan käsitellä samaan tapaan, jolloin päivitykset on mahdollista toteuttaa paikkoohjelmistoja suuremmassa mittakaavassa. Myös laitteistotason tuki voi olla tarpeen. Laitteisto saattaa esimerkiksi olla rakennettu siten, että ohjelmistosta kyetään ajamaan kahta eri versiota samanaikaisesti, ja vasta kun ollaan varmoja uuden version toimivuudesta, se otetaan varsinaisesti käyttöön. Tällöin eri versioiden rinnakkainen toiminta on tyypillisesti huomioitu jo järjestelmätason vaatimuksena, ja ohjelmoija näkee ominaisuuden osana käyttöjärjestelmän tarjoamia palveluita. 11.10 Yhteenveto Vikasietoinen järjestelmä kykenee jatkamaan toimintaansa itsenäisesti myös silloin, kun siinä on vikaa. Jos järjestelmän suunnittelussa on otettu erikseen huomioon, ettei vikaantuminen aiheuta vaaraa, kyseessä on vikaturvallinen järjestelmä.

202 Sulautettu ohjelmointi Vikasietoinen järjestelmä voi sietää vain sellaisia vikoja, jotka on erikseen otettu huomioon, eli ne on huomioitu osana suunnittelua. Vikasietoisen järjestelmän tulee pystyä valvomaan omaa toimintaansa, ja ongelmia havaittuaan sen tulee kyetä suorittamaan tarvittavat toipumisrutiinit. Tämä vaatii sekä ohjelmisto- että laitteistoredundanssia. Ohjelmistojen toteutuksessa on mahdollista käyttää defensiivistä ohjelmointia mahdollisimman korkean luotettavuustason saavuttamiseksi.