package org.jgroups.tests; import org.jgroups.JChannel; import org.jgroups.MembershipListener; import org.jgroups.Message; import org.jgroups.View; import org.jgroups.blocks.MethodCall; import org.jgroups.blocks.RequestOptions; import org.jgroups.blocks.ResponseMode; import org.jgroups.blocks.RpcDispatcher; import org.jgroups.jmx.JmxConfigurator; import org.jgroups.util.Average; import org.jgroups.util.Rsp; import org.jgroups.util.RspList; import org.jgroups.util.Util; import javax.management.MBeanServer; import java.lang.reflect.Method; /** * Test for measuring performance of RPCs. See {@link RoundTrip} for simple messages * @author Bela Ban */ public class RpcDispatcherSpeedTest implements MembershipListener { protected JChannel channel; protected RpcDispatcher disp; protected String props; protected boolean jmx; protected int num=5000; protected static final Method[] METHODS=new Method[1]; protected boolean oob, dont_bundle; protected static final String format="[1] invoke RPCs [2] num (%d) [o] oob (%b) [b] dont_bundle (%b) [x] exit\n"; static { try { METHODS[0]=RpcDispatcherSpeedTest.class.getMethod("measure"); } catch(Throwable t) { throw new RuntimeException(t); } } public static void measure() { ; } public void start(String props, boolean jmx, String name) throws Exception { channel=new JChannel(props).name(name); disp=new RpcDispatcher(channel, this) // no concurrent processing on incoming method calls .setMembershipListener(this).setMethodLookup(id -> METHODS[0]); if(jmx) { MBeanServer srv=Util.getMBeanServer(); if(srv == null) throw new Exception("No MBeanServers found"); JmxConfigurator.registerChannel(channel, srv, "jgroups", channel.getClusterName(), true); } channel.connect("rpc-speed-test"); View view=channel.getView(); if(view.size() > 2) System.err.printf("More than 2 members in cluster: %s; terminating\n", view); else loop(); Util.close(disp, channel); } protected void loop() { boolean looping=true; while(looping) { try { int c=Util.keyPress(String.format(format, num, oob, dont_bundle)); switch(c) { case '1': invokeRpcs(); break; case '2': num=Util.readIntFromStdin("num: "); break; case 'o': oob=!oob; break; case 'b': dont_bundle=!dont_bundle; break; case 'x': case -1: looping=false; break; } } catch(Exception e) { e.printStackTrace(); } } } protected void invokeRpcs() throws Exception { Average avg=new Average(); long min=Long.MAX_VALUE, max=0; RequestOptions opts=new RequestOptions(ResponseMode.GET_FIRST, 0).transientFlags(Message.TransientFlag.DONT_LOOPBACK); MethodCall call=new MethodCall((short)0); int print=num/10; if(oob) opts.flags(Message.Flag.OOB); if(dont_bundle) opts.flags(Message.Flag.DONT_BUNDLE); if(channel.getView().size() != 2) { System.err.printf("Cluster must have exactly 2 members: %s\n", channel.getView()); return; } System.out.printf("\nInvoking %d blocking RPCs (oob: %b, dont_bundle: %b)\n", num, oob, dont_bundle); for(int i=0; i < num; i++) { long start=System.nanoTime(); RspList<Void> rsps=disp.callRemoteMethods(null, call, opts); long time_ns=System.nanoTime() - start; if(i > 0 && i % print == 0) System.out.print("."); boolean all_received=rsps.values().stream().allMatch(Rsp::wasReceived); if(!all_received) System.err.printf("didn't receive all responses: %s\n", rsps); avg.add(time_ns); min=Math.min(min, time_ns); max=Math.max(max, time_ns); } System.out.println(""); System.out.printf("\nround-trip = min/avg/max: %.2f / %.2f / %.2f us\n\n", min/1000.0, avg.getAverage() / 1000.0, max/1000.0); } public void viewAccepted(View new_view) { System.out.println("-- new view: " + new_view); } public static void main(String[] args) throws Exception { String props=null, name=null; boolean jmx=false; for(int i=0; i < args.length; i++) { if("-props".equals(args[i])) { props=args[++i]; continue; } if("-jmx".equals(args[i])) { jmx=true; continue; } if("-name".equals(args[i])) { name=args[++i]; continue; } help(); return; } RpcDispatcherSpeedTest test=new RpcDispatcherSpeedTest(); test.start(props, jmx, name); } static void help() { System.out.println("RpcDispatcherSpeedTest [-help] [-props <props>] [-name name] [-jmx]"); } }