9. Luento: Ohjelmistotyö Arto Salminen, arto.salminen@tut.fi
Agenda Johdanto Ristikäännös Testaus ja virheen jäljitys Yleensä Kehitysympäristössä Käyttöympäristössä Laitteiston testaus Iteratiivisesta kehityksestä Yhteenveto
Johdanto Kehitystyö ja usein myös testaus ei yleensä tuotantoympäristössä Paitsi ohjelmiston myös laitteiston oikea toiminta usein varmennettava ohjelmallisesti Useita eri ongelmien lähteitä Eri käyttöjärjestelmäpalvelut, kääntäjät, kirjastot, jne. Usein kätevää rakentaa minimaalinen ohjelmisto, jonka toiminnan voi todentaa, ja käyttää sitä kehitysympäristön, työkaluketjun ja kohdelaitteen toiminnan varmentamiseen
Ristikäännös Ohjelma siis kirjoitetaan eri koneessa kuin mitä ajetaan Yleensä eri käskykannat ja laitteisto Joka tapauksessa kohdekoneelle ei yleensä voi suoraan kehittää ohjelmaa Usein useita kääntäjiä, joista osaa voidaan hyödyntää esim. moduulitestauksessa kehitysympäristössä Ongelmia: Kääntäjien erilaisuudet (virheet, rekisterirakenteen käsittely, jne) Käyttöjärjestelmien rajapinnat Käytettävissä olevat kirjastot
Ristikäännös yksinkertaisimmillaan Kehitystyöasema Laite Lähdekoodi Ristikäännös Laitteelle käännetty Siirto (asennus) Laitteessa suoritettava
Testaus ja virheiden jäljitys Yleensä ei (ainakaan kokonaan) mahdollista suorittaa siinä ympäristössä kuin missä kehitetään Muutokset ajoituksissa voivat aiheuttaa ongelmia joka tapauksessa Ei aina selvää testataanko laitteistoa vai ohjelmistoa Sulautettujen järjestelmien määritelmän mukaan itse asiassa molempien yhteistoimintaa! Virheettömyyteen kova pyrky erilaisin keinoin Cleanroom; työn organisointi; formaalit menetelmät, jne.
Virheiden paikantamisesta Vaikutus ja varsinainen vika eivät välttämättä lähellä toisiaan Jäänneviittaukset, roskaantuminen, fragmentoituminen Moniprosessiympäristö Ajoitus Joskus vikoja ei edes vaivauduta korjaamaan Ei kriittinen Riittävän harvinainen -> ei ilmene ehkä koskaan todellisessa käytössä Ylläpidon kannalta tämä tietysti tuo haasteita!
Pöytätestaus 2 versiota Kevyt: Ohjelman tekijä selittää toiselle ohjelmoijalle (tai jollekin joutilaalle!) mitä ohjelman pitäisi tehdä Kuuntelijan ei edes tarvitse ymmärtää, riittää että tekijä kertoo ja samalla huomaa omat ongelmansa Tyhmät kysymykset usein parhaita Raskas: Käydään ohjelmaa läpi rivi riviltä Ohjelma suoritetaan käsin Löytää usein myös muita ongelmia
Testipedit Ohjelmisto, jolla testattavan ohjelmiston moduuleja voidaan testata Interaktiivisesti käyttäjän ohjaamana Eräajotyyppisesti automaattisesti Muutoksen jälkeen voidaan tehdä regressiotestit koko aineistolla Usein ei päästä lähellekään sataa prosenttia ilman erityistoimenpiteitä Musta/valkoinen laatikko testit eri tilanteissa Usein valmisohjelmisto tai testaustarkoitukseen rakennettu sovelluskehys Usein suositeltavaa myös pöytäkoneissa ajettaville ohjelmille!
Profilointi Pyrkii löytämään ohjelman osat, joissa vietetään eniten aikaa Ei varsinaisesti testausta, mutta usein käyttökelpoinen menettelytapa sulautettujen ohjelmistojen yhteydessä Ei kuitenkaan kannata ylioptimoida tarpeettomasti Yleensä tehdään kehitysympäristössä (profilointitiedon keruu laitteella voi olla vaikeaa; muistinkulutus voi olla liika; jne) Ei siis välttämättä sama tulos kohdeympäristössä Profilointioperaatiot voivat myös siirtää pullonkaulaa (esim. profilointitulosten tiedostoonkirjoittamiseen!)
Kehitysympäristön työkaluista Yleensä kannattaa aloittaa näillä Nopeampaa (prosessori nopeampi, ei tarvita siirtoja) Työkalut monipuolisempia Ei kuitenkaan voi olla ainoa vaihtoehto Eroavaisuuksia joka tasolla Kääntäjä Kirjastot Käyttöjärjestelmä Prosessorin käskykanta Muistiavaruus Ajoitukset Nyrkkisääntö: Looginen toiminta kuntoon kehitysympäristössä; toisaalta ajastuksien takia kannattaa jo varhaisessa vaiheessa tutustua myös oikeaan laitteistoon
Järjestelmän simulointi Ohjelma käännetään kohdekoneen ymmärtämään muotoon, mutta kohdelaitteen sijasta sitä suoritetaan kehitysympäristössä simulaattorissa (yleensä ohjelma); myös laitteiston tila kuvataan Simulaattorissa mahdollista kuvata myös oheislaitteet, joten niihinkin liittyviä ominaisuuksia voidaan simuloida Ongelma: Jos monimutkainen kokonaisuus, simulaatioympäristö ei aina pysty tuottamaan tarpeeksi aitoja reaktioita Sopii kuitenkin perustestaukseen ennen varsinaiseen kohdelaitteeseen siirtoa
Virtualisointi Kuten simulointi, mutta laitteiston suhteen ollaan vähemmän tarkkoja; lopputulema on tärkeämpää kuin järjestelmän tila Suorituskyky lähellä natiivia; pyritään käyttämään alla olevaa laitteistoa Usein soveltuu myös kehitysympäristöksi Tavallinen ratkaisu sulautettujen Linux-ohjelmistojen kehityksessä Virtuaali-imageja + koneita ladattavissa suoraan Webistä eri tarkoituksiin mutta kannattaa kumminkin varautua säätämään oma ympäristö kuntoon (esim. näppäinkartta jne.)
Testaus ja jäljitys kohdejärjestelmässä Peräkkäisohjelman debuggaustyyli ei toimi kovin hyvin sulautetussa ympäristössä Ideana ei laskea inputista sopivaa outputtia Rivi kerrallaan eteneminen paljastaa vain osan totuudesta (yleensä rinnakkaisia suorituksia) Tarvitaan erilaisia apulaitteita Logiikka-analysaattorit, emulaattorit, seurannan apuvälineet ja erilliset testijärjestelmät, jopa led-valot
Logiikka-analysaattori Voidaan tutkia suorittimen tai väylän liikennettä Kopio väyläliikenteestä ja askelittainen tulkinta Jotkut laitteet jopa muuntavat bittivirran symboliseen konekoodimuotoon Muistikartta auttaa! Kaikkea ei kuitenkaan voi nauhoittaa; erilaiset nauhoitusehdot usein tarpeen Välimuistin käyttö voi aiheuttaa ongelmia Esimerkkejä: http://www.lauterbach.com/
Logiikka-analysaattori Analysaattori Kohdejärjestelmä CPU osoiteväylä Oheislaite dataväylä
Emulaattori Esim. suorittimen paikalle asennetaan välikannan avulla piirikortti, joka toimii ulkoisesti kuten suoritin Suoritus tyypillisesti mahdollista askelittain Muuttujien arvojen tarkastelut Vaikka alun perin vain HW, nykyisin myös SW toteutus (esim QEMU) Ero virtualisointiin alkaa häilyä; esim QEMUa voidaan käyttää virtualisointiinkin Monessa mielessä kuten järjestelmätason debuggeri ohjelmiston ja laitteiston rajanpinnan kannalta
Emulaattori ei pure kaikkeen. Ajastusongelmat Muistinkulutukseen liittyvät asiat (emulaattorissa on usein enemmän muistia kuin kohdejärjestelmässä) Joskus ohjelma voi toimia kohdelaitteessa mutta ei emulaattorissa (esim. lukumuistin korvaaminen luku-kirjoitusmuistilla voi aiheuttaa tällaisia ongelmia; samaten suojaukset voivat olla ongelmien lähde)
Erillinen testijärjestelmä Muistuttaa ohjelmistotuotannon V-mallin ideaa Laitekohtainen vs. yleiskäyttöinen testijärjestelmä Edellinen usein mahdollista vain kaikkien kalleimpien järjestelmien yhteydessä, sillä Vaatii pahimmassa tapauksessa oman projektinsa, jossa järjestelmälle rakennetaan sitä täysin vastaava testiympäristö Tyypillisesti myös testijärjestelmä on itse asiassa sulautettu järjestelmä Toteutus ja testijärjestelmä siis verifioivat toistensa oikean toiminnan!
Tiedon siirto koneelta toiselle analysoitavaksi Vaatii yleensä erityisen liitynnän Analysointi joko välittömästi (on-line) tai jälkikäteen (off-line) Tiedonkeruu ei välttämättä näkyvää Kerätään tapahtumatietoa väylältä; Usein kuitenkin tarvitaan lisäinfoa (mikä taas vaatii lisäsanomia) Lisäliitynnän avulla tiedonsiirto on kuitenkin usein yksinkertaisempaa Voi vaikuttaa ohjelman toimintaan Ehdollinen kääntäminen mahdollistaa erilliset debug/tuotantoversiot Joskus myös ongelmia sillä suoritettava ohjelma ei ole täysin sama
JTAG-luentotehtävä itseopiskeltavaksi Minkä tyyppinen debuggausmenetelmä on JTAG (IEEE 1149.1)? Mitkä ovat JTAG:in tavalliset käyttötarkoitukset (ainakin 3 kpl)? Miten sitä käytetään näihin tarkoituksiin? IEEE 1149.1 määrittelee seitsemän JTAG-käskyä (boundary scan instructions). Mitkä nämä käskyt ovat ja mihin niitä käytetään? Miten JTAG-liityntä on toteutettu käytännössä sitä tukevissa laitteistoissa? Mitä avoimia JTAG-yhteensopivia työkaluja on saatavilla? Mitä etuja JTAG:lla on muihin debuggausmenetelmiin nähden? Entä puutteita tai haittoja?
Reaaliaikajärjestelmän debuggauksesta Debuggaaminen breakpointien avulla ei onnistu reaaliaikajärjestelmien tapauksessa Debuggaukseen voi käyttää aiemmin kuvattuja logiikkaanalysaattoreita tai emulaattoria Joissakin prosessoreissa on sisäänrakennettu laitteistotuki ajonaikaisen tiedon tallentamiseen (real-time trace) Real-time trace menetelmässä prosessorin suoritus tallennetaan ja analysoidaan myöhemmin Kun laitteistotuki on sisäänrakennetu prosessoriin, välimuistin käyttö tai out of order execution eivät ole ongelma Sopii hyvin myös keskeytysaliohjelman tutkimiseen ja profilointiin
Laitteiston testaamisesta Tyypillisten laitteistovikojen tuntemus Huonot kontaktit Oikosulut Katkenneet johdot Sähkömagneettisesta induktiosta johtuva signaalin ylikuuluminen Väärät signaalitasot Ajoitusvirheet Työkaluina sähköiset mittalaitteet (esim. oskiloskooppi) Onneksi ohjelmallisestikin voi tehdä yhtä ja toista Nyrkkisääntö: Jos useampi kuin 1 vika, peli usein menetetty!
Muistien testaamisesta Lukumuistin testaus käymällä läpi muistipaikat ja laskemalla tarkistussumma (joka on myös tallennettu lukumuistiin) Luku/kirjoitusmuistin testaus ensin kirjoittamalla ja sitten lukemalla (esim. ensin 5555 hex ja sitten AAAA hex ) Jos väylien johdotus tavallisesta poikkeava, kannattaa pohtia testiarvoja joilla ylikuulumiset voidaan havaita HUOM: Välimuisti kannattaa kytkeä pois päältä!
Oheislaitteiden testaus Monimutkaisissa laitteissa erityisiä testitiloja Yksinkertaisissa piireissä testein voi kokeilla onnistuuko keskeyttäminen, tilarekisterien käsittely jne. Yleensä oheislaitteiden testaus onnistuu parhaassakin tapauksessa vain osittain Nyrkkisääntö: Käynnistyksen yhteydessä aina perustesti; tarvittaessa kattavampi huolto- ja valmiustilatesti
Iteratiivisuudesta Kätevää myös muita ohjelmistoja kehitettäessä, lähes välttämätöntä sulautetussa ympäristössä
Vähän pidempi selitys Yleensä kokonaisjärjestelmälle löytyy perinteinen määrittely Työnjakoon liittyvät syyt; laitteiston valmistustekniikkaan liittyvät syyt Kokonaismäärittely kattaa sekä laitteiston että ohjelmiston yhteistoiminnan Tämän jälkeen on suoritettu jako eri tekniikoin toteutettuihin osiin, jotka toteutetaan erikseen Ensimmäinen yritys yhteistoiminnasta harvoin osuu nappiin! Virheiden jäljitys myös helpompaa kun on pienempi toteutus
Ohjelmiston määrittely Ohjelmiston suunnittelu Ohjelmiston toteutus Kokonaismäärittely Kokonaissuunnittelu Työn jako osiin Laitteiston määrittely Laitteiston suunnittelu Laitteiston toteutus Ohjelmiston testaus Laitteiston testaus Integrointi ja testaus
Suunnittelun etenemisestä Ensimmäinen versio usein yksinkertaisin toteutus joka tekee jotain verifioitavaa Mukana usein myös laitetestit, mutta ei välttämättä Tarkoitus varmentaa työkaluketju Usein jo laitteen henkiin saaminen on melkoinen suoritus, vaikkei se tekisikään vielä mitään Seuraavat iteraatiot lisäävät toiminnallisuutta pieni pala kerrallaan jotta mahdolliset ongelmat on mahdollista korjata osittaen Usein insinöörityön hienous on juuri pienimpien muutosten löytämisessä (ja mahdollisuuksien mukaan erikseen testaamisessa ja toiminnan varmentamisessa!) Henkiin herääminen Laitteiston testaus Algoritmit Laitteiston ongelmien piilottaminen/kiertäminen Onnistunut suoritus ei kuitenkaan ole riittävä ehto ohjelmiston valmistumiselle
Yhteenveto Kehitys- ja käyttöympäristöt eivät ole samat Suuri joukko erilaisia avustavia työkaluja; eivät kuitenkaan voi kokonaan korvata oikean laitteen käyttöä kehityksen aikana Laitteiston testaus on osa ohjelmiston tehtävää oikeastaan lähes aina Iteratiivinen kehitystyyli lähes välttämätöntä ohjelmistotyössä