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