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; CRandomGenerator()21 public CRandomGenerator() { Init(); } Init()22 public void Init() { A1 = 362436069; A2 = 521288629; } GetRnd()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; Init()36 public void Init() 37 { 38 Value = 0; 39 NumBits = 0; 40 } GetRnd(int numBits)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 CBenchRandomGenerator()70 public CBenchRandomGenerator() { } 71 Set(UInt32 bufferSize)72 public void Set(UInt32 bufferSize) 73 { 74 Buffer = new Byte[bufferSize]; 75 Pos = 0; 76 BufferSize = bufferSize; 77 } GetRndBit()78 UInt32 GetRndBit() { return RG.GetRnd(1); } GetLogRandBits(int numBits)79 UInt32 GetLogRandBits(int numBits) 80 { 81 UInt32 len = RG.GetRnd(numBits); 82 return RG.GetRnd((int)len); 83 } GetOffset()84 UInt32 GetOffset() 85 { 86 if (GetRndBit() == 0) 87 return GetLogRandBits(4); 88 return (GetLogRandBits(4) << 10) | RG.GetRnd(10); 89 } GetLen1()90 UInt32 GetLen1() { return RG.GetRnd(1 + (int)RG.GetRnd(2)); } GetLen2()91 UInt32 GetLen2() { return RG.GetRnd(2 + (int)RG.GetRnd(2)); } Generate()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(); Init()123 public void Init() { CRC.Init(); } GetDigest()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 { } } Flush()131 public override void Flush() { } Seek(long offset, SeekOrigin origin)132 public override long Seek(long offset, SeekOrigin origin) { return 0; } SetLength(long value)133 public override void SetLength(long value) { } Read(byte[] buffer, int offset, int count)134 public override int Read(byte[] buffer, int offset, int count) { return 0; } 135 WriteByte(byte b)136 public override void WriteByte(byte b) 137 { 138 CRC.UpdateByte(b); 139 } Write(byte[] buffer, int offset, int count)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; Init()151 public void Init() { InSize = 0; } SetProgress(Int64 inSize, Int64 outSize)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 GetLogSize(UInt32 size)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 MyMultDiv64(UInt64 value, UInt64 elapsedTime)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 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 size)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 GetDecompressRating(UInt64 elapsedTime, UInt64 outSize, UInt64 inSize)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 GetTotalRating( UInt32 dictionarySize, UInt64 elapsedTimeEn, UInt64 sizeEn, UInt64 elapsedTimeDe, UInt64 inSizeDe, UInt64 outSizeDe)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 PrintValue(UInt64 v)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 PrintRating(UInt64 rating)218 static void PrintRating(UInt64 rating) 219 { 220 PrintValue(rating / 1000000); 221 System.Console.Write(" MIPS"); 222 } 223 PrintResults( UInt32 dictionarySize, UInt64 elapsedTime, UInt64 size, bool decompressMode, UInt64 secondSize)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 LzmaBenchmark(Int32 numIterations, UInt32 dictionarySize)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 } 341