f7b6bd016f62e05ff24c8f91a6d0787e71fc2024
[physicsfs] / lzma / CS / 7zip / Compress / LzmaAlone / LzmaBench.cs
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 }