All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgroups.tests.perf.UPerf Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

The newest version!
package org.jgroups.tests.perf;

import org.jgroups.*;
import org.jgroups.annotations.Property;
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.protocols.TP;
import org.jgroups.protocols.relay.RELAY;
import org.jgroups.stack.AddressGenerator;
import org.jgroups.tests.perf.PerfUtil.Config;
import org.jgroups.tests.perf.PerfUtil.GetCall;
import org.jgroups.tests.perf.PerfUtil.PutCall;
import org.jgroups.tests.perf.PerfUtil.Results;
import org.jgroups.util.*;

import javax.management.MBeanServer;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.LongAdder;


/**
 * Tests the UNICAST by invoking unicast RPCs between a sender and a receiver. Mimicks the DIST mode in Infinispan
 *
 * @author Bela Ban
 */
public class UPerf implements Receiver {
    private JChannel                           channel;
    private Address                            local_addr;
    private RpcDispatcher                      disp;
    static final String                        groupname="uperf";
    protected final List
members=new ArrayList<>(); protected volatile View view; protected volatile boolean looping=true; protected final LongAdder num_reads=new LongAdder(); protected final LongAdder num_writes=new LongAdder(); protected ThreadFactory thread_factory; protected final ResponseCollector results_coll=new ResponseCollector<>(); // ============ configurable properties ================== @Property protected boolean oob; @Property protected int num_threads=100; @Property protected int time=60; // in seconds @Property protected int msg_size=1000; @Property protected int anycast_count=2; @Property protected double read_percentage=0.8; // 80% reads, 20% writes @Property protected boolean print_invokers; @Property protected boolean print_details; @Property protected long rpc_timeout=0; // ... add your own here, just don't forget to annotate them with @Property // ======================================================= private static final Method[] METHODS=new Method[7]; private static final short START_TEST = 0; private static final short GET = 1; private static final short PUT = 2; private static final short GET_CONFIG = 3; private static final short SET = 4; private static final short QUIT_ALL = 5; private static final short ACCEPT_RESULTS = 6; protected static final Field OOB, NUM_THREADS, TIME, RPC_TIMEOUT, MSG_SIZE, ANYCAST_COUNT, READ_PERCENTAGE, PRINT_INVOKERS, PRINT_DETAILS; private byte[] BUFFER=new byte[msg_size]; protected static final String format= "[1] Start test [2] View [4] Threads (%d) [6] Time (%,ds) [7] Msg size (%s)" + "\n[o] OOB (%b) [t] RPC timeout (%,dms) [a] Anycast count (%d) [r] Read percentage (%.2f) " + "\n[d] print details (%b) [i] print invokers (%b)" + "\n[v] Version [x] Exit [X] Exit all\n"; static { try { METHODS[START_TEST] = UPerf.class.getMethod("startTest", Address.class); METHODS[GET] = UPerf.class.getMethod("get", long.class); METHODS[PUT] = UPerf.class.getMethod("put", long.class, byte[].class); METHODS[GET_CONFIG] = UPerf.class.getMethod("getConfig"); METHODS[SET] = UPerf.class.getMethod("set", String.class, Object.class); METHODS[QUIT_ALL] = UPerf.class.getMethod("quitAll"); METHODS[ACCEPT_RESULTS] = UPerf.class.getMethod("acceptResults", Address.class, Results.class); OOB=Util.getField(UPerf.class, "oob", true); NUM_THREADS=Util.getField(UPerf.class, "num_threads", true); TIME=Util.getField(UPerf.class, "time", true); RPC_TIMEOUT=Util.getField(UPerf.class, "rpc_timeout", true); MSG_SIZE=Util.getField(UPerf.class, "msg_size", true); ANYCAST_COUNT=Util.getField(UPerf.class, "anycast_count", true); READ_PERCENTAGE=Util.getField(UPerf.class, "read_percentage", true); PRINT_INVOKERS=Util.getField(UPerf.class, "print_invokers", true); PRINT_DETAILS=Util.getField(UPerf.class, "print_details", true); PerfUtil.init(); } catch(Exception e) { throw new RuntimeException(e); } } public void init(String props, String name, AddressGenerator generator, int bind_port, boolean use_virtual_threads, boolean async_rsp_handling) throws Throwable { thread_factory=new DefaultThreadFactory("invoker", false, true) .useVirtualThreads(use_virtual_threads); if(use_virtual_threads && Util.virtualThreadsAvailable()) System.out.println("-- using virtual threads instead of threads"); channel=new JChannel(props).addAddressGenerator(generator).setName(name); if(bind_port > 0) { TP transport=channel.getProtocolStack().getTransport(); transport.setBindPort(bind_port); } disp=(RpcDispatcher)new RpcDispatcher(channel,this).setReceiver(this) .setMethodLookup(id -> METHODS[id]) .asyncRspHandling(async_rsp_handling); channel.connect(groupname); local_addr=channel.getAddress(); try { MBeanServer server=Util.getMBeanServer(); JmxConfigurator.registerChannel(channel, server, "jgroups", channel.getClusterName(), true); } catch(Throwable ex) { System.err.println("registering the channel in JMX failed: " + ex); } if(members.size() < 2) return; Address coord=members.get(0); Config config=disp.callRemoteMethod(coord, new MethodCall(GET_CONFIG), new RequestOptions(ResponseMode.GET_ALL, 5000)); if(config != null) { applyConfig(config); System.out.println("Fetched config from " + coord + ": " + config + "\n"); } else System.err.println("failed to fetch config from " + coord); } void stop() { Util.close(disp, channel); } protected void stopEventLoop() { looping=false; Util.close(channel); } public void viewAccepted(View new_view) { this.view=new_view; System.out.println("** view: " + new_view); members.clear(); members.addAll(new_view.getMembers()); results_coll.retainAll(members); } // =================================== callbacks ====================================== public void startTest(Address sender) throws Throwable { CompletableFuture.supplyAsync(() -> { try { return startTest(); } catch(Throwable ex) { System.err.printf("failure running the test: %s", ex); return null; } }).thenAccept(r -> sendResults(sender, r)); } /** Called by worker when done; response to {@link #startTest()} */ public void acceptResults(Address sender, Results results) { results_coll.add(sender, results); } public void quitAll() { System.out.println("-- received quitAll(): shutting down"); stopEventLoop(); System.exit(0); } protected String printAverage(long start_time) { long tmp_time=System.currentTimeMillis() - start_time; long reads=num_reads.sum(), writes=num_writes.sum(); double reqs_sec=(reads+writes) / (tmp_time / 1000.0); return String.format("%,.0f reqs/sec (%,d reads %,d writes)", reqs_sec, reads, writes); } public void set(String field_name, Object value) { Field field=Util.getField(this.getClass(),field_name); if(field == null) System.err.println("Field " + field_name + " not found"); else { Util.setField(field, this, value); System.out.println(field.getName() + "=" + value); } } public byte[] get(@SuppressWarnings("UnusedParameters") long key) { return BUFFER; } @SuppressWarnings("UnusedParameters") public void put(long key, byte[] val) { } public Config getConfig() { Config config=new Config(); for(Field field: Util.getAllDeclaredFieldsWithAnnotations(UPerf.class, Property.class)) { if(field.isAnnotationPresent(Property.class)) { config.add(field.getName(), Util.getField(field, this)); } } return config; } protected Results startTest() throws Throwable { BUFFER=new byte[msg_size]; System.out.printf("running for %d seconds\n", time); final CountDownLatch latch=new CountDownLatch(1); num_reads.reset(); num_writes.reset(); Invoker[] invokers=new Invoker[num_threads]; Thread[] threads=new Thread[num_threads]; for(int i=0; i < threads.length; i++) { invokers[i]=new Invoker(members, latch); threads[i]=thread_factory.newThread(invokers[i]); threads[i].setName("invoker-" + (i+1)); threads[i].start(); // waits on latch } long start=System.currentTimeMillis(); latch.countDown(); long interval=(long)((time * 1000.0) / 10.0); for(int i=1; i <= 10; i++) { Util.sleep(interval); System.out.printf("%d: %s\n", i, printAverage(start)); } for(Invoker invoker: invokers) invoker.stop(); for(Thread t: threads) t.join(); long total_time=System.currentTimeMillis() - start; System.out.println(); AverageMinMax avg_gets=null, avg_puts=null; for(int i=0; i < invokers.length; i++) { Invoker invoker=invokers[i]; if(print_invokers) System.out.printf("invoker %s: gets %s puts %s\n", threads[i].getId(), print(invoker.avgGets(), print_details), print(invoker.avgPuts(), print_details)); if(avg_gets == null) avg_gets=invoker.avgGets(); else avg_gets.merge(invoker.avgGets()); if(avg_puts == null) avg_puts=invoker.avgPuts(); else avg_puts.merge(invoker.avgPuts()); } if(print_invokers) System.out.printf("\navg over all invokers: gets %s puts %s\n", print(avg_gets, print_details), print(avg_puts, print_details)); System.out.printf("\ndone (in %s ms)\n", total_time); return new Results((int)num_reads.sum(), (int)num_writes.sum(), total_time, avg_gets, avg_puts); } protected void sendResults(Address dest, Results results) { RequestOptions options=new RequestOptions(ResponseMode.GET_NONE, 0) .flags(Message.Flag.OOB, Message.Flag.DONT_BUNDLE, Message.Flag.NO_FC); try { disp.callRemoteMethod(dest, new MethodCall(ACCEPT_RESULTS, local_addr, results), options); } catch(Exception ex) { System.err.printf("failed sending results to %s: %s", dest, ex); } } protected void applyConfig(Config config) { for(Map.Entry entry: config.values.entrySet()) { Field field=Util.getField(getClass(), entry.getKey()); Util.setField(field, this, entry.getValue()); } } // ================================= end of callbacks ===================================== public void eventLoop() { while(looping) { try { int c=Util.keyPress(String.format(format, num_threads, time, Util.printBytes(msg_size), oob, rpc_timeout, anycast_count, read_percentage, print_details, print_invokers)); switch(c) { case '1': startBenchmark(); break; case '2': printView(); break; case '4': changeFieldAcrossCluster(NUM_THREADS, Util.readIntFromStdin("Number of sender threads: ")); break; case '6': changeFieldAcrossCluster(TIME, Util.readIntFromStdin("Time (secs): ")); break; case '7': changeFieldAcrossCluster(MSG_SIZE, Util.readIntFromStdin("Message size: ")); break; case 'a': int tmp=getAnycastCount(); if(tmp >= 0) changeFieldAcrossCluster(ANYCAST_COUNT, tmp); break; case 'o': changeFieldAcrossCluster(OOB, !oob); break; case 'r': double percentage=getReadPercentage(); if(percentage >= 0) changeFieldAcrossCluster(READ_PERCENTAGE, percentage); break; case 'd': changeFieldAcrossCluster(PRINT_DETAILS, !print_details); break; case 'i': changeFieldAcrossCluster(PRINT_INVOKERS, !print_invokers); break; case 't': changeFieldAcrossCluster(RPC_TIMEOUT, Util.readIntFromStdin("RPC timeout (millisecs): ")); break; case 'v': System.out.printf("Version: %s, Java version: %s\n", Version.printVersion(), System.getProperty("java.vm.version", "n/a")); break; case 'x': case -1: looping=false; break; case 'X': try { RequestOptions options=new RequestOptions(ResponseMode.GET_NONE, 0) .flags(Message.Flag.OOB, Message.Flag.DONT_BUNDLE, Message.Flag.NO_FC) .transientFlags(Message.TransientFlag.DONT_LOOPBACK); disp.callRemoteMethods(null, new MethodCall(QUIT_ALL), options); quitAll(); break; } catch(Throwable t) { System.err.println("Calling quitAll() failed: " + t); } break; default: break; } } catch(Throwable t) { t.printStackTrace(); } } stop(); } /** Kicks off the benchmark on all cluster nodes */ protected void startBenchmark() { results_coll.reset(members); try { RequestOptions options=new RequestOptions(ResponseMode.GET_NONE, 0) .flags(Message.Flag.OOB, Message.Flag.DONT_BUNDLE, Message.Flag.NO_FC); disp.callRemoteMethods(null, new MethodCall(START_TEST, local_addr), options); } catch(Throwable t) { System.err.println("starting the benchmark failed: " + t); return; } long total_reqs=0, total_time=0; AverageMinMax avg_gets=null, avg_puts=null; long time_to_wait=(long)(time * 1000 * 1.2); // add 20% more results_coll.waitForAllResponses(time_to_wait); Map results=results_coll.getResults(); System.out.println("\n======================= Results: ==========================="); for(Map.Entry entry: results.entrySet()) { Address mbr=entry.getKey(); Results result=entry.getValue(); if(result != null) { total_reqs+=result.num_gets + result.num_puts; total_time+=result.total_time; if(avg_gets == null) avg_gets=result.avg_gets; else avg_gets.merge(result.avg_gets); if(avg_puts == null) avg_puts=result.avg_puts; else avg_puts.merge(result.avg_puts); } System.out.println(mbr + ": " + result); } double total_reqs_sec=total_reqs / ( total_time/ 1000.0); double throughput=total_reqs_sec * BUFFER.length; System.out.println("\n"); System.out.println(Util.bold(String.format("Throughput: %,.2f reqs/sec/node (%s/sec)\n" + "Roundtrip: gets %s, puts %s\n", total_reqs_sec, Util.printBytes(throughput), print(avg_gets, print_details), print(avg_puts, print_details)))); System.out.println("\n\n"); } static double getReadPercentage() throws Exception { double tmp=Util.readDoubleFromStdin("Read percentage: "); if(tmp < 0 || tmp > 1.0) { System.err.println("read percentage must be >= 0 or <= 1.0"); return -1; } return tmp; } int getAnycastCount() throws Exception { int tmp=Util.readIntFromStdin("Anycast count: "); View tmp_view=channel.getView(); if(tmp > tmp_view.size()) { System.err.println("anycast count must be smaller or equal to the view size (" + tmp_view + ")\n"); return -1; } return tmp; } protected void changeFieldAcrossCluster(Field field, Object value) throws Exception { disp.callRemoteMethods(null, new MethodCall(SET, field.getName(), value), RequestOptions.SYNC()); } protected void printView() { System.out.printf("\n-- local: %s, view: %s\n", local_addr, view); try { System.in.skip(System.in.available()); } catch(Exception e) { } } protected static String print(AverageMinMax avg, boolean details) { return details? String.format("min/avg/max = %,.2f/%,.2f/%,.2f us", avg.min() / 1000.0, avg.average() / 1000.0, avg.max() / 1000.0) : String.format("avg = %,.2f us", avg.average() / 1000.0); } protected static List getSites(JChannel channel) { RELAY relay=channel.getProtocolStack().findProtocol(RELAY.class); return relay != null? relay.siteNames() : new ArrayList<>(0); } /** Picks the next member in the view */ private Address getReceiver() { try { List
mbrs=channel.getView().getMembers(); int index=mbrs.indexOf(local_addr); int new_index=index + 1 % mbrs.size(); return mbrs.get(new_index); } catch(Exception e) { System.err.println("UPerf.getReceiver(): " + e); return null; } } private class Invoker implements Runnable { private final List
dests=new ArrayList<>(); private final CountDownLatch latch; private final AverageMinMax avg_gets=new AverageMinMax(), avg_puts=new AverageMinMax(); // in ns private final List
targets=new ArrayList<>(anycast_count); private volatile boolean running=true; public Invoker(Collection
dests, CountDownLatch latch) { this.latch=latch; this.dests.addAll(dests); } public AverageMinMax avgGets() {return avg_gets;} public AverageMinMax avgPuts() {return avg_puts;} public void stop() {running=false;} public void run() { Object[] put_args={0, BUFFER}; Object[] get_args={0}; MethodCall get_call=new GetCall(GET, get_args); MethodCall put_call=new PutCall(PUT, put_args); RequestOptions get_options=new RequestOptions(ResponseMode.GET_ALL, rpc_timeout, false, null); RequestOptions put_options=new RequestOptions(ResponseMode.GET_ALL, rpc_timeout, true, null); if(oob) { get_options.flags(Message.Flag.OOB); put_options.flags(Message.Flag.OOB); } try { latch.await(); } catch(InterruptedException e) { e.printStackTrace(); } while(running) { boolean get=Util.tossWeightedCoin(read_percentage); try { if(get) { // sync GET Address target=pickTarget(); long start=System.nanoTime(); disp.callRemoteMethod(target, get_call, get_options); long get_time=System.nanoTime()-start; avg_gets.add(get_time); num_reads.increment(); } else { // sync or async (based on value of 'sync') PUT pickAnycastTargets(targets); long start=System.nanoTime(); disp.callRemoteMethods(targets, put_call, put_options); long put_time=System.nanoTime()-start; targets.clear(); avg_puts.add(put_time); num_writes.increment(); } } catch(Throwable t) { if(running) t.printStackTrace(); } } } private Address pickTarget() { return Util.pickRandomElement(dests); } private void pickAnycastTargets(List
anycast_targets) { int index=dests.indexOf(local_addr); for(int i=index + 1; i < index + 1 + anycast_count; i++) { int new_index=i % dests.size(); Address tmp=dests.get(new_index); if(!anycast_targets.contains(tmp)) anycast_targets.add(tmp); } } } public static void main(String[] args) throws IOException, ClassNotFoundException { String props=null, name=null; boolean run_event_loop=true, use_virtual_threads=true, async_rsp_handling=!Util.virtualThreadsAvailable(); // good with convential threads, bad with vthreads! AddressGenerator addr_generator=null; int port=0; for(int i=0; i < args.length; i++) { if("-props".equals(args[i])) { props=args[++i]; continue; } if("-name".equals(args[i])) { name=args[++i]; continue; } if("-nohup".equals(args[i])) { run_event_loop=false; continue; } if("-uuid".equals(args[i])) { addr_generator=new OneTimeAddressGenerator(Long.parseLong(args[++i])); continue; } if("-port".equals(args[i])) { port=Integer.parseInt(args[++i]); continue; } if("-use_virtual_threads".equals(args[i])) { use_virtual_threads=Boolean.parseBoolean(args[++i]); continue; } if("-async_rsp_handling".equals(args[i])) { async_rsp_handling=Boolean.parseBoolean(args[++i]); continue; } help(); return; } UPerf test=null; try { test=new UPerf(); test.init(props, name, addr_generator, port, use_virtual_threads, async_rsp_handling); if(run_event_loop) test.eventLoop(); else { for(;;) Util.sleep(60000); } } catch(Throwable ex) { ex.printStackTrace(); if(test != null) test.stop(); } } static void help() { System.out.println("UPerf [-props ] [-name name] [-nohup] [-uuid ] [-port ] " + "[-use_virtual_threads ] [-async_rsp_handling ]"); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy