[cosmetics] update date in GPL header
[vuplus_xbmc] / xbmc / guilib / GUIControlProfiler.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://www.xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
21 #include "GUIControlProfiler.h"
22 #include "utils/XBMCTinyXML.h"
23 #include "utils/TimeUtils.h"
24
25 bool CGUIControlProfiler::m_bIsRunning = false;
26
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)
29 {
30   if (m_pControl)
31   {
32     m_controlID = m_pControl->GetID();
33     m_ControlType = m_pControl->GetControlType();
34     m_strDescription = m_pControl->GetDescription();
35   }
36   else
37   {
38     m_controlID = 0;
39     m_ControlType = CGUIControl::GUICONTROL_UNKNOWN;
40   }
41 }
42
43 CGUIControlProfilerItem::~CGUIControlProfilerItem(void)
44 {
45   Reset(NULL);
46 }
47
48 void CGUIControlProfilerItem::Reset(CGUIControlProfiler *pProfiler)
49 {
50   m_controlID = 0;
51   m_ControlType = CGUIControl::GUICONTROL_UNKNOWN;
52   m_pControl = NULL;
53
54   m_visTime = 0;
55   m_renderTime = 0;
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();
60
61   m_pProfiler = pProfiler;
62 }
63
64 void CGUIControlProfilerItem::BeginVisibility(void)
65 {
66   m_i64VisStart = CurrentHostCounter();
67 }
68
69 void CGUIControlProfilerItem::EndVisibility(void)
70 {
71   m_visTime += (unsigned int)(m_pProfiler->m_fPerfScale * (CurrentHostCounter() - m_i64VisStart));
72 }
73
74 void CGUIControlProfilerItem::BeginRender(void)
75 {
76   m_i64RenderStart = CurrentHostCounter();
77 }
78
79 void CGUIControlProfilerItem::EndRender(void)
80 {
81   m_renderTime += (unsigned int)(m_pProfiler->m_fPerfScale * (CurrentHostCounter() - m_i64RenderStart));
82 }
83
84 void CGUIControlProfilerItem::SaveToXML(TiXmlElement *parent)
85 {
86   TiXmlElement *xmlControl = new TiXmlElement("control");
87   parent->LinkEndChild(xmlControl);
88
89   const char *lpszType = NULL;
90   switch (m_ControlType)
91   {
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:
158   default:
159     break;
160   }
161
162   if (lpszType)
163     xmlControl->SetAttribute("type", lpszType);
164   if (m_controlID != 0)
165   {
166     CStdString str;
167     str.Format("%u", m_controlID);
168     xmlControl->SetAttribute("id", str.c_str());
169   }
170
171   float pct = (float)GetTotalTime() / (float)m_pProfiler->GetTotalTime();
172   if (pct > 0.01f)
173   {
174     CStdString str;
175     str.Format("%.0f", pct * 100.0f);
176     xmlControl->SetAttribute("percent", str.c_str());
177   }
178
179   if (!m_strDescription.IsEmpty())
180   {
181     TiXmlElement *elem = new TiXmlElement("description");
182     xmlControl->LinkEndChild(elem);
183     TiXmlText *text = new TiXmlText(m_strDescription.c_str());
184     elem->LinkEndChild(text);
185   }
186
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;
190   if (vis || rend)
191   {
192     CStdString val;
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);
198
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);
204   }
205
206   if (m_vecChildren.size())
207   {
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);
213   }
214 }
215
216 CGUIControlProfilerItem *CGUIControlProfilerItem::AddControl(CGUIControl *pControl)
217 {
218   m_vecChildren.push_back(new CGUIControlProfilerItem(m_pProfiler, this, pControl));
219   return m_vecChildren.back();
220 }
221
222 CGUIControlProfilerItem *CGUIControlProfilerItem::FindOrAddControl(CGUIControl *pControl, bool recurse)
223 {
224   const unsigned int dwSize = m_vecChildren.size();
225   for (unsigned int i=0; i<dwSize; ++i)
226   {
227     CGUIControlProfilerItem *p = m_vecChildren[i];
228     if (p->m_pControl == pControl)
229       return p;
230     if (recurse && (p = p->FindOrAddControl(pControl, true)))
231       return p;
232   }
233
234   if (pControl->GetParentControl() == m_pControl)
235     return AddControl(pControl);
236
237   return NULL;
238 }
239
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
243 {
244   m_fPerfScale = 100000.0f / CurrentHostFrequency();
245 }
246
247 CGUIControlProfiler &CGUIControlProfiler::Instance(void)
248 {
249   static CGUIControlProfiler _instance;
250   return _instance;
251 }
252
253 bool CGUIControlProfiler::IsRunning(void)
254 {
255   return m_bIsRunning;
256 }
257
258 void CGUIControlProfiler::Start(void)
259 {
260   m_iFrameCount = 0;
261   m_bIsRunning = true;
262   m_pLastItem = NULL;
263   m_ItemHead.Reset(this);
264 }
265
266 void CGUIControlProfiler::BeginVisibility(CGUIControl *pControl)
267 {
268   CGUIControlProfilerItem *item = FindOrAddControl(pControl);
269   item->BeginVisibility();
270 }
271
272 void CGUIControlProfiler::EndVisibility(CGUIControl *pControl)
273 {
274   CGUIControlProfilerItem *item = FindOrAddControl(pControl);
275   item->EndVisibility();
276 }
277
278 void CGUIControlProfiler::BeginRender(CGUIControl *pControl)
279 {
280   CGUIControlProfilerItem *item = FindOrAddControl(pControl);
281   item->BeginRender();
282 }
283
284 void CGUIControlProfiler::EndRender(CGUIControl *pControl)
285 {
286   CGUIControlProfilerItem *item = FindOrAddControl(pControl);
287   item->EndRender();
288 }
289
290 CGUIControlProfilerItem *CGUIControlProfiler::FindOrAddControl(CGUIControl *pControl)
291 {
292   if (m_pLastItem)
293   {
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)
297       return m_pLastItem;
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)
303       return m_pLastItem;
304     // continued from above, this searches the original control's siblings
305     if (m_pLastItem)
306       m_pLastItem = m_pLastItem->FindOrAddControl(pControl, false);
307     if (m_pLastItem)
308       return m_pLastItem;
309   }
310
311   m_pLastItem = m_ItemHead.FindOrAddControl(pControl, true);
312   if (!m_pLastItem)
313     m_pLastItem = m_ItemHead.AddControl(pControl);
314
315   return m_pLastItem;
316 }
317
318 void CGUIControlProfiler::EndFrame(void)
319 {
320   m_iFrameCount++;
321   if (m_iFrameCount >= m_iMaxFrameCount)
322   {
323     const unsigned int dwSize = m_ItemHead.m_vecChildren.size();
324     for (unsigned int i=0; i<dwSize; ++i)
325     {
326       CGUIControlProfilerItem *p = m_ItemHead.m_vecChildren[i];
327       m_ItemHead.m_visTime += p->m_visTime;
328       m_ItemHead.m_renderTime += p->m_renderTime;
329     }
330
331     m_bIsRunning = false;
332     if (SaveResults())
333       m_ItemHead.Reset(this);
334   }
335 }
336
337 bool CGUIControlProfiler::SaveResults(void)
338 {
339   if (m_strOutputFile.IsEmpty())
340     return false;
341
342   CXBMCTinyXML doc;
343   TiXmlDeclaration decl("1.0", "", "yes");
344   doc.InsertEndChild(decl);
345
346   TiXmlElement *root = new TiXmlElement("guicontrolprofiler");
347   CStdString str;
348   str.Format("%d", m_iFrameCount);
349   root->SetAttribute("framecount", str.c_str());
350   root->SetAttribute("timeunit", "ms");
351   doc.LinkEndChild(root);
352
353   m_ItemHead.SaveToXML(root);
354   return doc.SaveFile(m_strOutputFile);
355 }