Skip to content

Instantly share code, notes, and snippets.

@seraphy
Last active October 6, 2020 14:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seraphy/c173e3d82afd1ad3f81c to your computer and use it in GitHub Desktop.
Save seraphy/c173e3d82afd1ad3f81c to your computer and use it in GitHub Desktop.
JavaのNIOのダイレクトバッファのベンチマーク。allocDirectのパフォーマンス比較およびネイティブメモリのコミットサイズの遷移の確認用、および、10MiBのファイル読み込みのパフォーマンス比較。
package jp.seraphyware.jmhexample;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.Files;
import java.nio.file.Path;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.annotations.TearDown;
/**
* テスト中にスレッドごとベンチマークごとの状態を保持するインスタンス.
*
* @author seraphy
*/
@State(Scope.Thread)
public abstract class AbstractFileBenchContext {
protected final ByteOrder byteOrder;
protected final int bufsiz;
private Path tempFile;
private ByteBuffer bufHeap;
private ByteBuffer bufDirect;
protected AbstractFileBenchContext(ByteOrder byteOrder, int bufsiz) {
this.byteOrder = byteOrder;
this.bufsiz = bufsiz;
}
/**
* データの初期化.
* Trialの場合、スレッドごとベンチマークの開始ごとに一度呼び出される.<br>
* (ウォームアップイテレーション、および計測イテレーション中には呼び出されない。)
* (Trialがデフォルト、そのほかにIteration, Invocationが指定可能.)
*/
@Setup(Level.Trial)
public void setup() throws IOException {
// バッファの確保 (ヒープ)
byte[] data = new byte[bufsiz];
bufHeap = ByteBuffer.wrap(data);
bufHeap.order(byteOrder);
// バッファの確保 (ダイレクト)
bufDirect = ByteBuffer.allocateDirect(data.length);
bufDirect.order(byteOrder);
// テストデータファイルの作成
tempFile = initTempFile();
}
protected abstract Path initTempFile() throws IOException;
/**
* スレッドごとベンチマーク終了ごとに呼び出される.
*/
@TearDown
public void teardown() {
try {
//System.out.println("★delete tempFile=" + tempFile);
Files.deleteIfExists(tempFile);
} catch (Exception ex) {
ex.printStackTrace();
}
}
public Path getTempFile() {
return tempFile;
}
public abstract void verify(Object actual);
public ByteBuffer getBufDirect() {
return bufDirect;
}
public ByteBuffer getBufHeap() {
return bufHeap;
}
}
package jp.seraphyware.jmhexample;
import java.nio.ByteBuffer;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Level;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;
public class BufferAllocBenchmark {
@State(Scope.Thread)
public static class BufferAllocContext {
private ByteBuffer buf;
@Setup(Level.Trial)
public void setup() {
}
public void setByteBuffer(ByteBuffer buf) {
this.buf = buf;
}
public ByteBuffer getButeBuffer() {
return this.buf;
}
}
@Benchmark
public void testAllocDirect8(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocateDirect(8 * 1024));
}
@Benchmark
public void testAllocHeap8(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocate(8 * 1024));
}
@Benchmark
public void testAllocDirect16(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocateDirect(16 * 1024));
}
@Benchmark
public void testAllocHeap16(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocate(16 * 1024));
}
@Benchmark
public void testAllocDirect32(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocateDirect(32 * 1024));
}
@Benchmark
public void testAllocHeap32(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocate(32 * 1024));
}
@Benchmark
public void testAllocDirect64(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocateDirect(64 * 1024));
}
@Benchmark
public void testAllocHeap64(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocate(64 * 1024));
}
@Benchmark
public void testAllocDirect128(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocateDirect(128 * 1024));
}
@Benchmark
public void testAllocHeap128(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocate(128 * 1024));
}
@Benchmark
public void testAllocDirect256(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocateDirect(256 * 1024));
}
@Benchmark
public void testAllocHeap256(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocate(256 * 1024));
}
@Benchmark
public void testAllocDirect512(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocateDirect(512 * 1024));
}
@Benchmark
public void testAllocHeap512(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocate(512 * 1024));
}
@Benchmark
public void testAllocDirect1024(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocateDirect(1024 * 1024));
}
@Benchmark
public void testAllocHeap1024(BufferAllocContext ctx) {
ctx.setByteBuffer(ByteBuffer.allocate(1024 * 1024));
}
/**
* IDEから実行する場合は、
* まず先にmvn package等を実行してサポートファイル類を生成しておく必要がある.
* (少なくともクラスまたはメソッドのシグネチャを変更追加するたびにmvnでビルドする必要がある。)
* その後、IDEから、このメイン関数を呼び出すことができるようになる.
* @param args
* @throws RunnerException
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
// 実行すべきベンチマークが定義された"クラス名.メソッド名"を正規表現で指定
.include(BufferAllocBenchmark.class.getSimpleName())
// ウォームアップイテレーション数 "-wi"オプションに相当
.warmupIterations(10)
// イテレーション数 "-i"オプションに相当
.measurementIterations(50)
// フォーク数 "-f"オプションに相当
.forks(1)
// 1回のテストメソッド実行時間 "-r"オプションに相当
.measurementTime(TimeValue.seconds(1))
// 同時実行スレッド数 (1測定毎のスレッド数 (サンプル数が増える))
// .threads(Math.max(1, Runtime.getRuntime().availableProcessors() - 1))
// 測定するモード = スループット
//.timeUnit(TimeUnit.MICROSECONDS)
//.mode(Mode.SampleTime)
.build();
new Runner(opt).run();
}
}
package jp.seraphyware.jmhexample;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
public class BufferAllocExample {
/**
* バイトバッファをallocする方法
*/
public enum ByteBufferAllocStrategy {
/**
* ヒープのByteBufferを構築する.
*/
heap() {
@Override
public ByteBuffer alloc(int siz) {
return ByteBuffer.allocate(siz);
}
},
/**
* ダイレクトのByteBufferを構築する.
*/
direct() {
@Override
public ByteBuffer alloc(int siz) {
return ByteBuffer.allocateDirect(siz);
}
};
public abstract ByteBuffer alloc(int siz);
}
/**
* エントリポイント.
* 第一引数にheapかdirectを指定する.
* @param args
* @throws Exception
*/
public static void main(String... args) throws Exception {
ByteBufferAllocStrategy allocator = ByteBufferAllocStrategy
.valueOf(args[0]);
Runtime rt = Runtime.getRuntime();
List<ByteBuffer> buffers = new ArrayList<>();
// 10MiBの割り当てを10回繰り返す
for (int idx = 0; idx < 10; idx++) {
System.gc();
System.out.println(rt.freeMemory() + "/" + rt.totalMemory());
ByteBuffer buf = allocator.alloc(1024 * 1024 * 10);
buffers.add(buf);
}
// 100MiB割り当て後のヒープの残量
System.gc();
System.out.println(rt.freeMemory() + "/" + rt.totalMemory());
// OSのコミットサイズ、プライベートワーキングセットのサイズを
// タスクマネージャで見られるように、アプリ終了前に一旦停止する。
System.console().readLine();
}
}
package jp.seraphyware.jmhexample;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.util.function.IntFunction;
import java.util.stream.IntStream;
public class BufferStressAndCleanupExample {
/**
* 最新のバイトバッファを保持するスレッドローカル
*/
public static ThreadLocal<ByteBuffer> lastBufTLS = new ThreadLocal<>();;
/**
* バイトバッファをallocする方法
*/
public enum ByteBufferAllocStrategy {
/**
* ヒープのByteBufferを構築する.
*/
heap() {
@Override
public ByteBuffer alloc(int siz) {
return ByteBuffer.allocate(siz);
}
},
/**
* ダイレクトのByteBufferを構築する.
*/
direct() {
@Override
public ByteBuffer alloc(int siz) {
return ByteBuffer.allocateDirect(siz);
}
};
public abstract ByteBuffer alloc(int siz);
}
/**
* バイトバッファの破棄方法.
*/
public enum ByteBufferDeallocStrategy {
/**
* 何もしない.システムにお任せ.
*/
none() {
@Override
public void dealloc(ByteBuffer buf) {
}
},
/**
* 明示的にgcを呼び出す.
*/
gc() {
@Override
public void dealloc(ByteBuffer buf) {
System.gc();
}
},
/**
* 明示的にcleanerを呼び出す.
*/
cleaner() {
@Override
public void dealloc(ByteBuffer buf) {
if (buf != null && buf.isDirect()) {
destroyDirectByteBuffer(buf);
}
}
};
public abstract void dealloc(ByteBuffer buf);
}
/**
* エントリポイント
* @param args
* @throws Exception
*/
public static void main(String... args) throws Exception {
ByteBufferAllocStrategy allocator = ByteBufferAllocStrategy.valueOf(args[0]);
ByteBufferDeallocStrategy deallocator;
if (args.length > 1) {
deallocator = ByteBufferDeallocStrategy.valueOf(args[1]);
} else {
deallocator = ByteBufferDeallocStrategy.none;
}
int mxthread = (args.length > 2) ? Integer.parseInt(args[2]) : 2;
// 10MiBの割り当てを永久に繰り返すジョブ
Runnable job = () -> {
for (;;) {
try {
// ByteBufferの構築
ByteBuffer buf = allocator.alloc(10 * 1024 * 1024); // 10MiB
// ByteBufferの破棄
deallocator.dealloc(lastBufTLS.get());
// 最後に確保したByteBufferの保存
lastBufTLS.set(buf);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
};
IntFunction<Thread> makeThread = (idx) -> {
Thread t = new Thread(job);
t.setDaemon(false);
t.setName("bufferStress:" + idx);
return t;
};
IntStream.range(0, mxthread)
.mapToObj(makeThread)
.forEach(Thread::start);
}
/**
* ダイレクトバッファを早期に開放する.
* (Hadoopのソースコードから引用.)
*
* DirectByteBuffers are garbage collected by using a phantom reference and a
* reference queue. Every once a while, the JVM checks the reference queue and
* cleans the DirectByteBuffers. However, as this doesn't happen
* immediately after discarding all references to a DirectByteBuffer, it's
* easy to OutOfMemoryError yourself using DirectByteBuffers. This function
* explicitly calls the Cleaner method of a DirectByteBuffer.
*
* @see https://hbase.apache.org/0.94/apidocs/src-html/org/apache/hadoop/hbase/util/DirectMemoryUtils.html#line.80
* @param toBeDestroyed
* The DirectByteBuffer that will be "cleaned". Utilizes reflection.
*
*/
public static void destroyDirectByteBuffer(ByteBuffer toBeDestroyed) {
try {
Method cleanerMethod = toBeDestroyed.getClass().getMethod("cleaner");
cleanerMethod.setAccessible(true);
Object cleaner = cleanerMethod.invoke(toBeDestroyed);
Method cleanMethod = cleaner.getClass().getMethod("clean");
cleanMethod.setAccessible(true);
cleanMethod.invoke(cleaner);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
}
package jp.seraphyware.jmhexample;
import static java.nio.file.StandardOpenOption.*;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;
/**
* ファイルアクセスベンチマーク定義クラス(Double)
*
* @author seraphy
*/
public class FileBufferAccessDoubleBenchmark {
/**
* テスト中にスレッドごとベンチマークごとの状態を保持するインスタンス.
*
* @author seraphy
*/
protected static class BenchContextBase extends AbstractFileBenchContext {
public static final int reqSize = 1024 * 1024 * 10; // 10MiBytes
private double total;
protected BenchContextBase(ByteOrder byteOrder, int bufsiz) {
super(byteOrder, bufsiz);
}
/**
* テストデータファイルの作成
* @throws IOException
*/
@Override
protected Path initTempFile() throws IOException {
Path tempFile = Files.createTempFile("filebufferbench", ".tmp");
//System.out.println("★create tempFile=" + tempFile);
ByteBuffer buf = ByteBuffer.allocate(bufsiz);
buf.order(byteOrder);
total = 0d;
int capacity = buf.capacity();
long siz;
try (FileChannel channel = (FileChannel) Files
.newByteChannel(tempFile, CREATE, TRUNCATE_EXISTING, WRITE)) {
double idx = 0;
int mx = reqSize / capacity;
for (int loop = 0; loop < mx; loop++) {
buf.clear();
while (buf.position() < capacity) {
buf.putDouble(idx);
total += idx;
idx += 1;
}
buf.flip();
channel.write(buf);
}
siz = channel.size();
}
if (reqSize != siz) {
throw new RuntimeException();
}
//System.out.println("★total=" + total + "/size=" + siz);
return tempFile;
}
@Override
public void verify(Object actual) {
if ((Double) actual != total) {
throw new RuntimeException("actual=" + actual);
}
}
}
public static class BenchContextLE8k extends BenchContextBase {
public BenchContextLE8k() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 8);
}
}
public static class BenchContextBE8k extends BenchContextBase {
public BenchContextBE8k() {
super(ByteOrder.BIG_ENDIAN, 1024 * 8);
}
}
public static class BenchContextLE16 extends BenchContextBase {
public BenchContextLE16() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 16);
}
}
public static class BenchContextBE16 extends BenchContextBase {
public BenchContextBE16() {
super(ByteOrder.BIG_ENDIAN, 1024 * 16);
}
}
public static class BenchContextLE32 extends BenchContextBase {
public BenchContextLE32() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 32);
}
}
public static class BenchContextBE32 extends BenchContextBase {
public BenchContextBE32() {
super(ByteOrder.BIG_ENDIAN, 1024 * 32);
}
}
public static class BenchContextLE64 extends BenchContextBase {
public BenchContextLE64() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 64);
}
}
public static class BenchContextBE64 extends BenchContextBase {
public BenchContextBE64() {
super(ByteOrder.BIG_ENDIAN, 1024 * 64);
}
}
public static class BenchContextLE128 extends BenchContextBase {
public BenchContextLE128() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 128);
}
}
public static class BenchContextBE128 extends BenchContextBase {
public BenchContextBE128() {
super(ByteOrder.BIG_ENDIAN, 1024 * 128);
}
}
public static class BenchContextLE256 extends BenchContextBase {
public BenchContextLE256() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 256);
}
}
public static class BenchContextBE256 extends BenchContextBase {
public BenchContextBE256() {
super(ByteOrder.BIG_ENDIAN, 1024 * 256);
}
}
public static class BenchContextLE512 extends BenchContextBase {
public BenchContextLE512() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 512);
}
}
public static class BenchContextBE512 extends BenchContextBase {
public BenchContextBE512() {
super(ByteOrder.BIG_ENDIAN, 1024 * 512);
}
}
public static class BenchContextLE1m extends BenchContextBase {
public BenchContextLE1m() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 1024);
}
}
public static class BenchContextBE1m extends BenchContextBase {
public BenchContextBE1m() {
super(ByteOrder.BIG_ENDIAN, 1024 * 1024);
}
}
/**
* バイトバッファからdouble値を読み出すテスト
* @param buf
*/
private static double runByteBuffer(FileChannel channel, ByteBuffer buf)
throws IOException {
double total = 0;
for (;;) {
buf.clear();
int len = channel.read(buf);
if (len < 0) {
break;
}
buf.flip();
int limit = buf.limit();
while (buf.position() < limit) {
total += buf.getDouble();
}
}
return total;
}
private static void doBench(BenchContextBase ctx, ByteBuffer buf)
throws IOException {
try (FileChannel channel = (FileChannel) Files.newByteChannel(
ctx.getTempFile(), READ)) {
ctx.verify(runByteBuffer(channel, buf));
}
}
@Benchmark
public void testHeapBufferLE8k(BenchContextLE8k ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE8k(BenchContextLE8k ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferLE16(BenchContextLE16 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE16(BenchContextLE16 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferLE32(BenchContextLE32 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE32(BenchContextLE32 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferLE64(BenchContextLE64 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE64(BenchContextLE64 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferLE128(BenchContextLE128 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE128(BenchContextLE128 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferLE256(BenchContextLE256 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE256(BenchContextLE256 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferLE512(BenchContextLE512 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE512(BenchContextLE512 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferLE1m(BenchContextLE1m ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE1m(BenchContextLE1m ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE8k(BenchContextBE8k ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE8k(BenchContextBE8k ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE16(BenchContextBE16 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE16(BenchContextBE16 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE32(BenchContextBE32 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE32(BenchContextBE32 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE64(BenchContextBE64 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE64(BenchContextBE64 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE128(BenchContextBE128 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE128(BenchContextBE128 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE256(BenchContextBE256 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE256(BenchContextBE256 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE512(BenchContextBE512 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE512(BenchContextBE512 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE1m(BenchContextBE1m ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE1m(BenchContextBE1m ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
private static double readDoubles(InputStream is, int cnt) throws IOException {
double total = 0;
try (DataInputStream dis = new DataInputStream(is)) {
for (int idx = 0; idx < cnt; idx++) {
total += dis.readDouble();
}
}
return total;
}
@Benchmark
public void testOldBufferedIO8k(BenchContextBE1m ctx) throws IOException {
double total;
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(ctx.getTempFile().toFile()))) {
total = readDoubles(bis, BenchContextBase.reqSize / 8);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedNIO8k(BenchContextBE1m ctx) throws IOException {
double total;
try (BufferedInputStream bis = new BufferedInputStream(
Files.newInputStream(ctx.getTempFile()))) {
total = readDoubles(bis, BenchContextBase.reqSize / 8);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedIO16(BenchContextBE1m ctx) throws IOException {
double total;
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(ctx.getTempFile().toFile()), 1024 * 16)) {
total = readDoubles(bis, BenchContextBase.reqSize / 8);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedNIO16(BenchContextBE1m ctx) throws IOException {
double total;
try (BufferedInputStream bis = new BufferedInputStream(
Files.newInputStream(ctx.getTempFile()), 1024 * 16)) {
total = readDoubles(bis, BenchContextBase.reqSize / 8);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedIO32(BenchContextBE1m ctx) throws IOException {
double total;
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(ctx.getTempFile().toFile()), 1024 * 32)) {
total = readDoubles(bis, BenchContextBase.reqSize / 8);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedNIO32(BenchContextBE1m ctx) throws IOException {
double total;
try (BufferedInputStream bis = new BufferedInputStream(
Files.newInputStream(ctx.getTempFile()), 1024 * 32)) {
total = readDoubles(bis, BenchContextBase.reqSize / 8);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedIO64(BenchContextBE1m ctx) throws IOException {
double total;
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(ctx.getTempFile().toFile()), 1024 * 64)) {
total = readDoubles(bis, BenchContextBase.reqSize / 8);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedNIO64(BenchContextBE1m ctx) throws IOException {
double total;
try (BufferedInputStream bis = new BufferedInputStream(
Files.newInputStream(ctx.getTempFile()), 1024 * 64)) {
total = readDoubles(bis, BenchContextBase.reqSize / 8);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedIO128k(BenchContextBE1m ctx) throws IOException {
double total;
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(ctx.getTempFile().toFile()), 1024 * 128)) {
total = readDoubles(bis, BenchContextBase.reqSize / 8);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedNIO128k(BenchContextBE1m ctx) throws IOException {
double total;
try (BufferedInputStream bis = new BufferedInputStream(
Files.newInputStream(ctx.getTempFile()), 1024 * 128)) {
total = readDoubles(bis, BenchContextBase.reqSize / 8);
}
ctx.verify(total);
}
@Benchmark
public void testOldIO(BenchContextBE1m ctx) throws IOException {
double total;
try (InputStream bis = new FileInputStream(
ctx.getTempFile().toFile())) {
total = readDoubles(bis, BenchContextBase.reqSize / 8);
}
ctx.verify(total);
}
@Benchmark
public void testOldNIO(BenchContextBE1m ctx) throws IOException {
double total;
try (InputStream bis = Files.newInputStream(ctx.getTempFile())) {
total = readDoubles(bis, BenchContextBase.reqSize / 8);
}
ctx.verify(total);
}
/**
* IDEから実行する場合は、
* まず先にmvn package等を実行してサポートファイル類を生成しておく必要がある.
* (少なくともクラスまたはメソッドのシグネチャを変更追加するたびにmvnでビルドする必要がある。)
* その後、IDEから、このメイン関数を呼び出すことができるようになる.
* @param args
* @throws RunnerException
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
// 実行すべきベンチマークが定義された"クラス名.メソッド名"を正規表現で指定
.include(FileBufferAccessDoubleBenchmark.class.getSimpleName())
// ウォームアップイテレーション数 "-wi"オプションに相当
.warmupIterations(1)
// イテレーション数 "-i"オプションに相当
.measurementIterations(1)
// フォーク数 "-f"オプションに相当
.forks(1)
// 1回のテストメソッド実行時間 "-r"オプションに相当
.measurementTime(TimeValue.seconds(1))
// 同時実行スレッド数 (1測定毎のスレッド数 (サンプル数が増える))
// .threads(Math.max(1, Runtime.getRuntime().availableProcessors() / 2))
// 測定するモード = スループット
//.timeUnit(TimeUnit.MICROSECONDS)
//.mode(Mode.SampleTime)
.build();
new Runner(opt).run();
}
}
package jp.seraphyware.jmhexample;
import static java.nio.file.StandardOpenOption.*;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;
/**
* ファイルアクセスベンチマーク定義クラス(Int)
*
* @author seraphy
*/
public class FileBufferAccessIntBenchmark {
public static class BenchContextBase extends AbstractFileBenchContext {
public static final int reqSize = 1024 * 1024 * 10; // 10MiBytes
private long total;
protected BenchContextBase(ByteOrder byteOrder, int bufsiz) {
super(byteOrder, bufsiz);
}
/**
* テストデータファイルの作成
* @throws IOException
*/
@Override
protected Path initTempFile() throws IOException {
Path tempFile = Files.createTempFile("filebufferbench", ".tmp");
//System.out.println("★create tempFile=" + tempFile);
ByteBuffer buf = ByteBuffer.allocate(bufsiz);
buf.order(byteOrder);
total = 0;
int capacity = buf.capacity();
long siz;
try (FileChannel channel = (FileChannel) Files
.newByteChannel(tempFile, CREATE, TRUNCATE_EXISTING, WRITE)) {
int idx = 0;
int mx = reqSize / capacity;
for (int loop = 0; loop < mx; loop++) {
buf.clear();
while (buf.position() < capacity) {
buf.putInt(idx);
total += idx;
idx += 1;
}
buf.flip();
channel.write(buf);
}
siz = channel.size();
}
if (reqSize != siz) {
throw new RuntimeException();
}
//System.out.println("★total=" + total + "/size=" + siz);
return tempFile;
}
@Override
public void verify(Object actual) {
if ((Long) actual != total) {
throw new RuntimeException("actual=" + actual);
}
}
}
public static class BenchContextLE8k extends BenchContextBase {
public BenchContextLE8k() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 8);
}
}
public static class BenchContextBE8k extends BenchContextBase {
public BenchContextBE8k() {
super(ByteOrder.BIG_ENDIAN, 1024 * 8);
}
}
public static class BenchContextLE16 extends BenchContextBase {
public BenchContextLE16() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 16);
}
}
public static class BenchContextBE16 extends BenchContextBase {
public BenchContextBE16() {
super(ByteOrder.BIG_ENDIAN, 1024 * 16);
}
}
public static class BenchContextLE32 extends BenchContextBase {
public BenchContextLE32() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 32);
}
}
public static class BenchContextBE32 extends BenchContextBase {
public BenchContextBE32() {
super(ByteOrder.BIG_ENDIAN, 1024 * 32);
}
}
public static class BenchContextLE64 extends BenchContextBase {
public BenchContextLE64() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 64);
}
}
public static class BenchContextBE64 extends BenchContextBase {
public BenchContextBE64() {
super(ByteOrder.BIG_ENDIAN, 1024 * 64);
}
}
public static class BenchContextLE128 extends BenchContextBase {
public BenchContextLE128() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 128);
}
}
public static class BenchContextBE128 extends BenchContextBase {
public BenchContextBE128() {
super(ByteOrder.BIG_ENDIAN, 1024 * 128);
}
}
public static class BenchContextLE256 extends BenchContextBase {
public BenchContextLE256() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 256);
}
}
public static class BenchContextBE256 extends BenchContextBase {
public BenchContextBE256() {
super(ByteOrder.BIG_ENDIAN, 1024 * 256);
}
}
public static class BenchContextLE512 extends BenchContextBase {
public BenchContextLE512() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 512);
}
}
public static class BenchContextBE512 extends BenchContextBase {
public BenchContextBE512() {
super(ByteOrder.BIG_ENDIAN, 1024 * 512);
}
}
public static class BenchContextLE1m extends BenchContextBase {
public BenchContextLE1m() {
super(ByteOrder.LITTLE_ENDIAN, 1024 * 1024);
}
}
public static class BenchContextBE1m extends BenchContextBase {
public BenchContextBE1m() {
super(ByteOrder.BIG_ENDIAN, 1024 * 1024);
}
}
/**
* バイトバッファからint値を読み出すテスト
* @param buf
*/
private static long runByteBuffer(FileChannel channel, ByteBuffer buf)
throws IOException {
long total = 0;
for (;;) {
buf.clear();
int len = channel.read(buf);
if (len < 0) {
break;
}
buf.flip();
int limit = buf.limit();
while (buf.position() < limit) {
total += buf.getInt();
}
}
return total;
}
private static void doBench(AbstractFileBenchContext ctx, ByteBuffer buf)
throws IOException {
try (FileChannel channel = (FileChannel) Files.newByteChannel(
ctx.getTempFile(), READ)) {
ctx.verify(runByteBuffer(channel, buf));
}
}
@Benchmark
public void testHeapBufferLE8k(BenchContextLE8k ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE8k(BenchContextLE8k ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferLE16(BenchContextLE16 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE16(BenchContextLE16 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferLE32(BenchContextLE32 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE32(BenchContextLE32 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferLE64(BenchContextLE64 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE64(BenchContextLE64 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferLE128(BenchContextLE128 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE128(BenchContextLE128 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferLE256(BenchContextLE256 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE256(BenchContextLE256 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferLE512(BenchContextLE512 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE512(BenchContextLE512 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferLE1m(BenchContextLE1m ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferLE1m(BenchContextLE1m ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE8k(BenchContextBE8k ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE8k(BenchContextBE8k ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE16(BenchContextBE16 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE16(BenchContextBE16 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE32(BenchContextBE32 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE32(BenchContextBE32 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE64(BenchContextBE64 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE64(BenchContextBE64 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE128(BenchContextBE128 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE128(BenchContextBE128 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE256(BenchContextBE256 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE256(BenchContextBE256 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE512(BenchContextBE512 ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE512(BenchContextBE512 ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
@Benchmark
public void testHeapBufferBE1m(BenchContextBE1m ctx) throws IOException {
doBench(ctx, ctx.getBufHeap());
}
@Benchmark
public void testDirectBufferBE1m(BenchContextBE1m ctx) throws IOException {
doBench(ctx, ctx.getBufDirect());
}
private static long readInts(InputStream is, int cnt) throws IOException {
long total = 0;
try (DataInputStream dis = new DataInputStream(is)) {
for (int idx = 0; idx < cnt; idx++) {
total += dis.readInt();
}
}
return total;
}
@Benchmark
public void testOldBufferedIO8k(BenchContextBE1m ctx) throws IOException {
long total;
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(ctx.getTempFile().toFile()))) {
total = readInts(bis, BenchContextBase.reqSize / 4);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedNIO8k(BenchContextBE1m ctx) throws IOException {
long total;
try (BufferedInputStream bis = new BufferedInputStream(
Files.newInputStream(ctx.getTempFile()))) {
total = readInts(bis, BenchContextBase.reqSize / 4);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedIO16k(BenchContextBE1m ctx) throws IOException {
long total;
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(ctx.getTempFile().toFile()), 16 * 1024)) {
total = readInts(bis, BenchContextBase.reqSize / 4);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedNIO16k(BenchContextBE1m ctx) throws IOException {
long total;
try (BufferedInputStream bis = new BufferedInputStream(
Files.newInputStream(ctx.getTempFile()), 16 * 1024)) {
total = readInts(bis, BenchContextBase.reqSize / 4);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedIO32k(BenchContextBE1m ctx) throws IOException {
long total;
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(ctx.getTempFile().toFile()), 32 * 1024)) {
total = readInts(bis, BenchContextBase.reqSize / 4);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedNIO32k(BenchContextBE1m ctx) throws IOException {
long total;
try (BufferedInputStream bis = new BufferedInputStream(
Files.newInputStream(ctx.getTempFile()), 32 * 1024)) {
total = readInts(bis, BenchContextBase.reqSize / 4);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedIO64k(BenchContextBE1m ctx) throws IOException {
long total;
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(ctx.getTempFile().toFile()), 64 * 1024)) {
total = readInts(bis, BenchContextBase.reqSize / 4);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedNIO64k(BenchContextBE1m ctx) throws IOException {
long total;
try (BufferedInputStream bis = new BufferedInputStream(
Files.newInputStream(ctx.getTempFile()), 64 * 1024)) {
total = readInts(bis, BenchContextBase.reqSize / 4);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedIO128k(BenchContextBE1m ctx) throws IOException {
long total;
try (BufferedInputStream bis = new BufferedInputStream(
new FileInputStream(ctx.getTempFile().toFile()), 128 * 1024)) {
total = readInts(bis, BenchContextBase.reqSize / 4);
}
ctx.verify(total);
}
@Benchmark
public void testOldBufferedNIO128k(BenchContextBE1m ctx) throws IOException {
long total;
try (BufferedInputStream bis = new BufferedInputStream(
Files.newInputStream(ctx.getTempFile()), 128 * 1024)) {
total = readInts(bis, BenchContextBase.reqSize / 4);
}
ctx.verify(total);
}
@Benchmark
public void testOldPlainIO(BenchContextBE1m ctx) throws IOException {
long total;
try (InputStream bis = new FileInputStream(
ctx.getTempFile().toFile())) {
total = readInts(bis, BenchContextBase.reqSize / 4);
}
ctx.verify(total);
}
@Benchmark
public void testOldPlainNIO(BenchContextBE1m ctx) throws IOException {
long total;
try (InputStream bis = Files.newInputStream(ctx.getTempFile())) {
total = readInts(bis, BenchContextBase.reqSize / 4);
}
ctx.verify(total);
}
/**
* IDEから実行する場合は、
* まず先にmvn package等を実行してサポートファイル類を生成しておく必要がある.
* (少なくともクラスまたはメソッドのシグネチャを変更追加するたびにmvnでビルドする必要がある。)
* その後、IDEから、このメイン関数を呼び出すことができるようになる.
* @param args
* @throws RunnerException
*/
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
// 実行すべきベンチマークが定義された"クラス名.メソッド名"を正規表現で指定
.include("FileBufferAccess.+Benchmark")
//.exclude(FileBufferAccessIntBenchmark.class.getSimpleName() + ".testOld")
// ウォームアップイテレーション数 "-wi"オプションに相当
.warmupIterations(10)
// イテレーション数 "-i"オプションに相当
.measurementIterations(10)
// フォーク数 "-f"オプションに相当
.forks(1)
// 1回のテストメソッド実行時間 "-r"オプションに相当
.measurementTime(TimeValue.seconds(1))
// 同時実行スレッド数 (1測定毎のスレッド数 (サンプル数が増える))
// .threads(Math.max(1, Runtime.getRuntime().availableProcessors() / 2))
// 測定するモード = スループット
//.timeUnit(TimeUnit.MICROSECONDS)
//.mode(Mode.SampleTime)
.build();
new Runner(opt).run();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment