// LzmaBench.cs | |
using System; | |
using System.IO; | |
namespace SevenZip | |
{ | |
/// <summary> | |
/// LZMA Benchmark | |
/// </summary> | |
internal abstract class LzmaBench | |
{ | |
const UInt32 kAdditionalSize = (6 << 20); | |
const UInt32 kCompressedAdditionalSize = (1 << 10); | |
const UInt32 kMaxLzmaPropSize = 10; | |
class CRandomGenerator | |
{ | |
UInt32 A1; | |
UInt32 A2; | |
public CRandomGenerator() { Init(); } | |
public void Init() { A1 = 362436069; A2 = 521288629; } | |
public UInt32 GetRnd() | |
{ | |
return | |
((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) ^ | |
((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16))); | |
} | |
}; | |
class CBitRandomGenerator | |
{ | |
CRandomGenerator RG = new CRandomGenerator(); | |
UInt32 Value; | |
int NumBits; | |
public void Init() | |
{ | |
Value = 0; | |
NumBits = 0; | |
} | |
public UInt32 GetRnd(int numBits) | |
{ | |
UInt32 result; | |
if (NumBits > numBits) | |
{ | |
result = Value & (((UInt32)1 << numBits) - 1); | |
Value >>= numBits; | |
NumBits -= numBits; | |
return result; | |
} | |
numBits -= NumBits; | |
result = (Value << numBits); | |
Value = RG.GetRnd(); | |
result |= Value & (((UInt32)1 << numBits) - 1); | |
Value >>= numBits; | |
NumBits = 32 - numBits; | |
return result; | |
} | |
}; | |
class CBenchRandomGenerator | |
{ | |
CBitRandomGenerator RG = new CBitRandomGenerator(); | |
UInt32 Pos; | |
UInt32 Rep0; | |
public UInt32 BufferSize; | |
public Byte[] Buffer = null; | |
public CBenchRandomGenerator() { } | |
public void Set(UInt32 bufferSize) | |
{ | |
Buffer = new Byte[bufferSize]; | |
Pos = 0; | |
BufferSize = bufferSize; | |
} | |
UInt32 GetRndBit() { return RG.GetRnd(1); } | |
UInt32 GetLogRandBits(int numBits) | |
{ | |
UInt32 len = RG.GetRnd(numBits); | |
return RG.GetRnd((int)len); | |
} | |
UInt32 GetOffset() | |
{ | |
if (GetRndBit() == 0) | |
return GetLogRandBits(4); | |
return (GetLogRandBits(4) << 10) | RG.GetRnd(10); | |
} | |
UInt32 GetLen1() { return RG.GetRnd(1 + (int)RG.GetRnd(2)); } | |
UInt32 GetLen2() { return RG.GetRnd(2 + (int)RG.GetRnd(2)); } | |
public void Generate() | |
{ | |
RG.Init(); | |
Rep0 = 1; | |
while (Pos < BufferSize) | |
{ | |
if (GetRndBit() == 0 || Pos < 1) | |
Buffer[Pos++] = (Byte)RG.GetRnd(8); | |
else | |
{ | |
UInt32 len; | |
if (RG.GetRnd(3) == 0) | |
len = 1 + GetLen1(); | |
else | |
{ | |
do | |
Rep0 = GetOffset(); | |
while (Rep0 >= Pos); | |
Rep0++; | |
len = 2 + GetLen2(); | |
} | |
for (UInt32 i = 0; i < len && Pos < BufferSize; i++, Pos++) | |
Buffer[Pos] = Buffer[Pos - Rep0]; | |
} | |
} | |
} | |
}; | |
class CrcOutStream : System.IO.Stream | |
{ | |
public CRC CRC = new CRC(); | |
public void Init() { CRC.Init(); } | |
public UInt32 GetDigest() { return CRC.GetDigest(); } | |
public override bool CanRead { get { return false; } } | |
public override bool CanSeek { get { return false; } } | |
public override bool CanWrite { get { return true; } } | |
public override Int64 Length { get { return 0; } } | |
public override Int64 Position { get { return 0; } set { } } | |
public override void Flush() { } | |
public override long Seek(long offset, SeekOrigin origin) { return 0; } | |
public override void SetLength(long value) { } | |
public override int Read(byte[] buffer, int offset, int count) { return 0; } | |
public override void WriteByte(byte b) | |
{ | |
CRC.UpdateByte(b); | |
} | |
public override void Write(byte[] buffer, int offset, int count) | |
{ | |
CRC.Update(buffer, (uint)offset, (uint)count); | |
} | |
}; | |
class CProgressInfo : ICodeProgress | |
{ | |
public Int64 ApprovedStart; | |
public Int64 InSize; | |
public System.DateTime Time; | |
public void Init() { InSize = 0; } | |
public void SetProgress(Int64 inSize, Int64 outSize) | |
{ | |
if (inSize >= ApprovedStart && InSize == 0) | |
{ | |
Time = DateTime.UtcNow; | |
InSize = inSize; | |
} | |
} | |
} | |
const int kSubBits = 8; | |
static UInt32 GetLogSize(UInt32 size) | |
{ | |
for (int i = kSubBits; i < 32; i++) | |
for (UInt32 j = 0; j < (1 << kSubBits); j++) | |
if (size <= (((UInt32)1) << i) + (j << (i - kSubBits))) | |
return (UInt32)(i << kSubBits) + j; | |
return (32 << kSubBits); | |
} | |
static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime) | |
{ | |
UInt64 freq = TimeSpan.TicksPerSecond; | |
UInt64 elTime = elapsedTime; | |
while (freq > 1000000) | |
{ | |
freq >>= 1; | |
elTime >>= 1; | |
} | |
if (elTime == 0) | |
elTime = 1; | |
return value * freq / elTime; | |
} | |
static UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 size) | |
{ | |
UInt64 t = GetLogSize(dictionarySize) - (18 << kSubBits); | |
UInt64 numCommandsForOne = 1060 + ((t * t * 10) >> (2 * kSubBits)); | |
UInt64 numCommands = (UInt64)(size) * numCommandsForOne; | |
return MyMultDiv64(numCommands, elapsedTime); | |
} | |
static UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 outSize, UInt64 inSize) | |
{ | |
UInt64 numCommands = inSize * 220 + outSize * 20; | |
return MyMultDiv64(numCommands, elapsedTime); | |
} | |
static UInt64 GetTotalRating( | |
UInt32 dictionarySize, | |
UInt64 elapsedTimeEn, UInt64 sizeEn, | |
UInt64 elapsedTimeDe, | |
UInt64 inSizeDe, UInt64 outSizeDe) | |
{ | |
return (GetCompressRating(dictionarySize, elapsedTimeEn, sizeEn) + | |
GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2; | |
} | |
static void PrintValue(UInt64 v) | |
{ | |
string s = v.ToString(); | |
for (int i = 0; i + s.Length < 6; i++) | |
System.Console.Write(" "); | |
System.Console.Write(s); | |
} | |
static void PrintRating(UInt64 rating) | |
{ | |
PrintValue(rating / 1000000); | |
System.Console.Write(" MIPS"); | |
} | |
static void PrintResults( | |
UInt32 dictionarySize, | |
UInt64 elapsedTime, | |
UInt64 size, | |
bool decompressMode, UInt64 secondSize) | |
{ | |
UInt64 speed = MyMultDiv64(size, elapsedTime); | |
PrintValue(speed / 1024); | |
System.Console.Write(" KB/s "); | |
UInt64 rating; | |
if (decompressMode) | |
rating = GetDecompressRating(elapsedTime, size, secondSize); | |
else | |
rating = GetCompressRating(dictionarySize, elapsedTime, size); | |
PrintRating(rating); | |
} | |
static public int LzmaBenchmark(Int32 numIterations, UInt32 dictionarySize) | |
{ | |
if (numIterations <= 0) | |
return 0; | |
if (dictionarySize < (1 << 18)) | |
{ | |
System.Console.WriteLine("\nError: dictionary size for benchmark must be >= 19 (512 KB)"); | |
return 1; | |
} | |
System.Console.Write("\n Compressing Decompressing\n\n"); | |
Compression.LZMA.Encoder encoder = new Compression.LZMA.Encoder(); | |
Compression.LZMA.Decoder decoder = new Compression.LZMA.Decoder(); | |
CoderPropID[] propIDs = | |
{ | |
CoderPropID.DictionarySize, | |
}; | |
object[] properties = | |
{ | |
(Int32)(dictionarySize), | |
}; | |
UInt32 kBufferSize = dictionarySize + kAdditionalSize; | |
UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize; | |
encoder.SetCoderProperties(propIDs, properties); | |
System.IO.MemoryStream propStream = new System.IO.MemoryStream(); | |
encoder.WriteCoderProperties(propStream); | |
byte[] propArray = propStream.ToArray(); | |
CBenchRandomGenerator rg = new CBenchRandomGenerator(); | |
rg.Set(kBufferSize); | |
rg.Generate(); | |
CRC crc = new CRC(); | |
crc.Init(); | |
crc.Update(rg.Buffer, 0, rg.BufferSize); | |
CProgressInfo progressInfo = new CProgressInfo(); | |
progressInfo.ApprovedStart = dictionarySize; | |
UInt64 totalBenchSize = 0; | |
UInt64 totalEncodeTime = 0; | |
UInt64 totalDecodeTime = 0; | |
UInt64 totalCompressedSize = 0; | |
MemoryStream inStream = new MemoryStream(rg.Buffer, 0, (int)rg.BufferSize); | |
MemoryStream compressedStream = new MemoryStream((int)kCompressedBufferSize); | |
CrcOutStream crcOutStream = new CrcOutStream(); | |
for (Int32 i = 0; i < numIterations; i++) | |
{ | |
progressInfo.Init(); | |
inStream.Seek(0, SeekOrigin.Begin); | |
compressedStream.Seek(0, SeekOrigin.Begin); | |
encoder.Code(inStream, compressedStream, -1, -1, progressInfo); | |
TimeSpan sp2 = DateTime.UtcNow - progressInfo.Time; | |
UInt64 encodeTime = (UInt64)sp2.Ticks; | |
long compressedSize = compressedStream.Position; | |
if (progressInfo.InSize == 0) | |
throw (new Exception("Internal ERROR 1282")); | |
UInt64 decodeTime = 0; | |
for (int j = 0; j < 2; j++) | |
{ | |
compressedStream.Seek(0, SeekOrigin.Begin); | |
crcOutStream.Init(); | |
decoder.SetDecoderProperties(propArray); | |
UInt64 outSize = kBufferSize; | |
System.DateTime startTime = DateTime.UtcNow; | |
decoder.Code(compressedStream, crcOutStream, 0, (Int64)outSize, null); | |
TimeSpan sp = (DateTime.UtcNow - startTime); | |
decodeTime = (ulong)sp.Ticks; | |
if (crcOutStream.GetDigest() != crc.GetDigest()) | |
throw (new Exception("CRC Error")); | |
} | |
UInt64 benchSize = kBufferSize - (UInt64)progressInfo.InSize; | |
PrintResults(dictionarySize, encodeTime, benchSize, false, 0); | |
System.Console.Write(" "); | |
PrintResults(dictionarySize, decodeTime, kBufferSize, true, (ulong)compressedSize); | |
System.Console.WriteLine(); | |
totalBenchSize += benchSize; | |
totalEncodeTime += encodeTime; | |
totalDecodeTime += decodeTime; | |
totalCompressedSize += (ulong)compressedSize; | |
} | |
System.Console.WriteLine("---------------------------------------------------"); | |
PrintResults(dictionarySize, totalEncodeTime, totalBenchSize, false, 0); | |
System.Console.Write(" "); | |
PrintResults(dictionarySize, totalDecodeTime, | |
kBufferSize * (UInt64)numIterations, true, totalCompressedSize); | |
System.Console.WriteLine(" Average"); | |
return 0; | |
} | |
} | |
} |