|
1 // LzmaBench.cs |
|
2 |
|
3 using System; |
|
4 using System.IO; |
|
5 |
|
6 namespace SevenZip |
|
7 { |
|
8 /// <summary> |
|
9 /// LZMA Benchmark |
|
10 /// </summary> |
|
11 internal abstract class LzmaBench |
|
12 { |
|
13 const UInt32 kAdditionalSize = (6 << 20); |
|
14 const UInt32 kCompressedAdditionalSize = (1 << 10); |
|
15 const UInt32 kMaxLzmaPropSize = 10; |
|
16 |
|
17 class CRandomGenerator |
|
18 { |
|
19 UInt32 A1; |
|
20 UInt32 A2; |
|
21 public CRandomGenerator() { Init(); } |
|
22 public void Init() { A1 = 362436069; A2 = 521288629; } |
|
23 public UInt32 GetRnd() |
|
24 { |
|
25 return |
|
26 ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) ^ |
|
27 ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16))); |
|
28 } |
|
29 }; |
|
30 |
|
31 class CBitRandomGenerator |
|
32 { |
|
33 CRandomGenerator RG = new CRandomGenerator(); |
|
34 UInt32 Value; |
|
35 int NumBits; |
|
36 public void Init() |
|
37 { |
|
38 Value = 0; |
|
39 NumBits = 0; |
|
40 } |
|
41 public UInt32 GetRnd(int numBits) |
|
42 { |
|
43 UInt32 result; |
|
44 if (NumBits > numBits) |
|
45 { |
|
46 result = Value & (((UInt32)1 << numBits) - 1); |
|
47 Value >>= numBits; |
|
48 NumBits -= numBits; |
|
49 return result; |
|
50 } |
|
51 numBits -= NumBits; |
|
52 result = (Value << numBits); |
|
53 Value = RG.GetRnd(); |
|
54 result |= Value & (((UInt32)1 << numBits) - 1); |
|
55 Value >>= numBits; |
|
56 NumBits = 32 - numBits; |
|
57 return result; |
|
58 } |
|
59 }; |
|
60 |
|
61 class CBenchRandomGenerator |
|
62 { |
|
63 CBitRandomGenerator RG = new CBitRandomGenerator(); |
|
64 UInt32 Pos; |
|
65 UInt32 Rep0; |
|
66 |
|
67 public UInt32 BufferSize; |
|
68 public Byte[] Buffer = null; |
|
69 |
|
70 public CBenchRandomGenerator() { } |
|
71 |
|
72 public void Set(UInt32 bufferSize) |
|
73 { |
|
74 Buffer = new Byte[bufferSize]; |
|
75 Pos = 0; |
|
76 BufferSize = bufferSize; |
|
77 } |
|
78 UInt32 GetRndBit() { return RG.GetRnd(1); } |
|
79 UInt32 GetLogRandBits(int numBits) |
|
80 { |
|
81 UInt32 len = RG.GetRnd(numBits); |
|
82 return RG.GetRnd((int)len); |
|
83 } |
|
84 UInt32 GetOffset() |
|
85 { |
|
86 if (GetRndBit() == 0) |
|
87 return GetLogRandBits(4); |
|
88 return (GetLogRandBits(4) << 10) | RG.GetRnd(10); |
|
89 } |
|
90 UInt32 GetLen1() { return RG.GetRnd(1 + (int)RG.GetRnd(2)); } |
|
91 UInt32 GetLen2() { return RG.GetRnd(2 + (int)RG.GetRnd(2)); } |
|
92 public void Generate() |
|
93 { |
|
94 RG.Init(); |
|
95 Rep0 = 1; |
|
96 while (Pos < BufferSize) |
|
97 { |
|
98 if (GetRndBit() == 0 || Pos < 1) |
|
99 Buffer[Pos++] = (Byte)RG.GetRnd(8); |
|
100 else |
|
101 { |
|
102 UInt32 len; |
|
103 if (RG.GetRnd(3) == 0) |
|
104 len = 1 + GetLen1(); |
|
105 else |
|
106 { |
|
107 do |
|
108 Rep0 = GetOffset(); |
|
109 while (Rep0 >= Pos); |
|
110 Rep0++; |
|
111 len = 2 + GetLen2(); |
|
112 } |
|
113 for (UInt32 i = 0; i < len && Pos < BufferSize; i++, Pos++) |
|
114 Buffer[Pos] = Buffer[Pos - Rep0]; |
|
115 } |
|
116 } |
|
117 } |
|
118 }; |
|
119 |
|
120 class CrcOutStream : System.IO.Stream |
|
121 { |
|
122 public CRC CRC = new CRC(); |
|
123 public void Init() { CRC.Init(); } |
|
124 public UInt32 GetDigest() { return CRC.GetDigest(); } |
|
125 |
|
126 public override bool CanRead { get { return false; } } |
|
127 public override bool CanSeek { get { return false; } } |
|
128 public override bool CanWrite { get { return true; } } |
|
129 public override Int64 Length { get { return 0; } } |
|
130 public override Int64 Position { get { return 0; } set { } } |
|
131 public override void Flush() { } |
|
132 public override long Seek(long offset, SeekOrigin origin) { return 0; } |
|
133 public override void SetLength(long value) { } |
|
134 public override int Read(byte[] buffer, int offset, int count) { return 0; } |
|
135 |
|
136 public override void WriteByte(byte b) |
|
137 { |
|
138 CRC.UpdateByte(b); |
|
139 } |
|
140 public override void Write(byte[] buffer, int offset, int count) |
|
141 { |
|
142 CRC.Update(buffer, (uint)offset, (uint)count); |
|
143 } |
|
144 }; |
|
145 |
|
146 class CProgressInfo : ICodeProgress |
|
147 { |
|
148 public Int64 ApprovedStart; |
|
149 public Int64 InSize; |
|
150 public System.DateTime Time; |
|
151 public void Init() { InSize = 0; } |
|
152 public void SetProgress(Int64 inSize, Int64 outSize) |
|
153 { |
|
154 if (inSize >= ApprovedStart && InSize == 0) |
|
155 { |
|
156 Time = DateTime.UtcNow; |
|
157 InSize = inSize; |
|
158 } |
|
159 } |
|
160 } |
|
161 const int kSubBits = 8; |
|
162 |
|
163 static UInt32 GetLogSize(UInt32 size) |
|
164 { |
|
165 for (int i = kSubBits; i < 32; i++) |
|
166 for (UInt32 j = 0; j < (1 << kSubBits); j++) |
|
167 if (size <= (((UInt32)1) << i) + (j << (i - kSubBits))) |
|
168 return (UInt32)(i << kSubBits) + j; |
|
169 return (32 << kSubBits); |
|
170 } |
|
171 |
|
172 static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime) |
|
173 { |
|
174 UInt64 freq = TimeSpan.TicksPerSecond; |
|
175 UInt64 elTime = elapsedTime; |
|
176 while (freq > 1000000) |
|
177 { |
|
178 freq >>= 1; |
|
179 elTime >>= 1; |
|
180 } |
|
181 if (elTime == 0) |
|
182 elTime = 1; |
|
183 return value * freq / elTime; |
|
184 } |
|
185 |
|
186 static UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 size) |
|
187 { |
|
188 UInt64 t = GetLogSize(dictionarySize) - (18 << kSubBits); |
|
189 UInt64 numCommandsForOne = 1060 + ((t * t * 10) >> (2 * kSubBits)); |
|
190 UInt64 numCommands = (UInt64)(size) * numCommandsForOne; |
|
191 return MyMultDiv64(numCommands, elapsedTime); |
|
192 } |
|
193 |
|
194 static UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 outSize, UInt64 inSize) |
|
195 { |
|
196 UInt64 numCommands = inSize * 220 + outSize * 20; |
|
197 return MyMultDiv64(numCommands, elapsedTime); |
|
198 } |
|
199 |
|
200 static UInt64 GetTotalRating( |
|
201 UInt32 dictionarySize, |
|
202 UInt64 elapsedTimeEn, UInt64 sizeEn, |
|
203 UInt64 elapsedTimeDe, |
|
204 UInt64 inSizeDe, UInt64 outSizeDe) |
|
205 { |
|
206 return (GetCompressRating(dictionarySize, elapsedTimeEn, sizeEn) + |
|
207 GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2; |
|
208 } |
|
209 |
|
210 static void PrintValue(UInt64 v) |
|
211 { |
|
212 string s = v.ToString(); |
|
213 for (int i = 0; i + s.Length < 6; i++) |
|
214 System.Console.Write(" "); |
|
215 System.Console.Write(s); |
|
216 } |
|
217 |
|
218 static void PrintRating(UInt64 rating) |
|
219 { |
|
220 PrintValue(rating / 1000000); |
|
221 System.Console.Write(" MIPS"); |
|
222 } |
|
223 |
|
224 static void PrintResults( |
|
225 UInt32 dictionarySize, |
|
226 UInt64 elapsedTime, |
|
227 UInt64 size, |
|
228 bool decompressMode, UInt64 secondSize) |
|
229 { |
|
230 UInt64 speed = MyMultDiv64(size, elapsedTime); |
|
231 PrintValue(speed / 1024); |
|
232 System.Console.Write(" KB/s "); |
|
233 UInt64 rating; |
|
234 if (decompressMode) |
|
235 rating = GetDecompressRating(elapsedTime, size, secondSize); |
|
236 else |
|
237 rating = GetCompressRating(dictionarySize, elapsedTime, size); |
|
238 PrintRating(rating); |
|
239 } |
|
240 |
|
241 static public int LzmaBenchmark(Int32 numIterations, UInt32 dictionarySize) |
|
242 { |
|
243 if (numIterations <= 0) |
|
244 return 0; |
|
245 if (dictionarySize < (1 << 18)) |
|
246 { |
|
247 System.Console.WriteLine("\nError: dictionary size for benchmark must be >= 19 (512 KB)"); |
|
248 return 1; |
|
249 } |
|
250 System.Console.Write("\n Compressing Decompressing\n\n"); |
|
251 |
|
252 Compression.LZMA.Encoder encoder = new Compression.LZMA.Encoder(); |
|
253 Compression.LZMA.Decoder decoder = new Compression.LZMA.Decoder(); |
|
254 |
|
255 |
|
256 CoderPropID[] propIDs = |
|
257 { |
|
258 CoderPropID.DictionarySize, |
|
259 }; |
|
260 object[] properties = |
|
261 { |
|
262 (Int32)(dictionarySize), |
|
263 }; |
|
264 |
|
265 UInt32 kBufferSize = dictionarySize + kAdditionalSize; |
|
266 UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize; |
|
267 |
|
268 encoder.SetCoderProperties(propIDs, properties); |
|
269 System.IO.MemoryStream propStream = new System.IO.MemoryStream(); |
|
270 encoder.WriteCoderProperties(propStream); |
|
271 byte[] propArray = propStream.ToArray(); |
|
272 |
|
273 CBenchRandomGenerator rg = new CBenchRandomGenerator(); |
|
274 |
|
275 rg.Set(kBufferSize); |
|
276 rg.Generate(); |
|
277 CRC crc = new CRC(); |
|
278 crc.Init(); |
|
279 crc.Update(rg.Buffer, 0, rg.BufferSize); |
|
280 |
|
281 CProgressInfo progressInfo = new CProgressInfo(); |
|
282 progressInfo.ApprovedStart = dictionarySize; |
|
283 |
|
284 UInt64 totalBenchSize = 0; |
|
285 UInt64 totalEncodeTime = 0; |
|
286 UInt64 totalDecodeTime = 0; |
|
287 UInt64 totalCompressedSize = 0; |
|
288 |
|
289 MemoryStream inStream = new MemoryStream(rg.Buffer, 0, (int)rg.BufferSize); |
|
290 MemoryStream compressedStream = new MemoryStream((int)kCompressedBufferSize); |
|
291 CrcOutStream crcOutStream = new CrcOutStream(); |
|
292 for (Int32 i = 0; i < numIterations; i++) |
|
293 { |
|
294 progressInfo.Init(); |
|
295 inStream.Seek(0, SeekOrigin.Begin); |
|
296 compressedStream.Seek(0, SeekOrigin.Begin); |
|
297 encoder.Code(inStream, compressedStream, -1, -1, progressInfo); |
|
298 TimeSpan sp2 = DateTime.UtcNow - progressInfo.Time; |
|
299 UInt64 encodeTime = (UInt64)sp2.Ticks; |
|
300 |
|
301 long compressedSize = compressedStream.Position; |
|
302 if (progressInfo.InSize == 0) |
|
303 throw (new Exception("Internal ERROR 1282")); |
|
304 |
|
305 UInt64 decodeTime = 0; |
|
306 for (int j = 0; j < 2; j++) |
|
307 { |
|
308 compressedStream.Seek(0, SeekOrigin.Begin); |
|
309 crcOutStream.Init(); |
|
310 |
|
311 decoder.SetDecoderProperties(propArray); |
|
312 UInt64 outSize = kBufferSize; |
|
313 System.DateTime startTime = DateTime.UtcNow; |
|
314 decoder.Code(compressedStream, crcOutStream, 0, (Int64)outSize, null); |
|
315 TimeSpan sp = (DateTime.UtcNow - startTime); |
|
316 decodeTime = (ulong)sp.Ticks; |
|
317 if (crcOutStream.GetDigest() != crc.GetDigest()) |
|
318 throw (new Exception("CRC Error")); |
|
319 } |
|
320 UInt64 benchSize = kBufferSize - (UInt64)progressInfo.InSize; |
|
321 PrintResults(dictionarySize, encodeTime, benchSize, false, 0); |
|
322 System.Console.Write(" "); |
|
323 PrintResults(dictionarySize, decodeTime, kBufferSize, true, (ulong)compressedSize); |
|
324 System.Console.WriteLine(); |
|
325 |
|
326 totalBenchSize += benchSize; |
|
327 totalEncodeTime += encodeTime; |
|
328 totalDecodeTime += decodeTime; |
|
329 totalCompressedSize += (ulong)compressedSize; |
|
330 } |
|
331 System.Console.WriteLine("---------------------------------------------------"); |
|
332 PrintResults(dictionarySize, totalEncodeTime, totalBenchSize, false, 0); |
|
333 System.Console.Write(" "); |
|
334 PrintResults(dictionarySize, totalDecodeTime, |
|
335 kBufferSize * (UInt64)numIterations, true, totalCompressedSize); |
|
336 System.Console.WriteLine(" Average"); |
|
337 return 0; |
|
338 } |
|
339 } |
|
340 } |