org.mentalog.test.MMapFileTest Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of menta-log Show documentation
Show all versions of menta-log Show documentation
A log library that embraces the kiss principle.
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);
}
}
}