package edu.mbl.jif.imaging.testio;
// From http://java.dzone.com/articles/java-sequential-io-performance
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import static java.lang.Integer.MAX_VALUE;
import static java.lang.System.out;
import static java.nio.channels.FileChannel.MapMode.READ_ONLY;
import static java.nio.channels.FileChannel.MapMode.READ_WRITE;
public final class TestSequentialIoPerf {
public static final int PAGE_SIZE = 1024 * 4;
public static final long FILE_SIZE = PAGE_SIZE * 2000L * 1000L;
public static final String FILE_NAME = "test.dat";
public static final byte[] BLANK_PAGE = new byte[PAGE_SIZE];
public static void main(final String[] arg) throws Exception {
preallocateTestFile(FILE_NAME);
for (final PerfTestCase testCase : testCases) {
for (int i = 0; i < 5; i++) {
System.gc();
long writeDurationMs = testCase.test(PerfTestCase.Type.WRITE, FILE_NAME);
System.gc();
long readDurationMs = testCase.test(PerfTestCase.Type.READ, FILE_NAME);
long bytesReadPerSec = (FILE_SIZE * 1000L) / readDurationMs;
long bytesWrittenPerSec = (FILE_SIZE * 1000L) / writeDurationMs;
out.format("%s\twrite=%,d\tread=%,d bytes/sec\n",
testCase.getName(),
bytesWrittenPerSec, bytesReadPerSec);
}
}
deleteFile(FILE_NAME);
}
private static void preallocateTestFile(final String fileName)
throws Exception {
RandomAccessFile file = new RandomAccessFile(fileName, "rw");
for (long i = 0; i < FILE_SIZE; i += PAGE_SIZE) {
file.write(BLANK_PAGE, 0, PAGE_SIZE);
}
file.close();
}
private static void deleteFile(final String testFileName) throws Exception {
File file = new File(testFileName);
if (!file.delete()) {
out.println("Failed to delete test file=" + testFileName);
out.println("Windows does not allow mapped files to be deleted.");
}
}
public abstract static class PerfTestCase {
public enum Type {
READ, WRITE
}
private final String name;
private int checkSum;
public PerfTestCase(final String name) {
this.name = name;
}
public String getName() {
return name;
}
public long test(final Type type, final String fileName) {
long start = System.currentTimeMillis();
try {
switch (type) {
case WRITE: {
checkSum = testWrite(fileName);
break;
}
case READ: {
final int checkSum = testRead(fileName);
if (checkSum != this.checkSum) {
final String msg = getName()
+ " expected=" + this.checkSum
+ " got=" + checkSum;
throw new IllegalStateException(msg);
}
break;
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
return System.currentTimeMillis() - start;
}
public abstract int testWrite(final String fileName) throws Exception;
public abstract int testRead(final String fileName) throws Exception;
}
private static PerfTestCase[] testCases = {
new PerfTestCase("RandomAccessFile") {
public int testWrite(final String fileName) throws Exception {
RandomAccessFile file = new RandomAccessFile(fileName, "rw");
final byte[] buffer = new byte[PAGE_SIZE];
int pos = 0;
int checkSum = 0;
for (long i = 0; i < FILE_SIZE; i++) {
byte b = (byte) i;
checkSum += b;
buffer[pos++] = b;
if (PAGE_SIZE == pos) {
file.write(buffer, 0, PAGE_SIZE);
pos = 0;
}
}
file.close();
return checkSum;
}
public int testRead(final String fileName) throws Exception {
RandomAccessFile file = new RandomAccessFile(fileName, "r");
final byte[] buffer = new byte[PAGE_SIZE];
int checkSum = 0;
int bytesRead;
while (-1 != (bytesRead = file.read(buffer))) {
for (int i = 0; i < bytesRead; i++) {
checkSum += buffer[i];
}
}
file.close();
return checkSum;
}
},
new PerfTestCase("BufferedStreamFile") {
public int testWrite(final String fileName) throws Exception {
int checkSum = 0;
OutputStream out =
new BufferedOutputStream(new FileOutputStream(fileName));
for (long i = 0; i < FILE_SIZE; i++) {
byte b = (byte) i;
checkSum += b;
out.write(b);
}
out.close();
return checkSum;
}
public int testRead(final String fileName) throws Exception {
int checkSum = 0;
InputStream in =
new BufferedInputStream(new FileInputStream(fileName));
int b;
while (-1 != (b = in.read())) {
checkSum += (byte) b;
}
in.close();
return checkSum;
}
},
new PerfTestCase("BufferedChannelFile") {
public int testWrite(final String fileName) throws Exception {
FileChannel channel =
new RandomAccessFile(fileName, "rw").getChannel();
ByteBuffer buffer = ByteBuffer.allocate(PAGE_SIZE);
int checkSum = 0;
for (long i = 0; i < FILE_SIZE; i++) {
byte b = (byte) i;
checkSum += b;
buffer.put(b);
if (!buffer.hasRemaining()) {
channel.write(buffer);
buffer.clear();
}
}
channel.close();
return checkSum;
}
public int testRead(final String fileName) throws Exception {
FileChannel channel =
new RandomAccessFile(fileName, "rw").getChannel();
ByteBuffer buffer = ByteBuffer.allocate(PAGE_SIZE);
int checkSum = 0;
while (-1 != (channel.read(buffer))) {
buffer.flip();
while (buffer.hasRemaining()) {
checkSum += buffer.get();
}
buffer.clear();
}
return checkSum;
}
},
new PerfTestCase("MemoryMappedFile") {
public int testWrite(final String fileName) throws Exception {
FileChannel channel =
new RandomAccessFile(fileName, "rw").getChannel();
MappedByteBuffer buffer =
channel.map(READ_WRITE, 0,
Math.min(channel.size(), MAX_VALUE));
int checkSum = 0;
for (long i = 0; i < FILE_SIZE; i++) {
if (!buffer.hasRemaining()) {
buffer =
channel.map(READ_WRITE, i,
Math.min(channel.size() - i, MAX_VALUE));
}
byte b = (byte) i;
checkSum += b;
buffer.put(b);
}
channel.close();
return checkSum;
}
public int testRead(final String fileName) throws Exception {
FileChannel channel =
new RandomAccessFile(fileName, "rw").getChannel();
MappedByteBuffer buffer =
channel.map(READ_ONLY, 0,
Math.min(channel.size(), MAX_VALUE));
int checkSum = 0;
for (long i = 0; i < FILE_SIZE; i++) {
if (!buffer.hasRemaining()) {
buffer =
channel.map(READ_WRITE, i,
Math.min(channel.size() - i, MAX_VALUE));
}
checkSum += buffer.get();
}
channel.close();
return checkSum;
}
},};
/* ouput like... with an SSD.
*
400MB file
===========
RandomAccessFile write=379,610,750 read=1,452,482,269 bytes/sec
RandomAccessFile write=294,041,636 read=1,494,890,510 bytes/sec
RandomAccessFile write=250,980,392 read=1,422,222,222 bytes/sec
RandomAccessFile write=250,366,748 read=1,388,474,576 bytes/sec
RandomAccessFile write=260,394,151 read=1,422,222,222 bytes/sec
BufferedStreamFile write=98,178,331 read=286,433,566 bytes/sec
BufferedStreamFile write=100,244,738 read=288,857,545 bytes/sec
BufferedStreamFile write=82,948,562 read=154,100,827 bytes/sec
BufferedStreamFile write=108,503,311 read=153,869,271 bytes/sec
BufferedStreamFile write=113,055,478 read=152,608,047 bytes/sec
BufferedChannelFile write=388,246,445 read=358,041,958 bytes/sec
BufferedChannelFile write=390,467,111 read=375,091,575 bytes/sec
BufferedChannelFile write=321,759,622 read=1,539,849,624 bytes/sec
BufferedChannelFile write=318,259,518 read=1,539,849,624 bytes/sec
BufferedChannelFile write=322,265,932 read=1,534,082,397 bytes/sec
MemoryMappedFile write=300,955,180 read=305,899,925 bytes/sec
MemoryMappedFile write=313,149,847 read=310,538,286 bytes/sec
MemoryMappedFile write=326,374,501 read=303,857,566 bytes/sec
MemoryMappedFile write=327,680,000 read=304,535,315 bytes/sec
MemoryMappedFile write=326,895,450 read=303,632,320 bytes/sec
8GB File
============
RandomAccessFile write=167,402,321 read=251,922,012 bytes/sec
RandomAccessFile write=193,934,802 read=257,052,307 bytes/sec
RandomAccessFile write=192,948,159 read=248,460,768 bytes/sec
RandomAccessFile write=191,814,180 read=245,225,408 bytes/sec
RandomAccessFile write=190,635,762 read=275,315,073 bytes/sec
BufferedStreamFile write=154,823,102 read=248,355,313 bytes/sec
BufferedStreamFile write=152,083,913 read=253,418,301 bytes/sec
BufferedStreamFile write=133,099,369 read=146,056,197 bytes/sec
BufferedStreamFile write=131,065,708 read=146,217,827 bytes/sec
BufferedStreamFile write=132,694,052 read=148,116,004 bytes/sec
BufferedChannelFile write=406,147,744 read=304,693,892 bytes/sec
BufferedChannelFile write=397,457,668 read=298,183,671 bytes/sec
BufferedChannelFile write=364,672,364 read=414,281,379 bytes/sec
BufferedChannelFile write=371,266,711 read=404,343,534 bytes/sec
BufferedChannelFile write=373,705,579 read=406,934,578 bytes/sec
MemoryMappedFile write=123,023,322 read=231,530,156 bytes/sec
MemoryMappedFile write=121,961,023 read=230,403,600 bytes/sec
MemoryMappedFile write=123,317,778 read=229,899,250 bytes/sec
MemoryMappedFile write=121,472,738 read=231,739,745 bytes/sec
MemoryMappedFile write=120,362,615 read=231,190,382 bytes/sec
*/
}