2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "GUIControlProfiler.h"
22 #include "utils/XBMCTinyXML.h"
23 #include "utils/TimeUtils.h"
24 #include "utils/StringUtils.h"
26 bool CGUIControlProfiler::m_bIsRunning = false;
28 CGUIControlProfilerItem::CGUIControlProfilerItem(CGUIControlProfiler *pProfiler, CGUIControlProfilerItem *pParent, CGUIControl *pControl)
29 : m_pProfiler(pProfiler), m_pParent(pParent), m_pControl(pControl), m_visTime(0), m_renderTime(0), m_i64VisStart(0), m_i64RenderStart(0)
33 m_controlID = m_pControl->GetID();
34 m_ControlType = m_pControl->GetControlType();
35 m_strDescription = m_pControl->GetDescription();
40 m_ControlType = CGUIControl::GUICONTROL_UNKNOWN;
44 CGUIControlProfilerItem::~CGUIControlProfilerItem(void)
49 void CGUIControlProfilerItem::Reset(CGUIControlProfiler *pProfiler)
52 m_ControlType = CGUIControl::GUICONTROL_UNKNOWN;
57 const unsigned int dwSize = m_vecChildren.size();
58 for (unsigned int i=0; i<dwSize; ++i)
59 delete m_vecChildren[i];
60 m_vecChildren.clear();
62 m_pProfiler = pProfiler;
65 void CGUIControlProfilerItem::BeginVisibility(void)
67 m_i64VisStart = CurrentHostCounter();
70 void CGUIControlProfilerItem::EndVisibility(void)
72 m_visTime += (unsigned int)(m_pProfiler->m_fPerfScale * (CurrentHostCounter() - m_i64VisStart));
75 void CGUIControlProfilerItem::BeginRender(void)
77 m_i64RenderStart = CurrentHostCounter();
80 void CGUIControlProfilerItem::EndRender(void)
82 m_renderTime += (unsigned int)(m_pProfiler->m_fPerfScale * (CurrentHostCounter() - m_i64RenderStart));
85 void CGUIControlProfilerItem::SaveToXML(TiXmlElement *parent)
87 TiXmlElement *xmlControl = new TiXmlElement("control");
88 parent->LinkEndChild(xmlControl);
90 const char *lpszType = NULL;
91 switch (m_ControlType)
93 case CGUIControl::GUICONTROL_BUTTON:
94 lpszType = "button"; break;
95 case CGUIControl::GUICONTROL_CHECKMARK:
96 lpszType = "checkmark"; break;
97 case CGUIControl::GUICONTROL_FADELABEL:
98 lpszType = "fadelabel"; break;
99 case CGUIControl::GUICONTROL_IMAGE:
100 case CGUIControl::GUICONTROL_BORDEREDIMAGE:
101 lpszType = "image"; break;
102 case CGUIControl::GUICONTROL_LARGE_IMAGE:
103 lpszType = "largeimage"; break;
104 case CGUIControl::GUICONTROL_LABEL:
105 lpszType = "label"; break;
106 case CGUIControl::GUICONTROL_LISTGROUP:
107 lpszType = "group"; break;
108 case CGUIControl::GUICONTROL_PROGRESS:
109 lpszType = "progress"; break;
110 case CGUIControl::GUICONTROL_RADIO:
111 lpszType = "radiobutton"; break;
112 case CGUIControl::GUICONTROL_RSS:
113 lpszType = "rss"; break;
114 case CGUIControl::GUICONTROL_SELECTBUTTON:
115 lpszType = "selectbutton"; break;
116 case CGUIControl::GUICONTROL_SLIDER:
117 lpszType = "slider"; break;
118 case CGUIControl::GUICONTROL_SETTINGS_SLIDER:
119 lpszType = "sliderex"; break;
120 case CGUIControl::GUICONTROL_SPIN:
121 lpszType = "spincontrol"; break;
122 case CGUIControl::GUICONTROL_SPINEX:
123 lpszType = "spincontrolex"; break;
124 case CGUIControl::GUICONTROL_TEXTBOX:
125 lpszType = "textbox"; break;
126 case CGUIControl::GUICONTROL_TOGGLEBUTTON:
127 lpszType = "togglebutton"; break;
128 case CGUIControl::GUICONTROL_VIDEO:
129 lpszType = "videowindow"; break;
130 case CGUIControl::GUICONTROL_MOVER:
131 lpszType = "mover"; break;
132 case CGUIControl::GUICONTROL_RESIZE:
133 lpszType = "resize"; break;
134 case CGUIControl::GUICONTROL_EDIT:
135 lpszType = "edit"; break;
136 case CGUIControl::GUICONTROL_VISUALISATION:
137 lpszType = "visualisation"; break;
138 case CGUIControl::GUICONTROL_MULTI_IMAGE:
139 lpszType = "multiimage"; break;
140 case CGUIControl::GUICONTROL_GROUP:
141 lpszType = "group"; break;
142 case CGUIControl::GUICONTROL_GROUPLIST:
143 lpszType = "grouplist"; break;
144 case CGUIControl::GUICONTROL_SCROLLBAR:
145 lpszType = "scrollbar"; break;
146 case CGUIControl::GUICONTROL_LISTLABEL:
147 lpszType = "label"; break;
148 case CGUIControl::GUICONTROL_MULTISELECT:
149 lpszType = "multiselect"; break;
150 case CGUIControl::GUICONTAINER_LIST:
151 lpszType = "list"; break;
152 case CGUIControl::GUICONTAINER_WRAPLIST:
153 lpszType = "wraplist"; break;
154 case CGUIControl::GUICONTAINER_FIXEDLIST:
155 lpszType = "fixedlist"; break;
156 case CGUIControl::GUICONTAINER_PANEL:
157 lpszType = "panel"; break;
158 //case CGUIControl::GUICONTROL_UNKNOWN:
164 xmlControl->SetAttribute("type", lpszType);
165 if (m_controlID != 0)
167 CStdString str = StringUtils::Format("%u", m_controlID);
168 xmlControl->SetAttribute("id", str.c_str());
171 float pct = (float)GetTotalTime() / (float)m_pProfiler->GetTotalTime();
174 CStdString str = StringUtils::Format("%.0f", pct * 100.0f);
175 xmlControl->SetAttribute("percent", str.c_str());
178 if (!m_strDescription.IsEmpty())
180 TiXmlElement *elem = new TiXmlElement("description");
181 xmlControl->LinkEndChild(elem);
182 TiXmlText *text = new TiXmlText(m_strDescription.c_str());
183 elem->LinkEndChild(text);
186 // Note time is stored in 1/100 milliseconds but reported in ms
187 unsigned int vis = m_visTime / 100;
188 unsigned int rend = m_renderTime / 100;
192 TiXmlElement *elem = new TiXmlElement("rendertime");
193 xmlControl->LinkEndChild(elem);
194 val = StringUtils::Format("%u", rend);
195 TiXmlText *text = new TiXmlText(val.c_str());
196 elem->LinkEndChild(text);
198 elem = new TiXmlElement("visibletime");
199 xmlControl->LinkEndChild(elem);
200 val = StringUtils::Format("%u", vis);
201 text = new TiXmlText(val.c_str());
202 elem->LinkEndChild(text);
205 if (m_vecChildren.size())
207 TiXmlElement *xmlChilds = new TiXmlElement("children");
208 xmlControl->LinkEndChild(xmlChilds);
209 const unsigned int dwSize = m_vecChildren.size();
210 for (unsigned int i=0; i<dwSize; ++i)
211 m_vecChildren[i]->SaveToXML(xmlChilds);
215 CGUIControlProfilerItem *CGUIControlProfilerItem::AddControl(CGUIControl *pControl)
217 m_vecChildren.push_back(new CGUIControlProfilerItem(m_pProfiler, this, pControl));
218 return m_vecChildren.back();
221 CGUIControlProfilerItem *CGUIControlProfilerItem::FindOrAddControl(CGUIControl *pControl, bool recurse)
223 const unsigned int dwSize = m_vecChildren.size();
224 for (unsigned int i=0; i<dwSize; ++i)
226 CGUIControlProfilerItem *p = m_vecChildren[i];
227 if (p->m_pControl == pControl)
229 if (recurse && (p = p->FindOrAddControl(pControl, true)))
233 if (pControl->GetParentControl() == m_pControl)
234 return AddControl(pControl);
239 CGUIControlProfiler::CGUIControlProfiler(void)
240 : m_ItemHead(NULL, NULL, NULL), m_pLastItem(NULL), m_iMaxFrameCount(200), m_iFrameCount(0)
241 // m_bIsRunning(false), no isRunning because it is static
243 m_fPerfScale = 100000.0f / CurrentHostFrequency();
246 CGUIControlProfiler &CGUIControlProfiler::Instance(void)
248 static CGUIControlProfiler _instance;
252 bool CGUIControlProfiler::IsRunning(void)
257 void CGUIControlProfiler::Start(void)
262 m_ItemHead.Reset(this);
265 void CGUIControlProfiler::BeginVisibility(CGUIControl *pControl)
267 CGUIControlProfilerItem *item = FindOrAddControl(pControl);
268 item->BeginVisibility();
271 void CGUIControlProfiler::EndVisibility(CGUIControl *pControl)
273 CGUIControlProfilerItem *item = FindOrAddControl(pControl);
274 item->EndVisibility();
277 void CGUIControlProfiler::BeginRender(CGUIControl *pControl)
279 CGUIControlProfilerItem *item = FindOrAddControl(pControl);
283 void CGUIControlProfiler::EndRender(CGUIControl *pControl)
285 CGUIControlProfilerItem *item = FindOrAddControl(pControl);
289 CGUIControlProfilerItem *CGUIControlProfiler::FindOrAddControl(CGUIControl *pControl)
293 // Typically calls come in pairs so the last control we found is probably
294 // the one we want again next time
295 if (m_pLastItem->m_pControl == pControl)
297 // If that control is not a match, usually the one we want is the next
298 // sibling of that control, or the parent of that control so check
299 // the parent first as it is more convenient
300 m_pLastItem = m_pLastItem->m_pParent;
301 if (m_pLastItem && m_pLastItem->m_pControl == pControl)
303 // continued from above, this searches the original control's siblings
305 m_pLastItem = m_pLastItem->FindOrAddControl(pControl, false);
310 m_pLastItem = m_ItemHead.FindOrAddControl(pControl, true);
312 m_pLastItem = m_ItemHead.AddControl(pControl);
317 void CGUIControlProfiler::EndFrame(void)
320 if (m_iFrameCount >= m_iMaxFrameCount)
322 const unsigned int dwSize = m_ItemHead.m_vecChildren.size();
323 for (unsigned int i=0; i<dwSize; ++i)
325 CGUIControlProfilerItem *p = m_ItemHead.m_vecChildren[i];
326 m_ItemHead.m_visTime += p->m_visTime;
327 m_ItemHead.m_renderTime += p->m_renderTime;
330 m_bIsRunning = false;
332 m_ItemHead.Reset(this);
336 bool CGUIControlProfiler::SaveResults(void)
338 if (m_strOutputFile.IsEmpty())
342 TiXmlDeclaration decl("1.0", "", "yes");
343 doc.InsertEndChild(decl);
345 TiXmlElement *root = new TiXmlElement("guicontrolprofiler");
346 CStdString str = StringUtils::Format("%d", m_iFrameCount);
347 root->SetAttribute("framecount", str.c_str());
348 root->SetAttribute("timeunit", "ms");
349 doc.LinkEndChild(root);
351 m_ItemHead.SaveToXML(root);
352 return doc.SaveFile(m_strOutputFile);