diff --git a/packages/mediacenter/xbmc/patches/xbmc-999.80.005-PR4234.patch b/packages/mediacenter/xbmc/patches/xbmc-999.80.005-PR4234.patch new file mode 100644 index 0000000000..80c8f7303f --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-999.80.005-PR4234.patch @@ -0,0 +1,392 @@ +From b039984e34db62d1b0d9ac2f673b4658fe0f64a5 Mon Sep 17 00:00:00 2001 +From: Ben Avison +Date: Wed, 12 Feb 2014 18:43:14 +0000 +Subject: [PATCH] Improved file buffering in CArchive. + +CArchive already did some file buffering, but only on writes. Added the +equivalent code for reads. Also improved the write buffer case so that it +only ever issues sector-aligned writes (the read code does this from the +start). Shuffled various bits of code into the header file to squeeze a bit +more performance out of it. + +Profiled the effect on CFileItemList::Archive(), which is one of the slow +parts of the process of reopening a media library, on a non-overclocked +Raspberry Pi. Times are in seconds: + +TV shows (253 items) + +Before After +Mean StdDev Mean StdDev Confidence Change +0.394 0.005 0.151 0.005 100.0% +159.8% + +Songs (4115 items) + +Before After +Mean StdDev Mean StdDev Confidence Change +2.931 0.045 0.690 0.019 100.0% +324.4% +--- + xbmc/utils/Archive.cpp | 158 ++++++++++++++++++------------------------------- + xbmc/utils/Archive.h | 130 ++++++++++++++++++++++++++++++++++------ + 2 files changed, 172 insertions(+), 116 deletions(-) + +diff --git a/xbmc/utils/Archive.cpp b/xbmc/utils/Archive.cpp +index 4519e19..b2ad273 100644 +--- a/xbmc/utils/Archive.cpp ++++ b/xbmc/utils/Archive.cpp +@@ -30,24 +30,29 @@ + + using namespace XFILE; + +-#define BUFFER_MAX 4096 +- + CArchive::CArchive(CFile* pFile, int mode) + { + m_pFile = pFile; + m_iMode = mode; + +- m_pBuffer = new uint8_t[BUFFER_MAX]; +- memset(m_pBuffer, 0, BUFFER_MAX); +- +- m_BufferPos = 0; ++ m_pBuffer = new uint8_t[CARCHIVE_BUFFER_MAX]; ++ memset(m_pBuffer, 0, CARCHIVE_BUFFER_MAX); ++ if (mode == load) ++ { ++ m_BufferPos = m_pBuffer + CARCHIVE_BUFFER_MAX; ++ m_BufferRemain = 0; ++ } ++ else ++ { ++ m_BufferPos = m_pBuffer; ++ m_BufferRemain = CARCHIVE_BUFFER_MAX; ++ } + } + + CArchive::~CArchive() + { + FlushBuffer(); + delete[] m_pBuffer; +- m_BufferPos = 0; + } + + void CArchive::Close() +@@ -214,89 +219,6 @@ bool CArchive::IsStoring() + return *this; + } + +-inline CArchive& CArchive::streamout(const void* dataPtr, size_t size) +-{ +- const uint8_t* ptr = (const uint8_t*)dataPtr; +- +- if (size + m_BufferPos >= BUFFER_MAX) +- { +- FlushBuffer(); +- while (size >= BUFFER_MAX) +- { +- memcpy(m_pBuffer, ptr, BUFFER_MAX); +- m_BufferPos = BUFFER_MAX; +- ptr += BUFFER_MAX; +- size -= BUFFER_MAX; +- FlushBuffer(); +- } +- } +- +- memcpy(m_pBuffer + m_BufferPos, ptr, size); +- m_BufferPos += size; +- +- return *this; +-} +- +-CArchive& CArchive::operator>>(float& f) +-{ +- return streamin(&f, sizeof(f)); +-} +- +-CArchive& CArchive::operator>>(double& d) +-{ +- return streamin(&d, sizeof(d)); +-} +- +-CArchive& CArchive::operator>>(short int& s) +-{ +- return streamin(&s, sizeof(s)); +-} +- +-CArchive& CArchive::operator>>(unsigned short int& us) +-{ +- return streamin(&us, sizeof(us)); +-} +- +-CArchive& CArchive::operator>>(int& i) +-{ +- return streamin(&i, sizeof(i)); +-} +- +-CArchive& CArchive::operator>>(unsigned int& ui) +-{ +- return streamin(&ui, sizeof(ui)); +-} +- +-CArchive& CArchive::operator>>(long int& l) +-{ +- return streamin(&l, sizeof(l)); +-} +- +-CArchive& CArchive::operator>>(unsigned long int& ul) +-{ +- return streamin(&ul, sizeof(ul)); +-} +- +-CArchive& CArchive::operator>>(long long int& ll) +-{ +- return streamin(&ll, sizeof(ll)); +-} +- +-CArchive& CArchive::operator>>(unsigned long long int& ull) +-{ +- return streamin(&ull, sizeof(ull)); +-} +- +-CArchive& CArchive::operator>>(bool& b) +-{ +- return streamin(&b, sizeof(b)); +-} +- +-CArchive& CArchive::operator>>(char& c) +-{ +- return streamin(&c, sizeof(c)); +-} +- + CArchive& CArchive::operator>>(std::string& str) + { + size_t iLength = 0; +@@ -450,23 +372,61 @@ bool CArchive::IsStoring() + return *this; + } + +-inline CArchive& CArchive::streamin(void* dataPtr, const size_t size) ++void CArchive::FlushBuffer() + { +- size_t read = m_pFile->Read(dataPtr, size); +- if (read < size) ++ if (m_iMode == store && m_BufferPos != m_pBuffer) + { +- CLog::Log(LOGERROR, "%s: can't stream out: requested %lu bytes, was read %lu bytes", __FUNCTION__, (unsigned long)size, (unsigned long)read); +- memset(dataPtr, 0, size); ++ m_pFile->Write(m_pBuffer, m_BufferPos - m_pBuffer); ++ m_BufferPos = m_pBuffer; ++ m_BufferRemain = CARCHIVE_BUFFER_MAX; + } ++} + ++CArchive &CArchive::streamout_bufferwrap(const uint8_t *ptr, size_t size) ++{ ++ do ++ { ++ size_t chunkSize = std::min(size, m_BufferRemain); ++ m_BufferPos = std::copy(ptr, ptr + chunkSize, m_BufferPos); ++ ptr += chunkSize; ++ size -= chunkSize; ++ m_BufferRemain -= chunkSize; ++ if (m_BufferRemain == 0) ++ FlushBuffer(); ++ } while (size > 0); + return *this; + } + +-void CArchive::FlushBuffer() ++void CArchive::FillBuffer() + { +- if (m_BufferPos > 0) ++ if (m_iMode == load && m_BufferRemain == 0) + { +- m_pFile->Write(m_pBuffer, m_BufferPos); +- m_BufferPos = 0; ++ m_BufferRemain = m_pFile->Read(m_pBuffer, CARCHIVE_BUFFER_MAX); ++ m_BufferPos = m_pBuffer; + } + } ++ ++CArchive &CArchive::streamin_bufferwrap(uint8_t *ptr, size_t size) ++{ ++ uint8_t *orig_ptr = ptr; ++ size_t orig_size = size; ++ do ++ { ++ if (m_BufferRemain == 0) ++ { ++ FillBuffer(); ++ if (m_BufferRemain < CARCHIVE_BUFFER_MAX && m_BufferRemain < size) ++ { ++ CLog::Log(LOGERROR, "%s: can't stream in: requested %lu bytes, was read %lu bytes", __FUNCTION__, (unsigned long) orig_size, (unsigned long) (ptr - orig_ptr + m_BufferRemain)); ++ memset(orig_ptr, 0, orig_size); ++ return *this; ++ } ++ } ++ size_t chunkSize = std::min(size, m_BufferRemain); ++ ptr = std::copy(m_BufferPos, m_BufferPos + chunkSize, ptr); ++ m_BufferPos += chunkSize; ++ m_BufferRemain -= chunkSize; ++ size -= chunkSize; ++ } while (size > 0); ++ return *this; ++} +diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h +index 0148fcb..5b25be5 100644 +--- a/xbmc/utils/Archive.h ++++ b/xbmc/utils/Archive.h +@@ -24,6 +24,8 @@ + #include + #include "PlatformDefs.h" // for SYSTEMTIME + ++#define CARCHIVE_BUFFER_MAX 4096 ++ + namespace XFILE + { + class CFile; +@@ -77,18 +79,66 @@ class CArchive + CArchive& operator<<(const std::vector& iArray); + + // loading +- CArchive& operator>>(float& f); +- CArchive& operator>>(double& d); +- CArchive& operator>>(short int& s); +- CArchive& operator>>(unsigned short int& us); +- CArchive& operator>>(int& i); +- CArchive& operator>>(unsigned int& ui); +- CArchive& operator>>(long int& l); +- CArchive& operator>>(unsigned long int& ul); +- CArchive& operator>>(long long int& ll); +- CArchive& operator>>(unsigned long long int& ull); +- CArchive& operator>>(bool& b); +- CArchive& operator>>(char& c); ++ inline CArchive& operator>>(float& f) ++ { ++ return streamin(&f, sizeof(f)); ++ } ++ ++ inline CArchive& operator>>(double& d) ++ { ++ return streamin(&d, sizeof(d)); ++ } ++ ++ inline CArchive& operator>>(short int& s) ++ { ++ return streamin(&s, sizeof(s)); ++ } ++ ++ inline CArchive& operator>>(unsigned short int& us) ++ { ++ return streamin(&us, sizeof(us)); ++ } ++ ++ inline CArchive& operator>>(int& i) ++ { ++ return streamin(&i, sizeof(i)); ++ } ++ ++ inline CArchive& operator>>(unsigned int& ui) ++ { ++ return streamin(&ui, sizeof(ui)); ++ } ++ ++ inline CArchive& operator>>(long int& l) ++ { ++ return streamin(&l, sizeof(l)); ++ } ++ ++ inline CArchive& operator>>(unsigned long int& ul) ++ { ++ return streamin(&ul, sizeof(ul)); ++ } ++ ++ inline CArchive& operator>>(long long int& ll) ++ { ++ return streamin(&ll, sizeof(ll)); ++ } ++ ++ inline CArchive& operator>>(unsigned long long int& ull) ++ { ++ return streamin(&ull, sizeof(ull)); ++ } ++ ++ inline CArchive& operator>>(bool& b) ++ { ++ return streamin(&b, sizeof(b)); ++ } ++ ++ inline CArchive& operator>>(char& c) ++ { ++ return streamin(&c, sizeof(c)); ++ } ++ + CArchive& operator>>(std::string &str); + CArchive& operator>>(std::wstring& wstr); + CArchive& operator>>(SYSTEMTIME& time); +@@ -105,12 +155,58 @@ class CArchive + enum Mode {load = 0, store}; + + protected: +- CArchive& streamout(const void* dataPtr, size_t size); +- CArchive& streamin(void* dataPtr, const size_t size); +- void FlushBuffer(); ++ inline CArchive &streamout(const void *dataPtr, size_t size) ++ { ++ const uint8_t *ptr = (const uint8_t *) dataPtr; ++ /* Note, the buffer is flushed as soon as it is full (m_BufferRemain == size) rather ++ * than waiting until we attempt to put more data into an already full buffer */ ++ if (m_BufferRemain > size) ++ { ++ switch (size) ++ { ++ case 1: *m_BufferPos++ = *ptr; m_BufferRemain--; break; ++ case 2: *(uint16_t *) m_BufferPos = *(const uint16_t *) ptr; m_BufferPos += 2; m_BufferRemain -= 2; break; ++ case 4: *(uint32_t *) m_BufferPos = *(const uint32_t *) ptr; m_BufferPos += 4; m_BufferRemain -= 4; break; ++ default: m_BufferPos = std::copy(ptr, ptr + size, m_BufferPos); m_BufferRemain -= size; break; ++ } ++ return *this; ++ } ++ else ++ { ++ return streamout_bufferwrap(ptr, size); ++ } ++ } ++ ++ inline CArchive &streamin(void *dataPtr, size_t size) ++ { ++ uint8_t *ptr = (uint8_t *) dataPtr; ++ /* Note, refilling the buffer is deferred until we know we need to read more from it */ ++ if (m_BufferRemain >= size) ++ { ++ switch (size) ++ { ++ case 1: *ptr = *m_BufferPos++; m_BufferRemain--; break; ++ case 2: *(uint16_t *) ptr = *(const uint16_t *) m_BufferPos; m_BufferPos += 2; m_BufferRemain -= 2; break; ++ case 4: *(uint32_t *) ptr = *(const uint32_t *) m_BufferPos; m_BufferPos += 4; m_BufferRemain -= 4; break; ++ default: std::copy(m_BufferPos, m_BufferPos + size, ptr); m_BufferPos += size; m_BufferRemain -= size; break; ++ } ++ return *this; ++ } ++ else ++ { ++ return streamin_bufferwrap(ptr, size); ++ } ++ } ++ + XFILE::CFile* m_pFile; + int m_iMode; + uint8_t *m_pBuffer; +- int m_BufferPos; +-}; ++ uint8_t *m_BufferPos; ++ size_t m_BufferRemain; + ++private: ++ void FlushBuffer(); ++ CArchive &streamout_bufferwrap(const uint8_t *ptr, size_t size); ++ void FillBuffer(); ++ CArchive &streamin_bufferwrap(uint8_t *ptr, size_t size); ++}; +-- +1.8.5.1 +