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