package jade.core;
//#J2ME_EXCLUDE_FILE
//#APIDOC_EXCLUDE_FILE
import jade.core.behaviours.*;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.util.leap.Properties;
import jade.imtp.leap.JICP.PDPContextManager;
import jade.imtp.leap.JICP.JICPProtocol;
import java.io.*;
public class ScalabilityTest {
private static final String CONTENT_SIZE = "s";
private static final int DEFAULT_CONTENT_SIZE = 1000;
private static final String TIME_INTERVAL = "t";
private static final long DEFAULT_TIME_INTERVAL = 1000;
private static final long STEPBYSTEP_TIME_INTERVAL = -1;
private static final String N_ITERATIONS = "i";
private static final int DEFAULT_N_ITERATIONS = -1;
private static final String N_COUPLES = "n";
private static final int DEFAULT_N_COUPLES = 10;
private static final String BASE = "base";
private static final int DEFAULT_BASE = 0;
private static final String MODE = "mode";
private static final String FAST_MODE_S = "fast";
private static final String SLOW_MODE_S = "slow";
private static final String STEP_BY_STEP_MODE_S = "stepbystep";
private static final String READY_GO_MODE_S = "readygo";
private static final int FAST_MODE = 0;
private static final int SLOW_MODE = 1;
private static final int STEP_BY_STEP_MODE = 2;
private static final int READY_GO_MODE = 3;
private static final String MEASURE = "measure";
private static final String BITRATE_MEASURE_S = "bitrate";
private static final String RTT_MEASURE_S = "rtt";
private static final int BITRATE_MEASURE = 0;
private static final int RTT_MEASURE = 1;
private static Object terminatedLock = new Object();
private static Object readyLock = new Object();
private static Object semaphore = new Object();
private static byte[] content;
private static long timeInterval;
private static int nIterations;
private static int nCouples;
private static int base;
private static int mode;
private static int measure;
private static int readyCnt = 0;
private static int terminatedCnt = 0;
private static long totalTime = 0;
private static long totalTime2 = 0;
private static Object lock = new Object();
private static BufferedReader inputReader;
public static void main(String[] args) {
Properties pp = parseArguments(args);
int contentSize = DEFAULT_CONTENT_SIZE;
try {
contentSize = Integer.parseInt(pp.getProperty(CONTENT_SIZE));
}
catch (Exception e) {
// Keep default
}
content = new byte[contentSize];
timeInterval = DEFAULT_TIME_INTERVAL;
try {
timeInterval = Long.parseLong(pp.getProperty(TIME_INTERVAL));
}
catch (Exception e) {
// Keep default
}
nIterations = DEFAULT_N_ITERATIONS;
try {
nIterations = Integer.parseInt(pp.getProperty(N_ITERATIONS));
}
catch (Exception e) {
// Keep default
}
base = DEFAULT_BASE;
try {
base = Integer.parseInt(pp.getProperty(BASE));
}
catch (Exception e) {
// Keep default
}
mode = READY_GO_MODE;
try {
String modeStr = pp.getProperty(MODE);
if (SLOW_MODE_S.equals(modeStr)) {
mode = SLOW_MODE;
}
else if (FAST_MODE_S.equals(modeStr)) {
mode = FAST_MODE;
}
else if (STEP_BY_STEP_MODE_S.equals(modeStr)) {
mode = STEP_BY_STEP_MODE;
}
}
catch (Exception e) {
// Keep default
}
// Prepare the inputReader to get user inputs if necessary
if (mode == READY_GO_MODE || mode == STEP_BY_STEP_MODE) {
inputReader = new BufferedReader(new InputStreamReader(System.in));
}
nCouples = DEFAULT_N_COUPLES;
try {
nCouples = Integer.parseInt(pp.getProperty(N_COUPLES));
}
catch (Exception e) {
// Keep default
}
measure = BITRATE_MEASURE;
try {
String measureStr = pp.getProperty(MEASURE);
if (RTT_MEASURE_S.equals(measureStr)) {
measure = RTT_MEASURE;
}
}
catch (Exception e) {
// Keep default
}
String prefix = Profile.getDefaultNetworkName();
for (int i = base; i < base+nCouples; i++) {
initCouple(pp.getProperty(MicroRuntime.HOST_KEY), pp.getProperty(MicroRuntime.PORT_KEY), pp.getProperty(MicroRuntime.CONN_MGR_CLASS_KEY), pp.getProperty(JICPProtocol.MEDIATOR_CLASS_KEY), pp.getProperty(JICPProtocol.MAX_DISCONNECTION_TIME_KEY), prefix, i);
switch (mode) {
case SLOW_MODE:
waitABit();
break;
case STEP_BY_STEP_MODE:
prompt("Couple #"+i+" started. Press enter to continue");
break;
default:
Thread.currentThread().yield();
}
}
waitUntilReady();
if (mode == READY_GO_MODE) {
prompt("All "+nCouples+" couples ready. Press enter to go");
}
start();
if (nIterations > 0) {
System.out.println("Measurement started....");
}
if (timeInterval == STEPBYSTEP_TIME_INTERVAL) {
int i = 0;
while (true) {
waitUntilReady();
prompt("Iteration # "+i+" terminated by all couples. Press enter to go");
++i;
start();
}
}
}
private static void notifyReady() {
synchronized (semaphore) {
synchronized (readyLock) {
readyCnt++;
readyLock.notifyAll();
}
try {
semaphore.wait();
}
catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
private static void waitUntilReady() {
synchronized (readyLock) {
while (readyCnt < nCouples) {
try {
readyLock.wait();
}
catch (InterruptedException ie) {
ie.printStackTrace();
}
}
}
}
private static void start() {
synchronized (semaphore) {
semaphore.notifyAll();
readyCnt = 0;
}
}
private static void waitABit() {
synchronized (lock) {
try {
lock.wait(1000);
}
catch (Exception e) {}
}
}
private static void prompt(String msg) {
System.out.println(msg);
try {
inputReader.readLine();
}
catch (IOException ioe) {
}
}
private static Properties parseArguments(String[] args) {
Properties props = new Properties();
int i = 0;
while (i < args.length) {
if (args[i].startsWith("-")) {
// Parse next option
String name = args[i].substring(1);
if (++i < args.length) {
props.setProperty(name, args[i]);
}
else {
throw new IllegalArgumentException("No value specified for property \""+name+"\"");
}
++i;
}
else {
throw new IllegalArgumentException("Invalid property \""+args[i]+"\". It does not start with '-'");
}
}
return props;
}
private static void initCouple(String host, String port, String connectionManager, String mediatorClass, String maxDiscTime, String prefix, int index) {
String senderClass = "jade.core.ScalabilityTest$BitrateSenderAgent";
String receiverClass = "jade.core.ScalabilityTest$BitrateReceiverAgent";
if (measure == RTT_MEASURE) {
senderClass = "jade.core.ScalabilityTest$RTTSenderAgent";
receiverClass = "jade.core.ScalabilityTest$RTTReceiverAgent";
}
Properties pp = new Properties();
if (host != null) {
pp.setProperty(MicroRuntime.HOST_KEY, host);
}
if (port != null) {
pp.setProperty(MicroRuntime.PORT_KEY, port);
}
if (connectionManager != null) {
pp.setProperty(MicroRuntime.CONN_MGR_CLASS_KEY, connectionManager);
}
if (mediatorClass != null) {
pp.setProperty(JICPProtocol.MEDIATOR_CLASS_KEY, mediatorClass);
}
if (maxDiscTime != null) {
pp.setProperty(JICPProtocol.MAX_DISCONNECTION_TIME_KEY, maxDiscTime);
}
String sName = "S-"+prefix+"-"+index;
pp.setProperty(PDPContextManager.MSISDN, sName);
String rName = "R-"+prefix+"-"+index;
String prop = sName+":"+senderClass+"("+rName+")";
pp.setProperty(MicroRuntime.AGENTS_KEY, prop);
pp.setProperty(JICPProtocol.KEEP_ALIVE_TIME_KEY, "-1");
FrontEndContainer fes = new FrontEndContainer();
fes.start(pp);
pp = new Properties();
if (host != null) {
pp.setProperty(MicroRuntime.HOST_KEY, host);
}
if (port != null) {
pp.setProperty(MicroRuntime.PORT_KEY, port);
}
if (connectionManager != null) {
pp.setProperty(MicroRuntime.CONN_MGR_CLASS_KEY, connectionManager);
}
if (mediatorClass != null) {
pp.setProperty(JICPProtocol.MEDIATOR_CLASS_KEY, mediatorClass);
}
if (maxDiscTime != null) {
pp.setProperty(JICPProtocol.MAX_DISCONNECTION_TIME_KEY, maxDiscTime);
}
pp.setProperty(PDPContextManager.MSISDN, rName);
prop = rName+":"+receiverClass;
pp.setProperty(MicroRuntime.AGENTS_KEY, prop);
pp.setProperty(JICPProtocol.KEEP_ALIVE_TIME_KEY, "-1");
FrontEndContainer fer = new FrontEndContainer();
fer.start(pp);
}
private static void notifyTerminated(long time, long time2) {
synchronized (terminatedLock) {
totalTime += time;
totalTime2 += time2;
terminatedCnt++;
if (terminatedCnt == nCouples) {
// All couples have terminated. Compute the average round-trip time
long n = nCouples * ((long) nIterations);
if (measure == BITRATE_MEASURE) {
double totBytes = n * ((double) content.length);
double averageBitrate = totBytes / totalTime;
System.out.println("----------------------------------\nTest completed successufully.\nAverage bitrate (Kbyte/s) = "+averageBitrate+"\n----------------------------------");
}
else if (measure == RTT_MEASURE) {
long averageRoundTripTime = totalTime / n;
double avg = (double) averageRoundTripTime;
double x = totalTime2 + n*avg*avg - 2*avg*totalTime;
double standardDeviation = Math.sqrt(x / n);
System.out.println("----------------------------------\nTest completed successufully.\nAverage round trip time = "+averageRoundTripTime+" ms\nStandard deviation = "+standardDeviation+"\n----------------------------------");
}
System.exit(0);
}
}
}
/**
Inner class BitrateSenderAgent
*/
public static class BitrateSenderAgent extends Agent {
private ACLMessage msg = new ACLMessage(ACLMessage.INFORM);
private AID myReceiver;
protected void setup() {
Object[] args = getArguments();
if (args != null && args.length == 1) {
myReceiver = new AID((String) args[0], AID.ISLOCALNAME);
}
else {
System.out.println("Missing receiver name !!!!!");
doDelete();
return;
}
msg.addReceiver(myReceiver);
msg.setByteSequenceContent(content);
System.out.println("Sender "+getName()+" ready: my receiver is "+myReceiver.getName());
notifyReady();
if (timeInterval > 0) {
addBehaviour(new TickerBehaviour(this, timeInterval) {
public void onTick() {
job();
}
} );
}
else {
addBehaviour(new CyclicBehaviour(this) {
public void action() {
job();
}
} );
}
}
private void job() {
send(msg);
if (timeInterval == STEPBYSTEP_TIME_INTERVAL) {
notifyReady();
}
}
} // END of inner class BitrateSenderAgent
/**
Inner class BitrateReceiverAgent
*/
public static class BitrateReceiverAgent extends Agent {
private boolean firstReceived = false;
private boolean terminated = false;
private long startTime;
private int cnt = 0;
protected void setup() {
addBehaviour(new CyclicBehaviour(this) {
public void action() {
ACLMessage msg = myAgent.receive();
if (msg != null) {
if (!firstReceived) {
firstReceived = true;
startTime = System.currentTimeMillis();
}
if (!terminated) {
if (nIterations > 0 && cnt >= nIterations) {
long endTime = System.currentTimeMillis();
long totalCoupleTime = endTime - startTime;
long totalCoupleTime2 = totalCoupleTime*totalCoupleTime;
notifyTerminated(totalCoupleTime, totalCoupleTime2);
terminated = true;
}
cnt++;
}
}
else {
block();
}
}
} );
}
} // END of inner class BitrateReceiverAgent
/**
Inner class RTTSenderAgent
*/
public static class RTTSenderAgent extends Agent {
private ACLMessage msg = new ACLMessage(ACLMessage.INFORM);
private AID myReceiver;
private MessageTemplate myTemplate;
private long totalCoupleTime = 0;
private long totalCoupleTime2 = 0;
private boolean terminated = false;
private int cnt = 0;
protected void setup() {
Object[] args = getArguments();
if (args != null && args.length == 1) {
myReceiver = new AID((String) args[0], AID.ISLOCALNAME);
}
else {
System.out.println("Missing receiver name !!!!!");
doDelete();
return;
}
msg.addReceiver(myReceiver);
msg.setByteSequenceContent(content);
myTemplate = MessageTemplate.MatchSender(myReceiver);
notifyReady();
if (timeInterval > 0) {
addBehaviour(new TickerBehaviour(this, timeInterval) {
public void onTick() {
job();
}
} );
}
else {
addBehaviour(new CyclicBehaviour(this) {
public void action() {
job();
}
} );
}
}
private void job() {
long start = System.currentTimeMillis();
send(msg);
blockingReceive(myTemplate);
long time = System.currentTimeMillis() - start;
if (!terminated) {
totalCoupleTime += time;
totalCoupleTime2 += (time*time);
if (nIterations > 0 && (++cnt) >= nIterations) {
notifyTerminated(totalCoupleTime, totalCoupleTime2);
terminated = true;
}
}
if (timeInterval == STEPBYSTEP_TIME_INTERVAL) {
notifyReady();
}
}
} // END of inner class RTTSenderAgent
/**
Inner class RTTReceiverAgent
*/
public static class RTTReceiverAgent extends Agent {
protected void setup() {
addBehaviour(new CyclicBehaviour(this) {
public void action() {
ACLMessage msg = myAgent.receive();
if (msg != null) {
ACLMessage reply = msg.createReply();
reply.setPerformative(ACLMessage.INFORM);
reply.setByteSequenceContent(msg.getByteSequenceContent());
myAgent.send(reply);
}
else {
block();
}
}
} );
}
} // END of inner class RTTReceiverAgent
}