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

org.mentalog.test.MMapFileTest Maven / Gradle / Ivy

There is a newer version: 2.1.2
Show newest version
package org.mentalog.test;

import java.io.File;
import java.io.FileOutputStream;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Random;

import org.mentaaffinity.Affinity;
import org.mentalog.util.Benchmarker;
import org.mentalog.util.DetailedBenchmarker;
import org.mentalog.util.SystemUtils;
import org.mentaqueue.AtomicQueue;
import org.mentaqueue.util.Builder;
import org.mentaqueue.wait.ParkWaitStrategy;
import org.mentaqueue.wait.WaitStrategy;

public class MMapFileTest {
	
	private static final Random RANDOM = new Random();
	private static final int QUEUE_SIZE = 1024;
	private static final String M = "This is a log message not so small that you can use to test. I hope you have fun and it works well!";
	private static final byte[] MSG = M.getBytes();
	private static final ByteBuffer BUF = ByteBuffer.wrap((M + "\n").getBytes());
	private static final Builder BUILDER = new ByteBufferBuilder();
	private static final AtomicQueue QUEUE = new AtomicQueue(QUEUE_SIZE, BUILDER);
	
	public static void main(String[] args) throws Exception {
		
		final int size = Integer.parseInt(args[0]);
		
		long x = size * (MSG.length + 1);
		
		if (x > Integer.MAX_VALUE) {
			throw new RuntimeException("Size too big for buffer: " + size);
		}
		
		int bufferSize = (int) x;
		
		ByteBuffer heapBuffer = ByteBuffer.allocate(bufferSize);
		ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize);
		
		File file = new File("mMapFile.txt");
		if (file.exists()) file.delete();
		RandomAccessFile memoryMappedFile = new RandomAccessFile(file, "rw");

		final boolean isProducerLazySet = SystemUtils.getBoolean("producerLazySet", true);
		final boolean isConsumerLazySet = SystemUtils.getBoolean("consumerLazySet", true);
		final boolean testFileChannel = SystemUtils.getBoolean("testFileChannel", true);
		
		File file2 = new File("channelFile.txt");
		if (file2.exists()) file2.delete();
		
		FileOutputStream fos = null;
		FileChannel fileChannel = null;
		
		if (testFileChannel) {
			fos = new FileOutputStream(file2);
			fileChannel = fos.getChannel();	
		}
	       
		//Mapping a file into memory
		MappedByteBuffer mappedBuffer = memoryMappedFile.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, bufferSize);
	      
		float warmupPerc = Float.parseFloat(SystemUtils.getString("warmupPerc", "0"));
		
		int logMaxDelay = Integer.parseInt(SystemUtils.getString("maxDelay", "-1"));
		int logMaxLogsBetweenPauses = Integer.parseInt(SystemUtils.getString("maxLogsBetweenPauses", "-1"));
		
		int warmup = (int) Math.round(warmupPerc * size);
		
		final WaitStrategy consumerWaitStrategy = new ParkWaitStrategy();
		
		Thread consumer = new Thread(new Runnable() {

			@Override
			public void run() {
				
				Affinity.bind();
				
				long count = 0;
				
				while (count < size) {
					
					long avail;
					
					while((avail = QUEUE.availableToPoll()) == 0) {
						consumerWaitStrategy.waitForOtherThread();
					}
					
					consumerWaitStrategy.reset();
					
					for(int i = 0; i < avail; i++) {
						ByteBuffer bb = QUEUE.poll();
						bb.clear();
					}
					count += avail;
					QUEUE.donePolling(isConsumerLazySet); // tell producer as soon as possible!
				}
				
				Affinity.unbind();
			}
		}, "Thread-Consumer");
		
		if (Affinity.isAvailable()) {
			Affinity.assignToProcessor(2, Thread.currentThread());
			Affinity.assignToProcessor(3, consumer);
		} else {
			System.err.println("Thread affinity not available!");
		}
		
		consumer.setDaemon(true);
		consumer.start();
		
		boolean isDetailed = SystemUtils.getBoolean("detailedBenchmark", false);
        Benchmarker heapBench = isDetailed ? new DetailedBenchmarker(warmup) : new Benchmarker(warmup);
        Benchmarker mappedBench = isDetailed ? new DetailedBenchmarker(warmup) : new Benchmarker(warmup);
        Benchmarker directBench = isDetailed ? new DetailedBenchmarker(warmup) : new Benchmarker(warmup);
        Benchmarker queueBench = isDetailed ? new DetailedBenchmarker(warmup) : new Benchmarker(warmup);
        Benchmarker channelBench = isDetailed ? new DetailedBenchmarker(warmup) : new Benchmarker(warmup);
		
		Affinity.bind();
		
		int count = 0;
		
		while(count < size) {
			
			// first calculate delay
			if (logMaxDelay > 0) {
				int delay = RANDOM.nextInt(logMaxDelay);
				PauseSupport.random(delay);
			}
			
			int logs = 1;
			
			// second calculate number of log
			if (logMaxLogsBetweenPauses > 0) {
				logs = RANDOM.nextInt(logMaxLogsBetweenPauses);
				if (count + logs >= size) {
					logs = size - count;
				}
			}
			
			for(int i = 0; i < logs; i++) {

				heapBench.mark();
    			heapBuffer.put(MSG);
    			heapBuffer.put((byte) '\n');
    			heapBench.measure();
    			
    			directBench.mark();
    			directBuffer.put(MSG);
    			directBuffer.put((byte) '\n');
    			directBench.measure();
    			
    			if (testFileChannel) {
        			channelBench.mark();
        			BUF.position(0);
        			fileChannel.write(BUF);
        			channelBench.measure();
    			}
    			
    			mappedBench.mark();
    			mappedBuffer.put(MSG);
    			mappedBuffer.put((byte) '\n');
    			mappedBench.measure();
    			
    			queueBench.mark();
    			send(isProducerLazySet);
    			queueBench.measure();
			}
			
			count += logs;
		}
		
		System.out.println("\nHeap: " + heapBench.results());
		System.out.println("\nDirect: " + directBench.results());
		if (testFileChannel) System.out.println("\nFile Channel: " + channelBench.results());
		System.out.println("\nMMap: " + mappedBench.results());
		System.out.println("\nQueue: " + queueBench.results());
		System.out.println();
		
		memoryMappedFile.close();
		
		if (testFileChannel) {
			fos.close();
			fileChannel.close();
			file2.delete();
		}
		
		file.delete();
		
		Affinity.unbind();
	}
	
	private static void send(boolean isProducerLazySet) {
		ByteBuffer bb;
		while((bb = QUEUE.nextToDispatch()) == null); // busy spin
		bb.put(MSG);
		bb.put((byte) '\n');
		QUEUE.flush(isProducerLazySet); // send lazily to minize producer latency
	}
	
	private static class ByteBufferBuilder implements Builder {
		@Override
        public ByteBuffer newInstance() {
	        return ByteBuffer.allocate(MSG.length + 1);
        }
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy