xbmc: add PR3717

Signed-off-by: Stephan Raue <stephan@openelec.tv>
This commit is contained in:
Stephan Raue 2014-02-20 00:14:46 +01:00
parent f6b2d09ec5
commit 42d082560c

View File

@ -0,0 +1,358 @@
From c38d57f0580372afa46602f8635d6bb284f0a2af Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Tue, 26 Nov 2013 20:09:48 +0000
Subject: [PATCH 1/2] Add caching of infolabels
The functions CGUIInfoLabel::GetLabel and CGUIInfoLabel::GetItemLabel take
a number of strings returned from CGUIInfoManager::GetImage or
CGUIInfoManager::GetLabel, and combine them with various constant strings
which were determined during CGUIInfoLabel::Parse.
Rather than perform all the string operations on every call, this patch
changes to use a two-pass process: first it queries all the GetImage/GetLabel
strings, and then only if at least one of them has changed does it bother
rebuilding the resultant string - otherwise it re-uses the copy built on a
preceding call.
CGUIInfoLabel::GetLabel/GetItemLabel are also changed to return string
references, rather than forcing an additional string copy.
I have measured the effect while the Videos window of the default skin was
open (but idle) on a Raspberry Pi, and this reduced the CPU usage by 0.8%
from 36.2% to 35.4%:
Before After
Mean StdDev Mean StdDev Confidence Change
IdleCPU% 36.2 0.5 35.4 0.5 99.9% +2.2%
---
xbmc/guilib/GUIInfoTypes.cpp | 102 +++++++++++++++++++++++++++++++++----------
xbmc/guilib/GUIInfoTypes.h | 11 ++++-
2 files changed, 87 insertions(+), 26 deletions(-)
diff --git a/xbmc/guilib/GUIInfoTypes.cpp b/xbmc/guilib/GUIInfoTypes.cpp
index 5648a77..6bb0eed 100644
--- a/xbmc/guilib/GUIInfoTypes.cpp
+++ b/xbmc/guilib/GUIInfoTypes.cpp
@@ -136,37 +136,64 @@ void CGUIInfoLabel::SetLabel(const CStdString &label, const CStdString &fallback
Parse(label, context);
}
-CStdString CGUIInfoLabel::GetLabel(int contextWindow, bool preferImage, CStdString *fallback /*= NULL*/) const
+const std::string &CGUIInfoLabel::GetLabel(int contextWindow, bool preferImage, CStdString *fallback /*= NULL*/) const
{
- CStdString label;
- for (unsigned int i = 0; i < m_info.size(); i++)
+ for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
{
const CInfoPortion &portion = m_info[i];
if (portion.m_info)
{
- CStdString infoLabel;
+ std::string infoLabel;
if (preferImage)
infoLabel = g_infoManager.GetImage(portion.m_info, contextWindow, fallback);
if (infoLabel.empty())
infoLabel = g_infoManager.GetLabel(portion.m_info, contextWindow, fallback);
- if (!infoLabel.empty())
- label += portion.GetLabel(infoLabel);
+ if (j == m_labelPortions.size())
+ m_labelPortions.push_back(infoLabel);
+ else if (infoLabel != m_labelPortions[j])
+ {
+ m_labelPortions[j] = infoLabel;
+ m_labelDirty = true;
+ }
+ j++;
}
- else
- { // no info, so just append the prefix
- label += portion.m_prefix;
+ }
+ if (m_labelDirty)
+ {
+ m_label.clear();
+ for (unsigned int i = 0, j= 0; i < m_info.size(); i++)
+ {
+ const CInfoPortion &portion = m_info[i];
+ if (portion.m_info)
+ {
+ if (!m_labelPortions[j].empty())
+ m_label += portion.GetLabel(m_labelPortions[j]);
+ j++;
+ }
+ else
+ { // no info, so just append the prefix
+ m_label += portion.m_prefix;
+ }
}
+ if (m_label.empty()) // empty label, use the fallback
+ m_label = m_fallback;
+ m_labelDirty = false;
}
- if (label.empty()) // empty label, use the fallback
- return m_fallback;
- return label;
+ return m_label;
}
-CStdString CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool preferImages, CStdString *fallback /*= NULL*/) const
+const std::string &CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool preferImages, CStdString *fallback /*= NULL*/) const
{
- if (!item->IsFileItem()) return "";
- CStdString label;
- for (unsigned int i = 0; i < m_info.size(); i++)
+ if (!item->IsFileItem())
+ {
+ if (m_itemLabelDirty)
+ {
+ m_itemLabel = "";
+ m_itemLabelDirty = false;
+ }
+ return m_itemLabel;
+ }
+ for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
{
const CInfoPortion &portion = m_info[i];
if (portion.m_info)
@@ -176,17 +203,38 @@ CStdString CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool preferImag
infoLabel = g_infoManager.GetItemImage((const CFileItem *)item, portion.m_info, fallback);
else
infoLabel = g_infoManager.GetItemLabel((const CFileItem *)item, portion.m_info, fallback);
- if (!infoLabel.empty())
- label += portion.GetLabel(infoLabel);
+ if (j == m_itemLabelPortions.size())
+ m_itemLabelPortions.push_back(infoLabel);
+ else if (infoLabel != m_itemLabelPortions[j])
+ {
+ m_itemLabelPortions[j] = infoLabel;
+ m_itemLabelDirty = true;
+ }
+ j++;
}
- else
- { // no info, so just append the prefix
- label += portion.m_prefix;
+ }
+ if (m_itemLabelDirty)
+ {
+ m_itemLabel.clear();
+ for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
+ {
+ const CInfoPortion &portion = m_info[i];
+ if (portion.m_info)
+ {
+ if (!m_itemLabelPortions[j].empty())
+ m_itemLabel += portion.GetLabel(m_itemLabelPortions[j]);
+ j++;
+ }
+ else
+ { // no info, so just append the prefix
+ m_itemLabel += portion.m_prefix;
+ }
}
+ if (m_itemLabel.empty())
+ m_itemLabel = m_fallback;
+ m_itemLabelDirty = false;
}
- if (label.empty())
- return m_fallback;
- return label;
+ return m_itemLabel;
}
bool CGUIInfoLabel::IsEmpty() const
@@ -270,6 +318,12 @@ CStdString CGUIInfoLabel::ReplaceAddonStrings(const CStdString &label)
void CGUIInfoLabel::Parse(const CStdString &label, int context)
{
m_info.clear();
+ m_labelDirty = true;
+ m_label.clear();
+ m_labelPortions.clear();
+ m_itemLabelDirty = true;
+ m_itemLabel.clear();
+ m_itemLabelPortions.clear();
// Step 1: Replace all $LOCALIZE[number] with the real string
CStdString work = ReplaceLocalize(label);
// Step 2: Replace all $ADDON[id number] with the real string
diff --git a/xbmc/guilib/GUIInfoTypes.h b/xbmc/guilib/GUIInfoTypes.h
index 8c1c1dc..418b2c4 100644
--- a/xbmc/guilib/GUIInfoTypes.h
+++ b/xbmc/guilib/GUIInfoTypes.h
@@ -83,7 +83,7 @@ class CGUIInfoLabel
\param fallback if non-NULL, is set to an alternate value to use should the actual value be not appropriate. Defaults to NULL.
\return label (or image).
*/
- CStdString GetLabel(int contextWindow, bool preferImage = false, CStdString *fallback = NULL) const;
+ const std::string &GetLabel(int contextWindow, bool preferImage = false, CStdString *fallback = NULL) const;
/*!
\brief Gets a label (or image) for a given listitem from the info manager.
@@ -92,7 +92,7 @@ class CGUIInfoLabel
\param fallback if non-NULL, is set to an alternate value to use should the actual value be not appropriate. Defaults to NULL.
\return label (or image).
*/
- CStdString GetItemLabel(const CGUIListItem *item, bool preferImage = false, CStdString *fallback = NULL) const;
+ const std::string &GetItemLabel(const CGUIListItem *item, bool preferImage = false, CStdString *fallback = NULL) const;
bool IsConstant() const;
bool IsEmpty() const;
@@ -132,6 +132,13 @@ class CGUIInfoLabel
CStdString m_fallback;
std::vector<CInfoPortion> m_info;
+
+ mutable bool m_labelDirty;
+ mutable std::string m_label;
+ mutable std::vector<std::string> m_labelPortions;
+ mutable bool m_itemLabelDirty;
+ mutable std::string m_itemLabel;
+ mutable std::vector<std::string> m_itemLabelPortions;
};
#endif
--
1.8.5.1
From c84740a80a94c6ed36f57f5fd48744a8fd5fc5b2 Mon Sep 17 00:00:00 2001
From: Ben Avison <bavison@riscosopen.org>
Date: Tue, 10 Dec 2013 01:12:31 +0000
Subject: [PATCH 2/2] De-duplication of string cache for non-item and item
labels
---
xbmc/guilib/GUIInfoTypes.cpp | 50 +++++++++++++++++++++++++-------------------
xbmc/guilib/GUIInfoTypes.h | 4 +---
2 files changed, 29 insertions(+), 25 deletions(-)
diff --git a/xbmc/guilib/GUIInfoTypes.cpp b/xbmc/guilib/GUIInfoTypes.cpp
index 6bb0eed..d096d8e 100644
--- a/xbmc/guilib/GUIInfoTypes.cpp
+++ b/xbmc/guilib/GUIInfoTypes.cpp
@@ -121,7 +121,7 @@ void CGUIInfoColor::Parse(const CStdString &label, int context)
m_color = g_colorManager.GetColor(label);
}
-CGUIInfoLabel::CGUIInfoLabel()
+CGUIInfoLabel::CGUIInfoLabel() : m_labelDirty(true)
{
}
@@ -178,7 +178,10 @@ void CGUIInfoLabel::SetLabel(const CStdString &label, const CStdString &fallback
if (m_label.empty()) // empty label, use the fallback
m_label = m_fallback;
m_labelDirty = false;
+ m_isLabelOfListItem = false;
}
+ else
+ assert(m_isLabelOfListItem == false);
return m_label;
}
@@ -186,12 +189,15 @@ void CGUIInfoLabel::SetLabel(const CStdString &label, const CStdString &fallback
{
if (!item->IsFileItem())
{
- if (m_itemLabelDirty)
+ if (m_labelDirty)
{
- m_itemLabel = "";
- m_itemLabelDirty = false;
+ m_label = "";
+ m_labelDirty = false;
+ m_isLabelOfListItem = true;
}
- return m_itemLabel;
+ else
+ assert(m_isLabelOfListItem == true);
+ return m_label;
}
for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
{
@@ -203,38 +209,41 @@ void CGUIInfoLabel::SetLabel(const CStdString &label, const CStdString &fallback
infoLabel = g_infoManager.GetItemImage((const CFileItem *)item, portion.m_info, fallback);
else
infoLabel = g_infoManager.GetItemLabel((const CFileItem *)item, portion.m_info, fallback);
- if (j == m_itemLabelPortions.size())
- m_itemLabelPortions.push_back(infoLabel);
- else if (infoLabel != m_itemLabelPortions[j])
+ if (j == m_labelPortions.size())
+ m_labelPortions.push_back(infoLabel);
+ else if (infoLabel != m_labelPortions[j])
{
- m_itemLabelPortions[j] = infoLabel;
- m_itemLabelDirty = true;
+ m_labelPortions[j] = infoLabel;
+ m_labelDirty = true;
}
j++;
}
}
- if (m_itemLabelDirty)
+ if (m_labelDirty)
{
- m_itemLabel.clear();
+ m_label.clear();
for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
{
const CInfoPortion &portion = m_info[i];
if (portion.m_info)
{
- if (!m_itemLabelPortions[j].empty())
- m_itemLabel += portion.GetLabel(m_itemLabelPortions[j]);
+ if (!m_labelPortions[j].empty())
+ m_label += portion.GetLabel(m_labelPortions[j]);
j++;
}
else
{ // no info, so just append the prefix
- m_itemLabel += portion.m_prefix;
+ m_label += portion.m_prefix;
}
}
- if (m_itemLabel.empty())
- m_itemLabel = m_fallback;
- m_itemLabelDirty = false;
+ if (m_label.empty())
+ m_label = m_fallback;
+ m_labelDirty = false;
+ m_isLabelOfListItem = true;
}
- return m_itemLabel;
+ else
+ assert(m_isLabelOfListItem == true);
+ return m_label;
}
bool CGUIInfoLabel::IsEmpty() const
@@ -321,9 +330,6 @@ void CGUIInfoLabel::Parse(const CStdString &label, int context)
m_labelDirty = true;
m_label.clear();
m_labelPortions.clear();
- m_itemLabelDirty = true;
- m_itemLabel.clear();
- m_itemLabelPortions.clear();
// Step 1: Replace all $LOCALIZE[number] with the real string
CStdString work = ReplaceLocalize(label);
// Step 2: Replace all $ADDON[id number] with the real string
diff --git a/xbmc/guilib/GUIInfoTypes.h b/xbmc/guilib/GUIInfoTypes.h
index 418b2c4..6d9ebf7 100644
--- a/xbmc/guilib/GUIInfoTypes.h
+++ b/xbmc/guilib/GUIInfoTypes.h
@@ -133,12 +133,10 @@ class CGUIInfoLabel
CStdString m_fallback;
std::vector<CInfoPortion> m_info;
+ mutable bool m_isLabelOfListItem;
mutable bool m_labelDirty;
mutable std::string m_label;
mutable std::vector<std::string> m_labelPortions;
- mutable bool m_itemLabelDirty;
- mutable std::string m_itemLabel;
- mutable std::vector<std::string> m_itemLabelPortions;
};
#endif
--
1.8.5.1