From e885ac1821c26c7e3ebed8e92db38239e1770255 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 8 Jul 2015 17:32:51 -0700 Subject: [PATCH] improved performance of ByteCountCoding<> decode --- interface/src/Application.cpp | 1 + interface/src/Util.cpp | 72 +++++++++++++++++++++ interface/src/Util.h | 1 + libraries/shared/src/ByteCountCoding.h | 88 ++++++++++++++------------ 4 files changed, 123 insertions(+), 39 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 48fa53777d..cd15f2f4c7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1014,6 +1014,7 @@ void Application::paintGL() { void Application::runTests() { runTimingTests(); + //runUnitTests(); } void Application::audioMuteToggled() { diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index bf4df3f3d2..5f04010b47 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -21,6 +21,7 @@ #include +#include #include #include @@ -229,6 +230,43 @@ void runTimingTests() { elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; qCDebug(interfaceapp, "vec3 assign and dot() usecs: %f, last result:%f", (double)(elapsedUsecs / numTests), (double)result); + + + quint64 BYTE_CODE_MAX_VALUE = 99999999; + quint64 BYTE_CODE_TESTS_SKIP = 999; + + QByteArray extraJunk; + const int EXTRA_JUNK_SIZE = 200; + extraJunk.append((unsigned char)255); + for (int i = 0; i < EXTRA_JUNK_SIZE; i++) { + extraJunk.append(QString("junk")); + } + + { + startTime.start(); + quint64 tests = 0; + quint64 failed = 0; + for (quint64 value = 0; value < BYTE_CODE_MAX_VALUE; value += BYTE_CODE_TESTS_SKIP) { + quint64 valueA = value; // usecTimestampNow(); + ByteCountCoded codedValueA = valueA; + QByteArray codedValueABuffer = codedValueA; + codedValueABuffer.append(extraJunk); + ByteCountCoded decodedValueA; + decodedValueA.decode(codedValueABuffer); + quint64 valueADecoded = decodedValueA; + tests++; + if (valueA != valueADecoded) { + qDebug() << "FAILED! value:" << valueA << "decoded:" << valueADecoded; + failed++; + } + + } + elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; + qCDebug(interfaceapp) << "ByteCountCoded usecs: " << elapsedUsecs + << "per test:" << (double) (elapsedUsecs / tests) + << "tests:" << tests + << "failed:" << failed; + } } bool rayIntersectsSphere(const glm::vec3& rayStarting, const glm::vec3& rayNormalizedDirection, @@ -271,3 +309,37 @@ bool pointInSphere(glm::vec3& point, glm::vec3& sphereCenter, double sphereRadiu } return false; } + +void runUnitTests() { + + quint64 LAST_TEST = 10; + quint64 SKIP_BY = 1; + + for (quint64 value = 0; value <= LAST_TEST; value += SKIP_BY) { + qDebug() << "value:" << value; + + ByteCountCoded codedValue = value; + + QByteArray codedValueBuffer = codedValue; + + codedValueBuffer.append((unsigned char)255); + codedValueBuffer.append(QString("junk")); + + qDebug() << "codedValueBuffer:"; + outputBufferBits((const unsigned char*)codedValueBuffer.constData(), codedValueBuffer.size()); + + ByteCountCoded valueDecoder = codedValueBuffer; + quint64 valueDecoded = valueDecoder; + qDebug() << "valueDecoded:" << valueDecoded; + + + if (value == valueDecoded) { + qDebug() << "SUCCESS!"; + } else { + qDebug() << "FAILED!"; + } + + } +} + + diff --git a/interface/src/Util.h b/interface/src/Util.h index ed05209747..d252c26bef 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -30,6 +30,7 @@ void drawText(int x, int y, float scale, float radians, int mono, void renderCollisionOverlay(int width, int height, float magnitude, float red = 0, float blue = 0, float green = 0); void runTimingTests(); +void runUnitTests(); bool rayIntersectsSphere(const glm::vec3& rayStarting, const glm::vec3& rayNormalizedDirection, const glm::vec3& sphereCenter, float sphereRadius, float& distance); diff --git a/libraries/shared/src/ByteCountCoding.h b/libraries/shared/src/ByteCountCoding.h index efde19d45b..88f07230be 100644 --- a/libraries/shared/src/ByteCountCoding.h +++ b/libraries/shared/src/ByteCountCoding.h @@ -26,6 +26,8 @@ #include #include +#include "SharedUtil.h" + #include "NumericalConstants.h" template class ByteCountCoded { @@ -40,6 +42,7 @@ public: QByteArray encode() const; void decode(const QByteArray& fromEncoded); + void decode(const char* encodedBuffer, int encodedSize); bool operator==(const ByteCountCoded& other) const { return data == other.data; } bool operator!=(const ByteCountCoded& other) const { return data != other.data; } @@ -113,50 +116,57 @@ template inline QByteArray ByteCountCoded::encode() const { } template inline void ByteCountCoded::decode(const QByteArray& fromEncodedBytes) { - // first convert the ByteArray into a BitArray... - QBitArray encodedBits; - int bitCount = BITS_IN_BYTE * fromEncodedBytes.count(); - encodedBits.resize(bitCount); - - // copies the QByteArray into a QBitArray - for(int byte = 0; byte < fromEncodedBytes.count(); byte++) { - char originalByte = fromEncodedBytes.at(byte); - for(int bit = 0; bit < BITS_IN_BYTE; bit++) { - int shiftBy = BITS_IN_BYTE - (bit + 1); - char maskBit = ( 1 << shiftBy); - bool bitValue = originalByte & maskBit; - encodedBits.setBit(byte * BITS_IN_BYTE + bit, bitValue); - } - } - - // next, read the leading bits to determine the correct number of bytes to decode (may not match the QByteArray) + decode(fromEncodedBytes.constData(), fromEncodedBytes.size()); +} + +template inline void ByteCountCoded::decode(const char* encodedBuffer, int encodedSize) { + data = 0; // reset data + int bitCount = BITS_IN_BYTE * encodedSize; + int encodedByteCount = 1; // there is at least 1 byte (after the leadBits) int leadBits = 1; // there is always at least 1 lead bit - int bitAt; - for (bitAt = 0; bitAt < bitCount; bitAt++) { - if (encodedBits.at(bitAt)) { - encodedByteCount++; - leadBits++; - } else { - break; - } - } - int expectedBitCount = (encodedByteCount * BITS_IN_BYTE) - leadBits; - - T value = 0; - - if (expectedBitCount <= (encodedBits.size() - leadBits)) { - // Now, keep reading... - int valueStartsAt = bitAt + 1; - T bitValue = 1; - for (bitAt = valueStartsAt; bitAt < (expectedBitCount + leadBits); bitAt++) { - if(encodedBits.at(bitAt)) { - value += bitValue; + bool inLeadBits = true; + int bitAt = 0; + int expectedBitCount; // unknown at this point + int lastValueBit; + T bitValue = 1; + + for(int byte = 0; byte < encodedSize; byte++) { + char originalByte = encodedBuffer[byte]; + unsigned char maskBit = 128; + for(int bit = 0; bit < BITS_IN_BYTE; bit++) { + //int shiftBy = BITS_IN_BYTE - (bit + 1); + //char maskBit = (1 << shiftBy); + bool bitIsSet = originalByte & maskBit; + + // Processing of the lead bits + if (inLeadBits) { + if (bitIsSet) { + encodedByteCount++; + leadBits++; + } else { + inLeadBits = false; // once we hit our first 0, we know we're out of the lead bits + expectedBitCount = (encodedByteCount * BITS_IN_BYTE) - leadBits; + lastValueBit = expectedBitCount + bitAt; + // check to see if the remainder of our buffer is sufficient + if (expectedBitCount > (bitCount - leadBits)) { + break; + } + } + } else { + if (bitAt > lastValueBit) { + break; + } + + if(bitIsSet) { + data += bitValue; + } + bitValue *= 2; } - bitValue *= 2; + bitAt++; + maskBit = maskBit >> 1; } } - data = value; } #endif // hifi_ByteCountCoding_h