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