package SevenZip; | |
import java.io.ByteArrayOutputStream; | |
import java.io.ByteArrayInputStream; | |
import java.io.IOException; | |
public class LzmaBench | |
{ | |
static final int kAdditionalSize = (1 << 21); | |
static final int kCompressedAdditionalSize = (1 << 10); | |
static class CRandomGenerator | |
{ | |
int A1; | |
int A2; | |
public CRandomGenerator() { Init(); } | |
public void Init() { A1 = 362436069; A2 = 521288629; } | |
public int GetRnd() | |
{ | |
return | |
((A1 = 36969 * (A1 & 0xffff) + (A1 >>> 16)) << 16) ^ | |
((A2 = 18000 * (A2 & 0xffff) + (A2 >>> 16))); | |
} | |
}; | |
static class CBitRandomGenerator | |
{ | |
CRandomGenerator RG = new CRandomGenerator(); | |
int Value; | |
int NumBits; | |
public void Init() | |
{ | |
Value = 0; | |
NumBits = 0; | |
} | |
public int GetRnd(int numBits) | |
{ | |
int result; | |
if (NumBits > numBits) | |
{ | |
result = Value & ((1 << numBits) - 1); | |
Value >>>= numBits; | |
NumBits -= numBits; | |
return result; | |
} | |
numBits -= NumBits; | |
result = (Value << numBits); | |
Value = RG.GetRnd(); | |
result |= Value & (((int)1 << numBits) - 1); | |
Value >>>= numBits; | |
NumBits = 32 - numBits; | |
return result; | |
} | |
}; | |
static class CBenchRandomGenerator | |
{ | |
CBitRandomGenerator RG = new CBitRandomGenerator(); | |
int Pos; | |
int Rep0; | |
public int BufferSize; | |
public byte[] Buffer = null; | |
public CBenchRandomGenerator() { } | |
public void Set(int bufferSize) | |
{ | |
Buffer = new byte[bufferSize]; | |
Pos = 0; | |
BufferSize = bufferSize; | |
} | |
int GetRndBit() { return RG.GetRnd(1); } | |
int GetLogRandBits(int numBits) | |
{ | |
int len = RG.GetRnd(numBits); | |
return RG.GetRnd((int)len); | |
} | |
int GetOffset() | |
{ | |
if (GetRndBit() == 0) | |
return GetLogRandBits(4); | |
return (GetLogRandBits(4) << 10) | RG.GetRnd(10); | |
} | |
int GetLen1() { return RG.GetRnd(1 + (int)RG.GetRnd(2)); } | |
int 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 | |
{ | |
int len; | |
if (RG.GetRnd(3) == 0) | |
len = 1 + GetLen1(); | |
else | |
{ | |
do | |
Rep0 = GetOffset(); | |
while (Rep0 >= Pos); | |
Rep0++; | |
len = 2 + GetLen2(); | |
} | |
for (int i = 0; i < len && Pos < BufferSize; i++, Pos++) | |
Buffer[Pos] = Buffer[Pos - Rep0]; | |
} | |
} | |
} | |
}; | |
static class CrcOutStream extends java.io.OutputStream | |
{ | |
public CRC CRC = new CRC(); | |
public void Init() | |
{ | |
CRC.Init(); | |
} | |
public int GetDigest() | |
{ | |
return CRC.GetDigest(); | |
} | |
public void write(byte[] b) | |
{ | |
CRC.Update(b); | |
} | |
public void write(byte[] b, int off, int len) | |
{ | |
CRC.Update(b, off, len); | |
} | |
public void write(int b) | |
{ | |
CRC.UpdateByte(b); | |
} | |
}; | |
static class MyOutputStream extends java.io.OutputStream | |
{ | |
byte[] _buffer; | |
int _size; | |
int _pos; | |
public MyOutputStream(byte[] buffer) | |
{ | |
_buffer = buffer; | |
_size = _buffer.length; | |
} | |
public void reset() | |
{ | |
_pos = 0; | |
} | |
public void write(int b) throws IOException | |
{ | |
if (_pos >= _size) | |
throw new IOException("Error"); | |
_buffer[_pos++] = (byte)b; | |
} | |
public int size() | |
{ | |
return _pos; | |
} | |
}; | |
static class MyInputStream extends java.io.InputStream | |
{ | |
byte[] _buffer; | |
int _size; | |
int _pos; | |
public MyInputStream(byte[] buffer, int size) | |
{ | |
_buffer = buffer; | |
_size = size; | |
} | |
public void reset() | |
{ | |
_pos = 0; | |
} | |
public int read() | |
{ | |
if (_pos >= _size) | |
return -1; | |
return _buffer[_pos++] & 0xFF; | |
} | |
}; | |
static class CProgressInfo implements ICodeProgress | |
{ | |
public long ApprovedStart; | |
public long InSize; | |
public long Time; | |
public void Init() | |
{ InSize = 0; } | |
public void SetProgress(long inSize, long outSize) | |
{ | |
if (inSize >= ApprovedStart && InSize == 0) | |
{ | |
Time = System.currentTimeMillis(); | |
InSize = inSize; | |
} | |
} | |
} | |
static final int kSubBits = 8; | |
static int GetLogSize(int size) | |
{ | |
for (int i = kSubBits; i < 32; i++) | |
for (int j = 0; j < (1 << kSubBits); j++) | |
if (size <= ((1) << i) + (j << (i - kSubBits))) | |
return (i << kSubBits) + j; | |
return (32 << kSubBits); | |
} | |
static long MyMultDiv64(long value, long elapsedTime) | |
{ | |
long freq = 1000; // ms | |
long elTime = elapsedTime; | |
while (freq > 1000000) | |
{ | |
freq >>>= 1; | |
elTime >>>= 1; | |
} | |
if (elTime == 0) | |
elTime = 1; | |
return value * freq / elTime; | |
} | |
static long GetCompressRating(int dictionarySize, long elapsedTime, long size) | |
{ | |
long t = GetLogSize(dictionarySize) - (18 << kSubBits); | |
long numCommandsForOne = 1060 + ((t * t * 10) >> (2 * kSubBits)); | |
long numCommands = (long)(size) * numCommandsForOne; | |
return MyMultDiv64(numCommands, elapsedTime); | |
} | |
static long GetDecompressRating(long elapsedTime, long outSize, long inSize) | |
{ | |
long numCommands = inSize * 220 + outSize * 20; | |
return MyMultDiv64(numCommands, elapsedTime); | |
} | |
static long GetTotalRating( | |
int dictionarySize, | |
long elapsedTimeEn, long sizeEn, | |
long elapsedTimeDe, | |
long inSizeDe, long outSizeDe) | |
{ | |
return (GetCompressRating(dictionarySize, elapsedTimeEn, sizeEn) + | |
GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2; | |
} | |
static void PrintValue(long v) | |
{ | |
String s = ""; | |
s += v; | |
for (int i = 0; i + s.length() < 6; i++) | |
System.out.print(" "); | |
System.out.print(s); | |
} | |
static void PrintRating(long rating) | |
{ | |
PrintValue(rating / 1000000); | |
System.out.print(" MIPS"); | |
} | |
static void PrintResults( | |
int dictionarySize, | |
long elapsedTime, | |
long size, | |
boolean decompressMode, long secondSize) | |
{ | |
long speed = MyMultDiv64(size, elapsedTime); | |
PrintValue(speed / 1024); | |
System.out.print(" KB/s "); | |
long rating; | |
if (decompressMode) | |
rating = GetDecompressRating(elapsedTime, size, secondSize); | |
else | |
rating = GetCompressRating(dictionarySize, elapsedTime, size); | |
PrintRating(rating); | |
} | |
static public int LzmaBenchmark(int numIterations, int dictionarySize) throws Exception | |
{ | |
if (numIterations <= 0) | |
return 0; | |
if (dictionarySize < (1 << 18)) | |
{ | |
System.out.println("\nError: dictionary size for benchmark must be >= 18 (256 KB)"); | |
return 1; | |
} | |
System.out.print("\n Compressing Decompressing\n\n"); | |
SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder(); | |
SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder(); | |
if (!encoder.SetDictionarySize(dictionarySize)) | |
throw new Exception("Incorrect dictionary size"); | |
int kBufferSize = dictionarySize + kAdditionalSize; | |
int kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize; | |
ByteArrayOutputStream propStream = new ByteArrayOutputStream(); | |
encoder.WriteCoderProperties(propStream); | |
byte[] propArray = propStream.toByteArray(); | |
decoder.SetDecoderProperties(propArray); | |
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; | |
long totalBenchSize = 0; | |
long totalEncodeTime = 0; | |
long totalDecodeTime = 0; | |
long totalCompressedSize = 0; | |
MyInputStream inStream = new MyInputStream(rg.Buffer, rg.BufferSize); | |
byte[] compressedBuffer = new byte[kCompressedBufferSize]; | |
MyOutputStream compressedStream = new MyOutputStream(compressedBuffer); | |
CrcOutStream crcOutStream = new CrcOutStream(); | |
MyInputStream inputCompressedStream = null; | |
int compressedSize = 0; | |
for (int i = 0; i < numIterations; i++) | |
{ | |
progressInfo.Init(); | |
inStream.reset(); | |
compressedStream.reset(); | |
encoder.Code(inStream, compressedStream, -1, -1, progressInfo); | |
long encodeTime = System.currentTimeMillis() - progressInfo.Time; | |
if (i == 0) | |
{ | |
compressedSize = compressedStream.size(); | |
inputCompressedStream = new MyInputStream(compressedBuffer, compressedSize); | |
} | |
else if (compressedSize != compressedStream.size()) | |
throw (new Exception("Encoding error")); | |
if (progressInfo.InSize == 0) | |
throw (new Exception("Internal ERROR 1282")); | |
long decodeTime = 0; | |
for (int j = 0; j < 2; j++) | |
{ | |
inputCompressedStream.reset(); | |
crcOutStream.Init(); | |
long outSize = kBufferSize; | |
long startTime = System.currentTimeMillis(); | |
if (!decoder.Code(inputCompressedStream, crcOutStream, outSize)) | |
throw (new Exception("Decoding Error"));; | |
decodeTime = System.currentTimeMillis() - startTime; | |
if (crcOutStream.GetDigest() != crc.GetDigest()) | |
throw (new Exception("CRC Error")); | |
} | |
long benchSize = kBufferSize - (long)progressInfo.InSize; | |
PrintResults(dictionarySize, encodeTime, benchSize, false, 0); | |
System.out.print(" "); | |
PrintResults(dictionarySize, decodeTime, kBufferSize, true, compressedSize); | |
System.out.println(); | |
totalBenchSize += benchSize; | |
totalEncodeTime += encodeTime; | |
totalDecodeTime += decodeTime; | |
totalCompressedSize += compressedSize; | |
} | |
System.out.println("---------------------------------------------------"); | |
PrintResults(dictionarySize, totalEncodeTime, totalBenchSize, false, 0); | |
System.out.print(" "); | |
PrintResults(dictionarySize, totalDecodeTime, | |
kBufferSize * (long)numIterations, true, totalCompressedSize); | |
System.out.println(" Average"); | |
return 0; | |
} | |
} |