1370b324cSopenharmony_ci// LzmaBench.cs
2370b324cSopenharmony_ci
3370b324cSopenharmony_ciusing System;
4370b324cSopenharmony_ciusing System.IO;
5370b324cSopenharmony_ci
6370b324cSopenharmony_cinamespace SevenZip
7370b324cSopenharmony_ci{
8370b324cSopenharmony_ci	/// <summary>
9370b324cSopenharmony_ci	/// LZMA Benchmark
10370b324cSopenharmony_ci	/// </summary>
11370b324cSopenharmony_ci	internal abstract class LzmaBench
12370b324cSopenharmony_ci	{
13370b324cSopenharmony_ci		const UInt32 kAdditionalSize = (6 << 20);
14370b324cSopenharmony_ci		const UInt32 kCompressedAdditionalSize = (1 << 10);
15370b324cSopenharmony_ci		const UInt32 kMaxLzmaPropSize = 10;
16370b324cSopenharmony_ci
17370b324cSopenharmony_ci		class CRandomGenerator
18370b324cSopenharmony_ci		{
19370b324cSopenharmony_ci			UInt32 A1;
20370b324cSopenharmony_ci			UInt32 A2;
21370b324cSopenharmony_ci			public CRandomGenerator() { Init(); }
22370b324cSopenharmony_ci			public void Init() { A1 = 362436069; A2 = 521288629; }
23370b324cSopenharmony_ci			public UInt32 GetRnd()
24370b324cSopenharmony_ci			{
25370b324cSopenharmony_ci				return
26370b324cSopenharmony_ci					((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) ^
27370b324cSopenharmony_ci					((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)));
28370b324cSopenharmony_ci			}
29370b324cSopenharmony_ci		};
30370b324cSopenharmony_ci
31370b324cSopenharmony_ci		class CBitRandomGenerator
32370b324cSopenharmony_ci		{
33370b324cSopenharmony_ci			CRandomGenerator RG = new CRandomGenerator();
34370b324cSopenharmony_ci			UInt32 Value;
35370b324cSopenharmony_ci			int NumBits;
36370b324cSopenharmony_ci			public void Init()
37370b324cSopenharmony_ci			{
38370b324cSopenharmony_ci				Value = 0;
39370b324cSopenharmony_ci				NumBits = 0;
40370b324cSopenharmony_ci			}
41370b324cSopenharmony_ci			public UInt32 GetRnd(int numBits)
42370b324cSopenharmony_ci			{
43370b324cSopenharmony_ci				UInt32 result;
44370b324cSopenharmony_ci				if (NumBits > numBits)
45370b324cSopenharmony_ci				{
46370b324cSopenharmony_ci					result = Value & (((UInt32)1 << numBits) - 1);
47370b324cSopenharmony_ci					Value >>= numBits;
48370b324cSopenharmony_ci					NumBits -= numBits;
49370b324cSopenharmony_ci					return result;
50370b324cSopenharmony_ci				}
51370b324cSopenharmony_ci				numBits -= NumBits;
52370b324cSopenharmony_ci				result = (Value << numBits);
53370b324cSopenharmony_ci				Value = RG.GetRnd();
54370b324cSopenharmony_ci				result |= Value & (((UInt32)1 << numBits) - 1);
55370b324cSopenharmony_ci				Value >>= numBits;
56370b324cSopenharmony_ci				NumBits = 32 - numBits;
57370b324cSopenharmony_ci				return result;
58370b324cSopenharmony_ci			}
59370b324cSopenharmony_ci		};
60370b324cSopenharmony_ci
61370b324cSopenharmony_ci		class CBenchRandomGenerator
62370b324cSopenharmony_ci		{
63370b324cSopenharmony_ci			CBitRandomGenerator RG = new CBitRandomGenerator();
64370b324cSopenharmony_ci			UInt32 Pos;
65370b324cSopenharmony_ci			UInt32 Rep0;
66370b324cSopenharmony_ci
67370b324cSopenharmony_ci			public UInt32 BufferSize;
68370b324cSopenharmony_ci			public Byte[] Buffer = null;
69370b324cSopenharmony_ci
70370b324cSopenharmony_ci			public CBenchRandomGenerator() { }
71370b324cSopenharmony_ci
72370b324cSopenharmony_ci			public void Set(UInt32 bufferSize)
73370b324cSopenharmony_ci			{
74370b324cSopenharmony_ci				Buffer = new Byte[bufferSize];
75370b324cSopenharmony_ci				Pos = 0;
76370b324cSopenharmony_ci				BufferSize = bufferSize;
77370b324cSopenharmony_ci			}
78370b324cSopenharmony_ci			UInt32 GetRndBit() { return RG.GetRnd(1); }
79370b324cSopenharmony_ci			UInt32 GetLogRandBits(int numBits)
80370b324cSopenharmony_ci			{
81370b324cSopenharmony_ci				UInt32 len = RG.GetRnd(numBits);
82370b324cSopenharmony_ci				return RG.GetRnd((int)len);
83370b324cSopenharmony_ci			}
84370b324cSopenharmony_ci			UInt32 GetOffset()
85370b324cSopenharmony_ci			{
86370b324cSopenharmony_ci				if (GetRndBit() == 0)
87370b324cSopenharmony_ci					return GetLogRandBits(4);
88370b324cSopenharmony_ci				return (GetLogRandBits(4) << 10) | RG.GetRnd(10);
89370b324cSopenharmony_ci			}
90370b324cSopenharmony_ci			UInt32 GetLen1() { return RG.GetRnd(1 + (int)RG.GetRnd(2)); }
91370b324cSopenharmony_ci			UInt32 GetLen2() { return RG.GetRnd(2 + (int)RG.GetRnd(2)); }
92370b324cSopenharmony_ci			public void Generate()
93370b324cSopenharmony_ci			{
94370b324cSopenharmony_ci				RG.Init();
95370b324cSopenharmony_ci				Rep0 = 1;
96370b324cSopenharmony_ci				while (Pos < BufferSize)
97370b324cSopenharmony_ci				{
98370b324cSopenharmony_ci					if (GetRndBit() == 0 || Pos < 1)
99370b324cSopenharmony_ci						Buffer[Pos++] = (Byte)RG.GetRnd(8);
100370b324cSopenharmony_ci					else
101370b324cSopenharmony_ci					{
102370b324cSopenharmony_ci						UInt32 len;
103370b324cSopenharmony_ci						if (RG.GetRnd(3) == 0)
104370b324cSopenharmony_ci							len = 1 + GetLen1();
105370b324cSopenharmony_ci						else
106370b324cSopenharmony_ci						{
107370b324cSopenharmony_ci							do
108370b324cSopenharmony_ci								Rep0 = GetOffset();
109370b324cSopenharmony_ci							while (Rep0 >= Pos);
110370b324cSopenharmony_ci							Rep0++;
111370b324cSopenharmony_ci							len = 2 + GetLen2();
112370b324cSopenharmony_ci						}
113370b324cSopenharmony_ci						for (UInt32 i = 0; i < len && Pos < BufferSize; i++, Pos++)
114370b324cSopenharmony_ci							Buffer[Pos] = Buffer[Pos - Rep0];
115370b324cSopenharmony_ci					}
116370b324cSopenharmony_ci				}
117370b324cSopenharmony_ci			}
118370b324cSopenharmony_ci		};
119370b324cSopenharmony_ci
120370b324cSopenharmony_ci		class CrcOutStream : System.IO.Stream
121370b324cSopenharmony_ci		{
122370b324cSopenharmony_ci			public CRC CRC = new CRC();
123370b324cSopenharmony_ci			public void Init() { CRC.Init(); }
124370b324cSopenharmony_ci			public UInt32 GetDigest() { return CRC.GetDigest(); }
125370b324cSopenharmony_ci
126370b324cSopenharmony_ci			public override bool CanRead { get { return false; } }
127370b324cSopenharmony_ci			public override bool CanSeek { get { return false; } }
128370b324cSopenharmony_ci			public override bool CanWrite { get { return true; } }
129370b324cSopenharmony_ci			public override Int64 Length { get { return 0; } }
130370b324cSopenharmony_ci			public override Int64 Position { get { return 0; } set { } }
131370b324cSopenharmony_ci			public override void Flush() { }
132370b324cSopenharmony_ci			public override long Seek(long offset, SeekOrigin origin) { return 0; }
133370b324cSopenharmony_ci			public override void SetLength(long value) { }
134370b324cSopenharmony_ci			public override int Read(byte[] buffer, int offset, int count) { return 0; }
135370b324cSopenharmony_ci
136370b324cSopenharmony_ci			public override void WriteByte(byte b)
137370b324cSopenharmony_ci			{
138370b324cSopenharmony_ci				CRC.UpdateByte(b);
139370b324cSopenharmony_ci			}
140370b324cSopenharmony_ci			public override void Write(byte[] buffer, int offset, int count)
141370b324cSopenharmony_ci			{
142370b324cSopenharmony_ci				CRC.Update(buffer, (uint)offset, (uint)count);
143370b324cSopenharmony_ci			}
144370b324cSopenharmony_ci		};
145370b324cSopenharmony_ci
146370b324cSopenharmony_ci		class CProgressInfo : ICodeProgress
147370b324cSopenharmony_ci		{
148370b324cSopenharmony_ci			public Int64 ApprovedStart;
149370b324cSopenharmony_ci			public Int64 InSize;
150370b324cSopenharmony_ci			public System.DateTime Time;
151370b324cSopenharmony_ci			public void Init() { InSize = 0; }
152370b324cSopenharmony_ci			public void SetProgress(Int64 inSize, Int64 outSize)
153370b324cSopenharmony_ci			{
154370b324cSopenharmony_ci				if (inSize >= ApprovedStart && InSize == 0)
155370b324cSopenharmony_ci				{
156370b324cSopenharmony_ci					Time = DateTime.UtcNow;
157370b324cSopenharmony_ci					InSize = inSize;
158370b324cSopenharmony_ci				}
159370b324cSopenharmony_ci			}
160370b324cSopenharmony_ci		}
161370b324cSopenharmony_ci		const int kSubBits = 8;
162370b324cSopenharmony_ci
163370b324cSopenharmony_ci		static UInt32 GetLogSize(UInt32 size)
164370b324cSopenharmony_ci		{
165370b324cSopenharmony_ci			for (int i = kSubBits; i < 32; i++)
166370b324cSopenharmony_ci				for (UInt32 j = 0; j < (1 << kSubBits); j++)
167370b324cSopenharmony_ci					if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))
168370b324cSopenharmony_ci						return (UInt32)(i << kSubBits) + j;
169370b324cSopenharmony_ci			return (32 << kSubBits);
170370b324cSopenharmony_ci		}
171370b324cSopenharmony_ci
172370b324cSopenharmony_ci		static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime)
173370b324cSopenharmony_ci		{
174370b324cSopenharmony_ci			UInt64 freq = TimeSpan.TicksPerSecond;
175370b324cSopenharmony_ci			UInt64 elTime = elapsedTime;
176370b324cSopenharmony_ci			while (freq > 1000000)
177370b324cSopenharmony_ci			{
178370b324cSopenharmony_ci				freq >>= 1;
179370b324cSopenharmony_ci				elTime >>= 1;
180370b324cSopenharmony_ci			}
181370b324cSopenharmony_ci			if (elTime == 0)
182370b324cSopenharmony_ci				elTime = 1;
183370b324cSopenharmony_ci			return value * freq / elTime;
184370b324cSopenharmony_ci		}
185370b324cSopenharmony_ci
186370b324cSopenharmony_ci		static UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 size)
187370b324cSopenharmony_ci		{
188370b324cSopenharmony_ci			UInt64 t = GetLogSize(dictionarySize) - (18 << kSubBits);
189370b324cSopenharmony_ci			UInt64 numCommandsForOne = 1060 + ((t * t * 10) >> (2 * kSubBits));
190370b324cSopenharmony_ci			UInt64 numCommands = (UInt64)(size) * numCommandsForOne;
191370b324cSopenharmony_ci			return MyMultDiv64(numCommands, elapsedTime);
192370b324cSopenharmony_ci		}
193370b324cSopenharmony_ci
194370b324cSopenharmony_ci		static UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 outSize, UInt64 inSize)
195370b324cSopenharmony_ci		{
196370b324cSopenharmony_ci			UInt64 numCommands = inSize * 220 + outSize * 20;
197370b324cSopenharmony_ci			return MyMultDiv64(numCommands, elapsedTime);
198370b324cSopenharmony_ci		}
199370b324cSopenharmony_ci
200370b324cSopenharmony_ci		static UInt64 GetTotalRating(
201370b324cSopenharmony_ci			UInt32 dictionarySize,
202370b324cSopenharmony_ci			UInt64 elapsedTimeEn, UInt64 sizeEn,
203370b324cSopenharmony_ci			UInt64 elapsedTimeDe,
204370b324cSopenharmony_ci			UInt64 inSizeDe, UInt64 outSizeDe)
205370b324cSopenharmony_ci		{
206370b324cSopenharmony_ci			return (GetCompressRating(dictionarySize, elapsedTimeEn, sizeEn) +
207370b324cSopenharmony_ci				GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2;
208370b324cSopenharmony_ci		}
209370b324cSopenharmony_ci
210370b324cSopenharmony_ci		static void PrintValue(UInt64 v)
211370b324cSopenharmony_ci		{
212370b324cSopenharmony_ci			string s = v.ToString();
213370b324cSopenharmony_ci			for (int i = 0; i + s.Length < 6; i++)
214370b324cSopenharmony_ci				System.Console.Write(" ");
215370b324cSopenharmony_ci			System.Console.Write(s);
216370b324cSopenharmony_ci		}
217370b324cSopenharmony_ci
218370b324cSopenharmony_ci		static void PrintRating(UInt64 rating)
219370b324cSopenharmony_ci		{
220370b324cSopenharmony_ci			PrintValue(rating / 1000000);
221370b324cSopenharmony_ci			System.Console.Write(" MIPS");
222370b324cSopenharmony_ci		}
223370b324cSopenharmony_ci
224370b324cSopenharmony_ci		static void PrintResults(
225370b324cSopenharmony_ci			UInt32 dictionarySize,
226370b324cSopenharmony_ci			UInt64 elapsedTime,
227370b324cSopenharmony_ci			UInt64 size,
228370b324cSopenharmony_ci			bool decompressMode, UInt64 secondSize)
229370b324cSopenharmony_ci		{
230370b324cSopenharmony_ci			UInt64 speed = MyMultDiv64(size, elapsedTime);
231370b324cSopenharmony_ci			PrintValue(speed / 1024);
232370b324cSopenharmony_ci			System.Console.Write(" KB/s  ");
233370b324cSopenharmony_ci			UInt64 rating;
234370b324cSopenharmony_ci			if (decompressMode)
235370b324cSopenharmony_ci				rating = GetDecompressRating(elapsedTime, size, secondSize);
236370b324cSopenharmony_ci			else
237370b324cSopenharmony_ci				rating = GetCompressRating(dictionarySize, elapsedTime, size);
238370b324cSopenharmony_ci			PrintRating(rating);
239370b324cSopenharmony_ci		}
240370b324cSopenharmony_ci
241370b324cSopenharmony_ci		static public int LzmaBenchmark(Int32 numIterations, UInt32 dictionarySize)
242370b324cSopenharmony_ci		{
243370b324cSopenharmony_ci			if (numIterations <= 0)
244370b324cSopenharmony_ci				return 0;
245370b324cSopenharmony_ci			if (dictionarySize < (1 << 18))
246370b324cSopenharmony_ci			{
247370b324cSopenharmony_ci				System.Console.WriteLine("\nError: dictionary size for benchmark must be >= 19 (512 KB)");
248370b324cSopenharmony_ci				return 1;
249370b324cSopenharmony_ci			}
250370b324cSopenharmony_ci			System.Console.Write("\n       Compressing                Decompressing\n\n");
251370b324cSopenharmony_ci
252370b324cSopenharmony_ci			Compression.LZMA.Encoder encoder = new Compression.LZMA.Encoder();
253370b324cSopenharmony_ci			Compression.LZMA.Decoder decoder = new Compression.LZMA.Decoder();
254370b324cSopenharmony_ci
255370b324cSopenharmony_ci
256370b324cSopenharmony_ci			CoderPropID[] propIDs =
257370b324cSopenharmony_ci			{
258370b324cSopenharmony_ci				CoderPropID.DictionarySize,
259370b324cSopenharmony_ci			};
260370b324cSopenharmony_ci			object[] properties =
261370b324cSopenharmony_ci			{
262370b324cSopenharmony_ci				(Int32)(dictionarySize),
263370b324cSopenharmony_ci			};
264370b324cSopenharmony_ci
265370b324cSopenharmony_ci			UInt32 kBufferSize = dictionarySize + kAdditionalSize;
266370b324cSopenharmony_ci			UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;
267370b324cSopenharmony_ci
268370b324cSopenharmony_ci			encoder.SetCoderProperties(propIDs, properties);
269370b324cSopenharmony_ci			System.IO.MemoryStream propStream = new System.IO.MemoryStream();
270370b324cSopenharmony_ci			encoder.WriteCoderProperties(propStream);
271370b324cSopenharmony_ci			byte[] propArray = propStream.ToArray();
272370b324cSopenharmony_ci
273370b324cSopenharmony_ci			CBenchRandomGenerator rg = new CBenchRandomGenerator();
274370b324cSopenharmony_ci
275370b324cSopenharmony_ci			rg.Set(kBufferSize);
276370b324cSopenharmony_ci			rg.Generate();
277370b324cSopenharmony_ci			CRC crc = new CRC();
278370b324cSopenharmony_ci			crc.Init();
279370b324cSopenharmony_ci			crc.Update(rg.Buffer, 0, rg.BufferSize);
280370b324cSopenharmony_ci
281370b324cSopenharmony_ci			CProgressInfo progressInfo = new CProgressInfo();
282370b324cSopenharmony_ci			progressInfo.ApprovedStart = dictionarySize;
283370b324cSopenharmony_ci
284370b324cSopenharmony_ci			UInt64 totalBenchSize = 0;
285370b324cSopenharmony_ci			UInt64 totalEncodeTime = 0;
286370b324cSopenharmony_ci			UInt64 totalDecodeTime = 0;
287370b324cSopenharmony_ci			UInt64 totalCompressedSize = 0;
288370b324cSopenharmony_ci
289370b324cSopenharmony_ci			MemoryStream inStream = new MemoryStream(rg.Buffer, 0, (int)rg.BufferSize);
290370b324cSopenharmony_ci			MemoryStream compressedStream = new MemoryStream((int)kCompressedBufferSize);
291370b324cSopenharmony_ci			CrcOutStream crcOutStream = new CrcOutStream();
292370b324cSopenharmony_ci			for (Int32 i = 0; i < numIterations; i++)
293370b324cSopenharmony_ci			{
294370b324cSopenharmony_ci				progressInfo.Init();
295370b324cSopenharmony_ci				inStream.Seek(0, SeekOrigin.Begin);
296370b324cSopenharmony_ci				compressedStream.Seek(0, SeekOrigin.Begin);
297370b324cSopenharmony_ci				encoder.Code(inStream, compressedStream, -1, -1, progressInfo);
298370b324cSopenharmony_ci				TimeSpan sp2 = DateTime.UtcNow - progressInfo.Time;
299370b324cSopenharmony_ci				UInt64 encodeTime = (UInt64)sp2.Ticks;
300370b324cSopenharmony_ci
301370b324cSopenharmony_ci				long compressedSize = compressedStream.Position;
302370b324cSopenharmony_ci				if (progressInfo.InSize == 0)
303370b324cSopenharmony_ci					throw (new Exception("Internal ERROR 1282"));
304370b324cSopenharmony_ci
305370b324cSopenharmony_ci				UInt64 decodeTime = 0;
306370b324cSopenharmony_ci				for (int j = 0; j < 2; j++)
307370b324cSopenharmony_ci				{
308370b324cSopenharmony_ci					compressedStream.Seek(0, SeekOrigin.Begin);
309370b324cSopenharmony_ci					crcOutStream.Init();
310370b324cSopenharmony_ci
311370b324cSopenharmony_ci					decoder.SetDecoderProperties(propArray);
312370b324cSopenharmony_ci					UInt64 outSize = kBufferSize;
313370b324cSopenharmony_ci					System.DateTime startTime = DateTime.UtcNow;
314370b324cSopenharmony_ci					decoder.Code(compressedStream, crcOutStream, 0, (Int64)outSize, null);
315370b324cSopenharmony_ci					TimeSpan sp = (DateTime.UtcNow - startTime);
316370b324cSopenharmony_ci					decodeTime = (ulong)sp.Ticks;
317370b324cSopenharmony_ci					if (crcOutStream.GetDigest() != crc.GetDigest())
318370b324cSopenharmony_ci						throw (new Exception("CRC Error"));
319370b324cSopenharmony_ci				}
320370b324cSopenharmony_ci				UInt64 benchSize = kBufferSize - (UInt64)progressInfo.InSize;
321370b324cSopenharmony_ci				PrintResults(dictionarySize, encodeTime, benchSize, false, 0);
322370b324cSopenharmony_ci				System.Console.Write("     ");
323370b324cSopenharmony_ci				PrintResults(dictionarySize, decodeTime, kBufferSize, true, (ulong)compressedSize);
324370b324cSopenharmony_ci				System.Console.WriteLine();
325370b324cSopenharmony_ci
326370b324cSopenharmony_ci				totalBenchSize += benchSize;
327370b324cSopenharmony_ci				totalEncodeTime += encodeTime;
328370b324cSopenharmony_ci				totalDecodeTime += decodeTime;
329370b324cSopenharmony_ci				totalCompressedSize += (ulong)compressedSize;
330370b324cSopenharmony_ci			}
331370b324cSopenharmony_ci			System.Console.WriteLine("---------------------------------------------------");
332370b324cSopenharmony_ci			PrintResults(dictionarySize, totalEncodeTime, totalBenchSize, false, 0);
333370b324cSopenharmony_ci			System.Console.Write("     ");
334370b324cSopenharmony_ci			PrintResults(dictionarySize, totalDecodeTime,
335370b324cSopenharmony_ci					kBufferSize * (UInt64)numIterations, true, totalCompressedSize);
336370b324cSopenharmony_ci			System.Console.WriteLine("    Average");
337370b324cSopenharmony_ci			return 0;
338370b324cSopenharmony_ci		}
339370b324cSopenharmony_ci	}
340370b324cSopenharmony_ci}
341