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

org.jgroups.util.RTT Maven / Gradle / Ivy

There is a newer version: 5.4.1.Final
Show newest version
package org.jgroups.util;

import org.jgroups.*;
import org.jgroups.annotations.MBean;
import org.jgroups.annotations.ManagedOperation;
import org.jgroups.annotations.Property;
import org.jgroups.protocols.TP;
import org.jgroups.protocols.TpHeader;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Measures round-trip times (RTT) between nodes
 * @author Bela Ban
 * @since  5.4, 5.3.8
 */
@MBean(description="Component measuring round-trip times to all other nodes")
public class RTT {
    protected TP                transport;
    protected short             tp_id;

    @Property(description="The number of RPCs to send")
    protected int               num_reqs=10;

    @Property(description="Timeout (ms) for an RPC")
    protected long              timeout=1000;

    @Property(description="Size (in bytes) of an RPC")
    protected int               size;

    @Property(description="Send requests and responses as OOB messages")
    protected boolean           oob;

    protected final Map rtts=Util.createConcurrentMap();
    protected final Map        times=Util.createConcurrentMap(); // list of start times (us)

    public int     numReqs()              {return num_reqs;}
    public RTT     numReqs(int n)         {this.num_reqs=n; return this;}
    public long    timeout()              {return timeout;}
    public RTT     timeout(long t)        {this.timeout=t; return this;}
    public int     size()                 {return size;}
    public RTT     size(int size)         {this.size=size; return this;}
    public boolean oob()                  {return oob;}
    public RTT     oob(boolean b)         {oob=b; return this;}

    public void init(TP tp) {
        this.transport=Objects.requireNonNull(tp);
        this.tp_id=transport.getId();
    }

    @ManagedOperation(description="Sends N RPCs to all other nodes and computes min/avg/max RTT")
    public String rtt() {
        return rtt(num_reqs, size, true, false);
    }

    /**
     * Sends N requests to all members and computes RTTs
     * @param num_reqs The number of requests to be sent to all members
     * @param details Whether to print details (e.g. min/max/percentiles)
     */
    @ManagedOperation(description="Sends N RPCs to all other nodes and computes min/avg/max RTT")
    public String rtt(int num_reqs, boolean details) {
        return rtt(num_reqs, this.size, details, false);
    }

    /**
     * Sends N requests to all members and computes RTTs
     * @param num_reqs The number of requests to be sent to all members
     * @param size The number of bytes a request should have
     * @param details Whether to print details (e.g. min/max/percentiles)
     * @param exclude_self Whether to exclude the local node
     */
    @ManagedOperation(description="Sends N RPCs to all other nodes and computes min/avg/max RTT")
    public String rtt(int num_reqs, int size, boolean details, boolean exclude_self) {
        Map m=_rtt(num_reqs, size, exclude_self);
        return m.entrySet().stream()
          .map(e -> String.format("%s: %s", e.getKey(), print(e.getValue(), details, TimeUnit.MICROSECONDS, num_reqs)))
          .collect(Collectors.joining("\n"));
    }

    public Map _rtt(int num_reqs, int size, boolean exclude_self) {
        rtts.clear();
        times.clear();
        View view=transport.view();
        byte[] payload=new byte[size];
        final List
targets=new ArrayList<>(view.getMembers()); if(exclude_self) targets.remove(transport.addr()); for(Address addr: targets) { rtts.put(addr, new AverageMinMax().usePercentiles(128).unit(TimeUnit.MICROSECONDS)); times.put(addr, new long[num_reqs]); } AsciiString cluster=transport.getClusterNameAscii(); for(int i=0; i < num_reqs; i++) { TpHeader hdr=new TpHeader(cluster, TpHeader.REQ, i); for(Address addr: targets) { Message msg=new BytesMessage(addr, payload).putHeader(tp_id, hdr); if(oob) msg.setFlag(Message.Flag.OOB); long[] t=times.get(addr); t[i]=Util.micros(); transport.down(msg); } } Util.waitUntilTrue(timeout, timeout/10, () -> rtts.values().stream().allMatch(a -> a.count() >= num_reqs)); return new HashMap<>(rtts); } /** Called when a message (request or response) is received */ public void handleMessage(Message msg, TpHeader hdr) { if(hdr != null) { switch(hdr.flag()) { case TpHeader.REQ: handleRequest(msg.src(), hdr); break; case TpHeader.RSP: handleResponse(msg.src(), hdr.index()); } } } protected void handleRequest(Address sender, TpHeader hdr) { Message rsp=new EmptyMessage(sender) .putHeader(tp_id, new TpHeader(transport.getClusterNameAscii(), TpHeader.RSP, hdr.index())); if(oob) rsp.setFlag(Message.Flag.OOB); transport.down(rsp); } protected void handleResponse(Address sender, int index) { long[] start_times=times.get(sender); if(start_times != null) { long time=Util.micros() - start_times[index]; AverageMinMax avg=rtts.get(sender); if(avg != null) avg.add(time); } } protected static String print(AverageMinMax avg, boolean details, TimeUnit unit, int num_reqs) { return details? avg.toString(unit) + String.format(" (%s)", percentiles(avg, num_reqs)) : Util.printTime(avg.average(), unit); } protected static String percentiles(AverageMinMax avg, int num_reqs) { List values=avg.values(); int received=values.size(), non_received=num_reqs - received; double failure_rate=non_received == 0? 0.0 : (double)non_received / received; String failures=non_received == 0? "" : String.format(" (failure rate: %.2f)", failure_rate); return String.format("p90=%s p99=%s p99.9=%s%s", Util.printTime(avg.p(90), avg.unit()), Util.printTime(avg.p(99), avg.unit()), Util.printTime(avg.p(99.9), avg.unit()), failures); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy