/*******************************************************************************
* Copyright (c) 2015 Institute for Pervasive Computing, ETH Zurich and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Eclipse Distribution License v1.0 which accompany this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.html.
*
* Contributors:
* Matthias Kovatsch - creator and main architect
* Martin Lanter - architect and initial implementation
******************************************************************************/
package org.eclipse.californium.tools;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.URI;
import org.eclipse.californium.tools.coapbench.VirtualDeviceManager;
public class CoapBench {
// TODO: add parameters for methods (GET, POST, ...), payload, checks, and logfile
// Modes: normal, master, slave
public static final String MASTER = "-master";
public static final String SLAVE = "-slave";
// Defaults
public static final int DEFAULT_CLIENTS = 1;
public static final int DEFAULT_SERVERS = 1;
public static final int DEFAULT_TIME = 30; // [s]
public static final String DEFAULT_MASTER_ADDRESS = "localhost";
public static final int DEFAULT_MASTER_PORT = 58888;
public static void main(String[] args) {
try {
if (args.length > 0) {
if ("-usage".equals(args[0]) || "-help".equals(args[0]) || "-?".equals(args[0])) {
printUsage();
} else if (args[0].equals(MASTER)) {
mainMaster(args);
} else if (args[0].equals(SLAVE)) {
mainSlave(args);
} else {
mainBench(args);
}
} else {
printUsage();
}
} catch (Throwable t) {
t.printStackTrace();
System.exit(-1);
}
}
public static void mainBench(String[] args) throws Exception {
String target = null;
String bindAddr = null;
String clients = ""+DEFAULT_CLIENTS;
int time = DEFAULT_TIME;
int index = 0;
boolean withLatency = false;
while (index < args.length) {
String arg = args[index];
if ("-c".equals(arg)) {
clients = args[index+1];
} else if ("-t".equals(arg)) {
time = Integer.parseInt(args[index+1]);
} else if ("-b".equals(arg)) {
bindAddr = args[index+1];
} else if ("-latency".equals(arg)) {
withLatency = true; index++; continue;
} else if ("-h".equals(arg)) {
printUsage();
return;
} else if (index == args.length - 1) {
// The last argument is the target address
target = arg;
} else {
System.err.println("Unknwon arg "+arg);
printUsage();
return;
}
index += 2;
}
if (target == null) {
System.err.println("Error: No target specified");
printUsage();
return;
}
URI uri = new URI(target);
InetSocketAddress bindSAddr = null;
if (bindAddr != null) {
InetAddress ba = InetAddress.getByName(bindAddr);
bindSAddr = new InetSocketAddress(ba, 0);
System.err.println("Bind clients to local address: "+bindSAddr);
System.err.println("Note that on some systems (e.g. Windows) it now is not possible to send requests to localhost.");
}
int[] series = convertSeries(clients);
VirtualDeviceManager manager = new VirtualDeviceManager(uri, bindSAddr);
if (withLatency) manager.setEnableLatency(true);
manager.runConcurrencySeries(series, time*1000);
// Thread.sleep(time*1000 + 1000);
System.exit(0); // stop all threads from virtual client manager
}
public static void mainMaster(String[] args) throws Exception {
int port = DEFAULT_MASTER_PORT;
int index = 1;
while (index < args.length) {
String arg = args[index];
if ("-p".equals(arg)) {
port = Integer.parseInt(args[index+1]);
} else {
System.err.println("Unknwon arg "+arg);
printUsage();
return;
}
index += 2;
}
new ClientMaster(port).start();
}
public static void mainSlave(String[] args) throws Exception {
String address = DEFAULT_MASTER_ADDRESS;
int port = DEFAULT_MASTER_PORT;
int index = 1;
boolean verbose = false;
//String requestType;
while (index < args.length) {
String arg = args[index];
if ("-a".equals(arg)) {
address = args[index+1];
} else if ("-p".equals(arg)) {
port = Integer.parseInt(args[index+1]);
} else if ("-v".equals(arg)) {
verbose = true;
//} else if ("-m".equals(arg)) {
// requestType = args[index+1];
}
index += 2;
}
ClientSlave slave = new ClientSlave(InetAddress.getByName(address), port);
slave.setVerbose(verbose);
slave.start();
}
// private static int[] convertSeries(String clientSeries) {
// // clientSeries is in format <from>:<step>:<to>
// int from = 0;
// int to = 0;
// int step = 1;
// if (clientSeries == null)
// return new int[] { DEFAULT_CLIENTS };
//
// else if (clientSeries.matches("\\d+"))
// return new int[] { Integer.parseInt(clientSeries) };
//
// else if (clientSeries.matches("\\d+:\\d+")) {
// from = Integer.parseInt(clientSeries.split(":")[0]);
// to = Integer.parseInt(clientSeries.split(":")[1]);
//
// } else if (clientSeries.matches("\\d+:\\d+:\\d+")) {
// from = Integer.parseInt(clientSeries.split(":")[0]);
// step = Integer.parseInt(clientSeries.split(":")[1]);
// to = Integer.parseInt(clientSeries.split(":")[2]);
// }
// int length = (to-from)/step + 1;
// int[] series = new int[length];
// for (int i=0;i<length;i++)
// series[i] = from + i*step;
// return series;
// }
private static int[] convertSeries(String clientSeries) {
// clientSeries is in format first,second,third...
String[] parts = clientSeries.split(",");
int[] series = new int[parts.length];
for (int i=0;i<parts.length;i++)
series[i] = Integer.parseInt(parts[i]);
return series;
}
public static void printUsage() {
System.out.println(
"SYNOPSIS"
+ "\n CoAPBench [[OPTIONS] URI | -master OPTIONS | -slave OPTIONS] [-v]"
+ "\n"
+ "\nURI: The target URI to benchmark"
+ "\n"
+ "\nOPTIONS are:"
+ "\n -c CONCURRENCY"
+ "\n Concurrency level, i.e., the number of parallel clients (default is "+ DEFAULT_CLIENTS + ")."
+ "\n This value can be of the form <from>:<step>:<to>, e.g., 10:2:16 for a subsequent run of 10, 12, 14, 16 clients."
+ "\n -t TIME"
+ "\n Limit the duration of the benchmark to TIME seconds (default is " + DEFAULT_TIME + ")."
+ "\n -b ADDRESS"
+ "\n Bind the clients to the specified local address (by default the system chooses)."
+ "\n"
+ "\nOPTIONS for the master are:"
+ "\n -p PORT"
+ "\n The port on which the master waits for slaves."
+ "\n"
+ "\nOPTIONS for the slave are:"
+ "\n -a ADDRESS"
+ "\n The address of the master."
+ "\n -p PORT"
+ "\n The port of the master."
+ "\n -s"
+ "\n Specifies whether the resource should be observed (applies if the request type is set to GET)."
+ "\n"
+ "\nExamples:"
+ "\nStart 50 clients that concurrently send GET requests for 60 seconds"
+ "\n java -jar coapbench.jar -c 50 -t 60 coap://localhost:5683/benchmark"
+ "\n"
+ "\nStart a master listening on port 8888 for slaves"
+ "\n java -jar coapbench.jar -master -p 8888"
+ "\n"
+ "\nStart a slave which connects with the specified master"
+ "\n java -jar coapbench.jar -slave -a 192.168.1.33 -p 8888"
);
// TODO: add parameters for methods (GET, POST, ...), payload, checks, and logfile
// TODO: stepwise increase
}
}