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"
25 bool CGUIControlProfiler::m_bIsRunning = false;
27 CGUIControlProfilerItem::CGUIControlProfilerItem(CGUIControlProfiler *pProfiler, CGUIControlProfilerItem *pParent, CGUIControl *pControl)
28 : m_pProfiler(pProfiler), m_pParent(pParent), m_pControl(pControl), m_visTime(0), m_renderTime(0), m_i64VisStart(0), m_i64RenderStart(0)
32 m_controlID = m_pControl->GetID();
33 m_ControlType = m_pControl->GetControlType();
34 m_strDescription = m_pControl->GetDescription();
39 m_ControlType = CGUIControl::GUICONTROL_UNKNOWN;
43 CGUIControlProfilerItem::~CGUIControlProfilerItem(void)
48 void CGUIControlProfilerItem::Reset(CGUIControlProfiler *pProfiler)
51 m_ControlType = CGUIControl::GUICONTROL_UNKNOWN;
56 const unsigned int dwSize = m_vecChildren.size();
57 for (unsigned int i=0; i<dwSize; ++i)
58 delete m_vecChildren[i];
59 m_vecChildren.clear();
61 m_pProfiler = pProfiler;
64 void CGUIControlProfilerItem::BeginVisibility(void)
66 m_i64VisStart = CurrentHostCounter();
69 void CGUIControlProfilerItem::EndVisibility(void)
71 m_visTime += (unsigned int)(m_pProfiler->m_fPerfScale * (CurrentHostCounter() - m_i64VisStart));
74 void CGUIControlProfilerItem::BeginRender(void)
76 m_i64RenderStart = CurrentHostCounter();
79 void CGUIControlProfilerItem::EndRender(void)
81 m_renderTime += (unsigned int)(m_pProfiler->m_fPerfScale * (CurrentHostCounter() - m_i64RenderStart));
84 void CGUIControlProfilerItem::SaveToXML(TiXmlElement *parent)
86 TiXmlElement *xmlControl = new TiXmlElement("control");
87 parent->LinkEndChild(xmlControl);
89 const char *lpszType = NULL;
90 switch (m_ControlType)
92 case CGUIControl::GUICONTROL_BUTTON:
93 lpszType = "button"; break;
94 case CGUIControl::GUICONTROL_CHECKMARK:
95 lpszType = "checkmark"; break;
96 case CGUIControl::GUICONTROL_FADELABEL:
97 lpszType = "fadelabel"; break;
98 case CGUIControl::GUICONTROL_IMAGE:
99 case CGUIControl::GUICONTROL_BORDEREDIMAGE:
100 lpszType = "image"; break;
101 case CGUIControl::GUICONTROL_LARGE_IMAGE:
102 lpszType = "largeimage"; break;
103 case CGUIControl::GUICONTROL_LABEL:
104 lpszType = "label"; break;
105 case CGUIControl::GUICONTROL_LISTGROUP:
106 lpszType = "group"; break;
107 case CGUIControl::GUICONTROL_PROGRESS:
108 lpszType = "progress"; break;
109 case CGUIControl::GUICONTROL_RADIO:
110 lpszType = "radiobutton"; break;
111 case CGUIControl::GUICONTROL_RSS:
112 lpszType = "rss"; break;
113 case CGUIControl::GUICONTROL_SELECTBUTTON:
114 lpszType = "selectbutton"; break;
115 case CGUIControl::GUICONTROL_SLIDER:
116 lpszType = "slider"; break;
117 case CGUIControl::GUICONTROL_SETTINGS_SLIDER:
118 lpszType = "sliderex"; break;
119 case CGUIControl::GUICONTROL_SPIN:
120 lpszType = "spincontrol"; break;
121 case CGUIControl::GUICONTROL_SPINEX:
122 lpszType = "spincontrolex"; break;
123 case CGUIControl::GUICONTROL_TEXTBOX:
124 lpszType = "textbox"; break;
125 case CGUIControl::GUICONTROL_TOGGLEBUTTON:
126 lpszType = "togglebutton"; break;
127 case CGUIControl::GUICONTROL_VIDEO:
128 lpszType = "videowindow"; break;
129 case CGUIControl::GUICONTROL_MOVER:
130 lpszType = "mover"; break;
131 case CGUIControl::GUICONTROL_RESIZE:
132 lpszType = "resize"; break;
133 case CGUIControl::GUICONTROL_EDIT:
134 lpszType = "edit"; break;
135 case CGUIControl::GUICONTROL_VISUALISATION:
136 lpszType = "visualisation"; break;
137 case CGUIControl::GUICONTROL_MULTI_IMAGE:
138 lpszType = "multiimage"; break;
139 case CGUIControl::GUICONTROL_GROUP:
140 lpszType = "group"; break;
141 case CGUIControl::GUICONTROL_GROUPLIST:
142 lpszType = "grouplist"; break;
143 case CGUIControl::GUICONTROL_SCROLLBAR:
144 lpszType = "scrollbar"; break;
145 case CGUIControl::GUICONTROL_LISTLABEL:
146 lpszType = "label"; break;
147 case CGUIControl::GUICONTROL_MULTISELECT:
148 lpszType = "multiselect"; break;
149 case CGUIControl::GUICONTAINER_LIST:
150 lpszType = "list"; break;
151 case CGUIControl::GUICONTAINER_WRAPLIST:
152 lpszType = "wraplist"; break;
153 case CGUIControl::GUICONTAINER_FIXEDLIST:
154 lpszType = "fixedlist"; break;
155 case CGUIControl::GUICONTAINER_PANEL:
156 lpszType = "panel"; break;
157 //case CGUIControl::GUICONTROL_UNKNOWN:
163 xmlControl->SetAttribute("type", lpszType);
164 if (m_controlID != 0)
167 str.Format("%u", m_controlID);
168 xmlControl->SetAttribute("id", str.c_str());
171 float pct = (float)GetTotalTime() / (float)m_pProfiler->GetTotalTime();
175 str.Format("%.0f", pct * 100.0f);
176 xmlControl->SetAttribute("percent", str.c_str());
179 if (!m_strDescription.IsEmpty())
181 TiXmlElement *elem = new TiXmlElement("description");
182 xmlControl->LinkEndChild(elem);
183 TiXmlText *text = new TiXmlText(m_strDescription.c_str());
184 elem->LinkEndChild(text);
187 // Note time is stored in 1/100 milliseconds but reported in ms
188 unsigned int vis = m_visTime / 100;
189 unsigned int rend = m_renderTime / 100;
193 TiXmlElement *elem = new TiXmlElement("rendertime");
194 xmlControl->LinkEndChild(elem);
195 val.Format("%u", rend);
196 TiXmlText *text = new TiXmlText(val.c_str());
197 elem->LinkEndChild(text);
199 elem = new TiXmlElement("visibletime");
200 xmlControl->LinkEndChild(elem);
201 val.Format("%u", vis);
202 text = new TiXmlText(val.c_str());
203 elem->LinkEndChild(text);
206 if (m_vecChildren.size())
208 TiXmlElement *xmlChilds = new TiXmlElement("children");
209 xmlControl->LinkEndChild(xmlChilds);
210 const unsigned int dwSize = m_vecChildren.size();
211 for (unsigned int i=0; i<dwSize; ++i)
212 m_vecChildren[i]->SaveToXML(xmlChilds);
216 CGUIControlProfilerItem *CGUIControlProfilerItem::AddControl(CGUIControl *pControl)
218 m_vecChildren.push_back(new CGUIControlProfilerItem(m_pProfiler, this, pControl));
219 return m_vecChildren.back();
222 CGUIControlProfilerItem *CGUIControlProfilerItem::FindOrAddControl(CGUIControl *pControl, bool recurse)
224 const unsigned int dwSize = m_vecChildren.size();
225 for (unsigned int i=0; i<dwSize; ++i)
227 CGUIControlProfilerItem *p = m_vecChildren[i];
228 if (p->m_pControl == pControl)
230 if (recurse && (p = p->FindOrAddControl(pControl, true)))
234 if (pControl->GetParentControl() == m_pControl)
235 return AddControl(pControl);
240 CGUIControlProfiler::CGUIControlProfiler(void)
241 : m_ItemHead(NULL, NULL, NULL), m_pLastItem(NULL), m_iMaxFrameCount(200), m_iFrameCount(0)
242 // m_bIsRunning(false), no isRunning because it is static
244 m_fPerfScale = 100000.0f / CurrentHostFrequency();
247 CGUIControlProfiler &CGUIControlProfiler::Instance(void)
249 static CGUIControlProfiler _instance;
253 bool CGUIControlProfiler::IsRunning(void)
258 void CGUIControlProfiler::Start(void)
263 m_ItemHead.Reset(this);
266 void CGUIControlProfiler::BeginVisibility(CGUIControl *pControl)
268 CGUIControlProfilerItem *item = FindOrAddControl(pControl);
269 item->BeginVisibility();
272 void CGUIControlProfiler::EndVisibility(CGUIControl *pControl)
274 CGUIControlProfilerItem *item = FindOrAddControl(pControl);
275 item->EndVisibility();
278 void CGUIControlProfiler::BeginRender(CGUIControl *pControl)
280 CGUIControlProfilerItem *item = FindOrAddControl(pControl);
284 void CGUIControlProfiler::EndRender(CGUIControl *pControl)
286 CGUIControlProfilerItem *item = FindOrAddControl(pControl);
290 CGUIControlProfilerItem *CGUIControlProfiler::FindOrAddControl(CGUIControl *pControl)
294 // Typically calls come in pairs so the last control we found is probably
295 // the one we want again next time
296 if (m_pLastItem->m_pControl == pControl)
298 // If that control is not a match, usually the one we want is the next
299 // sibling of that control, or the parent of that control so check
300 // the parent first as it is more convenient
301 m_pLastItem = m_pLastItem->m_pParent;
302 if (m_pLastItem && m_pLastItem->m_pControl == pControl)
304 // continued from above, this searches the original control's siblings
306 m_pLastItem = m_pLastItem->FindOrAddControl(pControl, false);
311 m_pLastItem = m_ItemHead.FindOrAddControl(pControl, true);
313 m_pLastItem = m_ItemHead.AddControl(pControl);
318 void CGUIControlProfiler::EndFrame(void)
321 if (m_iFrameCount >= m_iMaxFrameCount)
323 const unsigned int dwSize = m_ItemHead.m_vecChildren.size();
324 for (unsigned int i=0; i<dwSize; ++i)
326 CGUIControlProfilerItem *p = m_ItemHead.m_vecChildren[i];
327 m_ItemHead.m_visTime += p->m_visTime;
328 m_ItemHead.m_renderTime += p->m_renderTime;
331 m_bIsRunning = false;
333 m_ItemHead.Reset(this);
337 bool CGUIControlProfiler::SaveResults(void)
339 if (m_strOutputFile.IsEmpty())
343 TiXmlDeclaration decl("1.0", "", "yes");
344 doc.InsertEndChild(decl);
346 TiXmlElement *root = new TiXmlElement("guicontrolprofiler");
348 str.Format("%d", m_iFrameCount);
349 root->SetAttribute("framecount", str.c_str());
350 root->SetAttribute("timeunit", "ms");
351 doc.LinkEndChild(root);
353 m_ItemHead.SaveToXML(root);
354 return doc.SaveFile(m_strOutputFile);