xbmc: add PR4234

Signed-off-by: Stephan Raue <stephan@openelec.tv>
This commit is contained in:
Stephan Raue 2014-02-19 23:25:41 +01:00
parent 3bc6af38d5
commit 61981b6cd2

View File

@ -0,0 +1,392 @@
From b039984e34db62d1b0d9ac2f673b4658fe0f64a5 Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
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 <vector>
#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<int>& 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