org.mentaqueue.test.owt.LatencyTest2 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of menta-queue Show documentation
Show all versions of menta-queue Show documentation
A super fast inter-thread transfer queue.
The newest version!
package org.mentaqueue.test.owt;
import java.util.Random;
import java.util.concurrent.locks.LockSupport;
import org.mentaaffinity.Affinity;
import org.mentaqueue.AtomicQueue;
import org.mentaqueue.util.Builder;
import org.mentaqueue.util.DetailedBenchmarker;
import org.mentaqueue.wait.SpinWaitStrategy;
import org.mentaqueue.wait.WaitStrategy;
import org.tsutils.TSUtils;
import org.tsutils.Timestamper;
public class LatencyTest2 {
private static final int QUEUE_SIZE = 1024;
private static final Random RANDOM = new Random();
public static void main(String[] args) {
final long messagesToWarmup = Long.parseLong(args[0]);
final long messagesToTest = Long.parseLong(args[1]);
final int delayBetweenMessages = Integer.parseInt(args[2]);
final int messageSize = Integer.parseInt(args[3]);
final byte[] source = new byte[TransferObject.DEFAULT_CAPACITY];
for(int i = 0; i < source.length; i++) {
source[i] = (byte) RANDOM.nextInt(100);
}
final DetailedBenchmarker bench = new DetailedBenchmarker();
final AtomicQueue aToB = new AtomicQueue(QUEUE_SIZE, TransferObject.BUILDER);
final AtomicQueue bToA = new AtomicQueue(QUEUE_SIZE, TransferObject.BUILDER);
final WaitStrategy producerWaitStrategy = new SpinWaitStrategy();
final WaitStrategy consumerWaitStrategy = new SpinWaitStrategy();
final Timestamper timestamper = TSUtils.getTimestamper();
Thread producer = new Thread(new Runnable() {
private final void send(boolean warmup) {
long ts = timestamper.nanoTime();
TransferObject ml = aToB.nextToDispatch();
ml.copy(warmup ? 0 : ts, source, messageSize);
aToB.flush(); // no lazySet, send immediately
}
@Override
public void run() {
Affinity.bind();
// first warmup...
send(true); // send the first one to start!
long count = 0;
while(count < messagesToWarmup) {
// receive echo to send the next message...
long avail = bToA.availableToPoll();
if (avail > 0) {
bToA.poll();
count++;
bToA.donePolling(true); // can be lazy here because queue is not full...
producerWaitStrategy.reset();
if (count < messagesToWarmup) {
send(true);
}
} else {
producerWaitStrategy.waitForOtherThread();
}
}
// now benchmark...
send(false); // send the first one to start!
count = 0;
while(count < messagesToTest) {
// receive echo to send the next message...
long avail = bToA.availableToPoll();
if (avail > 0) {
bToA.poll();
count++;
bToA.donePolling(); // can be lazy here because queue is not full...
producerWaitStrategy.reset();
if (count < messagesToTest) {
if (delayBetweenMessages == 0) {
send(false);
} else if (delayBetweenMessages < 0) {
LockSupport.parkNanos(RANDOM.nextInt(-1 * delayBetweenMessages));
send(false);
} else {
LockSupport.parkNanos(delayBetweenMessages);
send(false);
}
}
} else {
producerWaitStrategy.waitForOtherThread();
}
}
Affinity.unbind();
// DONE!
System.out.println(bench.results());
}
}, "Thread-Producer");
Thread consumer = new Thread(new Runnable() {
@Override
public void run() {
byte[] target = new byte[TransferObject.DEFAULT_CAPACITY];
Affinity.bind();
while (true) {
// time and echo back...
long avail = aToB.availableToPoll();
if (avail > 0) {
TransferObject ml = aToB.poll();
long ts = ml.getTimestamp();
byte[] data = ml.getData();
int size = ml.getSize();
System.arraycopy(data, 0, target, 0, size);
aToB.donePolling(true); // can be lazy because queue will never be full...
if (ts > 0) {
bench.measure(timestamper.nanoTime() - ts);
}
consumerWaitStrategy.reset();
// echo back
TransferObject back = bToA.nextToDispatch();
back.copy(0, source, 1);
bToA.flush(); // send immediately so the producer gets the echo...
} else {
consumerWaitStrategy.waitForOtherThread();
}
}
}
}, "Thread-Consumer");
if (Affinity.isAvailable()) {
Affinity.assignToProcessor(2, producer);
Affinity.assignToProcessor(3, consumer);
} else {
System.err.println("Thread affinity not available!");
}
producer.setDaemon(false);
consumer.setDaemon(true);
consumer.start();
try { Thread.sleep(1); } catch(Exception e) { }
producer.start();
}
private static class TransferObject {
private static final int DEFAULT_CAPACITY = 1024;
private long timestamp;
private int size;
private byte[] data;
public TransferObject(int capacity) {
this.data = new byte[capacity];
}
public final int getSize() {
return size;
}
public final byte[] getData() {
return data;
}
public final long getTimestamp() {
return timestamp;
}
public final void copy(long ts, byte[] src, int size) {
this.timestamp = ts;
this.size = size;
System.arraycopy(src, 0, data, 0, size);
}
public final static Builder BUILDER = new Builder() {
@Override
public TransferObject newInstance() {
return new TransferObject(DEFAULT_CAPACITY);
}
};
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy