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 } |
|