From 42d082560cab1c333f91d6e9e8d62b929946eb68 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Thu, 20 Feb 2014 00:14:46 +0100 Subject: [PATCH] xbmc: add PR3717 Signed-off-by: Stephan Raue --- .../xbmc/patches/xbmc-999.80.006-PR3717.patch | 358 ++++++++++++++++++ 1 file changed, 358 insertions(+) create mode 100644 packages/mediacenter/xbmc/patches/xbmc-999.80.006-PR3717.patch diff --git a/packages/mediacenter/xbmc/patches/xbmc-999.80.006-PR3717.patch b/packages/mediacenter/xbmc/patches/xbmc-999.80.006-PR3717.patch new file mode 100644 index 0000000000..55a40e2e3d --- /dev/null +++ b/packages/mediacenter/xbmc/patches/xbmc-999.80.006-PR3717.patch @@ -0,0 +1,358 @@ +From c38d57f0580372afa46602f8635d6bb284f0a2af Mon Sep 17 00:00:00 2001 +From: Ben Avison +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 m_info; ++ ++ mutable bool m_labelDirty; ++ mutable std::string m_label; ++ mutable std::vector m_labelPortions; ++ mutable bool m_itemLabelDirty; ++ mutable std::string m_itemLabel; ++ mutable std::vector m_itemLabelPortions; + }; + + #endif +-- +1.8.5.1 + + +From c84740a80a94c6ed36f57f5fd48744a8fd5fc5b2 Mon Sep 17 00:00:00 2001 +From: Ben Avison +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 m_info; + ++ mutable bool m_isLabelOfListItem; + mutable bool m_labelDirty; + mutable std::string m_label; + mutable std::vector m_labelPortions; +- mutable bool m_itemLabelDirty; +- mutable std::string m_itemLabel; +- mutable std::vector m_itemLabelPortions; + }; + + #endif +-- +1.8.5.1 +