package org.jgroups.tests.perf; import org.jgroups.util.Util; import java.io.IOException; import java.net.*; import java.util.Date; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; /** * Dynamic tool to measure multicast performance of JGroups; every member sends N messages and we measure how long it * takes for all receivers to receive them. MPerf is <em>dynamic</em> because it doesn't accept any configuration * parameters (besides the channel config file and name); all configuration is done at runtime, and will be broadcast * to all cluster members. * @author Bela Ban (belaban@yahoo.com) * @since 3.1 */ public class UdpPerf { protected MulticastSocket mcast_sock; protected SocketAddress sock_addr; protected Receiver receiver; protected int num_msgs=1000 * 1000; protected int msg_size=1000; protected int num_threads=1; protected int log_interval=num_msgs / 10; // log every 10% protected int receive_log_interval=num_msgs / 10; /** Maintains stats per sender, will be sent to perf originator when all messages have been received */ protected final AtomicLong total_received_msgs=new AtomicLong(0); protected boolean looping=true; protected long last_interval=0; public void start() throws Exception { StringBuilder sb=new StringBuilder(); sb.append("\n\n----------------------- MPerf -----------------------\n"); sb.append("Date: ").append(new Date()).append('\n'); sb.append("Run by: ").append(System.getProperty("user.name")).append("\n"); System.out.println(sb); mcast_sock=new MulticastSocket(7500); sock_addr=new InetSocketAddress(InetAddress.getByName("232.5.5.5"), 7500); mcast_sock.joinGroup(InetAddress.getByName("232.5.5.5")); mcast_sock.setReceiveBufferSize(10 * 1000 * 1000); mcast_sock.setSendBufferSize(5 * 1000 * 1000); mcast_sock.setTrafficClass(8); receiver=new Receiver(); receiver.start(); } protected void loop() { int c; final String INPUT="[1] Send [x] Exit"; while(looping) { try { c=Util.keyPress(String.format(INPUT)); switch(c) { case '1': sendMessages(); break; case 'x': looping=false; break; } } catch(Throwable t) { System.err.println(t); } } stop(); } protected void send(byte[] payload) throws Exception { DatagramPacket packet=new DatagramPacket(payload, 0, payload.length, sock_addr); mcast_sock.send(packet); } public void stop() { looping=false; mcast_sock.close(); } protected void handleData() { if(last_interval == 0) last_interval=System.currentTimeMillis(); long received_so_far=total_received_msgs.incrementAndGet(); if(received_so_far % receive_log_interval == 0) { long curr_time=System.currentTimeMillis(); long diff=curr_time - last_interval; double msgs_sec=receive_log_interval / (diff / 1000.0); double throughput=msgs_sec * msg_size; last_interval=curr_time; System.out.println(String.format("-- received %d msgs %d ms, %.2f msgs/sec, %s / sec)", received_so_far, diff, msgs_sec, Util.printBytes(throughput))); } } void reset() { total_received_msgs.set(0); last_interval=0; } protected void sendMessages() { final AtomicInteger num_msgs_sent=new AtomicInteger(0); // all threads will increment this final Sender[] senders=new Sender[num_threads]; final CyclicBarrier barrier=new CyclicBarrier(num_threads +1); final byte[] payload=new byte[msg_size]; reset(); for(int i=0; i < num_threads; i++) { senders[i]=new Sender(barrier, num_msgs_sent, payload); senders[i].setName("sender-" + i); senders[i].start(); } try { System.out.println("-- sending " + num_msgs + " msgs"); barrier.await(); } catch(Exception e) { System.err.println("failed triggering send threads: " + e); } } protected class Sender extends Thread { protected final CyclicBarrier barrier; protected final AtomicInteger num_msgs_sent; protected final byte[] payload; protected Sender(CyclicBarrier barrier, AtomicInteger num_msgs_sent, byte[] payload) { this.barrier=barrier; this.num_msgs_sent=num_msgs_sent; this.payload=payload; } public void run() { try { barrier.await(); } catch(Exception e) { e.printStackTrace(); return; } for(;;) { try { int tmp=num_msgs_sent.incrementAndGet(); if(tmp > num_msgs) break; send(payload); if(tmp % log_interval == 0) System.out.println("++ sent " + tmp); if(tmp == num_msgs) // last message, send SENDING_DONE message break; } catch(Exception e) { } } } } protected class Receiver extends Thread { byte[] buf=new byte[10000]; public void run() { while(!mcast_sock.isClosed()) { DatagramPacket packet=new DatagramPacket(buf, 0, buf.length); try { mcast_sock.receive(packet); handleData(); } catch(IOException e) { e.printStackTrace(); } } } } public static void main(String[] args) { final UdpPerf test=new UdpPerf(); try { test.start(); test.loop(); } catch(Exception e) { e.printStackTrace(); } } }