1package SevenZip;
2
3import java.io.ByteArrayOutputStream;
4import java.io.ByteArrayInputStream;
5import java.io.IOException;
6
7public 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