package org.jgroups.tests;
// $Id: SpeedTest_NIO.java,v 1.1 2005/06/23 13:31:10 belaban Exp $
import org.jgroups.Channel;
import org.jgroups.JChannel;
import org.jgroups.Message;
import org.jgroups.debug.Debugger;
import org.jgroups.util.Util;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.nio.ByteBuffer;
/**
* Same test as SpeedTest, but using NIO ByteBuffer rather than serialization. For 10000 messages, this took
* 25% of SpeedTest !
* Test time taken for multicasting n local messages (messages sent to self). Uses simple MulticastSocket.
* Note that packets might get dropped if Util.sleep(1) is commented out (on certain systems this has
* to be increased even further). If running with -jg option and Util.sleep() is commented out, there will
* probably be packet loss, which will be repaired (by means of retransmission) by JGroups. To see the
* retransmit messages, enable tracing (trace=true) in jgroups.properties and add the following lines:
* <pre>
* trace0=NAKACK.retransmit DEBUG STDOUT
* trace1=UNICAST.retransmit DEBUG STDOUT
* </pre>
*
* @author Bela Ban
*/
public class SpeedTest_NIO {
static long start, stop;
public static void main(String[] args) {
MulticastSocket sock=null;
Receiver receiver=null;
int num_msgs=1000;
byte[] buf;
DatagramPacket packet;
InetAddress group_addr=null;
int[][] matrix;
boolean jg=false; // use JGroups channel instead of UDP MulticastSocket
JChannel channel=null;
String props=null, loopback_props;
String group_name="SpeedTest-Group";
Message send_msg;
boolean debug=false, cummulative=false;
Debugger debugger=null;
long sleep_time=1; // sleep in msecs between msg sends
boolean busy_sleep=false;
boolean yield=false;
int num_yields=0;
boolean loopback=false;
props="UDP(mcast_addr=224.0.0.36;mcast_port=55566;ip_ttl=32;" +
"ucast_send_buf_size=32000;ucast_recv_buf_size=64000;" +
"mcast_send_buf_size=32000;mcast_recv_buf_size=64000):" +
"PING(timeout=2000;num_initial_members=3):" +
"MERGE2(min_interval=5000;max_interval=10000):" +
"FD_SOCK:" +
"VERIFY_SUSPECT(timeout=1500):" +
"pbcast.NAKACK(max_xmit_size=8192;gc_lag=50;retransmit_timeout=600,800,1200,2400,4800):" +
"UNICAST(timeout=1200):" +
"pbcast.STABLE(desired_avg_gossip=10000):" +
"FRAG(frag_size=8192;down_thread=false;up_thread=false):" +
// "PIGGYBACK(max_size=16000;max_wait_time=500):" +
"pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;" +
"shun=false;print_local_addr=true):" +
"pbcast.STATE_TRANSFER";
// "PERF(details=true)";
loopback_props="LOOPBACK:" +
"PING(timeout=2000;num_initial_members=3):" +
"MERGE2(min_interval=5000;max_interval=10000):" +
"FD_SOCK:" +
"VERIFY_SUSPECT(timeout=1500):" +
"pbcast.NAKACK(gc_lag=50;retransmit_timeout=600,800,1200,2400,4800):" +
"UNICAST(timeout=5000):" +
"pbcast.STABLE(desired_avg_gossip=20000):" +
"FRAG(frag_size=16000;down_thread=false;up_thread=false):" +
"pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;" +
"shun=false;print_local_addr=true):" +
"pbcast.STATE_TRANSFER";
for(int i=0; i < args.length; i++) {
if("-help".equals(args[i])) {
help();
return;
}
if("-jg".equals(args[i])) {
jg=true;
continue;
}
if("-loopback".equals(args[i])) {
loopback=true;
props=loopback_props;
continue;
}
if("-props".equals(args[i])) {
props=args[++i];
continue;
}
if("-debug".equals(args[i])) {
debug=true;
continue;
}
if("-cummulative".equals(args[i])) {
cummulative=true;
continue;
}
if("-busy_sleep".equals(args[i])) {
busy_sleep=true;
continue;
}
if("-yield".equals(args[i])) {
yield=true;
num_yields++;
continue;
}
if("-sleep".equals(args[i])) {
sleep_time=Long.parseLong(args[++i]);
continue;
}
if("-num_msgs".equals(args[i])) {
num_msgs=Integer.parseInt(args[++i]);
continue;
}
help();
return;
}
System.out.println("jg = " + jg +
"\nloopback = " + loopback +
"\ndebug = " + debug +
"\nsleep = " + sleep_time +
"\nbusy_sleep=" + busy_sleep +
"\nyield=" + yield +
"\nnum_yields=" + num_yields +
"\nnum_msgs = " + num_msgs +
'\n');
try {
matrix=new int[num_msgs][2];
for(int i=0; i < num_msgs; i++) {
for(int j=0; j < matrix[i].length; j++)
matrix[i][j]=0;
}
if(jg) {
channel=new JChannel(props);
channel.connect(group_name);
if(debug) {
debugger=new Debugger(channel, cummulative);
debugger.start();
}
}
else {
group_addr=InetAddress.getByName("224.0.0.36");
sock=new MulticastSocket(7777);
sock.joinGroup(group_addr);
}
if(debug) {
System.out.println("Press key to start");
System.in.read();
}
receiver=new Receiver(sock, channel, matrix, jg);
receiver.start();
ByteBuffer bb=ByteBuffer.allocate(16);
bb.mark();
start=System.currentTimeMillis();
for(int i=0; i < num_msgs; i++) {
bb.reset();
bb.putInt(i);
buf=(byte[])(bb.array()).clone();
if(jg) {
send_msg=new Message(null, null, buf);
channel.send(send_msg);
}
else {
packet=new DatagramPacket(buf, buf.length, group_addr, 7777);
sock.send(packet);
}
if(i % 1000 == 0)
System.out.println("-- sent " + i);
matrix[i][0]=1;
if(yield) {
for(int k=0; k < num_yields; k++) {
Thread.yield();
}
}
else {
if(sleep_time > 0) {
sleep(sleep_time, busy_sleep);
}
}
}
while(true) {
System.in.read();
printMatrix(matrix);
}
}
catch(Exception ex) {
System.err.println(ex);
}
}
/**
* On most UNIX systems, the minimum sleep time is 10-20ms. Even if we specify sleep(1), the thread will
* sleep for at least 10-20ms. On Windows, sleep() seems to be implemented as a busy sleep, that is the
* thread never relinquishes control and therefore the sleep(x) is exactly x ms long.
*/
static void sleep(long msecs, boolean busy_sleep) {
if(!busy_sleep) {
Util.sleep(msecs);
return;
}
long start=System.currentTimeMillis();
long stop=start + msecs;
while(stop > start) {
start=System.currentTimeMillis();
}
}
static void printMatrix(int[][] m) {
int tmp=0;
System.out.print("not sent: ");
for(int i=0; i < m.length; i++) {
if(m[i][0] == 0) {
System.out.print(i + " ");
tmp++;
}
}
System.out.println("\ntotal not sent: " + tmp);
tmp=0;
System.out.print("not received: ");
for(int i=0; i < m.length; i++) {
if(m[i][1] == 0) {
System.out.print(i + " ");
tmp++;
}
}
System.out.println("\ntotal not received: " + tmp);
System.out.println("Press CTRL-C to kill this test");
}
static void help() {
System.out.println("SpeedTest [-help] [-num_msgs <num>] [-sleep <sleeptime in msecs between messages>] " +
"[-busy_sleep] [-yield] [-jg] [-loopback] [-props <channel properties>] [-debug] [-cummulative]");
System.out.println("Options -props -debug and -cummulative are only valid if -jg is used");
}
static class Receiver implements Runnable {
Thread t=null;
byte[] buf=new byte[1024];
MulticastSocket sock;
Channel channel;
int num_msgs=1000;
int[][] matrix=null;
boolean jg=false;
Receiver(MulticastSocket sock, Channel channel, int[][] matrix, boolean jg) {
this.sock=sock;
this.channel=channel;
this.matrix=matrix;
this.jg=jg;
num_msgs=matrix.length;
}
public void start() {
if(t == null) {
t=new Thread(this, "receiver thread");
t.start();
}
}
public void run() {
int num_received=0;
int number;
DatagramPacket packet;
Object obj;
Message msg;
byte[] msg_data=null;
long total_time;
double msgs_per_sec=0;
ByteBuffer rb=ByteBuffer.allocate(16);
rb.mark();
packet=new DatagramPacket(buf, buf.length);
while(num_received <= num_msgs) {
try {
if(jg) {
obj=channel.receive(0);
if(obj instanceof Message) {
msg=(Message)obj;
msg_data=msg.getBuffer();
}
else {
System.out.println("received non-msg: " + obj.getClass());
continue;
}
}
else {
sock.receive(packet);
msg_data=packet.getData();
}
rb.rewind();
rb.put(msg_data);
rb.rewind();
number=rb.getInt();
matrix[number][1]=1;
// System.out.println("#set " + number);
num_received++;
if(num_received % 1000 == 0)
System.out.println("received " + num_received + " packets");
if(num_received >= num_msgs)
break;
}
catch(Exception ex) {
System.err.println("receiver: " + ex);
}
}
stop=System.currentTimeMillis();
total_time=stop - start;
msgs_per_sec=(num_received / (total_time / 1000.0));
System.out.println("\n** Sending and receiving " + num_received + " took " +
total_time + " msecs (" + msgs_per_sec + " msgs/sec) **");
System.exit(1);
}
}
}