Home | History | Annotate | Download | only in SevenZip
      1 package SevenZip;
      2 
      3 import java.io.ByteArrayOutputStream;
      4 import java.io.ByteArrayInputStream;
      5 import java.io.IOException;
      6 
      7 public class LzmaBench
      8 {
      9 	static final int kAdditionalSize = (1 << 21);
     10 	static final int kCompressedAdditionalSize = (1 << 10);
     11 
     12 	static class CRandomGenerator
     13 	{
     14 		int A1;
     15 		int A2;
     16 		public CRandomGenerator() { Init(); }
     17 		public void Init() { A1 = 362436069; A2 = 521288629; }
     18 		public int GetRnd()
     19 		{
     20 			return
     21 				((A1 = 36969 * (A1 & 0xffff) + (A1 >>> 16)) << 16) ^
     22 				((A2 = 18000 * (A2 & 0xffff) + (A2 >>> 16)));
     23 		}
     24 	};
     25 
     26 	static class CBitRandomGenerator
     27 	{
     28 		CRandomGenerator RG = new CRandomGenerator();
     29 		int Value;
     30 		int NumBits;
     31 		public void Init()
     32 		{
     33 			Value = 0;
     34 			NumBits = 0;
     35 		}
     36 		public int GetRnd(int numBits)
     37 		{
     38 			int result;
     39 			if (NumBits > numBits)
     40 			{
     41 				result = Value & ((1 << numBits) - 1);
     42 				Value >>>= numBits;
     43 				NumBits -= numBits;
     44 				return result;
     45 			}
     46 			numBits -= NumBits;
     47 			result = (Value << numBits);
     48 			Value = RG.GetRnd();
     49 			result |= Value & (((int)1 << numBits) - 1);
     50 			Value >>>= numBits;
     51 			NumBits = 32 - numBits;
     52 			return result;
     53 		}
     54 	};
     55 
     56 	static class CBenchRandomGenerator
     57 	{
     58 		CBitRandomGenerator RG = new CBitRandomGenerator();
     59 		int Pos;
     60 		int Rep0;
     61 
     62 		public int BufferSize;
     63 		public byte[] Buffer = null;
     64 
     65 		public CBenchRandomGenerator() { }
     66 		public void Set(int bufferSize)
     67 		{
     68 			Buffer = new byte[bufferSize];
     69 			Pos = 0;
     70 			BufferSize = bufferSize;
     71 		}
     72 		int GetRndBit() { return RG.GetRnd(1); }
     73 		int GetLogRandBits(int numBits)
     74 		{
     75 			int len = RG.GetRnd(numBits);
     76 			return RG.GetRnd((int)len);
     77 		}
     78 		int GetOffset()
     79 		{
     80 			if (GetRndBit() == 0)
     81 				return GetLogRandBits(4);
     82 			return (GetLogRandBits(4) << 10) | RG.GetRnd(10);
     83 		}
     84 		int GetLen1() { return RG.GetRnd(1 + (int)RG.GetRnd(2)); }
     85 		int GetLen2() { return RG.GetRnd(2 + (int)RG.GetRnd(2)); }
     86 		public void Generate()
     87 		{
     88 			RG.Init();
     89 			Rep0 = 1;
     90 			while (Pos < BufferSize)
     91 			{
     92 				if (GetRndBit() == 0 || Pos < 1)
     93 					Buffer[Pos++] = (byte)(RG.GetRnd(8));
     94 				else
     95 				{
     96 					int len;
     97 					if (RG.GetRnd(3) == 0)
     98 						len = 1 + GetLen1();
     99 					else
    100 					{
    101 						do
    102 							Rep0 = GetOffset();
    103 						while (Rep0 >= Pos);
    104 						Rep0++;
    105 						len = 2 + GetLen2();
    106 					}
    107 					for (int i = 0; i < len && Pos < BufferSize; i++, Pos++)
    108 						Buffer[Pos] = Buffer[Pos - Rep0];
    109 				}
    110 			}
    111 		}
    112 	};
    113 
    114 	static class CrcOutStream extends java.io.OutputStream
    115 	{
    116 		public CRC CRC = new CRC();
    117 
    118 		public void Init()
    119 		{
    120 			CRC.Init();
    121 		}
    122 		public int GetDigest()
    123 		{
    124 			return CRC.GetDigest();
    125 		}
    126 		public void write(byte[] b)
    127 		{
    128 			CRC.Update(b);
    129 		}
    130 		public void write(byte[] b, int off, int len)
    131 		{
    132 			CRC.Update(b, off, len);
    133 		}
    134 		public void write(int b)
    135 		{
    136 			CRC.UpdateByte(b);
    137 		}
    138 	};
    139 
    140 	static class MyOutputStream extends java.io.OutputStream
    141 	{
    142 		byte[] _buffer;
    143 		int _size;
    144 		int _pos;
    145 
    146 		public MyOutputStream(byte[] buffer)
    147 		{
    148 			_buffer = buffer;
    149 			_size = _buffer.length;
    150 		}
    151 
    152 		public void reset()
    153 		{
    154 			_pos = 0;
    155 		}
    156 
    157 		public void write(int b) throws IOException
    158 		{
    159 			if (_pos >= _size)
    160 				throw new IOException("Error");
    161 			_buffer[_pos++] = (byte)b;
    162 		}
    163 
    164 		public int size()
    165 		{
    166 			return _pos;
    167 		}
    168 	};
    169 
    170 	static class MyInputStream extends java.io.InputStream
    171 	{
    172 		byte[] _buffer;
    173 		int _size;
    174 		int _pos;
    175 
    176 		public MyInputStream(byte[] buffer, int size)
    177 		{
    178 			_buffer = buffer;
    179 			_size = size;
    180 		}
    181 
    182 		public void reset()
    183 		{
    184 			_pos = 0;
    185 		}
    186 
    187 		public int read()
    188 		{
    189 			if (_pos >= _size)
    190 				return -1;
    191 			return _buffer[_pos++] & 0xFF;
    192 		}
    193 	};
    194 
    195 	static class CProgressInfo implements ICodeProgress
    196 	{
    197 		public long ApprovedStart;
    198 		public long InSize;
    199 		public long Time;
    200 		public void Init()
    201 		{ InSize = 0; }
    202 		public void SetProgress(long inSize, long outSize)
    203 		{
    204 			if (inSize >= ApprovedStart && InSize == 0)
    205 			{
    206 				Time = System.currentTimeMillis();
    207 				InSize = inSize;
    208 			}
    209 		}
    210 	}
    211 	static final int kSubBits = 8;
    212 
    213 	static int GetLogSize(int size)
    214 	{
    215 		for (int i = kSubBits; i < 32; i++)
    216 			for (int j = 0; j < (1 << kSubBits); j++)
    217 				if (size <= ((1) << i) + (j << (i - kSubBits)))
    218 					return (i << kSubBits) + j;
    219 		return (32 << kSubBits);
    220 	}
    221 
    222 	static long MyMultDiv64(long value, long elapsedTime)
    223 	{
    224 		long freq = 1000; // ms
    225 		long elTime = elapsedTime;
    226 		while (freq > 1000000)
    227 		{
    228 			freq >>>= 1;
    229 			elTime >>>= 1;
    230 		}
    231 		if (elTime == 0)
    232 			elTime = 1;
    233 		return value * freq / elTime;
    234 	}
    235 
    236 	static long GetCompressRating(int dictionarySize, long elapsedTime, long size)
    237 	{
    238 		long t = GetLogSize(dictionarySize) - (18 << kSubBits);
    239 		long numCommandsForOne = 1060 + ((t * t * 10) >> (2 * kSubBits));
    240 		long numCommands = (long)(size) * numCommandsForOne;
    241 		return MyMultDiv64(numCommands, elapsedTime);
    242 	}
    243 
    244 	static long GetDecompressRating(long elapsedTime, long outSize, long inSize)
    245 	{
    246 		long numCommands = inSize * 220 + outSize * 20;
    247 		return MyMultDiv64(numCommands, elapsedTime);
    248 	}
    249 
    250 	static long GetTotalRating(
    251 			int dictionarySize,
    252 			long elapsedTimeEn, long sizeEn,
    253 			long elapsedTimeDe,
    254 			long inSizeDe, long outSizeDe)
    255 	{
    256 		return (GetCompressRating(dictionarySize, elapsedTimeEn, sizeEn) +
    257 				GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2;
    258 	}
    259 
    260 	static void PrintValue(long v)
    261 	{
    262 		String s = "";
    263 		s += v;
    264 		for (int i = 0; i + s.length() < 6; i++)
    265 			System.out.print(" ");
    266 		System.out.print(s);
    267 	}
    268 
    269 	static void PrintRating(long rating)
    270 	{
    271 		PrintValue(rating / 1000000);
    272 		System.out.print(" MIPS");
    273 	}
    274 
    275 	static void PrintResults(
    276 			int dictionarySize,
    277 			long elapsedTime,
    278 			long size,
    279 			boolean decompressMode, long secondSize)
    280 	{
    281 		long speed = MyMultDiv64(size, elapsedTime);
    282 		PrintValue(speed / 1024);
    283 		System.out.print(" KB/s  ");
    284 		long rating;
    285 		if (decompressMode)
    286 			rating = GetDecompressRating(elapsedTime, size, secondSize);
    287 		else
    288 			rating = GetCompressRating(dictionarySize, elapsedTime, size);
    289 		PrintRating(rating);
    290 	}
    291 
    292 	static public int LzmaBenchmark(int numIterations, int dictionarySize) throws Exception
    293 	{
    294 		if (numIterations <= 0)
    295 			return 0;
    296 		if (dictionarySize < (1 << 18))
    297 		{
    298 			System.out.println("\nError: dictionary size for benchmark must be >= 18 (256 KB)");
    299 			return 1;
    300 		}
    301 		System.out.print("\n       Compressing                Decompressing\n\n");
    302 
    303 		SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
    304 		SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
    305 
    306 		if (!encoder.SetDictionarySize(dictionarySize))
    307 			throw new Exception("Incorrect dictionary size");
    308 
    309 		int kBufferSize = dictionarySize + kAdditionalSize;
    310 		int kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;
    311 
    312 		ByteArrayOutputStream propStream = new ByteArrayOutputStream();
    313 		encoder.WriteCoderProperties(propStream);
    314 		byte[] propArray = propStream.toByteArray();
    315 		decoder.SetDecoderProperties(propArray);
    316 
    317 		CBenchRandomGenerator rg = new CBenchRandomGenerator();
    318 
    319 		rg.Set(kBufferSize);
    320 		rg.Generate();
    321 		CRC crc = new CRC();
    322 		crc.Init();
    323 		crc.Update(rg.Buffer, 0, rg.BufferSize);
    324 
    325 		CProgressInfo progressInfo = new CProgressInfo();
    326 		progressInfo.ApprovedStart = dictionarySize;
    327 
    328 		long totalBenchSize = 0;
    329 		long totalEncodeTime = 0;
    330 		long totalDecodeTime = 0;
    331 		long totalCompressedSize = 0;
    332 
    333 		MyInputStream inStream = new MyInputStream(rg.Buffer, rg.BufferSize);
    334 
    335 		byte[] compressedBuffer = new byte[kCompressedBufferSize];
    336 		MyOutputStream compressedStream = new MyOutputStream(compressedBuffer);
    337 		CrcOutStream crcOutStream = new CrcOutStream();
    338 		MyInputStream inputCompressedStream = null;
    339 		int compressedSize = 0;
    340 		for (int i = 0; i < numIterations; i++)
    341 		{
    342 			progressInfo.Init();
    343 			inStream.reset();
    344 			compressedStream.reset();
    345 			encoder.Code(inStream, compressedStream, -1, -1, progressInfo);
    346 			long encodeTime = System.currentTimeMillis() - progressInfo.Time;
    347 
    348 			if (i == 0)
    349 			{
    350 				compressedSize = compressedStream.size();
    351 				inputCompressedStream = new MyInputStream(compressedBuffer, compressedSize);
    352 			}
    353 			else if (compressedSize != compressedStream.size())
    354 				throw (new Exception("Encoding error"));
    355 
    356 			if (progressInfo.InSize == 0)
    357 				throw (new Exception("Internal ERROR 1282"));
    358 
    359 			long decodeTime = 0;
    360 			for (int j = 0; j < 2; j++)
    361 			{
    362 				inputCompressedStream.reset();
    363 				crcOutStream.Init();
    364 
    365 				long outSize = kBufferSize;
    366 				long startTime = System.currentTimeMillis();
    367 				if (!decoder.Code(inputCompressedStream, crcOutStream, outSize))
    368 					throw (new Exception("Decoding Error"));;
    369 				decodeTime = System.currentTimeMillis() - startTime;
    370 				if (crcOutStream.GetDigest() != crc.GetDigest())
    371 					throw (new Exception("CRC Error"));
    372 			}
    373 			long benchSize = kBufferSize - (long)progressInfo.InSize;
    374 			PrintResults(dictionarySize, encodeTime, benchSize, false, 0);
    375 			System.out.print("     ");
    376 			PrintResults(dictionarySize, decodeTime, kBufferSize, true, compressedSize);
    377 			System.out.println();
    378 
    379 			totalBenchSize += benchSize;
    380 			totalEncodeTime += encodeTime;
    381 			totalDecodeTime += decodeTime;
    382 			totalCompressedSize += compressedSize;
    383 		}
    384 		System.out.println("---------------------------------------------------");
    385 		PrintResults(dictionarySize, totalEncodeTime, totalBenchSize, false, 0);
    386 		System.out.print("     ");
    387 		PrintResults(dictionarySize, totalDecodeTime,
    388 				kBufferSize * (long)numIterations, true, totalCompressedSize);
    389 		System.out.println("    Average");
    390 		return 0;
    391 	}
    392 }
    393