/* * [TestBufferedRatio.java] * * Summary: Discover best way to allocate buffers. * * Copyright: (c) 2014-2017 Roedy Green, Canadian Mind Products, http://mindprod.com * * Licence: This software may be copied and used freely for any purpose but military. * http://mindprod.com/contact/nonmil.html * * Requires: JDK 1.8+ * * Created with: JetBrains IntelliJ IDEA IDE http://www.jetbrains.com/idea/ * * Version History: * 1.0 2014-05-10 initial version */ package com.mindprod.example; import com.mindprod.common18.EIO; import com.mindprod.hunkio.HunkIO; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.text.DecimalFormat; import java.util.Random; import static java.lang.System.*; /** * Discover best way to allocate buffers. * * @author Roedy Green, Canadian Mind Products * @version 1.0 2014-05-10 initial version * @since 2014-05-10 */ public final class TestBufferedRatio { /** * how many benchmark trials */ private static final int TRIALS = 5; /** * size of test file in chars */ private static final long FILESIZE = 200L * 1024 * 1024; /** * size of line in chars including \n */ private static final int LINESIZE = 100; /** * allows us to display seconds to zero decimal places. */ private static final DecimalFormat df0 = new DecimalFormat( "###,##0" ); /** * allows us to display seconds to two decimal places. */ private static final DecimalFormat df2 = new DecimalFormat( "###,##0.00" ); /** * chars we allow in our random data */ private static final String ALLOWED = "abcdefghijklmnopqrstuvwxyzABCDEFGHJKMLMOPQRSTUVWXYZ 0123456789 +!@$#$%^&*()_-?/|\\\n"; /** * character set to use */ private static final Charset charset = Charset.forName( "UTF-16" ); /** * sample date file we read to test */ private static File sampleDataFile; /** * display nanoseconds as seconds to two decimal places. * * @param nanoseconds how many nanoseconds ( billionths of a second ) * * @return displayable String. */ private static String asSeconds( double nanoseconds ) { return df2.format( nanoseconds / 1000000000d ) + " seconds"; } /** * generate 100K of sample data in a temporary file. */ private static void generateSampleData() throws IOException { // place on hard disk, not SSD HunkIO.createTempFile( "temp_", ".tmp", new File( "H:/temp" ) ); sampleDataFile = File.createTempFile( "temp_", ".tmp" ); final Random wheel = new Random(); final BufferedWriter bw = EIO.getBufferedWriter( sampleDataFile, 256 * 1024, charset ); char[] line = new char[ LINESIZE - 1 ]; for ( int i = 0; i < ( FILESIZE / LINESIZE ); i++ ) { for ( int j = 0; j < line.length; j++ ) { line[ j ] = ALLOWED.charAt( ( wheel.nextInt() & Integer.MAX_VALUE ) % ALLOWED.length() ); } bw.write( line ); // encoding irrelevant here bw.write( "\n" ); } bw.close(); } /** * read test file with a withBufferedReader * * @param ratio 0.6 means give 60% of buffer space to the inputwriter and 40% to the inputStream * @param buffsize total buffer space to allocate in bytes. * * @throws java.io.IOException if trouble reading test file */ private static void withBufferedReader( double ratio, int buffsize ) throws IOException { assert .1 <= ratio && ratio <= .9 : "ratio must be in range [0.1,0.9]."; long prevTime = System.nanoTime(); final FileInputStream fis = new FileInputStream( sampleDataFile ); final BufferedInputStream bis = new BufferedInputStream( fis, ( int ) ( buffsize * ( 1 - ratio ) ) ); /* buffsize in bytes */ final InputStreamReader isr = new InputStreamReader( bis, charset ); final BufferedReader ibr = new BufferedReader( isr, ( int ) ( buffsize * ratio / 2 /* in chars */ ) ); String line; //noinspection UnusedAssignment while ( ( line = ibr.readLine() ) != null ) { // empty loop } ibr.close(); out.println( "BufferedReader backed with BufferedInputStream ratio " + df2.format( ratio ) + " buffsize " + buffsize + " bytes " + asSeconds( System.nanoTime() - prevTime ) ); } /** * read test file with a HunkIO * * @throws java.io.IOException if trouble reading test file */ private static void withHunkIO() throws IOException { long prevTime = System.nanoTime(); @SuppressWarnings( "UnusedAssignment" ) String contents = HunkIO.readEntireFile( sampleDataFile, charset ); out.println( "HunkIO " + asSeconds( System.nanoTime() - prevTime ) ); } /** * read test file with a withBufferedReader * * @param buffsize total buffer space to allocate in bytes. * * @throws java.io.IOException if trouble reading test file */ private static void withPlainBufferedReader( int buffsize ) throws IOException { long prevTime = System.nanoTime(); // cannot specify encoding. final BufferedReader ibr = new BufferedReader( new FileReader( sampleDataFile ), buffsize / 2 ); String line; //noinspection UnusedAssignment while ( ( line = ibr.readLine() ) != null ) { // empty loop } ibr.close(); out.println( "Unbacked BufferedReader default encoding buffsize " + buffsize + " bytes " + asSeconds( System.nanoTime() - prevTime ) ); } /** * Benchmark three ways of buffered writing and three ways of buffered reading. * * @param args not used * * @throws java.io.IOException if problem writing or reading the test file. */ public static void main( String[] args ) throws IOException { generateSampleData(); out.println( "Using a random sample data file of " + df0.format( FILESIZE ) + " chars " + df0.format( sampleDataFile.length() ) + " bytes." ); out.println( "Using charset " + charset ); int buffSize = 64 * 1024; out.println( "Using aggregate buffersize of " + df0.format( buffSize ) + " bytes." ); for ( int i = 0; i < TRIALS; i++ ) { withPlainBufferedReader( buffSize ); withBufferedReader( .1, buffSize ); withBufferedReader( .2, buffSize ); withBufferedReader( .3, buffSize ); withBufferedReader( .4, buffSize ); withBufferedReader( .5, buffSize ); withBufferedReader( .6, buffSize ); withBufferedReader( .7, buffSize ); withBufferedReader( .8, buffSize ); withBufferedReader( .9, buffSize ); withHunkIO(); } //noinspection ResultOfMethodCallIgnored sampleDataFile.delete(); // the results show the HunkIO is fastest. Next is BufferedReader with a ratio of .5 // and last is a Plain BufferedReader. The optimum ratio is the same no matter what the buffer size. } }