• No results found

Implementation och utvärdering av trådintensiv simulator i Java, Jetlang och Erlang

N/A
N/A
Protected

Academic year: 2021

Share "Implementation och utvärdering av trådintensiv simulator i Java, Jetlang och Erlang"

Copied!
70
0
0

Loading.... (view fulltext now)

Full text

(1)

Institutionen för datavetenskap

Department of Computer and Information Science

Examensarbete

Implementation och utvärdering av trådintensiv

simulator i Java, Jetlang och Erlang

av

Henrik Holmberg

LIU-IDA/LITH-EX-G--11/010--SE

(2)
(3)

Examensarbete

Implementation och utv¨

ardering av

tr˚

adintensiv simulator i Java, Jetlang

och Erlang

av

Henrik Holmberg

LIU-IDA/LITH-EX-G--11/010--SE

2011-05-26

Handledare: Mattias Eriksson & Patrik H¨oglund (ENEA)

(4)
(5)

Abstract

Efficient threading is difficult to create and it is complicated to write. This thesis describes an implementation and compares these. The evaluationof the implementations in Java, Jetlang and Erlang reveal that Jetlang is the best when it comes to scaling regarding complexity as well as hardware. Erlang requires the least extra code for the threading. When many small executions are needed, Erlang performs the best but loses the lead quickly when the complexity increases.

(6)

Sammanfattning

Tr˚adning ¨ar sv˚art att f˚a s˚a effektivt som m¨ojligt och det ¨ar komplicerat att skriva kod f¨or det. Det h¨ar examensarbetet beskriver en implementation

och j¨amf¨or sedan implementationerna. Utv¨arderingen av

implementationer-na i Java, Jetlang och Erlang avsl¨ojar att Jetlang skalar b¨ast b˚ade n¨ar det g¨aller komplexitet och h˚ardvara. Erlang beh¨over minst extra kod f¨or att hantera tr˚adning. N¨ar det g¨aller m˚anga sm˚a k¨orningar har ¨aven Erlang b¨ast prestanda men tappar f¨orspr˚anget snabbt n¨ar komplexiteten ¨okar.

(7)

Inneh˚

all

1 Inledning 1 1.1 Bakgrund . . . 1 1.2 Syfte . . . 1 1.3 Termer . . . 2 1.4 Relaterat arbete . . . 3 1.5 Metod . . . 3 2 Teori 5 2.1 Tr˚adar . . . 5 2.2 Objektdelning . . . 6 2.3 Meddelandeskickning . . . 6 2.4 Strategier . . . 6 2.5 Testning . . . 7 2.5.1 Korrekthet . . . 7 2.5.2 Prestanda . . . 7 2.6 Akt¨or-modellen . . . 8 3 Resultat 9 3.1 Testsystem . . . 9 3.1.1 Prestandatest . . . 10 3.2 Implementation i Java . . . 10 3.3 Implementation i Jetlang . . . 12 3.4 Implementation i Erlang . . . 13

3.5 J¨amf¨orelse grundl¨aggande . . . 13

3.5.1 Prestanda . . . 13

3.5.2 Tr˚addrivande kod . . . 14

3.6 J¨amf¨orelse ut¨okad . . . 15

3.6.1 Prestanda . . . 16

3.7 J¨amf¨orelse ytterligare ut¨okad . . . 17

3.7.1 Prestanda . . . 17

3.8 Sammanst¨allning . . . 18

(8)

INNEH˚ALL INNEH˚ALL

5 Slutsats 23

5.1 Framtida f¨orb¨attringar . . . 23

Litteraturf¨orteckning 24 Bilagor 25 A Exekvering . . . 25 B Digital kod . . . 26 C Java-implementation . . . 26 C.1 Grundl¨aggande . . . 26 C.2 Ut¨okad . . . 40

C.3 Ytterligare ut¨okad . . . 40

D Jetlang-implementation . . . 41

D.1 Grundl¨aggande . . . 41

D.2 Ut¨okad . . . 55

D.3 Ytterligare ut¨okad . . . 56

E Erlang-implementation . . . 57

E.1 Grundl¨aggande . . . 57

E.2 Ut¨okad . . . 60

(9)

Kapitel 1

Inledning

1.1

Bakgrund

Prestanda¨okning av processorer sker sedan n˚agra ˚ar tillbaka inte l¨angre ge-nom att ¨oka klockfrekvensen utan genom att ¨oka antalet k¨arnor i processorn f¨or att kunna k¨ora flera uppgifter parallellt. Sutter n¨amnde detta 2005 i sin artikel (Sutter, 2005) och trenden har fortsatt p˚a samma s¨att. Det inneb¨ar att programmerare inte kan utnyttja hela processorns kraft utan att dela upp program i flera tr˚adar. Program som ¨ar tr˚adade kan utnyttja flera pro-cessork¨arnor parallellt och d¨armed k¨oras snabbare. Om det handlar om ett grafiskt gr¨anssnitt blir det mer responsivt. Det ¨ar de goda egenskaperna hos tr˚adade program. De s¨amre egenskaperna ¨ar att de ¨ar sv˚ara att program-mera och ¨aven att testa. Ordningen olika tr˚adar k¨or i varierar mellan varje k¨orning och det finns inget bra s¨att att f¨orutsp˚a ordningen. D¨arf¨or ¨ar det sv˚art att f¨olja hur ett program k¨ors och verifiera att det fungerar korrekt. Det finns en del strategier f¨or att skriva fungerande tr˚adade program p˚a ett bra s¨att, men det saknas strategier som alltid fungerar. ¨Aven skalbarhet med tr˚adade program ¨ar ett problem d˚a det finns en kostnad n¨ar en annan tr˚ad ska k¨oras.

1.2

Syfte

Syftet med det h¨ar examensarbetet ¨ar att unders¨oka hur bra det g˚ar att

skriva tr˚adade program i Java med och utan Jetlang samt i Erlang. Vi

ska f¨ors¨oka svara p˚a vad som skiljer implementationerna ˚at n¨ar det g¨aller l¨asbarhet och prestanda.

(10)

1.3. TERMER Glossary

1.3

Termer

I den h¨ar rapporten anv¨ands en del termer som kan vara nya f¨or l¨asaren. Nedan listas f¨orkorningarna som anv¨ands.

F¨orkortning Utskrivning Motsvarar

UE UserEquipment mobiltelefon

SUT SystemUnderTest basstation

CI ControlInterface styrgr¨anssnitt

JVM Java Virtual Machine k¨or Java

Nedan f¨oljer ¨aven en ordlista med de viktigaste begreppen.

akt¨or eng. actor. 8

fiber synonym f¨or l¨attviktstr˚ad. 12 f¨orfr˚agan eng. request. 6, 7

genomstr¨omning eng. throughput. 7

interfolieras eng. interleaves. 6 kanal eng. channel. 6

kappl¨opningsfri eng. race-free, tv˚a tr˚adar t¨avlar inte om vem som hinner f¨orst. 8

kritiskt block eng. critical section. 6 l˚as eng. lock. 6, 8

meddelandes¨andning eng. message passing. 3, 6, 8, 21

objektdelning eng. object sharing. 6 of¨or¨anderliga eng. immutable. 6, 12

prestandam¨atning eng. benchmarking. 7, 8

responsivitet eng. responsiveness. 7 skalbarhet eng. scalability. 7

(11)

1.4. RELATERAT ARBETE Glossary

skr¨aphantering eng. garbage collection, samlar upp gammalt minne f¨or

˚ateranv¨andning. 7, 10 slutlig eng. final. 7, 12 svar eng. reply. 6 tillst˚and eng. state. 6 ¨

omsesidig uteslutning eng. mutual exclusion. 6

1.4

Relaterat arbete

Enligt Hal´en, Karlsson och Nilsson presterar Erlang mycket b¨attre ¨an Java n¨ar det g¨aller skapande av tr˚adar samt meddelandes¨andning (eng. message passing). Deras resultat visar att Erlang kan skapa 20 000 Erlang-processer (Erlangs l¨attviktstr˚adar, n¨armaste motsvarigheten till Javas tr˚adar) medan Java enbart klarar upp till 1 600 tr˚adar. N¨ar det g¨aller meddelandes¨andning ¨

ar tiden f¨or Erlang v¨aldigt stabil medan Java tar ungef¨ar ˚atta g˚anger l¨angre tid p˚a Microsoft Windows 95. (Hal´en, Karlsson & Nilsson, 1998)

Som Sun Microsystems n¨amner har prestandan ¨okat mycket sedan den

f¨orsta versionen i Java HotSpot Virtual Machine (VM). Exempelvis finns

funktionalitet f¨or att kunna eliminera kontroller vid indexering, snabbare

tr˚adsynkronisering och omorganisering av instruktioner som inte f¨orekommer i optimal ordning. (Sun Microsystems, 2002)

Christopher Frantz menar att Jetlang ¨ar ett av de b¨asta alternativen f¨or

introduktionen av actor-modellen i Java. Det ¨ar snabbt, enkelt och har alla

viktiga koncept. (Frantz, 2010)

1.5

Metod

Ett antal olika b¨ocker om Java, Erlang och tr˚adning anv¨ands som litteratur

tillsammans med ett antal artiklar f¨or att bygga upp en teoretisk grund.

¨

Aven dokumentationen f¨or Java, Jetlang och Erlang anv¨ands f¨or att hitta

information. Med den teoretiska grunden implementeras simulatorn i Java, Java tillsammans med Jetlang och till sist Erlang. Implementationerna ska-pas genom att b¨orja med enkla fall och sedan ut¨oka dem f¨or att fungera med

mer avancerade fall. Med j¨amna mellanrum refaktoreras koden f¨or att bli

mer strukturerad och l¨attl¨aslig. Med de olika implementationerna sida vid

sida kan de j¨amf¨oras i andel tr˚addrivande kod samt prestanda.

Enligt Bull, Smith, Westhead, Henty och Davey ska prestandam¨atning

vara representativ och l¨att att f¨orst˚a. De h¨ar egenskaperna tenderar att vara i konflikt. F¨or att vara s˚a realistiskt som m¨ojligt blir det mer komplex kod och d¨arf¨or sv˚arare att tolka resultatet. (Bull, Smith, Westhead, Henty & Davey, 1999)

(12)

1.5. METOD Glossary

Prestandam¨atningen i det h¨ar examensarbetet ska vara enkel f¨or att va-ra enklare att tolka. Den sker med fleva-ra k¨orningar f¨or att ta ut ett r¨attvist v¨arde. Andel tr˚addrivande kod tas fram genom att r¨akna antalet rader som uppfyller en given definition och dividera med totalt antal rader i filen. De-finitionen som anv¨ands ¨ar:

Rader som f¨orbereder f¨or meddelandes¨andning eller k¨orning av tr˚adar. Denna definition inneb¨ar att de rader som m˚aste finnas med, s˚asom starta

upp en tr˚ad och skicka meddelanden, inte r¨aknas som tr˚addrivande.

Simu-latorn ut¨okas f¨or att f˚a l¨angre k¨ortid. D¨armed blir den mer realistisk och resultaten kan anv¨andas f¨or att unders¨oka om hur v¨al implementationerna skalar.

Simulator

Programmet som implementeras ¨ar en simulator av en basstation f¨or

mo-biltelefonn¨at. F¨or att simulera ett stort antal (tiotusentals) instanser av

mobiltelefoner (UE:ar) beh¨over programmet tr˚adas. Det som sker i

simula-torn ¨ar att styrgr¨anssnittet (CI) startar upp basstationen (SUT) som sedan k¨ors oberoende av styrgr¨anssnittet. Sedan startas ett antal mobiltelefoner upp av styrgr¨anssnittet som skickar diverse signaler, till exempel en signal

om att den har slagits p˚a, till basstationen som svarar med en ny signal.

Figur 1.1 visualiserar detta.

ControlInterface SystemUnderTest UE 1. Create_UE 2. Power_On 3. Power_On_Ack UE UE

(13)

Kapitel 2

Teori

2.1

Tr˚

adar

Oaks och Wong h¨avdar att en tr˚ad ¨ar ett program eller del av ett program som k¨ors av en dator. Tr˚adar m¨ojligg¨or k¨orning av flera program samtidigt. Med flera tr˚adar i ett program kan det exekvera instruktioner parallellt och tr˚adarna delar ¨aven minne. (Oaks & Wong, 2004, s. 11–14)

Skapandet av en ny tr˚ad tar olika l˚ang tid p˚a olika plattformar enligt Oaks och Wong, men ¨ar aldrig kostnadsfritt. D¨arf¨or kan tr˚adpoolar vara ¨

onskv¨arda. De skapar ett best¨amt antal tr˚adar och ˚ateranv¨ander dessa f¨or att utf¨ora uppgifter ist¨allet f¨or att skapa nya f¨or varje ny uppgift. Skillnaden

mellan att skapa nya tr˚adar hela tiden och anv¨anda tr˚adpooler varierar

mellan olika plattformar men det skiljer i allm¨anhet 100–400 mikrosekunder.

Detta kan vara relativt mycket eller lite beroende p˚a hur l˚ang tid uppgifterna som k¨ors i tr˚adarna tar. F¨or en uppgift som tar 5 millisekunder att slutf¨ora ¨

ar detta en v¨aldigt l˚ang f¨ordr¨ojning men om uppgiften tar 30 sekunder ¨ar f¨ordr¨ojningen f¨orsumbar. (Oaks & Wong, 2004, s. 265–266)

Goetz m. fl. s¨ager att den optimala storleken p˚a en tr˚adpool ¨ar: Nthreads = Ncpu· Ucpu·



1 + W

C 

d¨ar Nthreads ¨ar antalet tr˚adar, Ncpu¨ar antalet processork¨arnor, Ucpu¨ar den ¨

onskade anv¨andningen av varje processork¨arna (0 ≤ Ucpu ≤ 1) och WC ¨ar

f¨orh˚allandet mellan v¨antetid och exekveringstid. V¨antetid ¨ar v¨antan p˚a data fr˚an exempelvis tangentbord, h˚arddisk eller n¨atverk. Denna formel tar bara

h¨ansyn till CPU som resurs och inte andra resurser s˚asom minne, databaser

(14)

2.2. OBJEKTDELNING KAPITEL 2. TEORI

2.2

Objektdelning

Objektdelning (eng. object sharing) inneb¨ar att tv˚a eller flera objekt kan

interagera med ett objekt. Det delade objektets tillst˚and (eng. state) kan

observeras och modifieras genom objektets metoder. Om objekt i flera

oli-ka tr˚adar interagerar med objektet samtidigt, kan dessa interfolieras (eng.

interleaves) p˚a godtyckligt s¨att. Detta g¨or att det kan ske uppdateringar av objektets tillst˚and som inte ¨ar korrekta. F¨or att alla tillst˚and ska vara

korrekta kan ¨omsesidig uteslutning (eng. mutual exclusion) anv¨andas. Det

inneb¨ar att endast en tr˚ad f˚ar vara i ett kritiskt block (eng. critical section) eller en kritisk metod vid ett givet tillf¨alle. (Magee & Kramer, 2006, s. 63–73) Enligt Goetz m. fl. finns det n˚agra olika tillv¨agag˚angss¨att f¨or att uppn˚a s¨aker objektdelning. Ett s¨att ¨ar att objektdelning enbart f˚ar ske i en och samma tr˚ad. Objekt kan delas problemfritt mellan flera tr˚adar om de enbart ¨

ar l¨asbara. Of¨or¨anderliga (eng. immutable) objekt uppfyller detta krav. Om flera tr˚adar m˚aste kunna ¨andra p˚a ett objekt kan det g¨oras korrekt om

det delade objektet har intern synkronisering. Ett annat alternativ ¨ar att

anv¨anda l˚as (eng. locks) som en tr˚ad m˚aste inneha f¨or att f˚a tillg˚ang till objektet. (Goetz m. fl., 2006, s. 33–54)

2.3

Meddelandeskickning

Carver och Kuo-Chung menar att ett alternativ till delade objekt eller va-riabler ¨ar att ist¨allet anv¨anda sig av meddelandes¨andning. Detta alternati-vet inneb¨ar att ingen extra synkronisering beh¨ovs f¨or att kommunicera med andra tr˚adar. Meddelandes¨andning kan vara synkron, d¨ar avs¨andaren v¨antar tills mottagaren har tagit emot meddelandet, eller asynkron, d¨ar avs¨andaren forts¨atter sin exekvering s˚a fort meddelandet skickats iv¨ag. Begreppet ka-nal (eng. channel) anv¨ands f¨or de objekt som tillhandah˚aller s˚adan

med-delandeskickning. Kommunikationen via kanaler sker endast ˚at ena h˚allet,

f¨or tv˚av¨agskommunikation finns rendezvous som anv¨ander sig av f¨orfr˚agan (eng. request) och svar (eng. reply). (Carver & Kuo-Chung, 2006, s. 258–275)

2.4

Strategier

Sand´en menar att det inte finns n˚agot s¨att att f¨orhindra att en programme-rare h˚aller l˚as i en l¨angre tid. F¨or att undvika detta kr¨avs en bra f¨orst˚aelse

f¨or olika typer av synkronisering och vet vilken typ av synkronisering som

ska anv¨andas. (Sand´en, 2004)

Det finns strategier f¨or att undvika problem vid tr˚adning. Goetz m. fl.

har sammanst¨allt en lista ¨over god praxis vid programmering som kr¨aver

flera tr˚adar. Den inkluderar f¨oljande punkter. • Of¨or¨anderliga objekt ¨ar automatiskt tr˚ads¨akra.

(15)

2.5. TESTNING KAPITEL 2. TEORI

• G¨or f¨alt konstanta (eng. final) om de inte m˚aste kunna ¨andras.

• Inkapsling g¨or det praktiskt att hantera komplexiteten.

• Skydda varje f¨or¨anderlig variabel med ett l˚as. • Beh˚all l˚as tills sammansatta instruktioner ¨ar klara.

• Ett program som l¨aser eller skriver en variabel fr˚an flera tr˚adar utan synkronisering ¨ar ett trasigt program.

• Inkludera tr˚ads¨akerhet i designprocessen. • Dokumentera synkroniseringspolicyn. (Goetz m. fl., 2006, s. 110)

2.5

Testning

2.5.1

Korrekthet

Goetz m. fl. n¨amner att enkla enhetstester inte skiljer sig mellan program

med en eller flera tr˚adar i vissa fall. De testerna ¨ar helt sekventiella och allt k¨ors i en tr˚ad. Testning av blockerande metoder ¨ar betydligt sv˚arare och kr¨aver en timeout eller n˚agot liknande f¨or att avg¨ora om en blockering har intr¨affat. (Goetz m. fl., 2006, s. 248–252)

2.5.2

Prestanda

Enligt Goetz m. fl. finns det ett antal olika s¨att f¨or att g¨ora prestandatester

p˚a tr˚adade program. Dessa inkluderar genomstr¨omning (eng. throughput),

responsivitet (eng. responsiveness) och skalbarhet (eng. scalability). Genom-str¨omning inneb¨ar hur fort ett antal parallella uppgifter blir slutf¨orda. Re-sponsivitet ¨ar hur l˚ang f¨ordr¨ojning det ¨ar mellan att en f¨orfr˚agan inkommer till det att n˚agot g¨ors. Skalbarhet inneb¨ar hur mycket mer genomstr¨omning det blir n¨ar man ¨okar antalet tillg¨angliga resurser. (Goetz m. fl., 2006, s. 247)

Prestandam¨atning i Java

Goetz m. fl. tar upp att det finns att antal fallgropar n¨ar det g¨aller

prestanda-m¨atning (eng. benchmarking) i Java. Skr¨aphantering (eng. garbage

collec-tion) i Java kan ske n¨ar som helst utan att programmeraren direkt kan

p˚averka den. Det g˚ar att s¨aga till Java Virtual Machine (JVM) att den b¨or k¨ora skr¨aphantering vid ett visst tillf¨alle men det finns ingenting som garan-terar att s˚a sker. Genom att l¨agga till en flagga till JVM skrivs det ut varje g˚ang skr¨aphantering k¨ors. N¨ar kod k¨ors ofta, optimerar JVM koden vilket g¨or att den k¨ors snabbare n¨ar den anropas n¨asta g˚ang. Detta p˚averkar dock resultatet eftersom optimeringen tar tid. ¨Aven f¨or detta g˚ar det att l¨agga till

(16)

2.6. AKT ¨OR-MODELLEN KAPITEL 2. TEORI

en flagga till JVM f¨or att f˚a utskrifter n¨ar optimering sker. En metod som anv¨ands f¨or att undvika optimering under prestandam¨atning ¨ar att v¨arma upp systemet f¨orst och k¨ora igenom koden ett antal g˚anger. (Goetz m. fl., 2006, s. 266–270)

Enligt Goetz optimerar ¨aven JVM bort d¨od kod, det vill s¨aga kod som

aldrig k¨ors. Det inneb¨ar att det kan ta olika l˚ang tid att k¨ora ett program

beroende p˚a vilken kod som exekveras under den k¨orningen. (Goetz, 2004)

Heisenberg-principen ¨ar enligt Goetz att resultaten av prestandam¨

atning-en atning-enbart ska visa hur l˚ang tid en viss operation tar. Eftersom JVM

optime-rar kod kan brus introduceras i m¨atningarna och m¨atningarna kanske inte

skildrar det som var t¨ankt. (Goetz, 2005)

2.6

Akt¨

or-modellen

Enligt Haller och Odersky ¨ar meddelandes¨andning i akt¨or (eng.

actor)-modellen kappl¨opningsfri (eng. race-free) enligt sin design och ¨ar d¨arf¨or mer s¨aker ¨an delat minne med l˚as. Meddelandes¨andning sker asynkront och bloc-kerar d¨armed inte den som skickar. Varje akt¨or ¨ar oberoende av alla andra actors. En akt¨or kan vara i princip vad som helst. Akt¨orer ¨ar l¨attare ¨an vanliga tr˚adar och kan k¨oras med en 1 000-faktor fler. (Haller & Odersky, 2007)

(17)

Kapitel 3

Resultat

3.1

Testsystem

Systemet d¨ar implementationerna k¨ors och testas ¨ar en PC med f¨oljande

specifikationer:

• Intel Core2 Duo 6400 @ 2,13 GHz (2 k¨arnor)

• 3,5 GB RAM

• Microsoft Windows XP Professional Service Pack 3 • Eclipse Helios

• Java 1.6 • Jetlang 0.2.5 • Erlang 5.8.3

Tester k¨ors ¨aven p˚a ett system med b¨attre prestanda:

• Intel Core i7 950 @ 3,07 GHz (4 k¨arnor med HyperThreading)

• 10 GB RAM • Ubuntu • Java 1.6 • Jetlang 0.2.5 • Erlang 5.5.5

(18)

3.2. IMPLEMENTATION I JAVA KAPITEL 3. RESULTAT

3.1.1

Prestandatest

F¨or att f˚a s˚a bra m¨atresultat som m¨ojligt anv¨ands en uppv¨armningsfas innan m¨atningen p˚ab¨orjas f¨or att de flesta av optimeringarna som JVM g¨or ska vara gjorda vid sj¨alva testet. Denna uppv¨armningsfas fungerar helt enkelt ge-nom att k¨ora igenom koden som ska anv¨andas ett antal (50–100) g˚anger vil-ket Goetz m. fl. n¨amnde. F¨ore varje m¨atning uppmanas ocks˚a JVM att k¨ora sin skr¨aphantering innan s˚a det sker s˚a lite som m¨ojligt under m¨atningen. Den skriver ¨aven ut n¨ar varje m¨atning b¨orjar och slutar f¨or att visa ifall det sker n˚agot extra i m¨atningen. ¨Aven detta n¨amnde Goetz m. fl. i avsnittet om testning. N¨ar antalet mobiltelefoner ¨okar visar det sig att skr¨aphantering ocks˚a ¨oka under sj¨alva m¨atningen vilket g¨or att resultaten blir mindre preci-sa. F¨oruts¨attningarna mellan de b˚ada Java-implementationerna b¨or d¨aremot vara tillr¨ackligt lika f¨or att en j¨amf¨orelse dem emellan ska vara r¨attvis. Detta

eftersom b˚ada implementationerna drabbas av den ¨okade skr¨aphanteringen.

¨

Aven j¨amf¨orelsen med Erlang b¨or vara r¨attvis eftersom Erlang ocks˚a har skr¨aphantering och det ¨ar den totala prestandan som ¨ar intressant. I Er-lang anv¨ands ett motsvarande testsystem som i Java f¨or att det ska vara s˚a r¨attvisa resultat som m¨ojligt.

P˚a systemet med i7-processorn k¨ors endast de ut¨okade

implementatio-nerna. Java- och Jetlang-implementationerna k¨ors genom att skapa en jar-fil

d˚a i7-datorn saknar Java-kompilator. Erlang-implementationen kan k¨oras p˚a

samma s¨att som p˚a Core2 Duo-datorn.

3.2

Implementation i Java

Dispatcher ControlInterface UE SUT 1. 2. 3. 4. 5. 6. 7. 8.

Figur 3.1: Implementation i Java

I figur 3.1 visas en ¨oversikt ¨over hur simulatorn fungerar i implemen-tationen i Java. All kommunikation mellan bassimplemen-tationen, mobiltelefonerna

(19)

3.2. IMPLEMENTATION I JAVA KAPITEL 3. RESULTAT

och styrgr¨anssnittet sker via Dispatcher som anv¨ander en tr˚adpool med ett konstant antal tr˚adar. Dispatcher anv¨ander tr˚adpoolen f¨or att skicka vidare signalerna till sin destination d¨ar de tas emot och hanteras. S˚a h¨ar ser ett typiskt exekveringsfl¨ode ut:

1. ControlInterface skickar CREATE UE till Dispatcher med en destina-tion till mobiltelefonen.

2. Dispatcher anv¨ander en tr˚ad ur tr˚adpoolen f¨or att skicka vidare sig-nalen till mobiltelefonen d¨ar signalen hanteras och tolkas som att den ska starta.

3. Mobiltelefonen skickar POWER ON till Dispatcher med en destination till basstationen.

4. Dispatcher anv¨ander en tr˚ad ur tr˚adpoolen f¨or att skicka vidare sig-nalen till basstationen d¨ar signalen tolkas.

5. Basstationen skickar POWER ON ACK till Dispatcher med en desti-nation till mobiltelefonen.

6. Dispatcher anv¨ander en tr˚ad ur tr˚adpoolen f¨or att skicka vidare sig-nalen till mobiltelefonen d¨ar signalen hanteras.

2–6 upprepas med NEGOTIATE CAPABILITIES.

7. Mobiltelefonen skickar CREATE UE ACK till Dispatcher med desti-nation till styrgr¨anssnittet.

8. Dispatcher anv¨ander en tr˚ad ur tr˚adpoolen f¨or att skicka vidare sig-nalen till styrgr¨anssnittet som tar emot signalen och d˚a vet att mobil-telefonen har startats.

Efter dessa signaler har mobiltelefonen startats och kan skicka andra signaler

som kan starta och avsluta samtal. Dessa signaler ¨ar enbart symboliska men

nedan beskrivs vad de representerar:

• CREATE UE talar om f¨or mobiltelefonen att den ska starta.

• POWER ON talar om f¨or basstationen att en mobiltelefon har slagits

p˚a.

• NEGOTIATE CAPABILITIES anv¨ands f¨or att best¨amma vad

mobil-telefonen kan och inte kan g¨ora.

• Alla som slutar med ACK skickas tillbaka till mobiltelefonen f¨or att

(20)

3.3. IMPLEMENTATION I JETLANG KAPITEL 3. RESULTAT

Implementationen m˚aste ha en Dispatcher eftersom en tr˚adpool ska anv¨ an-das f¨or att k¨ora alla uppgifter p˚a ett begr¨ansat antal tr˚adar. Detta eftersom Goetz m. fl. n¨amnde att en tr˚adpool ¨ar effektivare ¨an separata tr˚adar. Ef-tersom det ¨ar Java ¨ar implementationen objektorienterad och anv¨ander arv f¨or att modellera exempelvis olika objekt som signaler kan g˚a till och fr˚an (basstation och mobiltelefon ¨arver fr˚an Endpoint). Varje signal ¨ar slutlig och d¨armed of¨or¨anderliga vilket g¨or dem tr˚ads¨akra. Goetz m. fl. n¨amnde att ett objekt som ¨ar slutlig automatiskt blir tr˚ads¨akert. Endast objekt som ¨ar slut-liga delas mellan olika tr˚adar och en blockerande k¨o anv¨ands i Dispatcher

f¨or att hantera meddelandeskickningen.

3.3

Implementation i Jetlang

ControlInterface UE SUT 1. 2. 3. 4.

Figur 3.2: Implementation i Java med Jetlang

I figur 3.2 visas en ¨oversikt ¨over hur implementationen i Java tillsammans med Jetlang fungerar. Ett exekveringsfl¨ode ser typiskt ut som f¨oljer:

1. Styrgr¨anssnittet skickar CREATE UE till mobiltelefonen (k¨ors i en

egen fiber (l¨attviktstr˚ad)) via en kanal som sedan hanteras av mobilte-lefonen.

2. Mobiltelefonen skickar POWER ON via en kanal till basstationen d¨ar

signalen tolkas.

3. Basstationen skickar POWER ON ACK som svar i kanalen tillbaka till mobiltelefonen d¨ar den hanteras.

2–3 upprepas med NEGOTIATE CAPABILITIES.

4. Mobiltelefonen skickar CREATE UE ACK som svar i kanalen till styr-gr¨anssnittet.

(21)

3.4. IMPLEMENTATION I ERLANG KAPITEL 3. RESULTAT

Efter detta ¨ar mobiltelefonen startad och kan skicka signaler som kan starta och avsluta samtal. Implementationen startar allt i fibrer som ¨ar l¨attviktstr˚adar vilka tillhandah˚alls av Jetlang. Fibrerna k¨ors i en tr˚adpool som Jetlang han-terar. D¨arf¨or kan varje objekt som kr¨aver en oberoende exekvering startas upp i en egen fiber och anv¨anda kanaler som till˚ater tv˚av¨agskommunikation

(rendezvous). Detta n¨amner Magee och Kramer som en variant av

medde-landeskickning.

3.4

Implementation i Erlang

Implementationen i Erlang st¨ammer ¨overens med figur 3.2 och fungerar

p˚a samma s¨att som implementationen i Jetlang. Alla mobiltelefoner samt

basstationen k¨ors i var sin Erlang-process. De skickar meddelanden med

Er-langs inbyggda funktioner. Dessa kanaler st¨ammer ¨overens med det Magee

och Kramer n¨amnde.

3.5

amf¨

orelse grundl¨

aggande

J¨amf¨orelsen sker med avseende p˚a effektivitet d¨ar m˚attet ¨ar hur m˚anga

mobiltelefoner som hinner skapas p˚a en sekund och hur stor del av koden som

g˚ar ˚at till att hantera tr˚adningen. Dessa tv˚a m˚att ¨ar kvantitativa och l¨atta att m¨ata. Ut¨over dessa kan ¨aven l¨asbarhet tas med som ¨ar ett kvalitativt m˚att och mycket subjektivt. D¨armed ¨ar det sv˚art att anv¨anda detta p˚a ett r¨attvist s¨att.

3.5.1

Prestanda

Figur 3.3 visar resultatet av k¨orningar med olika antal tr˚adar. V¨ardet som anv¨andes ¨ar medianen av 20 k¨orningar efter varandra med 10 000

mobiltele-foner. Det minsta antalet tr˚adar som kan anv¨andas i Java-implementationen

¨

ar tre eftersom Dispatcher och basstationen beh¨over var sin tr˚ad. I Jetlang kr¨avs minst tv˚a f¨or att driva tr˚adpoolen. Resultatet visar att prestandan ¨

ar bland det b¨asta vid 4–6 tr˚adar. Efter det g˚ar det lite upp och ner men

prestandan blir inte b¨attre. Detta st¨ammer ¨overens med formeln Goetz m.

fl. n¨amnde.

En j¨amf¨orelse av hur m˚anga mobiltelefoner implementationerna klarar

av under 700 ms visas i figur 3.4. Enbart Java b¨orjar p˚a en s¨amre tid och tiden det tar att exekvera ¨okar lite snabbare ¨an med Jetlang. Av resultatet framg˚ar att med Jetlang g˚ar det i genomsnitt 30 % snabbare ¨an enbart Java.

I Erlang-implementationen g˚ar det betydligt snabbare ¨an i Java med

eller utan Jetlang. Detta visas i figur 3.6. Den klarar av att k¨ora m˚anga

fler mobiltelefoner p˚a samma tid och ¨ar b¨attre p˚a att utnyttja

proces-sorn. Implementationen i Java och Jetlang ligger p˚a 50–85 % av

(22)

3.5. J ¨AMF ¨ORELSE GRUNDL ¨AGGANDE KAPITEL 3. RESULTAT

Figur 3.3: Resultat av prestandatest med olika antal tr˚adar i Java och

Jet-lang.

v¨arden ¨ar tagna genom observation av aktivitetshanteraren i Windows

un-der testk¨orningarna. Vid ut¨okande av simulatorn med fler signaler och ¨aven att en mobiltelefon blir tvungen att skicka om en signal, blir prestandan i Erlang mycket s¨amre. Processoranv¨andningen ner till 50 % f¨or Erlang n¨ar fler ¨an 1 300 000 mobiltelefoner k¨ors i denna ut¨okade simulator.

3.5.2

Tr˚

addrivande kod

F¨or att m¨ata hur mycket av koden som g˚ar ˚at till att hantera tr˚adningen i im-plementationerna anv¨ands ett procentuellt m˚att p˚a de filerna som p˚averkas. M˚attet inneb¨ar att de rader som kr¨avs f¨or att starta eller stoppa tr˚adar, synkronisering, initiera objekt f¨or tr˚adhantering r¨aknas som rader f¨or att hantera tr˚adning. Dock ¨ar send och receive ej inr¨aknade i detta d˚a de alltid m˚aste vara med. Det gav f¨oljande resultat f¨or Java-implementationen:

• ControlInterface: 19 % • Dispatcher: 100 % • SystemUnderTest: 22 % • UserEquipment: 2 %

Resten av filerna p˚averkas inte och ¨ar d¨arf¨or inte med. P˚a hela koden inneb¨ar det att ungef¨ar 130 rader g˚ar ˚at till att hantera tr˚adningen. Dispatcher

(23)

3.6. J ¨AMF ¨ORELSE UT ¨OKAD KAPITEL 3. RESULTAT

Figur 3.4: Maximalt antal mobiltelefoner (UE) i Java

finns enbart f¨or att hantera tr˚adning och beh¨ovs enbart f¨or att k¨ora flera mobiltelefoner p˚a samma tr˚ad.

F¨or Java med Jetlang gav det f¨oljade resultat: • ControlInterface: 22 %

• UserEquipment: 15 %

Denna implementationen kr¨aver tr˚adrelaterad kod i enbart tv˚a av filerna

och ungef¨ar 70 rader g˚ar ˚at totalt.

I Erlang ¨ar den totala m¨angden kod mycket mindre och det kan d¨arf¨or vara sv˚arare att j¨amf¨ora med Java-implementationerna. M˚attet gav f¨oljande resultat:

• control interface: 21 % • system under test: 5 % • user equipment: 3 %

Totalt ¨ar det 10 rader som passar in p˚a definitionen av m˚attet.

3.6

amf¨

orelse ut¨

okad

(24)

3.6. J ¨AMF ¨ORELSE UT ¨OKAD KAPITEL 3. RESULTAT

Figur 3.5: Maximalt antal mobiltelefoner (UE) i Jetlang

• CALL SETUP, kopplar upp ett nytt samtal. • CALL SETUP ACK

• CALL END, avslutar ett samtal. • CALL END ACK

En mobiltelefon kan dessutom f˚a REJECT fr˚an basstationen vilket inneb¨ar

att den m˚aste skicka om signalen.

3.6.1

Prestanda

Som figur 3.7 visar ¨okade prestandan kraftigt n¨ar implementationen k¨ordes

p˚a en kraftfullare maskin. Denna maskin hade m˚anga komponenter som

var b¨attre ¨an den f¨orsta maskinen vilket inneb¨ar att siffrorna inte skildrar hur v¨al det skalar givet en viss komponent. ¨Aven operativsystemen ¨ar olika vilket g¨or att det endast g˚ar att j¨amf¨ora resultaten p˚a samma system med varandra. Figur 3.8 visar att Jetlang ¨okade ¨annu mer. Erlang ¨okade minst enligt figur 3.9.

Erlang k¨orde i snitt 3,0 g˚anger snabbare ¨an Java p˚a Core2 Duo. P˚a Core i7 k¨orde Erlang bara 1,2 g˚anger snabbare. J¨amf¨ort med Jetlang k¨orde Erlang 2,3 g˚anger snabbare p˚a Core2 Duo, men p˚a Core i7 var Jetlang 2,6 g˚anger snabbare ¨an Erlang.

(25)

3.7. J ¨AMF ¨ORELSE YTTERLIGARE UT ¨OKADKAPITEL 3. RESULTAT

Figur 3.6: Maximalt antal mobiltelefoner (UE) i Erlang

I den grundl¨aggande implementationen ¨ar Erlang effektivast f¨oljd

Jet-lang. Detta forts¨atter ¨aven upp till de andra implementationerna men

Er-langs f¨orspr˚ang minskar rej¨alt.

Sett till minnesanv¨andning anv¨ander Erlang ungef¨ar 60 MB vid k¨orning

av 50 000 mobiltelefoner. Java anv¨ander ungef¨ar lika mycket som Erlang.

¨

Aven Jetlang ligger kring samma v¨arden. Dessa v¨arden ¨ar tagna genom

observation av aktivitetshanteraren i Windows.

3.7

amf¨

orelse ytterligare ut¨

okad

Den ytterligare ut¨okade simulatorn skickar f¨oljande signaler ut¨over de i den ut¨okade:

• DATA SETUP, startar data¨overf¨oring.

• DATA SETUP ACK

• DATA END, avslutar data¨overf¨oring.

• DATA END ACK

3.7.1

Prestanda

I den ytterligare ut¨okade simulatorn ¨ar Erlang 3,1 g˚anger snabbare ¨an Java och 1,9 g˚anger snabbare ¨an Jetlang. Det inneb¨ar att Erlang ¨ar ungef¨ar lika

(26)

3.8. SAMMANST ¨ALLNING KAPITEL 3. RESULTAT

Figur 3.7: Maximalt antal mobiltelefoner (UE) i Java, Core2 Duo j¨amf¨ort

med i7.

mycket snabbare ¨an Java som med den ut¨okade simulatorn. Erlang ¨ar dock

inte lika mycket snabbare ¨an Jetlang.

3.8

Sammanst¨

allning

Figur 3.10 visar en sammanst¨allning ¨over testresultaten av den ut¨okade

simulatorn. Java p˚a Core2 Duo ¨ar l˚angsammast f¨oljt av Jetlang. Erlang

¨

ar snabbast p˚a Core2 Duo men ¨ar l˚angsammare ¨an Jetlang p˚a Core i7. Java ¨

ar l˚angsammast ¨aven p˚a Core i7.

Tabell 3.1 visar en sammanst¨allning ¨over hur olika implementationer

presterar i f¨orh˚allande till varandra p˚a Core2 Duo. 1, 2 och 3 i tabellen

mot-Impl Java1 Java2 Java3 Jet1 Jet2 Jet3 Erl1 Erl2 Erl3

Java1 100 % 86 % 60 % 119 % 100 % 88 % 466 % 225 % 178 % Java2 116 % 100 % 70 % 138 % 115 % 102 % 540 % 260 % 206 % Java3 166 % 143 % 100 % 197 % 166 % 146 % 773 % 373 % 295 % Jet1 84 % 73 % 51 % 100 % 84 % 74 % 392 % 189 % 150 % Jet2 100 % 86 % 60 % 119 % 100 % 88 % 465 % 225 % 178 % Jet3 114 % 99 % 69 % 136 % 114 % 100 % 531 % 256 % 203 % Erl1 21 % 19 % 13 % 26 % 21 % 19 % 100 % 48 % 38 % Erl2 44 % 38 % 27 % 53 % 45 % 39 % 207 % 100 % 79 % Erl3 56 % 49 % 34 % 67 % 56 % 49 % 262 % 126 % 100 %

(27)

3.8. SAMMANST ¨ALLNING KAPITEL 3. RESULTAT

Figur 3.8: Maximalt antal mobiltelefoner (UE) i Jetlang, Core2 Duo j¨amf¨ort med i7.

svarar grundl¨aggande, ut¨okad respektive ytterligare ut¨okad. F¨or att se hur snabb en implementation ¨ar i f¨orh˚allande till en annan, f¨olj raden som ska j¨amf¨oras till kolumnen den ska j¨amf¨oras med. 50 % inneb¨ar att implementa-tionen p˚a raden ¨ar dubbelt s˚a snabb som implementationen p˚a kolumnen.

(28)

3.8. SAMMANST ¨ALLNING KAPITEL 3. RESULTAT

Figur 3.9: Maximalt antal mobiltelefoner (UE) i Erlang, Core2 Duo j¨amf¨ort

med i7.

Figur 3.10: Tid f¨or att k¨ora 20 000 mobiltelefoner (UE) p˚a Core2 Duo samt Core i7.

(29)

Kapitel 4

Diskussion

Anledningen till att det f¨or varje m¨atv¨arde togs medianen av 20 k¨orningar ¨ar f¨or att vid observation verkade de flesta st¨amma v¨al ¨overens. En del avvek

men med medianen p˚averkas inte det slutliga m¨atv¨ardet. Det var ocks˚a

opraktiskt att ha f¨or m˚anga k¨orningar d˚a varje prestandam¨atning skulle ta v¨aldigt l˚ang tid.

M˚attet f¨or att m¨ata hur mycket av koden som g˚ar ˚at till att hantera tr˚adning ska tas med en nypa salt. Det ¨ar ett ungef¨arligt m˚att och inte helt

objektivt. D¨aremot b¨or det ge en uppfattning om hur v¨al konstruerat ett

spr˚ak ¨ar f¨or att hantera tr˚adning. Det kan ¨aven n¨amnas att m˚attet inte tar med alla rader som tillkommer indirekt av att tr˚adningen m˚aste sk¨otas

manuellt, till exempel att avs¨andare samt mottagare m˚aste finnas med i

Signal i den naiva implementationen men inte i de andra tv˚a. ¨Aven

blank-rader p˚averkar m˚attet d˚a det totala antalet rader anv¨ands. Fler blankrader inneb¨ar mindre andel som g˚ar ˚at till tr˚adning.

Personligen tycker jag att Erlang-implementationen ¨ar mest l¨attl¨ast ef-tersom det ¨ar mycket mindre kod och har inbyggd st¨od f¨or l¨attviktstr˚adar

samt meddelandes¨andning. Efter det kommer implementationen i Jetlang

eftersom signalerna inte beh¨over g˚a genom en Dispatcher d¨ar. I Erlang blir

det dessutom ett rakare exekveringsfl¨ode i varje mobiltelefon och inte s˚a

mycket hopp i koden. Med Jetlang blir det rakare ¨an i enbart Java men det

blir mer hopp i koden vilket g¨or det mindre l¨asbart.

Anledningen till att den ut¨okade Erlang-implementationen inte alls

pre-sterar lika bra som den grundl¨aggande ¨ar f¨ormodligen att det tar l¨angre tid att k¨ora varje Erlang-process och d¨armed hinner Erlang inte med. F¨or att or-ka med ¨okat antal som tar l¨angre tid att k¨ora m˚aste resurserna ¨okas. Denna teori st¨arks av att med den ytterligare ut¨okade implementationen skalar den ¨

annu s¨amre. Det verkar som att Erlang ¨ar b¨ast l¨ampat f¨or m˚anga, mycket korta processer.

I m¨atresultatet blir det v¨aldigt konstiga siffror mot slutet. Det beror p˚a att vissa av k¨orningarna inte hinner k¨ora klart p˚a under en sekund. De sista

(30)

KAPITEL 4. DISKUSSION

v¨arde i m¨atningarna varierar v¨aldigt mycket och ¨ar inte p˚alitliga. D¨arf¨or valde jag valde att s¨atta gr¨ansen vid 700 ms ¨aven om m¨atningar togs upp till 1000 ms f¨or att inte f˚a med de op˚alitliga siffrorna i diagrammen. Detta b¨or inte ha n˚agra implikationer p˚a det slutsatsen.

N¨ar det g¨aller resultaten av Jetlang-k¨orningen p˚a i7-datorn blev v¨arden v¨aldigt underliga i f¨orh˚allande till de andra k¨orningarna. De andra k¨ orning-arna gav ganska raka linjer medan den h¨ar k¨orningen gav v¨aldigt varierande v¨arden n¨ar antalet mobiltelefoner steg. Vad det beror p˚a kan jag inte riktigt f¨orklara men jag k¨orde testerna flera g˚anger med samma resultat. Det kan vara att det ¨ar en ¨aldre version av Erlang p˚a i7-datorn och d¨armed presterar den inte lika bra.

(31)

Kapitel 5

Slutsats

Erlang har mycket b¨attre prestanda ¨an Java med eller utan Jetlang i den

grundl¨aggande simulatorn. Samma antal mobiltelefoner k¨ors p˚a 5,3 g˚anger snabbare tid j¨amf¨ort med Java. Med den ut¨okade simulatorn k¨or den bara 3,0 g˚anger snabbare. Andel tr˚addrivande kod ¨ar h¨ogst i Java-implementationen och betydligt l¨agre i Jetlang-implementationen. Allra l¨agst ¨ar den i Erlang-implementationen. Exekveringsfl¨odet f¨or en mobiltelefon ¨ar mycket enkelt

att f¨olja i Erlang-implementationen med inga hopp i koden.

Jetlang-imple-mentationen ¨ar inte lika l¨att att f¨olja men ¨ar enklare ¨an Java-implementa-tionen.

Testresultaten blir b¨attre n¨ar de k¨ors p˚a ett kraftfullare system men

skalar olika bra. Erlang skalar inte lika bra n¨ar komplexiteten i

implemen-tationen ¨okar och inte heller n¨ar h˚ardvaran uppgraderas. Jetlang ¨ar d¨armed ett b¨attre val vid behov av tr˚adning med h¨og komplexitet och h¨oga pre-standakrav. Erlang ¨ar d¨aremot ¨overl¨agset l¨attast n¨ar det g¨aller hur lite tr˚addrivande kod som beh¨ovs.

5.1

Framtida f¨

orb¨

attringar

F¨or att utforska omr˚adet ytterligare kan implementationerna ut¨okas ytter-ligare f¨or att simulera mer komplexa system och p˚a s˚a vis f˚a mer precisa resultat. Testerna kan ¨aven f¨orb¨attras genom att k¨oras under en l¨angre pe-riod f¨or att andra faktorer ska spela s˚a liten roll som m¨ojligt. Det vore ¨aven intressant att se om det forts¨atter skala p˚a samma vis n¨ar testsystemets

prestanda ¨okar ytterligare. Ytterligare tester med Jetlang vore intressant

(32)

Litteraturf¨

orteckning

Bull, J. M., Smith, L. A., Westhead, M. D., Henty, D. S. & Davey, R. A. (1999). A benchmark suite for high performance java. I Proceedings of acm 1999 java grande conference (s. 81–88). ACM Press.

Carver, R. H. & Kuo-Chung, T. (2006). Modern Multithreading :

Implementing, Testing, and Debugging Multithreaded Java and C++/Pthreads/Win32 Programs. Hoboken, New Jersey, USA: Wiley. Frantz, C. (2010). Overview of Java based Message passing frameworks.

Goetz, B. (2004, december). Java theory and practice:

Dynamic compilation and performance measurement.

http://www.ibm.com/developerworks/java/library/j-jtp12214/.

Goetz, B. (2005, februari). Java theory and

practice: Anatomy of a flawed microbenchmark.

http://www.ibm.com/developerworks/java/library/j-jtp02225/. Goetz, B., Peierls, T., Bloch, J., Bowbeer, J., Holmes, D. & Lea, D.

(2006). Java Concurrency in Practice. Stouchton, Massachusetts,

USA: Addison-Wesley.

Haller, P. & Odersky, M. (2007). Actors That Unify Threads and

Events (forskningsrapport). ´Ecole Polytechnique F´ed´erale de Lausan-ne (EPFL), 1015 LausanLausan-ne, Switzerland: Programming Methods Lab (LAMP).

Hal´en, J., Karlsson, R. & Nilsson, M. (1998). Performance Measurements

of Threads in Java and Processes in Erlang (forskningsrapport). Er-icsson. http://www.sics.se/ joe/ericsson/du98024.html.

Magee, J. & Kramer, J. (2006). Concurrency : State Models & Java Pro-grams. Chichester, West Sussex, England: Wiley.

Oaks, S. & Wong, H. (2004). Java Threads. Sebastopol, California, USA: O’Reilly.

Sand´en, B. (2004, april). Coping with Java Threads. Computer , 37 (4),

20–27.

Sun Microsystems. (2002, september). The Java HotSpot Virtual Machi-ne, v1.4.1. http://java.sun.com/products/hotspot/docs/whitepaper/ Java Hotspot v1.4.1/Java HSpot WP v1.4.1 1002 1.html.

Sutter, H. (2005, mars). The Free Lunch Is Over. Dr. Dobb’s Journal , 30 (3).

(33)

Bilagor

A

Exekvering

F¨or att kunna kompilera och k¨ora Java-implementationen kr¨avs att Java

1.6 ¨ar installerat p˚a datorn. Simulatorn tar antalet mobiltelefoner (UE) som f¨orsta argument och antalet tr˚adar som ett eventuellt andra argument. F¨or att k¨ora testerna kr¨avs JUnit.

Kraven f¨or Jetlang-implementationen ¨ar samma som f¨or enbart Java men

kr¨aver ocks˚a att Jetlang-biblioteket ¨ar tillagt.

Vid enstaka k¨orning av simulatorn rekommenderas att anv¨anda f¨oljande

VM argument:

-Djava.util.logging.config.file="logging.properties"

F¨or att k¨ora testerna rekommenderas f¨oljande VM argument:

-verbose:gc

-XX:+PrintCompilation

-Djava.util.logging.config.file=

"src\com\enea\simulator\tests\logging.properties"

Det f¨orsta argumentet g¨or s˚a att VM skriver ut varje g˚ang den k¨or skr¨aphantering. Det andra argumentet g¨or s˚a VM skriver ut n¨ar kompilering och optimering sker. Det sista ¨ar f¨or att anv¨anda en speciell logginst¨allning som orsakar mindre utskrifter.

Erlang-implementationen kr¨aver att Erlang ¨ar installerat. Kompilering

sker med f¨oljande kommando i kommandoraden.

erl -make

Simulatorn startas med f¨oljande kommando i Erlang-interpretatorn.

control_interface:run(N).

N ¨ar antalet mobiltelefoner (UE). F¨or att k¨ora testet k¨ors med f¨oljande kommando.

(34)

B. DIGITAL KOD Litteraturf¨orteckning

B

Digital kod

All k¨allkod finns tillg¨anglig att ladda ner i zip-format p˚a f¨oljande webbplats. http://www-und.ida.liu.se/~henho106/exjobb/

D¨ar finns det paket f¨or enskilda versioner och ett stort paket. Det f¨oljer ocks˚a med instruktioner f¨or hur man ska k¨ora dem.

C

Java-implementation

C.1

Grundl¨

aggande

package com.enea.simulator; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.logging.Logger; import com.enea.simulator.behavior.Behavior; import com.enea.simulator.behavior.DefaultBehavior; import com.enea.simulator.behavior.NoDelayBehavior; import com.enea.simulator.behavior.TestBehavior; import com.enea.simulator.endpoint.Endpoint; import com.enea.simulator.endpoint.SystemUnderTest; import com.enea.simulator.endpoint.UserEquipment; import com.enea.simulator.signal.Signal; import com.enea.simulator.signal.SignalType; import com.enea.simulator.signal.order.DefaultSignalOrder; public class ControlInterface implements Endpoint {

public static boolean test = true;

public static void main(String[] args) throws InterruptedException {

// Get number of UserEquipments to use from arguments

if (args.length < 1) {

System.err.println("Please specify number of UserEquipments");

return;

}

int nrOfUEs = Integer.parseInt(args[0]);

if (nrOfUEs < 1) {

System.err

.println("Please specify a positive number of UserEquipments");

return;

}

ControlInterface controlInterface = new ControlInterface(3000);

int numberOfThreads = 0;

// Get optional argument for number of threads

if (args.length > 1) {

int nrThreadsTemp = Integer.parseInt(args[1]);

if (nrThreadsTemp > 0) {

numberOfThreads = nrThreadsTemp; }

}

// Start the control interface and catch unexpected exceptions.

try {

(35)

} catch (Exception e) { System.err.println(e.getMessage()); e.printStackTrace(); } } // Non−static // ////////////////////////////////////////////////////////////////////

private Logger log; private int waitTime; private long startTime; private long stopTime; private int createdUEs; private int targetUEs;

public ControlInterface(int waitTime) {

startTime = System.nanoTime(); this.waitTime = waitTime;

log = Logger.getLogger(this.getClass().getName()); }

@Override

public void handleSignal(final Signal signal) { try {

if (signal.getSignalType() == SignalType.CREATE_UE_ACK) {

Logger.getLogger(this.getClass().getName()).info( "ControlInterface: got CREATE_UE_ACK");

synchronized (this) { createdUEs++; stopTime = System.nanoTime(); } } } catch (Exception e) { System.err.println(e.getMessage()); e.printStackTrace(); } }

public void runControlInterface(int numberOfUEs) throws InterruptedException {

runControlInterface(numberOfUEs, 0); }

public boolean runControlInterface(final int numberOfUEs, int numberOfThreads) throws InterruptedException {

targetUEs = numberOfUEs;

ExecutorService threadPool = createUeThreadPool(numberOfThreads);

final Dispatcher dispatcher = new Dispatcher(threadPool);

Thread dispatcherThread = new Thread(dispatcher); dispatcherThread.start();

final SystemUnderTest sut; if (test) {

sut = new SystemUnderTest(dispatcher); } else {

sut = new SystemUnderTest(dispatcher); }

Thread sutThread = new Thread(sut); sutThread.start();

Thread createUeThread = new Thread(new Runnable() { @Override

public void run() {

createUes(numberOfUEs, sut, dispatcher); } }); createUeThread.start(); Thread.sleep(waitTime); log.warning("Interrupting"); threadPool.shutdown(); createUeThread.interrupt(); dispatcherThread.interrupt(); sutThread.interrupt(); Thread.sleep(10); threadPool.shutdownNow();

boolean result = checkAllCreated();

log.warning("" + getRunTime(TimeUnit.MILLISECONDS));

return result;

}

private boolean checkAllCreated() {

boolean success;

synchronized (this) {

success = createdUEs == targetUEs; }

if (success) {

log.warning("Got all CREATE_UE_ACK."); } else {

(36)

private void createUes(int nrOfUEs, SystemUnderTest sut,

Dispatcher dispatcher) {

for (int i = 0; i < nrOfUEs; i++) {

Behavior behavior = null;

switch (i % 2) { case 0:

behavior = new NoDelayBehavior();

break; case 1:

behavior = new DefaultBehavior();

break; default:

throw new RuntimeException(

"Should not happen, BehaviorType in ControlInterface."); }

if (test) {

behavior = new TestBehavior(); }

UserEquipment ue = new UserEquipment(sut, dispatcher, i, behavior, new DefaultSignalOrder()); dispatcher.dispatch(new Signal(this, ue, SignalType.CREATE_UE));

} }

private ExecutorService createUeThreadPool(int numberOfThreads) {

int nrOfCPU = Runtime.getRuntime().availableProcessors(); int utilization = 1;

double wc = 2.0;

int nrOfThreads = (int) ((double) nrOfCPU * (double) utilization * (1.0 + wc)); // Override if user specified number of threads

if (numberOfThreads > 2) {

nrOfThreads = numberOfThreads − 2; }

log.warning("Creating " + nrOfThreads + " threads on " + nrOfCPU + " CPUs.");

ExecutorService threadPool = Executors.newFixedThreadPool(nrOfThreads);

return threadPool;

}

public long getRunTime(TimeUnit unit) {

return unit.convert(stopTime − startTime, TimeUnit.NANOSECONDS);

} } package com.enea.simulator; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionException; import java.util.logging.Logger; import com.enea.simulator.signal.Signal; public class Dispatcher implements Runnable {

private final ExecutorService threadPool;

private final BlockingQueue<Signal> signalQueue = new LinkedBlockingQueue<Signal>(); private Logger log;

public Dispatcher(ExecutorService threadPool) {

this.threadPool = threadPool;

log = Logger.getLogger(ControlInterface.class.getName()); }

/**

* Sends a signal when the time set in Signal has past. */

@ThreadSafe

public void dispatch(final Signal signal) {

signalQueue.add(signal); }

@Override

public void run() { try {

handleSignals();

} catch (InterruptedException ignored) { log.info("Dispatcher exiting."); } catch (Exception e) {

log.severe("Dispatcher: " + e.getMessage()); }

}

/**

* Only to be called once to run in separate thread. Sends signals from the * queue when the delay has run out.

*/

public void handleSignals() throws InterruptedException { while (true) {

(37)

boolean notExecuted = true;

while (notExecuted) { try {

threadPool.execute(new Runnable() { @Override

public void run() { try { signal.getReceiver().handleSignal(signal); } catch (Exception e) { System.err.println(e.getMessage()); e.printStackTrace(); } } }); notExecuted = false;

} catch (RejectedExecutionException ignored) { Thread.sleep(10); } } } } } package com.enea.simulator; import java.util.logging.ConsoleHandler;

public class SimulatorConsoleHandler extends ConsoleHandler {

public SimulatorConsoleHandler() { super();

this.setOutputStream(System.out); }

(38)

package com.enea.simulator;

/**

* This class or method is thread safe and can be called without synchronization * across threads.

*/

public @interface ThreadSafe { }

package com.enea.simulator.behavior; import com.enea.simulator.signal.SignalType; public interface Behavior {

public void executeCalculations(SignalType signalType);

(39)

package com.enea.simulator.behavior; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.util.Random; import com.enea.simulator.ThreadSafe; import com.enea.simulator.signal.SignalType; @ThreadSafe

public class DefaultBehavior implements Behavior{

private Random generator = new Random();

@Override

public void executeCalculations(SignalType signalType) { if (signalType == SignalType.CALL_SETUP) { writeAndDeleteFile(10000); } else { writeAndDeleteFile(1000); } }

private void writeAndDeleteFile(int rounds) { try {

int number = generator.nextInt(100000);

FileWriter fstream = new FileWriter("tmpFile" + number + ".txt"); BufferedWriter out = new BufferedWriter(fstream);

for (int i = 0; i < rounds; i++) {

out.write("Dummy data123456"); }

out.close();

File file = new File("tmpFile" + number + ".txt"); file.delete();

} catch (Exception e) {

System.err.println("Error: " + e.getMessage()); }

} }

package com.enea.simulator.behavior; import com.enea.simulator.signal.SignalType; public class NoDelayBehavior implements Behavior {

@Override

public void executeCalculations(SignalType signalType) {

} }

(40)

package com.enea.simulator.behavior; import com.enea.simulator.signal.SignalType; public class TestBehavior implements Behavior {

@Override

public void executeCalculations(SignalType signalType) {

} }

package com.enea.simulator.endpoint; import com.enea.simulator.ThreadSafe; import com.enea.simulator.signal.Signal; public interface Endpoint {

/**

* Thread−safe if the class implementing it does not access non−thread−safe * methods.

*/

@ThreadSafe

public void handleSignal(final Signal signal);

(41)

package com.enea.simulator.endpoint; import java.util.HashMap; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Logger; import com.enea.simulator.Dispatcher; import com.enea.simulator.ThreadSafe; import com.enea.simulator.signal.Signal; import com.enea.simulator.signal.SignalType;

public class SystemUnderTest implements Endpoint, Runnable {

private final BlockingQueue<Signal> signalQueue = new LinkedBlockingQueue<Signal>(); private final Dispatcher dispatcher;

private final HashMap<SignalType, SignalType> responseSignalTypes = new HashMap<SignalType, SignalType>(); private Logger log;

public SystemUnderTest(Dispatcher dispatcher) {

this.dispatcher = dispatcher; log = Logger.getLogger(this.getClass().getName()); responseSignalTypes.put(SignalType.POWER_ON, SignalType.POWER_ON_ACK); responseSignalTypes.put(SignalType.NEGOTIATE_CAPABILITIES, SignalType.NEGOTIATE_CAPABILITIES_ACK); responseSignalTypes.put(SignalType.CALL_SETUP, SignalType.CALL_SETUP_ACK); responseSignalTypes.put(SignalType.CALL_END, SignalType.CALL_END_ACK); } /**

* For testing purposes. */

public BlockingQueue<Signal> getSignalQueue() { return signalQueue;

}

/**

* Do not call this from other threads. Use receiveSignal instead. */

@Override

public void handleSignal(final Signal signal) {

log.info("Processing signal: " + signal.toString());

final SignalType signalType = responseSignalTypes.get(signal.getSignalType()); if (signalType == null) {

log.severe("Unknown signal " + signal);

throw new IllegalArgumentException("Unknown signal " + signal); }

final Signal result = new Signal(this, signal.getSender(), signalType);

dispatcher.dispatch(result); }

/**

* Takes a signal and adds it to the signal queue and * immediately returns.

*/

@ThreadSafe

public void receiveSignal(final Signal signal) {

signalQueue.add(signal); }

@Override

public void run() { try {

handleSignals();

} catch (InterruptedException ignored) { log.info("System under test is exiting"); } catch (IllegalArgumentException e) {

log.severe("SUT: " + e.getMessage()); }

}

/**

* Keeps processing all the signals in the queue. */

private void handleSignals() throws InterruptedException { while (true) {

handleSignal(signalQueue.take()); }

} }

(42)

package com.enea.simulator.endpoint; import java.util.logging.Logger; import com.enea.simulator.ControlInterface; import com.enea.simulator.Dispatcher; import com.enea.simulator.behavior.Behavior; import com.enea.simulator.signal.Signal; import com.enea.simulator.signal.SignalType; import com.enea.simulator.signal.order.SignalOrder; public class UserEquipment implements Endpoint {

private final int id;

private final SystemUnderTest sut;

private SignalType expectedSignalType = SignalType.CREATE_UE; private final Dispatcher dispatcher;

private ControlInterface controlInterface; private final Logger log;

private final Behavior behavior; private final SignalOrder signalOrder;

public UserEquipment(SystemUnderTest sut, Dispatcher dispatcher, int id,

Behavior behavior, SignalOrder signalOrder) { this.id = id; this.sut = sut; this.dispatcher = dispatcher; this.behavior = behavior; this.signalOrder = signalOrder; log = Logger.getLogger(this.getClass().getName()); }

public int getId() { return id;

} @Override

public void handleSignal(final Signal signal) {

SignalType signalType = signal.getSignalType();

if (signalType != expectedSignalType) {

throw new IllegalStateException("Got unexpected signal: "

+ signalType + " Waiting for: " + expectedSignalType); }

log.info(createMessage(signalType.toString()));

if (signalType == SignalType.CREATE_UE) {

controlInterface = (ControlInterface) signal.getSender();

}

SignalType returnSignalType = signalOrder.getNextSignalType(signal.getSignalType());

if (returnSignalType != SignalType.NONE) {

expectedSignalType = signalOrder.getNextSignalType(returnSignalType);

if (returnSignalType == SignalType.CREATE_UE_ACK) {

behavior.executeCalculations(returnSignalType); // Send ack to CI

dispatcher.dispatch(new Signal(this, controlInterface, returnSignalType));

// Send next signal to SUT

returnSignalType = signalOrder.getNextSignalType(returnSignalType); expectedSignalType = signalOrder.getNextSignalType(returnSignalType); behavior.executeCalculations(returnSignalType);

dispatcher.dispatch(new Signal(this, sut, returnSignalType)); } else {

behavior.executeCalculations(returnSignalType);

dispatcher.dispatch(new Signal(this, sut, returnSignalType)); } } else { expectedSignalType = SignalType.NONE; } } @Override

public String toString() {

StringBuilder sb = new StringBuilder(); sb.append("ID: ");

sb.append(id);

return sb.toString();

}

private String createMessage(final String message) {

StringBuilder sb = new StringBuilder(); sb.append("UE "); sb.append(id); sb.append(": "); sb.append(message); sb.append("."); return sb.toString();

(43)

package com.enea.simulator.signal; import com.enea.simulator.ThreadSafe; import com.enea.simulator.endpoint.Endpoint;

/**

* This class represents an immutable signal with a sender, a receiver, a signal * type and optional delay.

*

* @author helm *

*/

@ThreadSafe

public class Signal {

private final Endpoint receiver; private final Endpoint sender; private final SignalType signal;

public Signal(final Endpoint sender, final Endpoint receiver, final SignalType signal) {

this.sender = sender; this.signal = signal; this.receiver = receiver; }

public Endpoint getReceiver() { return receiver;

}

public Endpoint getSender() { return sender;

}

public SignalType getSignalType() { return signal;

} @Override

public String toString() {

StringBuilder sb = new StringBuilder(); sb.append("Sender "); sb.append(sender.toString()); sb.append("; Signal: "); sb.append(signal.toString()); return sb.toString(); } } package com.enea.simulator.signal; public enum SignalType {

POWER_ON, POWER_ON_ACK, NEGOTIATE_CAPABILITIES, NEGOTIATE_CAPABILITIES_ACK, CREATE_UE, CREATE_UE_ACK, CALL_SETUP, CALL_SETUP_ACK, CALL_END, CALL_END_ACK, NONE }

(44)

package com.enea.simulator.tests; import java.util.Arrays; import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.enea.simulator.ControlInterface; public class PerformanceNoDelayTest {

private static final int WARMUP_WAIT_TIME = 25; private static final int WAIT_TIME = 2000; private static final int ROUNDS = 20;

private static final int NUMBER_OF_UES = 10000; private static final int MAX_THREADS = 15; private ControlInterface controlInterface;

@Before

public void setUp() throws Exception {

warmup(); }

private void warmup() {

System.out.println("Warming up..."); ControlInterface.test = true;

for (int i = 0; i < 50; i++) {

controlInterface = new ControlInterface(WARMUP_WAIT_TIME);

try {

controlInterface.runControlInterface(5, 3); } catch (InterruptedException ignored) {

System.err.println("Warmup interrupted"); }

}

for (int i = 0; i < 5; i++) {

controlInterface = new ControlInterface(WARMUP_WAIT_TIME);

try {

controlInterface.runControlInterface(NUMBER_OF_UES, MAX_THREADS); } catch (InterruptedException ignored) {

System.err.println("Warmup interrupted"); }

}

System.gc();

System.runFinalization();

System.out.println("Done warming up."); }

@After

public void tearDown() throws Exception {

} @Test

public void testRunControlInterface() {

long[] results = new long[MAX_THREADS];

for (int i = 2; i < MAX_THREADS; i++) { try { results[i] = testNumberOfThreads(i + 1); } catch (InterruptedException e) { System.out.println(e.getMessage()); e.printStackTrace(); } }

for (int i = 2; i < MAX_THREADS; i++) {

System.out.println((i + 1) + "\t" + (results[i] / (1000 * 1000))); }

System.out.println("Performance test done."); }

private long testRoundsForThreads(int numberOfThreads) throws InterruptedException {

controlInterface = new ControlInterface(WAIT_TIME); System.gc(); System.runFinalization(); Thread.sleep(50); System.out .println("Entering −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−"); try {

boolean success = controlInterface.runControlInterface(NUMBER_OF_UES, numberOfThreads);

if (!success) {

System.err.println("Did not finish all creations."); } } catch (InterruptedException e) { System.out.println("Oh no " + e.getMessage()); e.printStackTrace(); } System.out .println("Exiting −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−"); long result = controlInterface.getRunTime(TimeUnit.NANOSECONDS);

(45)

return result;

}

private long testNumberOfThreads(int numberOfThreads) throws InterruptedException {

long[] results = new long[ROUNDS]; long avg = 0;

long smooth = 0; double alpha = 0.125;

System.out.println("Testing: " + ROUNDS + " rounds, " + numberOfThreads + " threads, " + NUMBER_OF_UES + " UEs, " + WAIT_TIME + " wait time");

for (int i = 0; i < ROUNDS; i++) {

results[i] = testRoundsForThreads(numberOfThreads); avg += results[i];

if (i == 0) {

smooth = results[i]; } else {

smooth = (long) ((1 − alpha) * smooth + alpha * results[i]); }

}

avg /= ROUNDS;

for (int i = 0; i < ROUNDS; i++) {

System.out.println("Round " + (i + 1) + ": " + (results[i] / 1000) + " µs");

}

Arrays.sort(results);

long median = results[ROUNDS / 2];

System.out.println("Average: " + (avg / 1000) + " µs"); System.out.println("Smoothed: " + (smooth / 1000) + " µs"); System.out.println("Median: " + (median / 1000) + " µs");

return median; } } package com.enea.simulator.tests; import java.util.ArrayList; import java.util.Arrays; import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.enea.simulator.ControlInterface; public class PerformanceNoDelayTestMaxUE {

private static final int WARMUP_WAIT_TIME = 25; private static final int WAIT_TIME = 1000; private static final int ROUNDS = 20; private static final int NR_THREADS = 4; private static final int UE_INTERVAL = 1000; private ControlInterface controlInterface;

@Before

public void setUp() throws Exception {

warmup(); }

private void warmup() {

System.out.println("Warming up..."); ControlInterface.test = true;

for (int i = 0; i < 100; i++) {

controlInterface = new ControlInterface(WARMUP_WAIT_TIME);

try {

controlInterface.runControlInterface(5, 3); } catch (InterruptedException ignored) {

System.err.println("Warmup interrupted"); }

}

for (int i = 0; i < 50; i++) {

controlInterface = new ControlInterface(WARMUP_WAIT_TIME);

try {

(46)

System.gc();

System.runFinalization();

System.out.println("Done warming up."); }

@After

public void tearDown() throws Exception {

} @Test

public void testRunControlInterface() {

ArrayList<Long> results = new ArrayList<Long>(); int numberOfUEs = UE_INTERVAL;

for (; results.size() == 0 || results.get(results.size() − 1) != −1; numberOfUEs += UE_INTERVAL) { try { results.add(testNumberOfUEs(numberOfUEs)); } catch (InterruptedException e) { System.out.println(e.getMessage()); e.printStackTrace(); } } System.out.println();

for (int i = 0; i < results.size() − 1; i++) {

System.out.println(((i + 1) * UE_INTERVAL) + "\t" + (results.get(i) / (1000 * 1000))); }

System.out.println("Performance test done."); }

private long testRoundsForUEs(int numberOfUEs) throws InterruptedException {

controlInterface = new ControlInterface(WAIT_TIME); boolean success = false;

System.gc();

System.runFinalization(); Thread.sleep(50); System.out

.println("Entering −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−"); success = controlInterface.runControlInterface(numberOfUEs, NR_THREADS);

if (!success) {

System.err.println("Did not finish all creations."); }

System.out

.println("Exiting −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−"); long result = controlInterface.getRunTime(TimeUnit.NANOSECONDS);

System.gc(); System.runFinalization(); Thread.sleep(50); if (!success) { return −1; } return result; }

private long testNumberOfUEs(int numberOfUEs) throws InterruptedException {

long[] results = new long[ROUNDS];

System.out.println("Testing: " + ROUNDS + " rounds, " + numberOfUEs + " UEs, wait time: " + WAIT_TIME + " wait time");

for (int i = 0; i < ROUNDS; i++) {

results[i] = testRoundsForUEs(numberOfUEs);

if (results[i] == −1) { return −1;

} }

for (int i = 0; i < ROUNDS; i++) {

System.out.println("Round " + (i + 1) + ": " + (results[i] / 1000) + " µs");

}

Arrays.sort(results);

long median = results[ROUNDS / 2];

System.out.println("Median: " + (median / 1000) + " µs");

return median;

} }

(47)

package com.enea.simulator.signal.order; import java.util.HashMap;

import com.enea.simulator.signal.SignalType; public class DefaultSignalOrder implements SignalOrder {

private final HashMap<SignalType, SignalType> currentMappedToNext = new HashMap<SignalType, SignalType>(); public DefaultSignalOrder() { currentMappedToNext.put(SignalType.CREATE_UE, SignalType.POWER_ON); currentMappedToNext.put(SignalType.POWER_ON, SignalType.POWER_ON_ACK); currentMappedToNext.put(SignalType.POWER_ON_ACK, SignalType.NEGOTIATE_CAPABILITIES); currentMappedToNext.put(SignalType.NEGOTIATE_CAPABILITIES, SignalType.NEGOTIATE_CAPABILITIES_ACK); currentMappedToNext.put(SignalType.NEGOTIATE_CAPABILITIES_ACK, SignalType.CREATE_UE_ACK); currentMappedToNext.put(SignalType.CREATE_UE_ACK, SignalType.CALL_SETUP); currentMappedToNext.put(SignalType.CALL_SETUP, SignalType.CALL_SETUP_ACK); currentMappedToNext.put(SignalType.CALL_SETUP_ACK, SignalType.CALL_END); currentMappedToNext.put(SignalType.CALL_END, SignalType.CALL_END_ACK); currentMappedToNext.put(SignalType.CALL_END_ACK, SignalType.NONE); } @Override

public SignalType getNextSignalType(SignalType currentSignalType) { return currentMappedToNext.get(currentSignalType);

} }

package com.enea.simulator.signal.order; import com.enea.simulator.signal.SignalType; public interface SignalOrder {

public SignalType getNextSignalType(SignalType currentSignalType);

References

Related documents

När man kompilerar växlar NetBeans automatiskt till ”Build”-utskrifter och när man kör ett program så visas i stället information för avlusning1. Build, eller att bygga,

Frånkoppling sker genom att det föregående elementet sätts att peka på nästa element och vise versa; dess- utom kontrolleras om elementet som tas bort är det första elementet –

Tabellerna innehåller observerat väntevärde för körtiden, dess variationskoefficient och konfidensintervall med konfidensgrad 95% för samtliga grafinstanser och

Havnevik Bertil Oden Rune Skarstein..

Den teoretiska delen består av en redogörelse av hur klientbaserad programmering har växt fram, en beskrivning av några av de tekniker som finns för att åstadkomma

Det här betyder också att alla referenser till statiska attribut och metoder i appli- kationen måste riktas om till den nya singelton-instansen istället.. Problemet är att det

• Alla objekt av en viss klass kan användas på samma sätt–de har samma “gränssnitt”. • En definition av en viss klass kan ses som en mall för objekt av

Eftersom många tar hjälp av kineser när de gör affärer med leverantörer blir det sällan problem till exempel AX International och East Import har sådan hjälp?. Mottagaren