• No results found

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

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 Lausanne, 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).

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.

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 {

} 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 {

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) {

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); }

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);

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) {

} }

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);

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()); }

} }

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();

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 }

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);

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 {

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;

} }

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);

C. JAVA-IMPLEMENTATION Litteraturf¨orteckning

C.2

Ut¨okad

Den ut¨okade simulatorn ¨ar samma som den grundl¨aggande med f¨oljande

¨ andringar. SignalType: CALL_SETUP, CALL_SETUP_ACK, CALL_END, CALL_END_ACK, DefaultSignalOrder - konstruktor: currentMappedToNext.put(SignalType.NEGOTIATE_CAPABILITIES_ACK, SignalType.CREATE_UE_ACK); bytt mot currentMappedToNext.put(SignalType.NEGOTIATE_CAPABILITIES_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.CREATE_UE_ACK); SystemUnderTest - konstruktor: responseSignalTypes.put(SignalType.CALL_SETUP, SignalType.CALL_SETUP_ACK); responseSignalTypes.put(SignalType.CALL_END, SignalType.CALL_END_ACK); SystemUnderTest:

private int runNumber = 0; SystemUnderTest - handleSignal: signalType = responseSignalTypes.get(signal.getSignalType()); bytt mot if (runNumber % 100 == 1) { signalType = SignalType.REJECT; } else { signalType = responseSignalTypes.get(signal.getSignalType()); }

Related documents