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

org.mentaqueue.test.owt.LatencyTest2 Maven / Gradle / Ivy

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