import java.io.*;


/** Tests the performance of alligned writes versus non-alligned writes with
 *  various buffer sizes. Perfoms writes on each buffer size N times and prints the 
 *  amount of time it takes to write single buffer on average in alligned Write Vs
 *  Non-Alligned on a preallocated file.
 *  To run :  java allignWritePerfTest <file Name>  <No Of Writes>
 */
public class allignWritePerfTest{

	public static void main(String[] args)
	{

		if(args.length < 2)
		{
			System.out.println("java allignWritePefTest <file Name> <No Of Writes>");
			return;
		}

		String filepath = args[0];
		int nWrites  = (Integer.valueOf(args[1])).intValue();
		int bufferSizes[] = {512, 256 , 128 , 64, 32, 16 , 12 , 10 , 8 , 6, 4, 2, 1};

		System.out.println("(Buffer-Size(K) " + "| Alligned Write(msec) " +  "|NonAlligned Write(msec))");
		System.out.println();
		for(int k = 0 ; k < bufferSizes.length; k++)
		{	
			int bufferSize = bufferSizes[k] * 1024 ;
			byte[] dataBuffer = new byte[bufferSize];
			
			for(int i =0 ; i < bufferSize ; i++)
				dataBuffer[i] = (byte) i;
			

			// perform alligned writes
			double allignedWriteTime = measureWriteTime(filepath,dataBuffer, nWrites,true);

			// non alligned writes
			double NonAllignedWriteTime = measureWriteTime(filepath, dataBuffer, nWrites, false);

			System.out.println(bufferSizes[k] +" |  " + allignedWriteTime +
							   "  |  " + NonAllignedWriteTime );

		}
	}


	// returns the amount of time taken to write the given buffer   
	private static double  measureWriteTime(String filepath, byte dataBuffer[], 
											int nWrites, boolean alligned)
	{			
		double writeTime = -1;
		File fl = new File(filepath);
		try{
			
			//delete the file
			if(fl.exists())
			{
				if(!fl.delete())
				{
					System.out.println("Error: File Could Not Be Deleted:" + filepath);
					return -1;
				}
			}

			//create a  new File 
			if(!fl.createNewFile())
			{
				System.out.println("New File Creation Error:" + filepath);
				return -1;
			}
					
			//preallocate the file and fill it up with zeros
			preAllocate(filepath, dataBuffer.length, nWrites);
			writeTime = doWrites(filepath, dataBuffer, nWrites, alligned);
		
		}catch(IOException ioe)
		{
			ioe.printStackTrace();
		}

		fl=null; //release the file handle
		return writeTime;
	}

	
	//mesure the time taken to write a given buffer
	private static double doWrites(String filename, byte[] buffer, 
								   int nWrites,  boolean aligned)
		throws IOException 
	{
        RandomAccessFile frs = new RandomAccessFile(filename, "rws");

		//in case of non alligned writes, seek to random
		//position in the first sector, it will make the 
		//write request non-alligned on sector boundaries.
		if(!aligned)
			frs.seek(24);

		double before = (double)System.currentTimeMillis();
		for(int i = 0 ; i < nWrites ; i++)
			frs.write(buffer);
		double after = (double)System.currentTimeMillis();
        frs.close();
		double timetakeForWrite = (after - before)/nWrites;
		return  timetakeForWrite;
    }

		
	//preallocate the file by filling it up with zeros.
	private static void  preAllocate(String filename, int bufferSize, int nWrites)
		throws IOException 
	{
		byte[] buffer = new byte[bufferSize];
		RandomAccessFile frs = new RandomAccessFile(filename, "rw");
		FileDescriptor fd = frs.getFD();
		for(int i = 0; i < nWrites ; i++)
		{
			frs.write(buffer);
		}

		fd.sync();
		double after = (double)System.currentTimeMillis();
        frs.close();
    }

}















