LzmaBench.cs 9.2 KB

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