Studie av utvecklingsverktyg med inriktning mot
PLC-system
(HS-IDA-EA-99-103)
Christoffer Brax ([email protected])
Institutionen för datavetenskap
Högskolan i Skövde, Box 408
S-54128 Skövde, SWEDEN
Examensarbete på program för systemprogrammering under
vårterminen 1999.
Handledare: Joakim Eriksson
Studie av utvecklingsverktyg med inriktning mot PLC-system
Examensrapport inlämnad av Christoffer Brax till Högskolan i Skövde, för
Kandidatexamen (B.Sc.) vid Institutionen för Datavetenskap.
99-06-18
Härmed intygas att allt material i denna rapport, vilket inte är mitt eget, har blivit
tydligt identifierat och att inget material är inkluderat som tidigare använts för
erhållande av annan examen.
Signerat: _______________________________________________
Studie av utvecklingsverktyg med inriktning mot PLC-system
Christoffer Brax ([email protected])
Sammanfattning
Datoranvändningen i samhället växer för varje dag. Det är då viktigt att programvara
håller hög kvalité, då vissa programvaror styr kritiska maskiner som exempelvis
flygplan. Ett sätt att få kvalitativa programvaror är att använda bra
utvecklingsverktyg. I detta arbete utvärderas fem olika utvecklingsverktyg: GNAT
(Ada), Microsoft Visual C++, Microsoft J++, Borland Delphi och Active Perl.
Inriktningen på utvärderingen är mot utveckling av programvara för PLC-system. Det
som utvärderats är effektivitet av genererad kod, kompileringstid, storlek på genererad
kod, kodportabilitet och utbud av färdiga komponenter. Undersökningen har
genomförts med hjälp av praktiska tester.
Nyckelord:
Kompilering,
Realtidssystem
PLC-system,
Benchmark,
Utvecklingsverktyg,
Innehållsförteckning
1
2
Introduktion ......................................................................................1
Bakgrund och begrepp.....................................................................2
2.1
Utvecklingsprocessen vid programvaruutveckling ......................................... 2
2.2
Allmänt om utvecklingsmiljöer....................................................................... 2
2.3
Allmänt om kompilatorer ................................................................................ 2
2.4
Programmeringsspråk som ingår i de utvärderade utvecklingsverktygen....... 5
2.4.1 C/C++ ......................................................................................................... 5
2.4.2 Pascal .......................................................................................................... 6
2.4.3 Java ............................................................................................................. 6
2.4.4 Ada/Ada95.................................................................................................. 7
2.4.5 Perl.............................................................................................................. 7
3
2.5
Realtidssystem................................................................................................. 7
2.6
PLC-system ..................................................................................................... 8
Problemprecisering ..........................................................................9
3.1
Problemformulering ........................................................................................ 9
3.1.1 Kvantitativa kriterier................................................................................... 9
3.1.2 Kvalitativa kriterier..................................................................................... 9
3.1.3 Undersökningskriterier ............................................................................. 10
3.1.4 Val av programmeringsspråk för undersökningen ................................... 10
3.2
4
Avgränsning .................................................................................................. 11
Metoder............................................................................................13
4.1
Jämförelse av metoder................................................................................... 13
4.1.1 Kvantitativa kriterier................................................................................. 13
4.1.2 Kvalitativa kriterier................................................................................... 15
4.2
Vald metod .................................................................................................... 15
4.3
Precisering av utvärderingskriterier för undersökningen .............................. 15
4.4
Benchmarks ................................................................................................... 17
4.4.1 Språkfunktionstester ................................................................................. 17
4.4.2 Testfall för kodeffektivitet........................................................................ 18
4.4.3 Testfall för kompileringshastighet............................................................ 19
5
Genomförande ................................................................................20
I
5.1
Förutsättningar för tester ............................................................................... 20
5.2
Effektivitet hos genererad kod ...................................................................... 21
5.2.1 Loop overhead .......................................................................................... 21
5.2.2 Lokal variabeltilldelning........................................................................... 22
5.2.3 Global variabeltilldelning ......................................................................... 22
5.2.4 Matristilldelning ....................................................................................... 23
5.2.5 Uppräkning av 8-bitarsvariabel ................................................................ 23
5.2.6 Uppräkning av 16-bitarsvariabel .............................................................. 24
5.2.7 Uppräkning av 32-bitarsvariabel .............................................................. 24
5.2.8 Uppräkning av 64-bitarsvariabel .............................................................. 25
5.2.9 Uppräkning av 64-bitars flyttalsvariabel .................................................. 25
5.2.10 Matrisallokering ..................................................................................... 26
5.2.11 Funktionsanrop....................................................................................... 27
5.2.12 Anrop av matematisk funktion 1 ............................................................ 27
5.2.13 Anrop av matematisk funktion 2 ............................................................ 28
5.2.14 Villkorstest ............................................................................................. 29
5.2.15 Strängallokering ..................................................................................... 29
5.2.16 Typecasting ............................................................................................ 30
5.2.17 Rekursivt anrop ...................................................................................... 31
5.2.18 Lintest..................................................................................................... 31
5.3
Kompileringshastighet................................................................................... 32
5.4
Storlek på kompilerad kod ............................................................................ 33
5.4.1 Filstorlekar vid kodeffektivitetstester ....................................................... 33
5.4.2 Filstorlekar vid kompileringshastighetstester ........................................... 34
6
5.5
Kodportabilitet............................................................................................... 35
5.6
Utbud av färdiga komponenter...................................................................... 36
Analys av resultat ...........................................................................37
6.1
Slutsatser av kvantitativa undersökningar..................................................... 37
6.1.1 Kodeffektivitet.......................................................................................... 37
6.1.2 Kompileringshastighet.............................................................................. 38
6.1.3 Storlek på kompilerad och länkad kod ..................................................... 38
6.2
Slutsatser av kvalitativa undersökningen ...................................................... 39
6.2.1 Kodportabilitet.......................................................................................... 39
6.2.2 Utbud av färdiga komponenter ................................................................. 40
II
7
Sammanfattning .............................................................................41
7.1
Framtida arbete.............................................................................................. 42
Referenser................................................................................................43
Bilaga A. Källkod för benchmarkprogram............................................1
Källkod för Ada-program ......................................................................................... 1
Källkod för C++-program......................................................................................... 2
Källkod för Javaprogram .......................................................................................... 6
Källkod för Delphiprogram .................................................................................... 12
Källkod för Perlprogram ......................................................................................... 16
Bilaga B. Poäng vid betygsbedömningar................................................1
III
1 Introduktion
1 Introduktion
I takt med att samhället blir mer och mer datoriserat så ökar kraven på tillförlitlighet
hos produkter som innehåller mikroprocessorer.
Dessa produkter är numera inte bara PC-datorer utan även mobiltelefoner,
mikrovågsugnar, bilar, industriella styrsystem, TV-apparater etc. Detta leder till att
större krav ställs på programvarorna. En bil får till exempel inte börja accelerera
okontrollerat för att programvaran är felaktig. Kravet på tillförlitliga programvaror för
dessa system ökar. Det finns många aspekter som måste beaktas när ett system med
krav på tillförlitlighet ska utvecklas. Dels så måste själva hårdvaran vara av bra
kvalité, om hårdvaran går sönder leder detta ofta till att systemet ”går ner”.
Idag är det vanligare att det är något fel på mjukvaran än på hårdvaran i ett system.
Detta beror på att mjukvaran ofta blir väldigt komplex och är svårare att kontrollera
än hårdvaran. Ett sätt att få en programvara som är tillförlitlig är att använda ett
utvecklingsverktyg som underlättar för programmeraren. Med tillförlitlighet (eng.
reliability) menas att en programvara uppför sig på det sätt den är avsedd att göra i
alla situationer (även i onormala situationer).
Vid val av utvecklingsverktyg finns det många aspekter att ta hänsyn till. Dels själva
utvecklingsmiljön, vilka hjälpmedel det finns som förenklar arbetet och dels själva
kompileringsdelen som innehåller kompilatorn, bibliotekshanterare, länkare och
avlusare. Det är också viktigt att utvecklingsverktyget är anpassad till den typ av
applikation som ska skrivas. Varje program har speciella krav på funktionalitet, och
vissa program kan till exempel ha krav på att utföra sina uppgifter inom en
förutbestämd tid. Dessa kallas realtidssystem, på denna typ av system ställs speciella
krav på kompilatorn för att systemet ska uppfylla vissa kriterier, som exempelvis
förutsägbarhet och punktlighet. I andra system är dessa krav inte alls lika viktiga och
där kanske andra aspekter hos kompilatorn är mer betydande som exempelvis
kompileringshastighet, avlusningsmöjligheter och inbyggda funktioner.
Utveckling av programvara är ofta en itererande process. Detta innebär bland annat att
själva kompileringen måste utföras många gånger under utvecklingsarbetet. Det är då
en fördel om kompileringstiden är kort, vilket leder till kortare väntetider för
utvecklaren. Andra detaljer som är viktiga är hur väl de olika delarna i
utvecklingsmiljön är integrerade med varandra, hur felsökning kan göras och hur bra
stöd för tredjepartsbibliotek som finns.
I detta arbete utvärderas ett antal utvecklingsmiljöer. Dessa är baserade på ett antal
olika programmeringsspråk. De språk som används är C/C++, Pascal, Java, Ada och
Perl. Inriktningen på utvärderingen kommer att vara mot PLC-system (Programable
Logic Controller). PLC-system är mycket vanliga inom industrin där de används för
att styra allt ifrån dörrar och fönster till stora maskiner.
Vid utvärderingen används ett antal utvärderingskriterier. Dessa kriterier är prestanda
vid kompilering, prestanda vid exekvering av kompilerad kod, storlek på genererad
kod,
kodportabilitet
och
utbud
av
färdiga
komponenter.
1
2 Bakgrund och begrepp
2 Bakgrund och begrepp
Detta avsnitt beskriver centrala begrepp som används i detta arbete. Här beskrivs även
de fem olika programmeringsspråken som ingår i de utvärderade
utvecklingsverktygen.
2.1
Utvecklingsprocessen vid programvaruutveckling
Enligt Pressman (1997) finns det ett antal olika modeller som beskriver
utvecklingsprocessen vid programvaruutveckling. En vanlig modell är den som
Pressman kallar för spiralmodellen. Spiralmodellen är en iterativ modell som består
av ett antal olika faser, vanligtvis mellan tre och sex. Under utvecklingen växlar
arbetet mellan dessa olika faser ett antal varv tills det att den utvecklade
programvaran är klar.
De faser som Pressman tar upp är: kundkontakt, planering, riskanalys, utveckling,
konstruktion & testning, och kundutvärdering. Var och en av dessa faser består av ett
antal olika arbetsmoment. Beroende på projektets storlek varierar antalet
arbetsmoment. Vid större projekt finns en del paraplyaktiviteter som till exempel
kvalitetsförsäkran och konfigurationshantering. Var och en av de ovanstående faserna
är själva itererande. I faserna konstruktion och testning är det en vanlig itererande
process att programmeraren gör ändringar för att sedan testa programmet för att se om
programmet uppför sig på rätt sätt.
2.2
Allmänt om utvecklingsmiljöer
En utvecklingsmiljö består ofta av ett antal olika delar. Dessa delar kan till exempel
vara en editor där programmen skrivs, kompilatorn och länkaren som skapar körbara
filer, avlusaren som används för felsökning och som ofta är integrerad med editorn,
hjälpfunktioner och bibliotekshanterare. Utöver dessa kan utvecklingsmiljön även
innehålla verktyg för att till exempel utforma gränssnitt och skapa databaskopplingar.
Vissa utvecklingsmiljöer innehåller även funktioner för att grafiskt rita upp
programmet och skapar sedan kod efter den grafiska representationen.
2.3
Allmänt om kompilatorer
En kompilator är enligt Aho, Sethi och Ullman (1986) ett program som läser in ett
program skrivet i ett speciellt språk (källspråk) och översätter denna till ett annat
språk (målspråk). Vid översättningen rapporterar kompilatorn eventuella fel i det
översatta programmet till användaren.
En kompilator består i huvudsak av åtta olika delar eller faser (Aho, Sethi och
Ullman, 1986), och trots att det finns många olika programmeringsspråk så är de
flesta kompilatorer uppbyggda på ungefär samma sätt. De åtta faserna besktriver
Aho, Sethi och Ullman på följande sätt:
2
2 Bakgrund och begrepp
Lexisk analys
Lexisk analys innebär att varje programrad analyseras och alla element identifieras.
Exempel:
position := ursprunglig + förändring * 60
Den ovanstående raden skulle i den lexiska analysen delas upp i sju olika delar.
1.
Identifieraren position
2. Tilldelningssymbolen :=
3. Identifieraren ursprunglig
4. Plustecknet
5. Identifieraren förändring
6. Multiplikationstecknet
7. Värdet 60
Syntaxanalys
Detta steg kallas ibland även ”parsing” och innebär att de olika elementen på en rad
grupperas hierarkiskt i till exempel ett träd i form av grammatiska fraser som används
av kompilatorn. I detta steg kontrolleras så att programmeraren inte har gjort några
syntaxfel. Uppdelningen görs efter ett antal förutbestämda regler. Exempelvis så
skulle uttrycket ursprunglig + förändring * 60 delas upp i två delar. Dels
ursprunglig och dels förändring * 60. Detta på grund av de aritmetiska reglerna
som säger att multiplikation går före addition.
Semantisk analys
Under den semantiska analysen undersöks om källprogramkoden har några
semantiska fel. Vidare så samlas information om vilka olika datatyper som används.
Denna information används bland annat för så kallad datatyp-kontroll vilket innebär
att en undersökning görs om några otillåtna datatyper används. Exempelvis så är det i
en del språk förbjudet att använda variabler av datatypen flyttal vid indexering av
listor. Andra saker som undersöks är operationer mellan två olika datatyper som till
exempel en addition av ett heltal och ett flyttal. Om en sådan operation inte kan
utföras utan extra omvandlingar, så kan kompilatorn se till att lämpliga omvandlingar
görs.
Mellanliggande kodgeneration
I denna fas genereras en abstrakt programkod. Syftet med detta är att på ett så bra sätt
som möjligt binda ihop de tre första faserna med de två sista. Den abstrakta
programkoden bör ha två egenskaper: den ska vara lätt att producera och lätt att
översätta till målprogrammet. Genereringen av abstrakt kod kan ske på många olika
sätt; ett exempel är ”three-adress code”, där varje minnesadress ses som ett register.
”Three-adress code” är uppbyggt av en sekvens med operationer. Dessa operationer
3
2 Bakgrund och begrepp
får maximalt innehålla tre operander. Den tidigare exempelkoden skulle se ut på
följande sätt:
temp1
:= id3 * 60
temp2 := id2 + temp1
id1 := temp2
Kodoptimering
Kodoptimeringen försöker förbättra koden som genererats i den mellanliggande
kodgenerationen, för att få en så snabb kod som möjligt. Även detta kan göras på
många olika sätt med olika avancerade algoritmer.
En enkel optimering av ovanstående kod skulle kunna vara:
temp1 := id3 * 60
id1 := id2 + temp1
Vid detta steg måste en avvägning göras. Antingen kan koden optimeras så bra som
möjligt vilket tar lång tid och ger snabba och små program eller också kan koden
optimeras på ett enklare sätt som går snabbare men resulterar i större och
långsammare program.
Kodgenerering
Är den sista fasen i kompileringen. Här översätts den mellanliggande koden till
maskinkod eller assemblerkod.
Symboltabell
I symboltabellen lagras information om de identifierare som används i programmet.
Här samlas även olika attribut för identifierarna. De attribut som lagas kan vara
minnesadressen till identifieraren, identifierarens typ och var i programmet den gäller.
Om identifieraren är en procedur så lagras procedurens namn, dess argument och typ
hos eventuell returvariabel.
Felhanterare
I var och en av de ovan beskrivna faserna kan fel uppstå. Om ett fel uppstår i en av
faserna så ska inte kompileringen stanna utan fortsätta så att fel längre fram i
programmet kan detekteras. Felhanterarens uppgift är att ta hand om de fel som
uppstår och lösa dessa så att kompileringen kan fortsätta.
4
2 Bakgrund och begrepp
Källprogram
Lexisk analys
Syntaxanalys
Semantisk analys
Symboltabell
hanterare
Felhanterare
Mellanliggande kodgeneration
Kodoptimerare
Kodgenerator
Målprogram
Bild 2.1: Olika faser i en kompilator
2.4 Programmeringsspråk
utvecklingsverktygen
som
ingår
i
de
utvärderade
I detta arbete utvärderas utvecklingsverktyg baserade på fem olika
programmeringsspråk. I detta avsnitt kommer en kort beskrivning av dessa fem språk.
2.4.1
C/C++
C utvecklades av Bell Laboratories 1972 och användes i början mest som
programmeringsspråk för UNIX (som också är skrivet i C) (Houston, 1989). Numera
har C flyttats till ett antal olika maskiner och finns nu till de flesta olika plattformar,
från små så kallade en-chipsdatorer till stordatorer.
C använder en två-pass kompilator. Med detta menas att kompilatorn gör två
genomgångar av programkoden. Vid den första översätts alla funktionsnamn,
variabler och anrop till minnesadresser som används vid det andra passet. Fördelen
med detta är till exempel att en funktion eller variabel som anropas inte behöver vara
deklarerad tidigare i koden utan kan vara deklarerad efter den punkt där den anropas.
C++ är en vidareutveckling av C och utvecklades av Bjarne Stroustrup på AT&T
Laboratories i början av 1980-talet. C++ skiljer sig ifrån C på tre viktiga punkter
(Lippman, 1995):
1. Stöd för att skapa och använda dataabstraktioner
5
2 Bakgrund och begrepp
2. Stöd för objektorienterad design och programmering
3. Förbättringar av många av de befintliga C-funktionerna
Trots detta behöll C++ många av de fördelar som fanns i C, som snabb exekvering
och stor uttryckbarhet (Lippman, 1995). Även C++ finns portat till många olika
plattformar och är numera också standardiserad av ANSI-kommittén (ANSI C++).
C/C++ är ett av de mest använda språken och används för att utveckla många olika
typer av applikationer. Det finns en mängd färdiga komponenter och bibliotek att
köpa ifrån tredjepartstillverkare.
2.4.2
Pascal
Pascal utvecklades av Nicklaus Wirth 1971 (Koffman, 1985). Syntaxen är relativt
enkel att lära sig och programkoden är lätt att läsa och förstå, varför Pascal ofta
används som programmeringsspråk vid programmeringskurser. Pascal är nu en
ISO/ANSI-standard och det som skiljer Pascal-kompilatorer mest ifrån de som finns
för C/C++ är att de är ”single pass”. ”Single pass” innebär att kompilatorn bara går
igenom koden en gång. Detta medför att alla funktioner och variabler som används
måste vara deklarerade tidigare i koden. Dessutom har Pascal hårdare ”typning” än
C/C++. Med hårdare typning menas bland annat att omvandlingar mellan olika
datatyper inte sker implicit som i C/C++ utan måste utföras explicit av
programmeraren.
2.4.3
Java
Java är utvecklat av Sun Microsystems och var från början tänkt att användas som ett
plattformsoberoende operativsystem för hemelektronik (Cohn, 1996).
Idag består Java av två delar. En del är själva programmeringsspråket och en del är
programkörningsmiljön. Java skiljer sig ifrån traditionella programmeringsspråk som
C++ och Pascal på det sättet att istället för att generera maskinkod för en speciell
plattform så genererar Java en så kallad ”byte-kod” som kan interpreteras på vilken
plattform som helst förutsatt att det finns en så kallad virtuell Javamaskin (Java
Virtual Machine).
Med kod som interpreteras menas att koden inte kompileras till maskinkod vid
utvecklingsarbetet utan tolkas av en programtolk varje gång programmet körs.
Syntaxen hos Java påminner om den som finns i C++ och har en del funktioner som
inte finns i C++. Till exempel har Java automatisk minneshantering och support för
multitrådade applikationer på språknivå (Cohn, 1996). Java är ett rent objektorienterat
programmeringspråk och är enligt Cohn i många avseenden lättare att använda än
C++ då det saknar multipla arv, pekare och goto-satser.
Eftersom Java är ett interpreterande språk så är prestandan beroende av hur bra
implementationen av den virtuella Javamaskinen är.
Java är starkt på frammarsch inom många olika applikationsområden, även när det
gäller PLC-system där speciella varianter för inbäddade och realtidssystem håller på
6
2 Bakgrund och begrepp
att utvecklas. I denna undersökning kommer dock inte någon av dessa varianter att
undersökas på grund av att de fortfarande är under utveckling. Det som gör Java
speciellt intressant i detta arbete är för att se hur det står sig i prestandatesterna
gentemot C/C++ och Pascal.
2.4.4
Ada/Ada95
Ada är ett hårt ”typat”, modulärt uppbyggt programmeringsspråk som påminner om
Pascal och Modula (Burns, 1985). Ada utvecklades för den amerikanska militären där
det användes som standardspråk för i stort sett all programmering. Ada är designat för
att skapa feltoleranta program och innehåller funktioner för undantagshantering och
modularitet.
Den första ANSI-standarden för Ada kom 1983 och 1995 kom nästa standard, Ada95,
som bland annat innehåller stöd för objektorientering och trådhantering (Kempe,
1996).
2.4.5
Perl
Perl står för ”Practical Extraction Report Language” och utvecklades 1986 av Larry
Wall som ville underlätta bearbetning av textfiler på UNIX (Husain, 1996). Perl är ett
interpreterande programmeringsspråk som syntaxmässigt påminner om C. Perl
innehåller bland annat mönstermatchning, modularisering, objektorientering och
POSIX-kompatibilitet (Husain, 1996). Perl används i detta arbete för att se om ett
skriptspråk med interpreterande kod, prestandamässigt går att använda i PLC-system.
Interpreterande kod är intressant i ett PLC-system då det skulle vara möjligt att ändra i
programkoden direkt i minnet på PLC-systemet, vilket eliminerar nerladdningstiden
av programmet ifrån värddatorn där programmen skrivs till måldatorn där
programmen körs.
2.5
Realtidssystem
Ett realtidssystem är ett system som reagerar på en utomstående signal inom en
förbestämd tid (Burns och Wellings, 1997), och kan delas upp i två grupper: hårda
och mjuka realtidssystem.
Ett hårt realtidssystem måste garantera att de tidskrav som är uppsatta hålls. Exempel
på ett hårt realtidssystem är styrsystem i flygplan och om dessa inte håller tidskraven
kan det resultera i en katastrof.
I mjuka realtidssystem är tidskraven viktiga men systemet fungerar även om de inte
uppfylls. Exempel på ett mjukt realtidssystem är bankomater som i värsta fall kan låta
kunden vänta en längre tid på att få ut sina pengar. Enligt Burns och Wellings är
många realtidssystem både hårda och mjuka, det vill säga de har mjuka tidskrav som
ibland kan överskridas och hårda tidskrav som inte får överskridas.
7
2 Bakgrund och begrepp
2.6
PLC-system
PLC står för ”Programable Logic Controller”, och är ett programmerbart styrsystem
som används till många olika applikationer. Ett PLC-system är uppbyggt kring en
central processor, in/ut-gränssnitt och ett minne. Själva styrprogrammet ligger i ett
minne som kan programmeras av användaren. Detta styrprogram innehåller
funktioner för in/ut-hantering, aritmetiska operationer och reglering.
Till in/ut-gränssnittet kopplas bland annat olika sensorer som läser in data ifrån
omvärlden. Beroende på vilken data som kommer in utför systemet olika uppgifter.
I ett PLC-system läggs liten vikt på presentation av information till användaren då de
flesta PLC-system saknar någon typ av bildskärm. PLC-system utför i allmänhet
ingen eller mycket liten filhantering och saknar i många fall hårddiskar. Programvaran
ligger ofta i ett ROM, (Read Only Memory) vilket gör att laddningstider blir mycket
korta jämfört med ett hårddiskbaserat system. PLC-system utför ofta någon typ av
datainsamling, exempelvis ifrån sensorer, den insamlade datan bearbetas och sedan
skapas ofta någon typ av utdata. Insamlingen och bearbetningen av data sker ofta
periodiskt, men ett PLC-system kan även arbeta avbrottsstyrt. Programmering av ett
PLC-system sker ibland bara vid utvecklingen men ofta så måste programändringar
göras även när systemet är installerat. Ett exempel på en applikation för ett PLCsystem är ett system som styr en svetsrobot.
Beroende på hur omgivningen ser ut så kan ett PLC-system både vara ett hårt och
mjukt realtidssystem. Vissa PLC-system använder sig inte av några signaler från
omgivningen och räknas därför inte som realtidssystem.
8
3 Problemprecisering
3 Problemprecisering
I detta avsnitt formuleras själva problemet och vissa avgränsningar identifieras.
3.1
Problemformulering
Vid utvärdering av utvecklingsverktyg för realtidssystem finns det ett stort antal
aspekter att ta hänsyn till. Dessa aspekter är vid kompilering, prestanda vid
exekvering av den kompilerade koden, kostnad vid inköp och vid utbildning av
personal, kvalité på dokumentation, support från tillverkaren, avlusningsfunktioner,
medföljande funktionsbibliotek och kvalité på medföljande verktyg (till exempel för
att rita gränssnitt).
I detta arbete utvärderas ett antal utvecklingsverktyg för PLC-system baserade på fem
olika språk (C/C++, Pascal, Java, Ada och Perl) utifrån både kvantitativa och
kvalitativa kriterier. Exempel på kvantitativa kriterier är effektivitet som kan mätas i
kompileringshastighet, kodeffektivitet, funktionalitet och inköpskostnad. Kvalitativa
kriterier kan vara användarvänlighet, kvalité på dokumentation och support från
tillverkaren.
3.1.1
Kvantitativa kriterier
Enligt Weiderman (1989) är det som karaktäriserar kvantitativa kriterier att de ofta
kan kontrolleras med någon typ av test. De tester som används för att mäta prestanda
kallas för benchmarktester. Ett exempel på ett prestandakriterium är
kompileringshastighet, vilken går att mäta genom att kompilera olika testprogram
under utvecklingsverktygen.
Det finns dock enligt Weiderman en hel del nackdelar med benchmarks, de påverkas
av många olika variabler vilket gör det svårt att få exakta mätningar utan att göra en
avancerad analys av systemet som testerna körs på. Det är inte bara själva systemet
som påverkar resultaten av tester. Beroende på vilka inställningar som görs i
utvecklingsverktyget kan till exempel kompileringshastigheten ändras drastiskt.
Vidare säger Weiderman att en annan svår avvägning när det gäller konstruktion av
benchmarks är att skriva själva testprogrammen. Hur ska valet av vilka funktioner
som ska utföras göras? Mer om dessa problem kommer att tas upp senare i detta
arbete.
3.1.2
Kvalitativa kriterier
Till kvalitativa kriterier hör kriterier som är svåra att mäta med hjälp av testning
(Weiderman, 1989). Ett exempel på ett kvalitativt kriterium är användarvänlighet,
alltså hur lätt det är att lära sig att behärska och använda ett utvecklingsverktyg.
Denna typen av kriterium påverkas mycket av bakgrund och erfarenhet hos
användaren.
De flesta kvalitativa kriterier kan enligt Weiderman utvärderas genom att sätta upp ett
antal checklistor där olika kvalitativa kriterier ställs upp i form av ja/nej-frågor. Till
exempel: Stödjer utvecklingsverktyget några avlusningsfunktioner? Det är sedan
9
3 Problemprecisering
relativt enkelt att undersöka de olika kriterierna. Det är enligt Weiderman alltid en
avvägning mellan att använda ja/nej-frågor och mer subjektiva frågor. I många fall så
räcker dock enligt Weiderman, ja/nej-frågorna långt när en bedömning ska göras.
3.1.3
Undersökningskriterier
Weiderman (1989, s.25) räknar upp ett antal kriterier som är intressanta vid
utvärdering av Ada-kompilatorer och vissa av dessa kriterier är även applicerbara på
andra typer av kompilatorer.
Bland de kriterier som Weiderman satt upp betraktas följande som relevanta för detta
arbete:
•
effektivitet hos genererad kod
•
kompileringshastighet
•
storlek på kompilerad kod
•
kodportabilitet
•
utbud av färdiga komponenter (bibliotek, arkiv, paket, klasser)
•
support och ”recompilation avoidance” (Undvikande av omkompilering av hela
programmet vid små ändringar).
Andra kriterier som är intressanta i ett utvecklingsverktyg är bland annat:
•
avlusningsfunktioner
•
integration mellan de olika delarna i utvecklingsmiljön
•
kopplingar till andra komponenter som exempelvis databaser.
De tre första kriterierna är kvantitativa och de övriga kvalitativa. Bland dessa kriterier
kommer de fem första att undersökas.
En utförligare förklaring och motivering av var och ett av kriterierna återfinns i
kapitel 4.3.
3.1.4
Val av programmeringsspråk för undersökningen
De programmeringsspråk som kommer att vara med i detta arbete är följande:
•
C/C++
•
Pascal
•
Java
•
Ada
•
Perl.
10
3 Problemprecisering
3.2
Avgränsning
På grund av den begränsade tiden för arbetet, så kommer vissa avgränsningar att göras
rörande vilka kriterier som skall undersökas och vilka utvecklingsverktyg som
kommer att vara med i undersökningen. Det applikationsområde utvärderingen riktar
sig mot är begränsat till utveckling av styrprogram för PLC-system och alla tester
kommer att göras med avseende på denna typ av system.
De utvecklingsverktyg som kommer att utvärderas är följande:
•
Microsoft Visual C++ v6.0: Anledningen till att använda Microsofts
utvecklingsverktyg i detta arbete är att det är den ledande utvecklingsverktyget för
PC-baserade program idag.
•
Borland Delphi v4.0 (Pascal): Innehåller en ”Single pass”-kompilator. Delphi är
ett populärt utvecklingsverktyg för många olika typer av applikationer.
•
Mircosoft Visual J++ v1.1: Visual J++ är en av de större kommersiella
utvecklingsverktygen för Java. Det har är en mer komplett utvecklingsmiljö
jämfört med Suns JDK (Java Development Kit) och fanns tillgängligt för detta
arbete.
•
AdaIDE v2.5 for GNAT 3.09 (Ada 95): AdaIDE är ett utvecklingsverktyg som
använder GNAT för att generera C-kod av Ada-kod. GCC (Gnu C Compiler)
används sedan för kompilering.
•
Active Perl 5.15 med Perl Development Kit 1.14: Ett utvecklingsverktyg för
Perl.
Förutom dessa finns det ytterligare ett antal utvecklingsverktyg/programmeringsspråk
som hade varit intressanta att ta med i utvärderingen. Bland dessa finns till exempel
Diabs realtidskompilator för C (Diab Data). Anledningen till att inga
realtidskompilatorer för C är med i utvärderingen är att de som finns tillgängliga för
detta arbete inte kan köras under Windows utan bara under Solaris på Sun-hårdvara.
Vissa av utvärderingskriterierna är svåra att jämföra om alla tester inte körs med
samma förutsättningar. Vidare skulle det vara intressant att undersöka hur ett
utvecklingsverktyg baserat på assembler hade stått sig mot utvecklingsverktyg
baserade på högnivåspråk. Anledningen till att ingen assembler finns med är på grund
av att assembler saknar många av de funktioner som finns i ”modernare”
programmeringsspråk, till exempel funktioner med parameterlistor och abstrakta
datatyper. Assembler används inte heller i större utsträckning när det gäller större
system. När det gäller utvecklingsverktyg för C/C++ (ej med realtidskompilatorer) så
finns många att välja mellan från olika tillverkare. Om en begränsning görs till att
använda Windows95/98/NT så finns det fortfarande många att tillgå. Bland de som
inte kommer att undersökas är Borland C++ Builder och Watcom C++, vilka är två av
de större utvecklingsverktygen för C++. Anledningen till att dessa inte undersöks är
dels att de inte finns tillgängliga för detta arbete och dels för att tiden är begränsad.
11
3 Problemprecisering
Förutom dessa så finns det ett antal andra programmeringsspråk som kunde vara
intressanta att ha med i jämförelsen. Bland dessa finns Modula, Basic och Fortran.
Dessa valdes bort på grund av att de sällan används för realtidssystem idag.
12
4 Metoder
4 Metoder
De flesta metoderna i en utvärdering går ut på att samla in information om det som
skall utvärderas. Information kan inhämtas på flera olika sätt. Patel och Davidson
(1994) beskriver ett antal tekniker som ofta används för att samla information om en
frågeställning. Informationen kan fås via befintliga dokument, test och prov, olika
typer av självrapporteringar, observationer, enkäter, intervjuer och attitydskalor.
De informationskällorna som är mest relevanta för detta arbete är:
•
befintliga dokument: böcker, tekniska rapporter, information ifrån tillverkaren etc.
•
egna tester
•
enkäter och intervjuer av de som arbetar med det som skall utvärderas.
I detta arbete används de tre ovanstående informationskällorna för att samla in
information. Den insamlade informationen används för att utvärdera två typer av
kriterier:
•
Kvantitativa kriterier: Vid utvärdering av kvantitativa kriterier är olika tester en
bra metod. Det är en fördel om testerna görs med avseende på den typ av uppgift
systemet är tänkt att utföra. Detta är dock inte alltid möjligt då sådana tester ibland
blir väldigt omfattande.
•
Kvalitativa kriterier: När kvalitativa kriterier skall undersökas är det viktigt att
resultatet inte blir alltför subjektivt, vilket kan vara fallet vid för detaljerade
frågor. Den som utvärderar ett kriterium kan med sina egna åsikter påverka
resultatet, både positivt och negativt.
4.1
Jämförelse av metoder
Här utvärderas de olika metoderna för informationsinhämtning för att se vilka som
passar bäst för att utvärdera kvantitativa och kvalitativa kriterier.
4.1.1
Kvantitativa kriterier
Befintliga dokument: Det finns ofta mycket information att hämta från befintliga
dokument. När det gäller benchmarks så kan information fås både från tillverkaren
och från användare. Dock finns det en del problem med benchmarks. För att
exempelvis utvärdera hastigheten hos en kompilator behövs ett mått på snabbhet
(Weiderman, 1989). Många tillverkare använder ”rader kod per minut” som mått.
Detta mått är inte speciellt bra definierat och är väldigt beroende av de givna
förutsättningarna. Bland de faktorer som påverkar resultatet finns:
•
maskinen och operativsystemet testen körts på
•
vilka parametrar kompilatorn har fått (till exempel för optimering och avlusning)
•
antalet kommentarer och tomma rader
•
definitionen på en ”rad kod” (vanligtvis brukar en rad räknas för varje
radmatningstecken som finns i programkoden)
13
4 Metoder
•
storleken på programmet som kompileras (små program har ofta lägre ”rader kod
per minut” än stora program)
•
definition av tid (en vanlig klocka räknar med I/O-fördröjningar medan CPU-tid
inte alltid gör det).
Om hänsyn tas till detta så är benchmarkresultat från tillverkare inte speciellt
relevanta i en jämförelse mellan olika programmeringsspråk och kompilatorer. För att
en relevant jämförelse ska kunna göras så måste alla tester göras med samma
förutsättningar, vilket inte är troligt då många tillverkare anpassar förutsättningarna så
att deras produkter ger så bra resultat som möjligt. Samma problem finns med resultat
från utomstående tester på en viss kompilator. Att använda befintlig information från
prestandatester är alltså ingen bra metod i detta arbete.
Egna tester: Fördelarna med att göra egna tester är att samma förutsättningar kan ges
för alla utvecklingsverktyg som testas. Resultatet blir därför mer rättvist än
information från tillverkare och användare. När testfall skapas är det många faktorer
som måste tas med, både när det gäller plattformen testet skall göras på och själva
testprogrammen. De faktorer som kan påverka resultatet är bland annat (Weiderman,
1989):
•
Processorn: Beroende på hur processorn är uppbyggd påverkas testresultat på
olika sätt. De delar i processorn som påverkar resultatet är bland annat
cacheminne, pipelines, register, klockfrekvens, minneshantering, bredd på bussar,
intern arkitektur, interrupt och upplösningen på klockgeneratorn.
•
Operativsystemet: De faktorer i operativsystemet som påverkar tester är bland
annat enanvändarsystem kontra fleranvändarsystem, en eller flera processer som
körs parallellt, minneshantering och filsystem, schemaläggning i multiprocess
system, olika typer av systemprocesser och ”garbage collection”.
•
Minne: Faktorer här som kan påverka resultaten är cacheminne, bandbredd till
processorn, bredd på minnesbussen, klockfrekvens på minnesbussen,
periferienheter som ”stjäl” minnesklockcyklar och grad av minnesfragmentering.
•
Arkitektur: Hur datorn är uppbyggd, hur många processorer datorn har och vilka
databussar som finns och hur de används.
•
Tidmätning: Hur tiden mäts och vilken noggrannhet som används.
•
Kompilering: Vid kompilering kan till exempel vald grad av optimering påverka
resultatet på benchmarks.
Många av dessa faktorer påverkar resultatet av testerna i detta arbete. För att få så
rättvisa tester som möjligt vidtas vissa åtgärder för att eliminera påverkan från så
många som möjligt av ovanstående faktorer. Mer information om dessa åtgärder finns
i kapitel 5.1.
Enkäter och intervjuer: Med enkäter och intervjuer finns samma problem som vid
information via befintliga dokument. En annan nackdel är att informationen från
14
4 Metoder
denna typ av källa ofta är subjektiv. Denna informationskälla är därför inte speciellt
intressant för benchmarkresultat och används inte i detta arbete.
4.1.2
Kvalitativa kriterier
Befintliga dokument: Oavsett om de kvalitativa kriterierna är omskrivna på ja/nejform eller inte, så är befintliga dokument en utmärkt informationskälla för kvalitativa
utvärderingar. Både information från tillverkaren och från andra utomstående källor
kan användas i en utvärdering.
Egna tester: Egna tester fungera som en informationskälla för kvalitativa kriterier
och har samma för och nackdelar som befintliga dokument. I detta arbete har egna
tester av kvalitativa kriterier fungera som ett komplement till befintliga dokument.
Enkäter och intervjuer: En bra informationskälla om frågorna ställs på rätt sätt.
Även här finns risk för att svaren blir subjektiva. På grund av den begränsade
tidsramen för detta arbete genomförs inga enkäter eller intervjuer.
4.2
Vald metod
De undersökningar som görs i detta arbete kan delas upp i två olika kategorier:
undersökningar av kvantitativa kriterier och undersökningar av kvalitativa kriterier.
För att undersöka de kvantitativa kriterierna har egna tester att gjorts då detta ger den
mest rättvisa jämförelsen mellan de olika kompilatorerna och utvecklingsverktygen.
För de kvalitativa kriterierna har en litteraturstudie av befintliga dokument att gjorts.
4.3
Precisering av utvärderingskriterier för undersökningen
De kvantitativa kriterier som utvärderas i detta arbete är följande:
•
effektivitet hos genererad kod
•
kompileringshastighet
•
storlek på kompilerad kod.
Effektivitet hos genererad kod: Med detta menas hur snabbt den genererade
maskinkoden eller den interpreterade koden exekveras. Detta är viktigt i ett PLCsystem då olika tidskrav ofta är inblandade och ju effektivere koden är desto lättare är
det att möta dessa tidskrav.
Effektivitet hos genererad kod har utvärderas genom att ett antal testprogram skrivs
och sedan testkörs. Testprogrammen redovisas längre fram.
Kompileringshastighet: Kompileringshastigheten utvärderas i detta arbete genom att
kompileringstiden för ett antal testprogram mäts. Kompileringstid innebär hur snabbt
kompilatorn kompilerar ett visst program. Mer information om testprogrammen följer
längre fram i rapporten.
Vid utveckling av programvara för PLC-system är kompileringshastigheten viktig då
många omkompileringar kan behövas när ett system skall anpassas till att fungera
enligt specifikationen.
15
4 Metoder
Storlek på kompilerad kod: Vid utveckling av program för persondatorer är
storleken på den kompilerade programfilen inte speciellt viktig, då de datorer
programmen kommer att köras på ofta har stora hårddiskar och ramminne. När det
gäller PLC-system är dock både den eventuella hårddisken och ramminnet
begränsade, men ofta är detta inget problem då det för det mesta går att utöka dessa
minnen. Ännu viktigare är nerladdningstiden, det vill säga den tid det tar att ladda ner
ett program ifrån utvecklingsplattformen till målplattformen. Denna nerladdning sker
många gånger under utvecklingsarbetet och det är då viktigt att den går så fort som
möjligt. Det är alltså positivt om en kompilator skapar så små programfiler som
möjligt. Vid testerna av effektiviteten hos den kompilerade koden kommer även
storleken på programfilen att mätas. När det gäller Java och Perl behövs det extra filer
för att köra programmen, dels en programtolk och dels de bibliotek eller klasser som
används. Vid storleksmätningarna kommer även dessa att räknas in.
De två övriga kriterier som kommer att undersökas är kvalitativa och är följande:
•
kodportabilitet
•
utbud av färdiga komponenter (bibliotek, arkiv, klasser och moduler).
Kodportabilitet: Med kodportabilitet menas dels hur lätt det är att flytta kod ifrån ett
utvecklingsverktyg till ett annat och kompilera om den där, och dels hur lätt kod kan
flyttas från ett målsystem till ett annat med annorlunda hårdvara. Hur god
kodportabilitet ett visst utvecklingsverktyg har är viktigt att tänka på när man
utvecklar programvara för PLC-system. Det beror på att målsystemets hårdvara ibland
måste bytas ut för att till exempel få ett snabbare system. Om själva programkoden då
är lätt att flytta mellan olika hårdvaruplattformar så leder detta till att kostnaden för ett
hårdvarubyte kan hållas nere, då stora delar av den gamla programkoden kan
användas. Kodportabiliteten undersöks med en subjektiv bedömning av den
information som finns tillgänglig på tillverkarens hemsida på Internet samt delvis via
egna tester. Alla utvecklingsverktyg bedöms och tilldelats ett av tre olika omdömen:
• God kodportabilitet: Koden kan utan några som helst problem eller
ändringar användas i ett annat utvecklingsverktyg eller på en annan hårdvara.
• Medelgod kodportabilitet: Koden kan med vissa mindre ändringar användas
i ett annat utvecklingsverktyg eller på en annan hårdvara.
• Dålig kodportabilitet: Koden kan inte utan stora ändringar användas i ett
annat utvecklingsverktyg eller på en annan hårdvara.
16
4 Metoder
Utbud av färdiga komponenter (bibliotek, arkiv, klasser och moduler): Hur
mycket färdiga komponenter som ingår i utvecklingsverktyget och som kan köpas
ifrån tredjepartstillverkare. Exempel på färdiga komponenter är funktionsbibliotek för
databaskoppling och TCP/IP (nätverksprotokoll). Utbudet av färdiga komponenter
görs genom en subjektiv bedömning av information från tillverkaren och olika källor
på Internet. Även här används tre olika omdömen. Dessa tre är:
• God tillgång till färdiga komponenter: Många typer av färdiga komponenter
finns att få tag på, antingen via tredjepartstillverkare eller direkt från
tillverkaren.
• Medelgod tillgång till färdiga komponenter: Många typer av färdiga
komponenter finns att få tag på, antingen via tredjepartstillverkare eller direkt
från tillverkaren, dock är utbudet av leverantörer begränsat.
• Dålig tillgång till färdiga komponenter: Få färdiga komponenter finns att få
tag på, via tredjepartstillverkare eller direkt av tillverkaren.
Tom text för att word inte ska bugga
4.4
Benchmarks
De benchmarktester som används i detta arbete kommer dels från Bolin (1997) och
dels från idéer av Weiderman (1989) som vidareutvecklats. Test 1-16 kommer ifrån
Bolin (1997). Dessa tester är anpassade till detta arbete. Anpassningen är att i detta
arbete körs testprogrammen i en loop ett fast antal gånger, Bolin använder en loop
som kör testprogrammen under en bestämd tid. Mätningarna görs med ett fast antal
iterationer och tiden mäts med 4DOS (JP Software, 1999). Test 17 bygger på
Weidermans förslag till tester av Ada-kompilatorer och test 18 är ett av deltesten i
Linpacktesten, (Grace, 1996) som har anpassats för detta arbete.
4.4.1
Språkfunktionstester
Enligt Weiderman (1989) finns det många olika typer av benchmarks. Weiderman
beskriver fem olika typer: språkfunktionstester, kapacitetstester, komposittester,
symmetriska tester samt applikationsspecifika tester. I detta arbete genomförs bara
språkfunktionstester. Det innebär att testerna i detta arbete testar enstaka funktioner
var för sig hos ett språk. De funktioner som testas är grundfunktioner. Anledningen
till detta är att ett program ofta består av en kombination av dessa funktioner. Denna
typ av tester visar svagheter hos olika delar i ett utvecklingsverktyg. Om den
programvara som skall utvecklas använder vissa funktioner mycket kan
utvecklingsverktyget väljas med stöd av denna typ av tester. Dock är det svårt att få
den exakta prestandan utvärderad i denna typ av test. I detta arbete är
språkfunktionstest intressanta för att de visar skillnaden i prestanda mellan olika
utvecklingsverktyg. De övriga testtyperna ger inte heller ett exakt prestandavärde utan
bara ett ungefärligt prestandavärde. Undantaget är applikationsspecifika tester.
Problemet med dessa är att applikationen inte är skriven när utvecklingsverktyg skall
väljas.
17
4 Metoder
4.4.2
Testfall för kodeffektivitet
1. Loopoverhead: Testerna körs i en loop ett antal gånger. Vid dessa tester är det
inte bara själva testfallet som påverkar tiden utan också de anrop som behövs för
själva loopen. För att eliminera de fel som kan uppstå körs detta test med en tom
loop med fyra olika loopvärden: 100,000; 1,000,000; 10,000,000 och
100,000,000. Resultatet på detta test används för att justera resultaten på de andra
testen.
2. Lokal variabeltilldelning: Testar hastigheten vid en lokal variabeltilldelning.
Exempel: n:=i, där i är en ökande 32-bitars lokal heltalsvariabel. Under testet görs
10,000,000 tilldelningar i en loop.
3. Global variabeltilldelning: Testar hastigheten vid en global variabeltilldelning.
Exempel: n:=i, där i är en ökande 32-bitars global heltalsvariabel. Under testet
görs 10,000,000 tilldelningar i en loop.
4. Matristilldelning: Testar hastigheten vid tilldelning av värden till olika element i
en matris. Matrisen består av fyra heltal som tilldelas stigande heltalsvärden.
Under testet körs en loop 10,000,000 varv där alla fyra elementen tilldelas nya
värden på varje varv i loopen.
5. Uppräkning av 8-bitarsvariabel: Detta test räknar upp en 8-bitars teckenlös
heltalsvariabel ett antal gånger. Under testet så körs 10,000,000 uppräkningar där
varje uppräkning ökar variabeln med 1. Variabeln tillåts ”slå runt” när den nått sitt
maxvärde.
6. Uppräkning av 16-bitarsvariabel: Räknar upp en 16-bitars heltalsvariabel med
tecken ett antal gånger. Under testet så körs 10,000,000 uppräkningar där varje
uppräkning ökar variabeln med 1. Variabeln tillåts ”slå runt” när den nått sitt
maxvärde.
7. Uppräkning av 32-bitarsvariabel: Detta test räknar upp en 32-bitars
heltalsvariabel med tecken ett antal gånger. Under testet så körs 10,000,000
uppräkningar där varje uppräkning ökar variabeln med 1. Variabeln tillåts ”slå
runt” när den nått sitt maxvärde.
8. Uppräkning av 64-bitarsvariabel: Detta test räknar upp en 64-bitars
heltalsvariabel med tecken ett antal gånger. Under testet så körs 10,000,000
uppräkningar där varje uppräkning ökar variabeln med 1. Variabeln tillåts ”slå
runt” när den nått sitt maxvärde.
9. Uppräkning av 64-bitars flyttalsvariabel: Detta test räknar upp en 64-bitars
flyttalsvariabel med tecken ett antal gånger. Under testet så körs 10,000,000
uppräkningar där varje uppräkning ökar variabeln med 1. Variabeln tillåts ”slå
runt” när den nått sitt maxvärde.
10. Matrisallokering: Detta test skapar en matris med 4 stycken 32-bitars heltal.
Under testet skapas matrisen 10,000,000 gånger i en loop. De gamla matriserna
18
4 Metoder
deallokeras direkt efter att de allokerats för att minnet inte skall ta slut under
testen.
11. Funktionsanrop: Detta test anropar en parameterlös funktion som inte innehåller
någon kod. Även detta test kommer att utföras 10,000,000 gånger i en loop.
12. Anrop av matematisk funktion 1: Detta test anropar funktionen för absolutvärde
på en heltalsvariabel. Under testet körs 10,000,000 anrop av funktionen.
13. Anrop av matematisk funktion 2: Detta test anropar den inbyggda funktionen
för cosinus på en 32 bitars flyttalsvariabel. Under testet körs 10,000,000 anrop av
funktionen men fyra olika värden: 15.0, 30.0, 45.0 och 60.0.
14. Villkorstest: Detta test utför utvärderingar av villkor. Under testet körs
10,000,000 anrop av en if-else if-else-sats.
15. Strängallokering: Detta test allokerar upp en ny sträng på 50 tecken. Under testet
skapas strängen 10,000,000 gånger i en loop. De gamla strängarna deallokeras
direkt efter de allokerats för att minnet inte skall ta slut under testen.
16. Typecasting: Detta test gör en ”typecast” på en flyttals- till en heltalsvariabel.
Under testet körs denna ”typecast” 10,000,000 gånger i en loop. Flyttalsvariabeln
initieras till värdet 1000.
17. Rekursivt anrop: Detta test gör ett rekursivt anrop som resulterar i 100,000
iterationer.
18. Lintest: Detta test är en del av Linpacktesten (Grace, 1996) och testar hastigheten
vid linjära funktioner. I detta arbete beräknas den linjära funktionen:
2/3n^3+2n^2. Detta görs 10,000,000 gånger i en loop. Istället för n^3 och n^2 så
används loopräknarvariabeln/10 och loopräknarvariabeln/100 vid uträkningarna.
4.4.3
Testfall för kompileringshastighet
För att testa kompileringshastighet hos de olika utvecklingsverktygen används
speciella testprogram. Dessa testprogram består av alla de ovanstående testfallen i ett
och samma program där var och ett av testfallen är duplicerade ett antal gånger för att
få ett så stort program som möjligt. Anledningen till att de ovanstående testfallen
används istället för att skriva ett helt nytt testprogram är att den begränsade tiden för
detta arbete inte tillåter att ett helt nytt testprogram utvecklas.
19
5 Genomförande
5 Genomförande
I detta avsnitt redovisas resultat av genomförandet av tester och undersökningar. Först
redovisas resultatet av de kvantitativa testerna och sedan resultaten av de kvalitativa
undersökningarna.
5.1
Förutsättningar för tester
Alla tester i undersökningen körs på en 200 MHz Pentiumdator med 32Mbyte
ramminne och 4.3Gbyte IDE hårddisk. Vid testerna används Windows 98 som
operativsystem. För tidmätningarna används 4DOS inbyggda tidmätningsfunktioner.
Dessa ger en noggrannhet på en hundradels sekund vilket är betydligt bättre än att
använda ett stoppur. Ett bättre alternativ till 4DOS för tidmätning är att i varje
testprogram läsa av systemtimern före och efter själva testen. Anledningen till att
detta inte gjordes är att de nödvändiga funktionerna för detta inte finns tillgängliga i
alla utvecklingsverktyg som testas och att inte finns tid att skapa den nödvändiga
funktionaliteten under detta arbete. Ett problemet med att använda 4DOS för
tidsmätning är att även programladdning ingår i den uppmätta tiden. För att förhindra
att detta påverkar resultatet allt för mycket, så körs alla tester 12 gånger efter varandra
där det högsta och lägsta resultatet tas bort och de övriga används för att beräkna ett
medelvärde på tiden för testet. Denna metod förhindrar att laddningstiderna påverkar
resultatet allt för mycket. Efter den första testkörningen så befinner sig programmet i
disk-cachen och laddas mycket fort. Dock är det inte alltid säkert att det första testet
tar längst tid. I ett PLC-system är programmets laddningstid inte speciellt intressant
då programmen ofta laddas från ett snabbt ROM-minne och inte från en hårddisk.
För att inte datorns cache ska påverka resultatet, har både den interna (i processorn)
och den externa cachen i testdatorns varit avstängda. Under testkörningarna finns
endast två processer på testdatorn: Explorer och 4DOS. Explorer måste vara igång för
att kunna använda Windows och går inte att stänga av. Utöver dessa processer körs
testprogrammet och dess eventuella tolk. Vid alla tester är all optimering i
kompilatorerna avstängd.
Alla tester kan inte genomföras med alla de fem utvecklingsmiljöerna, till exempel så
saknar Perl vissa av de funktioner som krävs för dynamisk minneshantering. I dessa
fall anpassas testprogrammen för att köras på ett liknande sätt. Hur denna anpassning
gjordes beskrivs i kapitel 5.2.
Vid testkörningar av Javaprogram användes Suns JRE 1.1.8 (Java Run-time
Environment) med JIT (Just In Time compilation) påslaget. JIT innebär att delar av
Javakoden kompileras till maskinkod vid exekvering i tolken.
20
5 Genomförande
5.2
Effektivitet hos genererad kod
I dessa tester har 18 olika testprogram körts på var och ett av utvecklingsverktygen.
Vissa av testerna har inte kunnat genomföras på alla verktygen på grund av att några
av verktygen saknar vissa av de funktioner som används i testerna.
I diagrammen för benchmark 2 till 18 finns två tider. En som kallas totaltid och är den
uppmätta tiden för testet. Den andra tiden kallas för omräknad tid och består av
totaltiden med loopoverheaden bortdragen.
5.2.1
Loop overhead
Kör en tom loop mellan 10^5 och 10^8 gånger.
Loop overhead - Loopvärde: 10^5 - 10^8
1000
100
sekunder
10^5
10^6
10^7
10^8
10
1
GNAT (Ada)
Microsoft Visual
C++
Mircosoft J++
Borland Delphi
Active Perl
10^5
1,852
0,7012
7,675
0,835
11,246
10^6
3,746
2,169
8,209
1,306
94,019
10^7
20,737
13,603
13,546
6,463
922,107
10^8
187,789
125,535
66,87
52,198
9184,32
GNAT, Visual C++, J++ och Delphi har jämförbara prestanda i loopoverheadtesten.
Värdena ifrån testerna med Active Perl är så höga att de inte kommer att redovisas i
diagramform i resten av testerna, detta för att resultaten från de fyra första
utvecklingsverktygen skall synas bättre.
21
5 Genomförande
5.2.2
Lokal variabeltilldelning
Testar exekveringstiden vid tilldelning av värde till en lokal variabel.
Lokal variabeltilldelning - Loopvärde: 10^7
80,00
70,00
60,00
sekunder
50,00
Totaltid (sek)
40,00
Omr. tid (sek)
30,00
20,00
10,00
0,00
5.2.3
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
30,79
30,94
66,86
19,16
Omr. tid (sek)
10,06
17,34
53,31
6,49
Active Perl
1359,63
437,53
Global variabeltilldelning
Testar exekveringstiden vid tilldelning av värde till en global variabel.
Global variabeltilldelning - Loopvärde: 10^7
80,00
70,00
60,00
sekunder
50,00
Totaltid (sek)
40,00
Omr. tid (sek)
30,00
20,00
10,00
0,00
Active Perl
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
29,80
20,85
66,87
17,25
1358,44
Omr. tid (sek)
9,06
7,25
53,32
4,58
436,33
22
5 Genomförande
5.2.4
Matristilldelning
Tilldelar värden till olika element i en matris.
Matristilldelning - Loopvärde: 10^7
120,00
100,00
sekunder
80,00
Totaltid (sek)
60,00
Omr. tid (sek)
40,00
20,00
0,00
5.2.5
Active Perl
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
41,57
35,75
103,06
33,04
6083,47
Omr. tid (sek)
20,83
22,15
89,51
20,37
5161,37
Uppräkning av 8-bitarsvariabel
Räknar upp en 8-bitarsvariabel och låter den ”slå runt” vid maxvärde.
Uppräkning av 8-bitarsvariabel - Loopvärde: 10^7
80,00
70,00
60,00
sekunder
50,00
Totaltid (sek)
40,00
Omr. tid (sek)
30,00
20,00
10,00
0,00
Active Perl
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
29,08
21,02
66,83
16,35
1136,22
Omr. tid (sek)
8,35
7,42
53,29
3,67
214,12
I Perl finns bara en enda variabeltyp som kan innehålla allt ifrån heltal och flyttal till
strängar. Perl finns med i alla av de fem uppräkningstesterna. Dock så används
23
5 Genomförande
samma testprogram till alla heltalsuppräkningstesterna. Till flyttalsuppräkningen
används en lite modifierad version. Mer om detta i avsnitt 5.2.9.
5.2.6
Uppräkning av 16-bitarsvariabel
Räknar upp en 16-bitarsvariabel och låter den ”slå runt” vid maxvärde.
Uppräkning av 16-bitarsvariabel - Loopvärde 10^7
80,00
70,00
60,00
sekunder
50,00
Totaltid (sek)
40,00
Omr. tid (sek)
30,00
20,00
10,00
0,00
Active Perl
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
31,20
21,98
66,85
16,33
1136,22
Omr. tid (sek)
10,46
8,38
53,31
3,66
214,12
Testprogrammet för Perl är samma som vid uppräkning av 8-bitarsvariabel.
5.2.7
Uppräkning av 32-bitarsvariabel
Räknar upp en 32-bitarsvariabel och låter den ”slå runt” vid maxvärde.
Uppräkning av 32-bitarsvariabel - Loopvärde: 10^7
80,00
70,00
60,00
sekunder
50,00
Totaltid (sek)
40,00
Omr. tid (sek)
30,00
20,00
10,00
0,00
Active Perl
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
29,93
21,02
66,92
16,36
1136,22
Omr. tid (sek)
9,19
7,41
53,37
3,69
214,12
24
5 Genomförande
Testprogrammet för Perl är samma som vid uppräkning av 8-bitarsvariabel.
5.2.8
Uppräkning av 64-bitarsvariabel
Räknar upp en 64-bitarsvariabel och låter den ”slå runt” vid maxvärde.
Uppräkning av 64-bitarsvariabel - Loopvärde: 10^7
80,00
70,00
60,00
sekunder
50,00
Totaltid (sek)
40,00
Omr. tid (sek)
30,00
20,00
10,00
0,00
Active Perl
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
62,01
21,07
66,86
24,50
1136,22
Omr. tid (sek)
41,27
7,46
53,32
11,83
214,12
Testprogrammet för Perl är samma som vid uppräkning av 8-bitarsvariabel.
5.2.9
Uppräkning av 64-bitars flyttalsvariabel
Räknar upp en 64-bitars flyttalsvariabel och låter den ”slå runt” vid maxvärde.
Uppräkning av 64-bitars flyttalsvariabel - Loopvärde: 10^7
80,00
70,00
60,00
sekunder
50,00
Totaltid (sek)
40,00
Omr. tid (sek)
30,00
20,00
10,00
0,00
Active Perl
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
29,21
23,95
66,88
20,20
1184,21
Omr. tid (sek)
8,48
10,34
53,33
7,53
262,11
25
5 Genomförande
Testprogrammet för Perl är samma som används vid uppräkning av 8-bitarsvariabel
med en modifikation så att uppräkningsvariabeln initieras till ett flyttal och inte ett
heltal.
5.2.10 Matrisallokering
Allokerar upp en matris med fyra 32-bitars heltalsvärden. Matrisen deallokeras i varje
varv i loopen.
Matrisallokering - Loopvärde: 10^7
16000,00
14000,00
12000,00
sekunder
10000,00
Totaltid (sek)
8000,00
Omr. tid (sek)
6000,00
4000,00
2000,00
0,00
Active Perl
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
420,77
896,17
14869,96
427,51
N/A
Omr. tid (sek)
400,03
882,57
14856,41
414,84
N/A
Detta test gick inte att genomföra i Perl. Anledningen till detta är att funktioner för
dynamisk allokering av variabler inte finns tillgängliga.
Anledningen till att Java kommer så långt efter de övriga i denna test kan bero på att
Java automatiskt genomför ”garbage collection”. Deallokering av ett dynamiskt
allokerat element sker när alla referenser till det frigörs. I detta fallet frigörs
referensen varje varv i loopen vilket kan medföra att den Virtuella Javamaskinen utför
en ”garbage collection” vilket skulle förklara resultatet av detta test.
26
5 Genomförande
5.2.11 Funktionsanrop
Anropar en tom, parameterlös funktion.
Funktionsanrop - Loopvärde: 10^7
80,00
70,00
60,00
sekunder
50,00
Totaltid (sek)
40,00
Omr. tid (sek)
30,00
20,00
10,00
0,00
Active Perl
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
46,86
36,39
67,16
22,20
2710,45
Omr. tid (sek)
26,13
22,79
53,61
9,53
1788,34
5.2.12 Anrop av matematisk funktion 1
Beräknar absolutvärdet av –30.
Matematisk funktion 1 (abs) - Loopvärde: 10^7
70,00
60,00
50,00
40,00
Totaltid (sek)
Omr. tid (sek)
30,00
20,00
10,00
0,00
Active Perl
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
25,18
36,78
58,79
15,32
1319,95
Omr. tid (sek)
4,44
23,18
45,25
2,65
397,85
Nämnvärt i denna test är att Visual C++ kommer så långt efter GNAT och Borland
Delphi. Detta kan bero på att abs-funktionen är implementerad på ett långsammare
sätt än hos GNAT och Borland Delphi.
27
5 Genomförande
5.2.13 Anrop av matematisk funktion 2
Beräknar cosinus för 15.0; 30.0; 45.0 och 60.0.
Matematisk funktion 2 (cos) - Loopvärde: 10^7
2000,00
1800,00
1600,00
sekunder
1400,00
1200,00
Totaltid (sek)
1000,00
Omr. tid (sek)
800,00
600,00
400,00
200,00
0,00
Active Perl
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
1753,63
121,63
67,27
36,91
1338,62
Omr. tid (sek)
1732,89
108,02
53,73
24,24
416,51
I detta test utfördes fyra deltester där olika värden på cosinus används. I diagrammet
finns medelvärdet för dessa fyra testerna.
GNAT får väldigt dåliga testresultat vilket kan bero på en långsam implemenation av
cosinusfunktionen. Visual C++ tar dubbelt så lång tid på sig som Java i detta test men
skillnaden är inte så stor som mellan GNAT och de övriga. Även detta kan bero på att
implementationen av cosinus i Visual C++ inte är lika snabb som den i Java och
Borland Delphi.
28
5 Genomförande
5.2.14 Villkorstest
Utvärderar en ”if-else if-else” selektion.
Villkorstest - Loopvärde: 10^7
80,00
70,00
60,00
sekunder
50,00
Totaltid (sek)
40,00
Omr. tid (sek)
30,00
20,00
10,00
0,00
Active Perl
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
29,64
15,47
67,21
25,51
1405,41
Omr. tid (sek)
8,91
1,87
53,67
12,84
483,31
Anmärkningsvärt i detta test är att Visual C++ får så väldigt bra resultat. Detta kan
bero på en bra implementation av selektioner.
5.2.15 Strängallokering
Allokerar upp minne för en 50 tecken lång sträng. Strängen deallokeras vid varje varv
i loopen.
Strängallokering - Loopvärde: 10^7
40000,00
35000,00
30000,00
sekunder
25000,00
Totaltid (sek)
20000,00
Omr. tid (sek)
15000,00
10000,00
5000,00
0,00
Active Perl
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
425,75
895,28
37050,22
426,89
N/A
Omr. tid (sek)
405,02
881,68
37036,67
414,22
N/A
29
5 Genomförande
Detta test gick inte att genomföra i Perl. Anledningen till detta är att funktioner för
dynamisk allokering av variabler inte finns tillgängliga. Anledningen till att Java fick
så dåliga värden är troligtvis samma som för matrisallokeringstesten. Axlarna är
skalade så att skillnaden mellan GNAT, Visual C++ och Delphi ska synas.
5.2.16 Typecasting
Utför en typecast från en flyttalsvariabel innehållande värdet 1000 till en 32-bitars
heltalsvariabel.
Typecasting - Loopvärde: 10^7
80,00
70,00
60,00
sekunder
50,00
Totaltid (sek)
40,00
Omr. tid (sek)
30,00
20,00
10,00
0,00
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Active Perl
Totaltid (sek)
69,22
61,08
67,20
N/A
N/A
Omr. tid (sek)
48,48
47,48
53,66
N/A
N/A
Detta test har inte varit möjligt att köra i Delphi och Perl. Detta beror på att Delphi
inte tillåter den typ av typecasting som testen gör. Perl har bara en datatyp vilket leder
till att typecasting inte behövs.
30
5 Genomförande
5.2.17 Rekursivt anrop
Utför en rekursiv loop.
Rekursivt anrop - Loopvärde: 10^5
9,00
8,00
7,00
sekunder
6,00
5,00
Tid (sek)
4,00
3,00
2,00
1,00
0,00
Tid (sek)
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
2,96
1,10
8,17
1,18
Active Perl
N/A
Perl stöder inte rekursiva anrop och kan därför inte vara med i denna test.
5.2.18 Lintest
Utför en beräkning av en linjär ekvation.
Lintest - Loopvärde: 10^7
60,00
50,00
sekunder
40,00
Totaltid (sek)
30,00
Omr. tid (sek)
20,00
10,00
0,00
Active Perl
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Totaltid (sek)
55,70
38,23
36,17
39,82
4005,92
Omr. tid (sek)
34,96
24,63
22,62
27,15
3083,81
31
5 Genomförande
5.3
Kompileringshastighet
I denna test har tre speciella testprogram kompilerats och tiden för kompileringen är
uppmätt på samma sätt som i exekveringshastighetstesterna. Perlprogram behöver inte
kompileras vilket leder till att kompileringstiden är noll.
Kompileringstid
250,00
sekunder
200,00
150,00
100,00
50,00
0,00
K-Test 1
K-Test 2
K-Test 3
Ada
99,25
137,97
206,46
C++
20,99
22,9
38,01
Java
19,99
44
109,03
Delphi
10,00
16,97
19,99
0
0
0
Perl
Vid test har tre olika program kompilerats. Det som skiljer dessa är främst storleken.
Testprogram ett (K-Test 1) är mellan 33 och 45 kb, testprogram två (K-Test 2) är
mellan 66 och 92 kb och det tredje testprogrammet (K-Test 3) är mellan 134 och 180
kb. Alla olika språkversioner av varje testprogram utför samma sak, dock varierar
programstorlekarna på grund av de enskilda språkens egenskaper. K-Test 1 består av
19 av benchmarktestprogrammen i 5.2, inlagda i ett och samma program, som var och
ett är duplicerade 9 gånger med olika namn. I K-Test 2 har hela K-Test 1 duplicerats.
Det samma gäller K-Test 3 där K-Test 2 har duplicerats.
32
5 Genomförande
5.4
Storlek på kompilerad kod
I detta avsnitt redovisas storleken på den körbara koden som genererats av de olika
utvecklingsverktygen. Först redovisas storlekar från kodeffektivitets-testerna och
sedan från kompileringshastighetstesterna.
5.4.1
Filstorlekar vid kodeffektivitetstester
När det gäller storleken på den kompilerade koden, varierar denna ganska mycket
mellan de olika utvecklingsverktygen. Skillnaden mellan de olika testprogrammen i
samma utvecklingsverktyg är däremot inte så stora och därför kommer ett medelvärde
av alla testprogrammens storlek att redovisas istället för storleken på var och ett av
testprogrammen. I de fall där ett test inte gick att genomföra i någon av
utvecklingsmiljöerna, räknas resultatet för det testet inte med för någon av
utvecklingsmiljöerna. Alltså kommer benchmarktest 10 och 15-17 inte att vara med i
uträkningen.
Medelstorlek på de kompilerade och länkade testprogrammen i
5.2
300000
250000
200000
150000
Medelstorlek (bytes):
100000
50000
0
Medelstorlek (bytes):
GNAT
(Ada) *
Visual
C++ *
MS J++
Borland
Delphi *
Active
Perl
259760
27034
276
40448
134
Följande diagram innehåller både storleken på den genererade programfilen samt
storlek på de filer som behövs för att köra Java- och Perlprogrammen. Till dessa filer
hör själva tolken, samt eventuella dll-filer (dynamiska länk bibliotek som används av
Windows) som laddas när programmet körs.
*
Betyder att den kompilerade och länkade koden kan köras direkt utan några extra filer.
33
5 Genomförande
Medelstorlek de på kompilerade och länkade testprogrammen i
5.2 inklusive nödvändiga filer
2500000
2000000
1500000
Total medelstorlek (bytes):
1000000
500000
0
GNAT
(Ada) *
Visual
C++ *
MS J++
Borland
Delphi *
Active
Perl
Total medelstorlek 259760
(bytes):
27034
2264449
40448
847494
5.4.2
Filstorlekar vid kompileringshastighetstester
Siffrorna i nedanstående diagram är från programmen som används vid testen av
kompileringshastighet. I diagrammet är inte programfiler som är nödvändiga för att
köra Javaprogram inräknade. En anledningen till att Javafilerna blir stora är att alla
funktioner i programfilen är definierade som klasser, vilket leder till en viss overhead.
Storlek på kompilerade och länkade programfiler vid kompileringstidstest
400000
350000
300000
bytes
250000
K-Test 1
200000
K-Test 2
K-Test 3
150000
100000
50000
0
*
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
K-Test 1
293468
45056
54539
40448
K-Test 2
312684
53248
109268
40448
K-Test 3
351328
73728
219106
40448
Betyder att den kompilerade och länkade koden kan köras direkt utan några extra filer.
34
5 Genomförande
5.5
Kodportabilitet
Den kod som skrivs i Microsoft Visual C++ kan i många fall överföras till andra
utvecklingsverktyg för samma miljö. Om för mycket av de medföljande
funktionsbiblioteken används, kan det i många fall bli svårt att göra en direkt
överföring utan att behöva skriva om delar av koden. Om ett utvecklingsverktyg på en
annan plattform som till exempel UNIX skall användas, måste de plattformsspecifika
delarna skrivas om så att de passar för den nya plattformen.
När det gäller Borland Delphi är det mycket svårt att föra över koden till en annan
plattform. Detta beror dels på att Delphis grafiska uppbyggnad inte följer någon
standard och dels på att den Pascal-dialekt som används inte heller följer någon
standard, utan är en av Borland utvecklad dialekt på de Pascal-standarder som finns.
Med Microsoft J++ däremot är det ofta lätt att flytta program mellan plattformar.
Detta beror på att Java på många sätt är plattformsoberoende. Även om speciella
funktionsbibliotek används går dessa ofta också att flytta till en annan
utvecklingsmiljö och/eller plattform. Den ”byte-kod” som genereras vid kompilering
av ett Javaprogram kan köras på vilken hårdvara som helst, kravet är dock att en
Virtuell Javamaskin finns tillgänglig för den plattform som Javaprogrammet skall
köras på. De flesta tillverkare av utvecklingsverktyg för Java följer Suns
Javastandard.
GNAT följer Ada95-standarden och gör det därför möjligt att på ett enkelt sätt flytta
program mellan olika utvecklingsmiljöer och plattformar. Om målmiljöns hårdvara
byts ut måste dock de hårdvarunära funktionerna i programvaran anpassas för den nya
hårdvaran.
När det gäller Perl är det inte aktuellt med portningar mellan olika utvecklingsmiljöer
utan mer om att porta mellan olika tolkar. Detta fungerar ofta mycket bra om inte allt
för många specialbibliotek används. Det är till exempel omöjligt att direkt porta ett
Perlprogram som använder Win32-anrop till UNIX som saknar dessa anrop helt. I
detta fall måste Win32-anropen bytas ut mot motsvarande UNIX-anrop.
Microsoft
Visual C++
Borland
Delphi
God
Medelgod
Dålig
Microsoft
J++
GNAT
(Ada)
Active Perl
X
X
X
X
X
35
5 Genomförande
5.6
Utbud av färdiga komponenter
Till Microsoft Visual C++ finns det gott om färdiga komponenter, både från
Microsoft själva och från kommersiella tredjepartstillverkare. Det finns även mycket
fria komponenter på Internet. Anledningen till den goda tillgången på färdiga
komponenter är att Visual C++ är ett av de mest använda utvecklingsverktygen för
PC-baserade program.
Även till Borland Delphi finns det mycket färdiga komponenter, dels från Borland
själva men det finns även här ett stort utbud av komponenter från
tredjepartstillverkare. Dock är detta utbud inte riktigt lika stort som det för Visual
C++. Mycket fria komponenter finns att få tag på ifrån Internet.
När det gäller Microsoft J++ är utbudet lite mer begränsat. Det finns i och för sig
mycket färdiga komponenter från Microsoft själva, från Sun och även från
tredjepartstillverkare. Men eftersom Java är relativt nytt finns det inte lika mycket
färdiga komponenter som för till exempel Visual C++ som har varit ute på marknaden
mycket längre.
Till Ada är utbudet av kommersiella komponenter lite större än till Java. Ada har
funnits i många år och det finns kommersiella komponenter till det mesta. Dock finns
det inte lika många tredjepartstillverkare att välja mellan, jämfört med till exempel
Visual C++. Fria komponenter finns att få tag på men utbudet är inte alls lika stort
som för till exempel Visual C++. Detta beror på att Ada inte används så mycket för att
utveckla ”vanliga” program utan mest för att utveckla program för olika typer av
styrsystem.
Utbudet av komponenter till Perl är stort, dock är det mest fria komponenter och inte
så mycket kommersiella vilket kan leda till att supporten är sämre än hos
kommersiella komponenter.
God
Medelgod
Microsoft
Visual C++
Borland
Delphi
X
X
Microsoft
J++
GNAT
(Ada)
Active Perl
X
X
X
Dålig
36
6 Analys av resultat
6 Analys av resultat
I detta kapitel dras slutsatser från resultatet av de olika benchmarktesterna och
undersökningarna i detta arbete. Resultatet av de kvantitativa undersökningarna
kommer för effektivitet av kompilerad kod leda till ett betyg av vart och ett av
utvecklingsverktygen. För kompileringshastighet och storlek på kompilerad och
länkad kod kommer ett omdöme att ges till vart och ett av utvecklingsverktygen.
Även vid resultatet av de kvalitativa undersökningarna; utbud av färdiga komponenter
och kodportabilitet kommer ett omdöme att ges till vart och ett av
utvecklingsverktygen.
6.1
Slutsatser av kvantitativa undersökningar
Betygsättningen av utvecklingsverktygen i kodeffektivitetstesterna kommer att göras
med betyg mellan 1 och 5, där 5 är bästa betyg. Om två utvecklingsverktyg ligger
väldigt jämnt i ett test så kan båda få samma betyg. En komplett lista av
betygsättningen finns i bilaga 2. När betygen beräknas används bara resultat från test
1-9, 11-14 och 18, anledningen till detta är att de övriga testerna inte är möjliga att
köra på alla utvecklingsverktyg.
6.1.1
Kodeffektivitet
I tabellen nedan har betygen för var och ett av utvecklingsverktygen sammanställts
och räknats ihop till en totalpoäng.
GNAT
Visual C++
MS J++
Delphi
Active Perl
Antal 5:or
4
6
1
12
0
Antal 4:or
7
6
2
1
0
Antal 3:or
2
2
9
1
0
Antal 2:or
0
0
2
0
2
Antal 1:or
1
0
0
0
12
Totalpoäng:
55
60
44
67
14
Resultaten i tabellen visar att Delphi är det snabbaste utvecklingsverktyget. Därefter
kommer Visual C++ följt av GNAT. Slutsatsen blir att både GNAT, Visual C++ och
Delphi lämpar sig bättre än MS J++ och Active Perl för att utveckla programvara för
tidskritiska PLC-system.
MS J++ klarar sig förvånansvärt bra för att vara ett semi-interpreterande
programmeringsspråk. Detta kan bero på att JRE, som används som tolk för att köra
Javaprogrammen, utför en ”just in time compilation”. Det vill säga den kompilerar
delar av byte-koden till maskinkod innan programmet börjar köras. Dock så har MS
J++ dålig prestanda när det gäller dynamisk minnesallokering.
GNAT, Visual C++ och Delphi är i genomsnitt tre gånger så snabba som MS J++.
Därför kan det bli problem att få ett program tillräckligt snabbt på en given hårdvara
37
6 Analys av resultat
vid tidskritiska system. Det finns dock lösningar på detta. Det skulle vara möjligt att
använda en Javakompilator som skapar ren maskinkod för en specifik
hårdvaruplattform. Då skulle Javaprogrammen kunna bli lika snabba som GNAT,
Visual C++ och Delphiprogrammen, med biverkningen att portabiliteten mellan olika
målmiljöer minskar. Detta är dock inget stort problem om programmen kompileras
om för den nya målmiljön. Slutsatsen blir att Java kan användas till PLC-system. Om
prestandan inte räcker så kan koden kompileras till maskinkod istället för byte-kod.
Perl ligger långt efter de övriga i nästan alla tester och är därmed inte särskilt
intressant som programmeringsspråk för PLC-system ur prestandasynpunkt.
6.1.2
Kompileringshastighet
När det gäller kompileringshastigheten skiljer den sig mycket mellan de olika
utvecklingsverktygen. Perl har den absolut kortaste ”kompileringstiden”. Detta beror
på att Perlprogram inte behöver kompileras utan kan köras direkt via en tolk.
Bland de utvecklingsverktyg där program måste kompileras har Delphi den kortaste
kompileringstiden. Delphi tar i genomsnitt halva tiden på sig att kompilera ett
program jämfört med Visual C++. Detta kan bero på att Delphi är en så kallad
”single-pass” kompilator och går bara igenom programkoden en gång till skillnad från
de övriga (undantaget Perl) som går igenom programkoden två gånger.
GNAT tar ungefär fem gånger så lång tid på sig att kompilera ett program som Visual
C++. Detta beror på att GNATprogrammen först översätts till C-kod och sedan
kompileras med GCC som i sig är en långsam C-kompilator jämfört med många
kommersiella kompilatorer.
Vid små program tar MS J++ lika lång tid på sig som Visual C++ vid kompilering.
Vid större program ökar kompileringstiden för GNAT och MS J++ mycket snabbare
än kompileringstiden för Visual C++ och Delphi. I fallet med MS J++ kan det som
tidigare nämnts delvis bero på att varje funktion i testprogrammet är deklarerad som
en egen klass och skapar därmed en egen fil, vilket kan leda till en viss ”overhead” då
en mängd filer på hårddisken måste skapas. Denna ”overhead” leder också till att den
totala storleken på de genererade filerna blir större. När det gäller GNAT så är det
troligt att omvandlingen ifrån Ada till C bidrar till den snabbare ökningen av
kompileringstiden.
Om kompileringshastigheten är viktig är Delphi eller Visual C++ bättre alternativ än
GNAT och MS J++.
6.1.3
Storlek på kompilerad och länkad kod
När det gäller storleken på de körbara programfiler som genererats av
utvecklingsverktygen så skiljer den sig mycket. Här går det att dela upp
utvecklingsverktygen i två olika kategorier: De som skapar körbara filer och de som
skapar filer som måste köras vi en tolk. Om storleken på tolken och de filer som
används vid tolkning inte inräknas är dessa program tveklöst minst.
Genomsnittsstorleken på programmen i benchmarktesterna är för Javaprogrammen
38
6 Analys av resultat
289 bytes och för Perlprogrammen bara 134 bytes. Om de filer som behövs för att
köra programmen räknas in så ser det lite annorlunda ut. För Javaprogrammet blir då
den totala storleken över 2 Mb och för Perlprogrammet över 800 kb. Om programvara
för ett PLC-system utvecklas så är som tidigare nämnt programstorleken väldigt
viktig då programmet måste laddas ner ifrån utvecklingsdatorn till en målmiljö.
Denna nerladdning går ofta med låg hastighet och tar lång tid om programfilerna är
stora. Därför är Java och Perl utmärkta språk i den aspekten då de ger små
programfiler. Tolken och dess tillhörande filer förändras sällan och kan ligga i ett
ROM på målsystemet och behöver då inte laddas ner varje gång en programändring
har gjorts.
Vid kompileringshastighetstestet ser det dock lite annorlunda ut. Här är
Javaprogrammen ungefär lika stora som Visual C++- och Delphiprogrammen.
Storleken på de kompilerade Javaprogrammen växer snabbt vid större program. Detta
beror delvis som tidigare nämnts på att alla funktioner är klasser. Om källkodens
storlek dubbleras så dubbleras även storleken på de genererade filerna.
Visual C++ och Delphi genererar ungefär lika stora filer. Anmärkningsvärt är dock att
filstorleken i Delphi är densamma i alla tester. Även om källkodens storlek fyrdubblas
är den kompilerade och länkade filens storlek samma. Detta kan bero på att Delphi
utför någon typ av optimering som inte går att stänga av. Visual C++- och
GNATprogram däremot växer när källkodsstorleken ökar, dock inte lika snabbt som
Javaprogrammen.
Av de program som inte behöver någon tolk för att köras är det GNAT-programmen
som är klart störst. Detta beror troligtvis på att fler standardfunktioner länkas med och
att vissa av de speciella funktioner som Adaspråket har tar plats i programfilen.
Om nerladdningstiden i ett PLC-system är viktig är GNAT inte det bästa alternativet,
då är Visual C++ eller Delphi bättre alternativ med avseende på genererade
programfilsstorlekar. Om systemet inte skall utföra uppgifter som är
prestandakrävande så kan även MS J++ och Perl passa bra då dessas nerladdningstid
ofta blir väldigt kort. MS J++ har även fördelen med klassuppdelning som följer med
Javaspråket. Men hjälp av denna kan programmet delas upp i mindre delar på en
enkelt sätt och vid uppdatering av programvara i en målmiljö kanske inte alla klasser
behöver laddas över utan bara de som är ändrade.
6.2
Slutsatser av kvalitativa undersökningen
I den kvalitativa undersökningen kommer inte utvecklingsmiljöerna att få några betyg
utan får istället ett omdöme.
6.2.1
Kodportabilitet
Vid kodportabilitet hamnar Visual C++ och Delphi bland de sämre
utvecklingsverktygen. Inget av dem är dock direkt dåligt men om det är viktigt att den
kod som skrivs skall kunna flyttas mellan olika hård- och mjukvaruplattformar, är
GNAT, MS J++ och Perl bättre alternativ. Det bästa alternativet när det gäller
39
6 Analys av resultat
kodportabilitet, är något av de interpreterande språken. Javaprogram kan köras på
vilken hårdvara som helst, förutsatt att det finns en virtuell Javamaskin. Perlprogram
kan också köras på de flesta plattformar om det finns en tolk tillgänglig.
6.2.2
Utbud av färdiga komponenter
När det gäller utbudet av färdiga komponenter utmärker sig Delphi och Visual C++.
Detta beror mest på att dessa två används mycket för att utveckla ”vanliga” PCprogram och har därigenom ett stort utbud av färdiga komponenter för de flesta olika
användningsområden. Exempel på komponenter som kan vara till nytta i ett PLCsystem är komponenter för nätverkskommunikation, databashantering och
matematiska beräkningar. Det går att få tag på denna typ av komponenter för GNAT,
MS J++ och Perl men utbudet är inte riktigt lika stort.
40
7 Sammanfattning
7 Sammanfattning
Vid val av utvecklingsverktyg för programvaruutveckling mot PLC-system finns det
mycket att tänka på. I detta arbete har en del viktiga kriterier utvärderats. Det är dock
inte alltid dessa kriterier är de som är viktigast för en specifik applikation.
Resultaten i detta arbete kan användas som beslutshjälp vid val av utvecklingsverktyg.
GNAT (Ada)
Rent prestandamässigt ligger GNAT bra till även om Visual C++ och Delphi är
snabbare. Prestandan räcker dock till de flesta typer av system och om prestandan inte
skulle räcka till så går det alltid att skaffa snabbare hårdvara att köra programmen på.
Om korta kompilerings- och nerladdningstider är viktiga så är GNAT ett dåligt
alternativ. Kompileringshastigheten är låg och programfilerna blir stora jämfört med
de övriga utvecklingsmiljöerna i utvärderingen. God portabilitet av kod och medelbra
utbud av färdiga komponenter gör GNAT till ett intressant alternativ för många typer
av PLC-system.
Microsoft Visual C++
Microsoft Visual C++ har bra prestanda vid kodexekvering och kompilering och
genererar små programfiler. Utbudet av färdiga komponenter är stort. Dock kan koden
i vissa fall vara svår att porta mellan olika hård- och mjukvaruplattformar.
Microsoft J++
Microsoft J++ är prestandamässigt inte i samma klass som exempelvis Visual C++
men borde räcka till vissa typer av applikationer. Om en kompilator som genererar ren
maskinkod används blir prestandan jämförbar med Visual C++ vilket borde vara fullt
tillräcklig även för tidskritiska system. Java ger små program på grund av att många
funktioner finns i standardklasser och en bra moduluppdelning vilket leder till att
nerladdningstider mellan utvecklingssystem och målmiljö går snabbt. Kompilering
går relativt snabbt och kan snabbas upp ytterligare genom en smart moduluppdelning
av programmet. Portabilitet av koden är en av Javas starka sidor. Utbudet av färdiga
komponenter är inte lika stort som för Visual C++, men de viktigaste komponenterna
går ofta att få tag på.
Borland Delphi
Borland Delphi är den snabbaste av de utvecklingsmiljöer som utvärderats i detta
arbete, både när det gäller kompileringshastighet och kodeffektivitet. Delphi är därför
ett intressant alternativ om låga kompileringstider och snabba program efterfrågas.
Även storleksmässigt ligger Delphiprogram bra till, vilket leder till korta
nerladdningstider vid uppdatering av programvaran i ett PLC-system. Utbudet av
färdiga komponenter är stort. En nackdel med Delphi är att koden är svår att porta till
andra hård- och mjukvaruplattformar.
41
7 Sammanfattning
Active Perl
Active Perl har väldigt dålig prestanda och kan därför inte användas till annat än
system som inte är prestandakrävande. Dock finns ingen kompileringstid då
programmen tolkas direkt av en tolk. Programfilerna blir små och möjliggör därför
korta nerladdningstider. På grund av att koden inte behöver kompileras finns
möjligheten att ändra i koden direkt på målmiljön utan att behöva ladda ner den ifrån
utvecklingsdatorn. Perlprogram är enkla att porta mellan olika plattformar. Det enda
som krävs är att en tolk för målmiljön finns tillgänglig. Utbudet av färdiga
komponenter är dock ganska begränsat även om komponenter för nätverkskommunikation och databastillgång finns tillgängliga.
7.1
Framtida arbete
Vid fortsatt arbete finns det mycket att göra. Till exempel kan fler av de kriterier som
satts upp utvärderas och fler utvecklingsmiljöer undersökas. Undersökningen skulle
kunna inriktas på andra typer av målsystem än PLC-system. Vid de kvantitativa
testerna kan andra typer av testprogram användas. Istället för att bara testa
språkfunktioner så kan större och mer komplexa testprogram skrivas.
Förutsättningarna för testerna kan ändras. Det skulle till exempel vara intressant att se
hur mycket de olika cache-minnena i datorn inverkar på prestandan. Tidmätningen
skulle kunna genomföras genom att läsa av systemklockan före och efter själva
testkoden utförts, vilket skulle leda till exaktare tider. Vid kompileringstidstester
skulle ett mer varierande testprogram kunna användas där fler funktioner ifrån externa
bibliotek används, detta för att se hur väl ett utvecklingsverktyg hanterar externa
bibliotek.
42
Referenser
Referenser
Aho, A. V., Sethi, R. & Ullman, J. D., 1986, Compilers – Principles, Techniques and
Tools, Addison-Wesley Publishing.
Bolin, R. L., 1997, CSc882 Research Paper Java Optimization and Performance.
[Online]. Tillgänglig från: http://www.mindspring.com/~rlb/csc882/index.html
[Hämtad 1999-04-13].
Burns, A., 1985, Concurrent programming in Ada, University of Cambridge
Burns, A. & Wellings, A., 1997, Real-Time Systems and Programming Languages,
Tredje upplagan, Addison-Wesley Publishing.
Cohn, M., Morgan, B., Nygard, M., Joshi, D. & Trinke, T., 1996, Java Developer´s
Reference, Sams Publishing.
Diab Data, 1999, Power Compiling Solutions, [Online]. Tillgänglig från:
http://www.ddi.com/products/products.htm, [Hämtad 1999-04-15].
Grace, R., 1996, The Benchmark Book, Prentice Hall.
Houston, 1989, Looking into C, Merrill Publishing.
Husain K. & Breedlove R., 1996, Perl 5 Unleashed, Sams Publishing.
Lippman, S. B., C++ Primer, Andra upplagan, Addison-Wesley Publishing.
JP Software, 1999, JP Software – The Prompt Solution, [Online]. Tillgänglig från:
http://www.jpsoft.com/index.htm, [Hämtad 1999-04-21].
Kempe, M., 1996, Ada 95 Reference Manual, [Online]. Tillgänglig från:
http://www.adahome.com/rm95/ [Hämtad 1999-04-15].
Koffman, E. B., 1985, Pascal, Andra upplagan, Addison-Wesley Publishing.
Pressman, S. R., 1997, Software Engineering – A Practitioner´s Approach, Fjärde
upplagan, McGraw-Hill.
Weidermanm, N. H., 1989, Ada Adoption Handbook: Compiler Evaluation and
Selection, Carnegie Mellon University.
43
Bilaga A. Källkod för benchmarkprogram
Bilaga A. Källkod för benchmarkprogram
Källkod för Ada-program
-Benchmark
Loopoverhead.
1
test
-- Loopvärde: 10^7
1:
procedure ben2 is
-- Loopvärde: 10^5
procedure loopen is
procedure ben1 is
j : integer;
begin
begin
for I in 1..100000 loop
for I in 1..10000000 loop
null;
j := I;
end loop;
end loop;
end ben1;
-Benchmark
Loopoverhead.
end loopen;
1
test
2:
begin
loopen;
-- Loopvärde: 10^6
end ben2;
procedure ben2 is
begin
-- Benchmark 3 test
variabeltilldelning.
for I in 1..1000000 loop
null;
1:
Global
-- Loopvärde: 10^7
end loop;
procedure ben3 is
end ben2;
j : integer;
begin
-Benchmark
Loopoverhead.
1
test
3:
for I in 1..10000000 loop
j := I;
-- Loopvärde: 10^7
end loop;
procedure ben3 is
end ben3;
begin
for I in 1..10000000 loop
-Benchmark
Matristilldelning
null;
end loop;
4
test
1:
-- Loopvärde: 10^7
end ben3;
procedure ben4 is
j : array(1..4) of integer;
-Benchmark
Loopoverhead.
1
test
4:
begin
for I in 1..10000000 loop
-- Loopvärde: 10^8
procedure ben4 is
j(1) := I;
begin
j(2) := I;
j(3) := I;
for I in 1..100000000 loop
j(4) := I;
null;
end loop;
end loop;
end ben4;
end ben4;
-- Benchmark 2 test
variabeltilldelning.
1:
-- Benchmark 5 test 1: Uppräkning
av 8-bitarsvariabel
Lokal
1
Bilaga A. Källkod för benchmarkprogram
begin
-- Loopvärde: 10^7
j:=0;
procedure ben5 is
for I in 1..10000000 loop
type Byte is mod 256;
j:=j+1;
j : Byte;
end loop;
begin
end ben8;
j := 0;
for I in 1..10000000 loop
-- Benchmark 9 test 1: Uppräkning
av 64-bitars flyttalsvariabel
j := j + 1;
end loop;
-- Loopvärde: 10^7
end ben5;
procedure ben9 is
j : float;
-- Benchmark 6 test 1: Uppräkning
av 16-bitarsvariabel
begin
-- Loopvärde: 10^7
j := 0.0;
procedure ben6 is
for I in 1..10000000 loop
j := j + 1.0;
type Short is mod 65536;
end loop;
j : Short;
end ben9;
begin
j := 0;
-Benchmark
Matrisallokering
for I in 1..10000000 loop
j := j + 1;
10
test
1:
-- Loopvärde: 10^7
end loop;
with Unchecked_Deallocation;
end ben6;
procedure ben10 is
type MATRIS
Integer;
-- Benchmark 7 test 1: Uppräkning
av 32-bitarsvariabel
is
array
(1..4)
of
type Ptr is access MATRIS;
-- Loopvärde: 10^7
procedure
Free
Unchecked_Deallocation
Ptr);
procedure ben7 is
j : integer;
is
new
(MATRIS,
j : Ptr;
begin
j := 0;
begin
for I in 1..10000000 loop
for I in 1..10000000 loop
j := j + 1;
j := new MATRIS;
end loop;
Free(j);
end ben7;
end loop;
-- Benchmark 8 test 1: Uppräkning
av 64-bitarsvariabel
end ben10;
-- Fungerar ej i Ada d† Ada saknar
64-bitars variabler
-Benchmark
Funktionsanrop
-- Loopvärde: 10^7
-- Loopvärde: 10^7
procedure ben8 is
type
longint
2**63+1..+2**63-1;
11
procedure ben11 is
is
range
-
procedure loopen is
begin
j : longint;
null;
2
test
1:
Bilaga A. Källkod för benchmarkprogram
j:=cos(30.0);
end loopen;
end loop;
end ben13b;
begin
for I in 1..10000000 loop
-- Benchmark 13 test 3: Matematisk
funktion 2
loopen;
end loop;
-- Loopvärde: 10^7
end ben11;
with
Ada.Numerics.Elementary_Functions;
-- Benchmark 12 test 1: Matematisk
funktion 1
use
Ada.Numerics.Elementary_Functions;
-- Loopvärde: 10^7
procedure ben13c is
procedure ben12 is
j : float;
j : integer;
begin
begin
for I in 1..10000000 loop
j:=cos(45.0);
for I in 1..10000000 loop
end loop;
j:=abs(-30);
end ben13c;
end loop;
end ben12;
-- Benchmark 13 test 4: Matematisk
funktion 2
-- Benchmark 13 test 1: Matematisk
funktion 2
-- Loopvärde: 10^7
-- Loopvärde: 10^7
with
Ada.Numerics.Elementary_Functions;
with
Ada.Numerics.Elementary_Functions;
use
Ada.Numerics.Elementary_Functions;
use
Ada.Numerics.Elementary_Functions;
procedure ben13d is
procedure ben13a is
begin
j : float;
j : float;
for I in 1..10000000 loop
begin
j:=cos(60.0);
for I in 1..10000000 loop
end loop;
j:=cos(15.0);
end ben13d;
end loop;
end ben13a;
-Benchmark
Villkorstest
-- Benchmark 13 test 2: Matematisk
funktion 2
-- Loopvärde: 10^7
14
test
procedure ben14 is
-- Loopvärde: 10^7
j : integer;
with
Ada.Numerics.Elementary_Functions;
begin
j:=1;
use
Ada.Numerics.Elementary_Functions;
for I in 1..10000000 loop
if j>0 then
procedure ben13b is
null;
j : float;
elsif j<0 then
begin
null;
for I in 1..10000000 loop
3
1:
Bilaga A. Källkod för benchmarkprogram
end loop;
else
end ben16;
null;
end if;
-Benchmark
Funktionsanrop
end loop;
end ben14;
17
test
1:
-- Loopvärde: 10^7
-Benchmark
Strängallokering
15
test
procedure ben17 is
1:
j : integer;
-- Loopvärde: 10^7
procedure rekloop is
with Unchecked_Deallocation;
begin
if j<100000 then
procedure ben15 is
type MATRIS
Character;
is
array
(1..50)
j:=j+1;
of
rekloop;
type Ptr is access MATRIS;
procedure
Free
Unchecked_Deallocation
Ptr);
is
end if;
new
(MATRIS,
end rekloop;
j : Ptr;
begin
j:=0;
begin
rekloop;
for I in 1..10000000 loop
end ben17;
j := new MATRIS;
Free(j);
-- Benchmark 18 test 1: Lintest
end loop;
-- Loopvärde: 10^7
end ben15;
procedure ben18 is
j : float;
-- Benchmark 16 test 1: Typecasting
begin
-- Loopvärde: 10^7
for I in 1..10000000 loop
procedure ben16 is
j:=Float(3.0*(Float(I)/10.0))+Float
(2.0*(Float(I)/100.0));
j : integer;
k : float;
j:=2.0/j;
begin
end loop;
k:=1000.0;
end ben18;
for I in 1..10000000 loop
j:=integer(k);
4
Bilaga A. Källkod för benchmarkprogram
Källkod för C++-program
*
int i;
Benchmark 1 test 1:
for(i=0;i<100000000;i++){
Loopoverhead. Testar hur mycket
}
overhead en tom loop orsakar.
}
Loopvärde: 10^5
*/
/*
#include <stdio.h>
Benchmark 2 test 1: Lokal
void main(){
variabeltilldelning
int i;
Loopvärde: 10^7
for(i=0;i<100000;i++){
*/
}
#include <stdio.h>
}
void loop(){
/*
int i;
Benchmark 1 test 2:
int j;
Loopoverhead. Testar hur mycket
for(i=0;i<10000000;i++){
overhead en tom loop orsakar.
j=i;
Loopvärde: 10^6
}
*/
}
#include <stdio.h>
void main(){
void main(){
int i;
loop();
for(i=0;i<1000000;i++){
}
}
}
/*
Benchmark 3 test 1: Global
/*
variabeltilldelning
Benchmark 1 test 3:
Loopvärde: 10^7
Loopoverhead. Testar hur mycket
*/
overhead en tom loop orsakar.
#include <stdio.h>
Loopvärde: 10^7
int i;
*/
int j;
#include <stdio.h>
void main(){
void main(){
int i;
for(i=0;i<10000000;i++){
for(i=0;i<10000000;i++){
j=i;
}
}
}
}
/*
Benchmark 1 test 4:
/*
Loopoverhead. Testar hur mycket
Benchmark 4 test 1:
overhead en tom loop orsakar.
Matristilldelning
Loopvärde: 10^8
Loopvärde: 10^7
*/
*/
#include <stdio.h>
#include <stdio.h>
void main(){
int i;
2
Bilaga A. Källkod för benchmarkprogram
int j[4];
int i;
int j = 0;
void main(){
for(i=0;i<10000000;i++){
void main(){
j[0]=i;
for(i=0;i<10000000;i++){
j[1]=i;
j++;
j[2]=i;
}
j[3]=i;
}
}
}
/*
/*
av 64-bitarsvariabel
Benchmark 8 test 1: Uppräkning
Benchmark 5 test 1: Uppräkning
Loopvärde: 10^7
av 8-bitarsvariabel
*/
Loopvärde: 10^7
#include <stdio.h>
*/
int i;
#include <stdio.h>
long j = 0;
int i;
char j = 0;
void main(){
for(i=0;i<10000000;i++){
void main(){
j++;
for(i=0;i<10000000;i++){
}
j++;
}
}
}
/*
Benchmark 9 test 1: Uppräkning
/*
av 64-bitars flyttalsvariabel
Benchmark 6 test 1: Uppräkning
Loopvärde: 10^7
av 16-bitarsvariabel
*/
Loopvärde: 10^7
#include <stdio.h>
*/
int i;
#include <stdio.h>
float j = 0;
int i;
short j = 0;
void main(){
for(i=0;i<10000000;i++){
void main(){
j++;
for(i=0;i<10000000;i++){
}
j++;
}
}
}
/*
Benchmark 10 test 1:
/*
Matrisallokering
Benchmark 7 test 1: Uppräkning
Loopvärde: 10^7
av 32-bitarsvariabel
*/
Loopvärde: 10^7
#include <stdio.h>
*/
int i;
#include <stdio.h>
int* j;
3
Bilaga A. Källkod för benchmarkprogram
float j;
void main(){
for(i=0;i<10000000;i++){
void main(){
j = (int*)malloc(16);
for(i=0;i<10000000;i++){
free(j);
j = cos(15.0);
}
}
}
}
/*
/*
Benchmark 13 test 2: Matematisk
Benchmark 11 test 1:
funktion 2
Funktionsanrop
Loopvärde: 10^7
Loopvärde: 10^7
*/
*/
#include <stdio.h>
#include <stdio.h>
int i;
int i;
float j;
void funk(){
void main(){
}
for(i=0;i<10000000;i++){
void main(){
}
j = cos(30.0);
for(i=0;i<10000000;i++){
}
funk();
}
/*
}
Benchmark 13 test 3: Matematisk
funktion 2
/*
Loopvärde: 10^7
Benchmark 12 test 1: Matematisk
*/
funktion 1
#include <stdio.h>
Loopvärde: 10^7
int i;
*/
float j;
#include <stdio.h>
int i;
void main(){
int j;
for(i=0;i<10000000;i++){
j = cos(45.0);
void main(){
}
for(i=0;i<10000000;i++){
}
j = abs(-30);
}
/*
}
Benchmark 13 test 4: Matematisk
funktion 2
/*
Loopvärde: 10^7
Benchmark 13 test 1: Matematisk
*/
funktion 2
#include <stdio.h>
Loopvärde: 10^7
int i;
*/
float j;
#include <stdio.h>
int i;
void main(){
4
Bilaga A. Källkod för benchmarkprogram
for(i=0;i<10000000;i++){
int i;
j = cos(60.0);
int j;
}
double k = 1000;
}
void main(){
/*
for(i=0;i<10000000;i++){
Benchmark 14 test 1:
j = (int)k;
Villkorstest
}
Loopvärde: 10^7
}
*/
#include <stdio.h>
/*
int i;
Benchmark 17 test 1: Rekursivt
int j;
anrop.
Loopvärde: 10^7
void main(){
*/
j=1;
#include <stdio.h>
for(i=0;i<10000000;i++){
int i=0;
if(j>0){
}
void rekloop(){
else if(j<0){
if(i<100000){
}
i++;
else{
rekloop();
}
}
}
}
}
void main(){
/*
rekloop();
Benchmark 15 test 1:
}
Strängallokering
Loopvärde: 10^7
/*
*/
Benchmark 18 test 1: Linpacktest
#include <stdio.h>
Loopvärde: 10^7
int i;
*/
char* j;
#include <stdio.h>
int i;
void main(){
double j;
for(i=0;i<10000000;i++){
void main(){
j = (char*)malloc(50);
for(i=0;i<10000000;i++){
free(j);
j = (3*(i/10)+2*(i/100));
}
j = 2/j;
}
}
}
/*
Benchmark 16 test 1: Typecast
Loopvärde: 10^7
*/
#include <stdio.h>
5
Bilaga A. Källkod för benchmarkprogram
Källkod för Javaprogram
/*
public static void main (String
Benchmark 1 test 1:
args[]) {
Loopoverhead. Testar hur mycket
int i;
overhead en tom loop orsakar.
for(i=0;i<10000000;i++){
Loopvärde: 10^5
}
*/
}
import java.lang.System;
}
class ben1t1 {
/*
public static void main (String
Benchmark 1 test 4:
args[]) {
Loopoverhead. Testar hur mycket
int i;
overhead en tom loop orsakar.
for(i=0;i<100000;i++){
Loopvärde: 10^8
}
*/
}
import java.lang.System;
}
class ben1t4 {
/*
public static void main (String
Benchmark 1 test 2:
args[]) {
Loopoverhead. Testar hur mycket
int i;
overhead en tom loop orsakar.
for(i=0;i<100000000;i++){
Loopvärde: 10^6
}
*/
}
import java.lang.System;
}
class ben1t2 {
/*
public static void main (String
Benchmark 2 test 1: Lokal
args[]) {
variabeltilldelning
int i;
Loopvärde: 10^7
for(i=0;i<1000000;i++){
*/
}
import java.lang.System;
}
}
class ben2 {
public static void loop(){
/*
int i;
Benchmark 1 test 3:
int j;
Loopoverhead. Testar hur mycket
for(i=0;i<100000000;i++){
overhead en tom loop orsakar.
j=i;
Loopvärde: 10^7
}
*/
}
import java.lang.System;
public static void main (String
class ben1t3 {
args[]) {
6
Bilaga A. Källkod för benchmarkprogram
loop();
*/
}
import java.lang.System;
}
class ben5 {
/*
public static void main (String
Benchmark 3 test 1: Global
args[]) {
variabeltilldelning
int i;
Loopvärde: 10^7
byte j=0;
*/
for(i=0;i<100000000;i++){
import java.lang.System;
j++;
}
class ben3 {
}
public static void main (String
}
args[]) {
int i;
/*
int j;
Benchmark 6 test 1: Uppräkning
for(i=0;i<100000000;i++){
av 16-bitarsvariabel
j=i;
Loopvärde: 10^7
}
*/
}
import java.lang.System;
}
class ben6 {
/*
public static void main (String
Benchmark 4 test 1:
args[]) {
Matristilldelning
int i;
Loopvärde: 10^7
short j=0;
*/
for(i=0;i<100000000;i++){
import java.lang.System;
j++;
}
class ben4{
}
public static void main (String
}
args[]) {
int i;
/*
int j[]=new int[4];
Benchmark 7 test 1: Uppräkning
for(i=0;i<100000000;i++){
av 32-bitarsvariabel
j[0]=i;
Loopvärde: 10^7
j[1]=i;
*/
j[2]=i;
import java.lang.System;
j[3]=i;
}
class ben7 {
}
public static void main (String
}
args[]) {
int i;
/*
int j=0;
Benchmark 5 test 1: Uppräkning
for(i=0;i<100000000;i++){
av 8-bitarsvariabel
j++;
Loopvärde: 10^7
}
7
Bilaga A. Källkod för benchmarkprogram
}
import java.util.Vector;
}
class ben10 {
/*
public static void main (String
Benchmark 8 test 1: Uppräkning
args[]) {
av 64-bitarsvariabel
int i;
Loopvärde: 10^7
Vector j;
*/
for(i=0;i<100000000;i++){
import java.lang.System;
j = new Vector(4);
}
class ben8 {
}
public static void main (String
}
args[]) {
int i;
/*
long j=0;
Benchmark 11 test 1:
for(i=0;i<100000000;i++){
Funktionsanrop
j++;
Loopvärde: 10^7
}
*/
}
import java.lang.System;
}
class ben11 {
/*
public static void loop(){
Benchmark 9 test 1: Uppräkning
}
av 64-bitars flyttalsvariabel
Loopvärde: 10^7
public static void main (String
*/
args[]) {
import java.lang.System;
int i;
for(i=0;i<100000000;i++){
class ben9 {
loop();
public static void main (String
}
args[]) {
}
int i;
}
double j=0;
for(i=0;i<100000000;i++){
/*
j++;
Benchmark 12 test 1: Matematisk
}
funktion 1
}
Loopvärde: 10^7
}
*/
import java.lang.System;
/*
import java.lang.Math;
Benchmark 10 test 1:
Matrisallokering, inte helt riktig.
class ben12 {
Allokerar bara upp en vektor med
public static void main (String
plats för fyra värden.
args[]) {
Loopvärde: 10^7
int i;
*/
int j=0;
import java.lang.System;
for(i=0;i<100000000;i++){
8
Bilaga A. Källkod för benchmarkprogram
j=Math.abs(-30);
*/
}
import java.lang.System;
}
import java.lang.Math;
}
class ben13t3 {
/*
public static void main (String
Benchmark 13 test 1: Matematisk
args[]) {
funktion 2
int i;
Loopvärde: 10^7
double j;
*/
for(i=0;i<100000000;i++){
import java.lang.System;
j=Math.cos(45.0);
import java.lang.Math;
}
}
class ben13t1 {
}
public static void main (String
args[]) {
/*
int i;
Benchmark 13 test 4: Matematisk
double j;
funktion 2
for(i=0;i<100000000;i++){
Loopvärde: 10^7
j=Math.cos(15.0);
*/
}
import java.lang.System;
}
import java.lang.Math;
}
class ben13t4 {
/*
public static void main (String
Benchmark 13 test 2: Matematisk
args[]) {
funktion 2
int i;
Loopvärde: 10^7
double j;
*/
for(i=0;i<100000000;i++){
import java.lang.System;
j=Math.cos(60.0);
import java.lang.Math;
}
}
class ben13t2 {
}
public static void main (String
args[]) {
/*
int i;
Benchmark 14 test 1:
double j;
Villkorstest
for(i=0;i<100000000;i++){
Loopvärde: 10^7
j=Math.cos(30.0);
*/
}
import java.lang.System;
}
import java.lang.Math;
}
class ben14 {
/*
public static void main (String
Benchmark 13 test 3: Matematisk
args[]) {
funktion 2
int i;
Loopvärde: 10^7
int j=1;
9
Bilaga A. Källkod för benchmarkprogram
for(i=0;i<100000000;i++){
int j;
if(j>0){
double k = 1000;
}
for(i=0;i<100000000;i++){
else if(j<0){
j = (int)k;
}
}
else{
}
}
}
}
}
/*
}
Benchmark 17 test 1: Rekursivt
anrop
/*
Loopvärde: 10^7
Benchmark 15 test 1:
*/
Strängallokering
import java.lang.System;
Loopvärde: 10^7
import java.lang.Math;
*/
import java.lang.System;
class ben17 {
import java.lang.Math;
public static int i=0;
import java.lang.String;
import java.util.Vector;
public static void rekloop(){
if(i<100000){
class ben15 {
i++;
public static void main (String
rekloop();
args[]) {
}
int i;
}
Vector j;
String s = "
public static void main (String
";
args[]) {
for(i=0;i<100000000;i++){
rekloop();
j=new Vector();
}
j.addElement(s);
}
j.removeAllElements();
}
/*
}
Benchmark 18 test 1: Lintest
}
Loopvärde: 10^7
*/
/*
import java.lang.System;
Benchmark 16 test 1: Typecasting
import java.lang.Math;
Loopvärde: 10^7
*/
class ben18 {
import java.lang.System;
import java.lang.Math;
public static void main (String
args[]) {
class ben16 {
int i;
public static void main (String
double j=0;
args[]) {
for(i=0;i<10000000;i++){
int i;
j = (3*(i/10)+2*(i/100));
10
Bilaga A. Källkod för benchmarkprogram
j = 2/j;
}
}
}
11
Bilaga A. Källkod för benchmarkprogram
Källkod för Delphiprogram
// Benchmark 1 test 1:
uses sysutils;
Loopoverhead. Testar hur mycket
overhead en tom loop orsakar.
var i:integer;
// Loopvärde: 10^5
begin
program ben1t1;
for i:=1 to 100000000 do begin
uses sysutils;
end;
end.
var i:integer;
begin
// Benchmark 2 test 1: Lokal
for i:=1 to 100000 do begin
variabeltilldelning
end;
end.
// Loopvärde: 10^7
program ben2;
uses sysutils;
// Benchmark 1 test 2:
Loopoverhead. Testar hur mycket
procedure loop;
overhead en tom loop orsakar.
var i:integer;
// Loopvärde: 10^6
var j:integer;
program ben1t2;
begin
uses sysutils;
for i:=1 to 10000000 do begin
j:=i;
var i:integer;
end;
begin
end;
for i:=1 to 1000000 do begin
end;
begin
end.
loop;
end.
// Benchmark 1 test 3:
Loopoverhead. Testar hur mycket
// Benchmark 3 test 1: Global
overhead en tom loop orsakar.
variabeltilldelning
// Loopvärde: 10^7
// Loopvärde: 10^7
program ben1t3;
program ben3;
uses sysutils;
uses sysutils;
var i:integer;
var i:integer;
begin
var j:integer;
for i:=1 to 10000000 do begin
begin
end;
for i:=1 to 10000000 do begin
end.
j:=i;
end;
// Benchmark 1 test 4:
end.
Loopoverhead. Testar hur mycket
overhead en tom loop orsakar.
// Benchmark 4 test 1:
// Loopvärde: 10^8
Matristilldelning
program ben1t4;
12
Bilaga A. Källkod för benchmarkprogram
// Loopvärde: 10^7
uses sysutils;
program ben4;
uses sysutils;
var i:integer;
j:integer;
var i:integer;
begin
var j: array[1..4] of integer;
for i:=1 to 10000000 do begin
begin
j:=j+1;
for i:=1 to 10000000 do begin
end;
j[1]:=i;
end.
j[2]:=i;
j[3]:=i;
// Benchmark 8 test 1: Uppräkning
j[4]:=i;
av 64-bitsvariabel
end;
// Loopvärde: 10^7
end.
program ben8;
uses sysutils;
// Benchmark 5 test 1: Uppräkning
av 8-bitarsvariabel
var i:integer;
// Loopvärde: 10^7
j:int64;
program ben5;
begin
uses sysutils;
for i:=1 to 10000000 do begin
j:=j+1;
var i:integer;
end;
var j:byte;
end.
begin
for i:=1 to 10000000 do begin
// Benchmark 9 test 1: Uppräkning
j:=j+1;
av 64-bits flyttalsvariabel
end;
// Loopvärde: 10^7
end.
program ben9;
uses sysutils;
// Benchmark 6 test 1: Uppräkning
av 16-bitsvariabel
var i:integer;
// Loopvärde: 10^7
j:double;
program ben6;
begin
uses sysutils;
for i:=1 to 10000000 do begin
var i:integer;
end;
j:=j+1;
j:smallint;
end.
begin
for i:=1 to 10000000 do begin
// Benchmark 10 test 1:
j:=j+1;
Matrisallokering
end;
// Loopvärde: 10^7
end.
program ben10;
uses sysutils;
// Benchmark 7 test 1: Uppräkning
av 32-bitsvariabel
type intarr = array[1..4] of
// Loopvärde: 10^7
integer;
program ben7;
var i:integer;
13
Bilaga A. Källkod för benchmarkprogram
j:^intarr;
begin
begin
for i:=1 to 10000000 do begin
for i:=1 to 10000000 do begin
j:=cos(15.0);
new(j);
end;
dispose(j);
end.
end;
end.
// Benchmark 13 test 2: Matematisk
funktion 2
// Benchmark 11 test 1:
// Loopvärde: 10^7
Funktionsanrop
program ben13t2;
// Loopvärde: 10^7
uses sysutils;
program ben11;
uses sysutils;
var i:integer;
j:double;
var i:integer;
begin
procedure funk();
for i:=1 to 10000000 do begin
begin
j:=cos(30.0);
end;
end;
end.
begin
for i:=1 to 10000000 do begin
// Benchmark 13 test 3: Matematisk
funk;
funktion 2
end;
// Loopvärde: 10^7
end.
program ben13t3;
uses sysutils;
// Benchmark 12 test 1: Matematisk
funktion 1
var i:integer;
// Loopvärde: 10^7
j:double;
program ben12;
begin
uses sysutils;
for i:=1 to 10000000 do begin
var i:integer;
end;
j:=cos(45.0);
j:integer;
end.
begin
for i:=1 to 10000000 do begin
// Benchmark 13 test 4: Matematisk
j:=abs(-30);
funktion 2
end;
// Loopvärde: 10^7
end.
program ben13t4;
uses sysutils;
// Benchmark 13 test 1: Matematisk
funktion 2
var i:integer;
// Loopvärde: 10^7
j:double;
program ben13t1;
begin
uses sysutils;
for i:=1 to 10000000 do begin
j:=cos(60.0);
var i:integer;
end;
j:double;
end.
14
Bilaga A. Källkod för benchmarkprogram
program ben16;
// Benchmark 14 test 1:
uses sysutils;
Villkorstest
begin
// Loopvärde: 10^7
end.
program ben14;
uses sysutils;
// Benchmark 17 test 1: Rekursivt
anrop
var i:integer;
// Loopvärde: 10^7
j:double;
program ben16;
begin
uses sysutils;
for i:=1 to 10000000 do begin
if(j>0) then begin
var i:integer;
end
procedure rekloop();
else if(j<0) then begin
begin
end
if(i<100000) then begin
else begin
i:=i+1;
end;
rekloop();
end;
end;
end.
end;
begin
// Benchmark 15 test 1:
i:=0;
Strängallokering
rekloop();
// Loopvärde: 10^7
end.
program ben15;
uses sysutils;
// Benchmark 18 test 1: Linjär
type strang = string[50];
funktiontest.
var i:integer;
// Loopvärde: 10^7
j:^strang;
program ben18;
begin
uses sysutils;
for i:=1 to 10000000 do begin
new(j);
var i:integer;
dispose(j);
j:double;
end;
begin
end.
for i:=1 to 10000000 do begin
j:=3*(i/10)+2*(i/100);
// Benchmark 16 test 1:
j:=2/j;
Typecasting, funkar inte i Pascal
end;
// Loopvärde: 10^7
end.
15
Bilaga A. Källkod för benchmarkprogram
Källkod för Perlprogram
};
# Benchmark 1 test 1: Loopoverhead.
Testar hur mycket overhead en tom
# Benchmark 4 test 1:
loop orsakar
Matristilldelning
# Loopvärde: 10^5
# Loopvärde: 10^7
for($i=0;$i<100000;$i++){
@j=();
};
for($i=0;$i<10000000;$i++){
@j[0]=$i;
# Benchmark 1 test 2: Loopoverhead.
@j[1]=$i;
Testar hur mycket overhead en tom
@j[2]=$i;
loop orsakar.
@j[3]=$i;
# Loopvärde: 10^6
};
for($i=0;$i<1000000;$i++){
};
# Benchmark 5 test 1: Uppräkning av
8-bitarsvariabel.
# Benchmark 1 test 3: Loopoverhead.
# Loopvärde: 10^7
Testar hur mycket overhead en tom
$j=0;
loop orsakar.
for($i=0;$i<10000000;$i++){
# Loopvärde: 10^7
$j++;
for($i=0;$i<10000000;$i++){
};
};
# Benchmark 6 test 1: Uppräkning av
# Benchmark 1 test 3: Loopoverhead.
16-bitarsvariabel.
Testar hur mycket overhead en tom
# Loopvärde: 10^7
loop orsakar.
$j=0;
# Loopvärde: 10^8
for($i=0;$i<10000000;$i++){
for($i=0;$i<100000000;$i++){
$j++;
};
};
# Benchmark 2 test 1: Lokal
# Benchmark 7 test 1: Uppräkning av
variabeltilldelning
32-bitarsvariabel.
# Loopvärde: 10^7
# Loopvärde: 10^7
$j=0;
sub loop{
for($i=0;$i<10000000;$i++){
$j=0;
$j++;
for($i=0;$i<10000000;$i++){
};
$j=$i;
};
# Benchmark 8 test 1: Uppräkning av
}
64-bitarsvariabel.
loop()
# Loopvärde: 10^7
$j=0;
# Benchmark 3 test 1: Global
for($i=0;$i<10000000;$i++){
variabeltilldelning
$j++;
# Loopvärde: 10^7
};
$j=0;
for($i=0;$i<10000000;$i++){
# Benchmark 9 test 1: Uppräkning av
$j=$i;
64-bitars flyttalsvariabel.
16
Bilaga A. Källkod för benchmarkprogram
# Loopvärde: 10^7
# Benchmark 13 test 3: Matematisk
$j=0.0;
funktion 2
for($i=0;$i<10000000;$i++){
# Loopvärde: 10^7
$j++;
$j=0;
};
for($i=0;$i<10000000;$i++){
$j=cos(45.0);
# Benchmark 10 test 1:
};
Matrisallokering - Går ej
implementera. Dynamisk
# Benchmark 13 test 4: Matematisk
minnesallokering
funktion 2
# finns ej i Perl.
# Loopvärde: 10^7
# Loopvärde: 10^7
$j=0;
for($i=0;$i<10000000;$i++){
# Benchmark 11 test 1:
$j=cos(60.0);
Funktionsanrop
};
# Loopvärde: 10^7
sub funktion{
# Benchmark 14 test 1: Villkorstest
}
# Loopvärde: 10^7
$j=1;
for($i=0;$i<10000000;$i++){
for($i=0;$i<10000000;$i++){
funktion;
if($j>0){
};
}
elsif($j<0){
# Benchmark 12 test 1: Matematisk
}
funktion 1
else{
# Loopvärde: 10^7
}
$j=0;
};
for($i=0;$i<10000000;$i++){
$j=abs(-30);
# Benchmark 15 test 1:
};
Strängallokering. Funkar inte i
Perl p.g.a. av avsaknad av dyn.
# Benchmark 13 test 1: Matematisk
allokering.
funktion 2
# Loopvärde: 10^7
# Loopvärde: 10^7
$j=0;
# Benchmark 16 test 1: Typecasting.
for($i=0;$i<10000000;$i++){
Perl har inga datatyper.
$j=cos(15.0);
# Loopvärde: 10^7
};
# Benchmark 13 test 2: Matematisk
# Benchmark 17 test 1: Rekursivt
funktion 2
anrop. Funkar inte i Perl.
# Loopvärde: 10^7
# Loopvärde: 10^7
$j=0;
for($i=0;$i<10000000;$i++){
# Benchmark 18 test 1: Lintest
$j=cos(30.0);
# Loopvärde: 10^7
};
$j=0;
17
Bilaga A. Källkod för benchmarkprogram
for($i=1;$i<10000001;$i++){
$j=2/$j;
$j=(3*($i/10))+(2*($i/100));
}
18
Bilaga B. Poäng vid betygsbedömningar
Bilaga B. Poäng vid betygsbedömningar
Benchmarktest
GNAT (Ada)
Visual C++
MS J++
Borland Delphi
Active Perl
1
3
3
4
5
1
2
4
4
3
5
1
3
5
5
3
5
1
4
5
5
3
5
1
5
4
4
2
5
1
6
4
4
3
5
1
7
4
4
3
5
2
8
3
5
3
5
1
9
5
5
3
5
1
11
4
4
3
5
1
12
5
4
3
5
1
13
1
3
4
5
2
14
4
5
2
3
1
18
4
5
5
4
1
1