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;
CRandomGenerator()16 		public CRandomGenerator() { Init(); }
Init()17 		public void Init() { A1 = 362436069; A2 = 521288629; }
GetRnd()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;
Init()31 		public void Init()
32 		{
33 			Value = 0;
34 			NumBits = 0;
35 		}
GetRnd(int numBits)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 
CBenchRandomGenerator()65 		public CBenchRandomGenerator() { }
Set(int bufferSize)66 		public void Set(int bufferSize)
67 		{
68 			Buffer = new byte[bufferSize];
69 			Pos = 0;
70 			BufferSize = bufferSize;
71 		}
GetRndBit()72 		int GetRndBit() { return RG.GetRnd(1); }
GetLogRandBits(int numBits)73 		int GetLogRandBits(int numBits)
74 		{
75 			int len = RG.GetRnd(numBits);
76 			return RG.GetRnd((int)len);
77 		}
GetOffset()78 		int GetOffset()
79 		{
80 			if (GetRndBit() == 0)
81 				return GetLogRandBits(4);
82 			return (GetLogRandBits(4) << 10) | RG.GetRnd(10);
83 		}
GetLen1()84 		int GetLen1() { return RG.GetRnd(1 + (int)RG.GetRnd(2)); }
GetLen2()85 		int GetLen2() { return RG.GetRnd(2 + (int)RG.GetRnd(2)); }
Generate()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 
Init()118 		public void Init()
119 		{
120 			CRC.Init();
121 		}
GetDigest()122 		public int GetDigest()
123 		{
124 			return CRC.GetDigest();
125 		}
write(byte[] b)126 		public void write(byte[] b)
127 		{
128 			CRC.Update(b);
129 		}
write(byte[] b, int off, int len)130 		public void write(byte[] b, int off, int len)
131 		{
132 			CRC.Update(b, off, len);
133 		}
write(int b)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 
MyOutputStream(byte[] buffer)146 		public MyOutputStream(byte[] buffer)
147 		{
148 			_buffer = buffer;
149 			_size = _buffer.length;
150 		}
151 
reset()152 		public void reset()
153 		{
154 			_pos = 0;
155 		}
156 
write(int b)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 
size()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 
MyInputStream(byte[] buffer, int size)176 		public MyInputStream(byte[] buffer, int size)
177 		{
178 			_buffer = buffer;
179 			_size = size;
180 		}
181 
reset()182 		public void reset()
183 		{
184 			_pos = 0;
185 		}
186 
read()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;
Init()200 		public void Init()
201 		{ InSize = 0; }
SetProgress(long inSize, long outSize)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 
GetLogSize(int size)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 
MyMultDiv64(long value, long elapsedTime)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 
GetCompressRating(int dictionarySize, long elapsedTime, long size)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 
GetDecompressRating(long elapsedTime, long outSize, long inSize)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 
GetTotalRating( int dictionarySize, long elapsedTimeEn, long sizeEn, long elapsedTimeDe, long inSizeDe, long outSizeDe)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 
PrintValue(long v)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 
PrintRating(long rating)269 	static void PrintRating(long rating)
270 	{
271 		PrintValue(rating / 1000000);
272 		System.out.print(" MIPS");
273 	}
274 
PrintResults( int dictionarySize, long elapsedTime, long size, boolean decompressMode, long secondSize)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 
LzmaBenchmark(int numIterations, int dictionarySize)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