2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
9 #include "GUIControlProfiler.h"
11 #include "utils/StringUtils.h"
12 #include "utils/TimeUtils.h"
13 #include "utils/XBMCTinyXML.h"
15 bool CGUIControlProfiler::m_bIsRunning
= false;
17 CGUIControlProfilerItem::CGUIControlProfilerItem(CGUIControlProfiler
* pProfiler
,
18 CGUIControlProfilerItem
* pParent
,
19 CGUIControl
* pControl
)
20 : m_pProfiler(pProfiler
), m_pParent(pParent
), m_pControl(pControl
)
24 m_controlID
= m_pControl
->GetID();
25 m_ControlType
= m_pControl
->GetControlType();
26 m_strDescription
= m_pControl
->GetDescription();
31 m_ControlType
= CGUIControl::GUICONTROL_UNKNOWN
;
35 CGUIControlProfilerItem::~CGUIControlProfilerItem(void)
40 void CGUIControlProfilerItem::Reset(CGUIControlProfiler
*pProfiler
)
43 m_ControlType
= CGUIControl::GUICONTROL_UNKNOWN
;
48 const unsigned int dwSize
= m_vecChildren
.size();
49 for (unsigned int i
=0; i
<dwSize
; ++i
)
50 delete m_vecChildren
[i
];
51 m_vecChildren
.clear();
53 m_pProfiler
= pProfiler
;
56 void CGUIControlProfilerItem::BeginVisibility(void)
58 m_i64VisStart
= CurrentHostCounter();
61 void CGUIControlProfilerItem::EndVisibility(void)
63 m_visTime
+= (unsigned int)(m_pProfiler
->m_fPerfScale
* (CurrentHostCounter() - m_i64VisStart
));
66 void CGUIControlProfilerItem::BeginRender(void)
68 m_i64RenderStart
= CurrentHostCounter();
71 void CGUIControlProfilerItem::EndRender(void)
73 m_renderTime
+= (unsigned int)(m_pProfiler
->m_fPerfScale
* (CurrentHostCounter() - m_i64RenderStart
));
76 void CGUIControlProfilerItem::SaveToXML(TiXmlElement
*parent
)
78 TiXmlElement
*xmlControl
= new TiXmlElement("control");
79 parent
->LinkEndChild(xmlControl
);
81 const char *lpszType
= NULL
;
82 switch (m_ControlType
)
84 case CGUIControl::GUICONTROL_BUTTON
:
85 lpszType
= "button"; break;
86 case CGUIControl::GUICONTROL_FADELABEL
:
87 lpszType
= "fadelabel"; break;
88 case CGUIControl::GUICONTROL_IMAGE
:
89 case CGUIControl::GUICONTROL_BORDEREDIMAGE
:
90 lpszType
= "image"; break;
91 case CGUIControl::GUICONTROL_LABEL
:
92 lpszType
= "label"; break;
93 case CGUIControl::GUICONTROL_LISTGROUP
:
94 lpszType
= "group"; break;
95 case CGUIControl::GUICONTROL_PROGRESS
:
96 lpszType
= "progress"; break;
97 case CGUIControl::GUICONTROL_RADIO
:
98 lpszType
= "radiobutton"; break;
99 case CGUIControl::GUICONTROL_RSS
:
100 lpszType
= "rss"; break;
101 case CGUIControl::GUICONTROL_SLIDER
:
102 lpszType
= "slider"; break;
103 case CGUIControl::GUICONTROL_SETTINGS_SLIDER
:
104 lpszType
= "sliderex"; break;
105 case CGUIControl::GUICONTROL_SPIN
:
106 lpszType
= "spincontrol"; break;
107 case CGUIControl::GUICONTROL_SPINEX
:
108 lpszType
= "spincontrolex"; break;
109 case CGUIControl::GUICONTROL_TEXTBOX
:
110 lpszType
= "textbox"; break;
111 case CGUIControl::GUICONTROL_TOGGLEBUTTON
:
112 lpszType
= "togglebutton"; break;
113 case CGUIControl::GUICONTROL_VIDEO
:
114 lpszType
= "videowindow"; break;
115 case CGUIControl::GUICONTROL_MOVER
:
116 lpszType
= "mover"; break;
117 case CGUIControl::GUICONTROL_RESIZE
:
118 lpszType
= "resize"; break;
119 case CGUIControl::GUICONTROL_EDIT
:
120 lpszType
= "edit"; break;
121 case CGUIControl::GUICONTROL_VISUALISATION
:
122 lpszType
= "visualisation"; break;
123 case CGUIControl::GUICONTROL_MULTI_IMAGE
:
124 lpszType
= "multiimage"; break;
125 case CGUIControl::GUICONTROL_GROUP
:
126 lpszType
= "group"; break;
127 case CGUIControl::GUICONTROL_GROUPLIST
:
128 lpszType
= "grouplist"; break;
129 case CGUIControl::GUICONTROL_SCROLLBAR
:
130 lpszType
= "scrollbar"; break;
131 case CGUIControl::GUICONTROL_LISTLABEL
:
132 lpszType
= "label"; break;
133 case CGUIControl::GUICONTAINER_LIST
:
134 lpszType
= "list"; break;
135 case CGUIControl::GUICONTAINER_WRAPLIST
:
136 lpszType
= "wraplist"; break;
137 case CGUIControl::GUICONTAINER_FIXEDLIST
:
138 lpszType
= "fixedlist"; break;
139 case CGUIControl::GUICONTAINER_PANEL
:
140 lpszType
= "panel"; break;
141 case CGUIControl::GUICONTROL_COLORBUTTON
:
142 lpszType
= "colorbutton";
144 //case CGUIControl::GUICONTROL_UNKNOWN:
150 xmlControl
->SetAttribute("type", lpszType
);
151 if (m_controlID
!= 0)
153 std::string str
= std::to_string(m_controlID
);
154 xmlControl
->SetAttribute("id", str
.c_str());
157 float pct
= (float)GetTotalTime() / (float)m_pProfiler
->GetTotalTime();
160 std::string str
= StringUtils::Format("{:.0f}", pct
* 100.0f
);
161 xmlControl
->SetAttribute("percent", str
.c_str());
164 if (!m_strDescription
.empty())
166 TiXmlElement
*elem
= new TiXmlElement("description");
167 xmlControl
->LinkEndChild(elem
);
168 TiXmlText
*text
= new TiXmlText(m_strDescription
.c_str());
169 elem
->LinkEndChild(text
);
172 // Note time is stored in 1/100 milliseconds but reported in ms
173 unsigned int vis
= m_visTime
/ 100;
174 unsigned int rend
= m_renderTime
/ 100;
178 TiXmlElement
*elem
= new TiXmlElement("rendertime");
179 xmlControl
->LinkEndChild(elem
);
180 val
= std::to_string(rend
);
181 TiXmlText
*text
= new TiXmlText(val
.c_str());
182 elem
->LinkEndChild(text
);
184 elem
= new TiXmlElement("visibletime");
185 xmlControl
->LinkEndChild(elem
);
186 val
= std::to_string(vis
);
187 text
= new TiXmlText(val
.c_str());
188 elem
->LinkEndChild(text
);
191 if (m_vecChildren
.size())
193 TiXmlElement
*xmlChilds
= new TiXmlElement("children");
194 xmlControl
->LinkEndChild(xmlChilds
);
195 const unsigned int dwSize
= m_vecChildren
.size();
196 for (unsigned int i
=0; i
<dwSize
; ++i
)
197 m_vecChildren
[i
]->SaveToXML(xmlChilds
);
201 CGUIControlProfilerItem
*CGUIControlProfilerItem::AddControl(CGUIControl
*pControl
)
203 m_vecChildren
.push_back(new CGUIControlProfilerItem(m_pProfiler
, this, pControl
));
204 return m_vecChildren
.back();
207 CGUIControlProfilerItem
*CGUIControlProfilerItem::FindOrAddControl(CGUIControl
*pControl
, bool recurse
)
209 const unsigned int dwSize
= m_vecChildren
.size();
210 for (unsigned int i
=0; i
<dwSize
; ++i
)
212 CGUIControlProfilerItem
*p
= m_vecChildren
[i
];
213 if (p
->m_pControl
== pControl
)
215 if (recurse
&& (p
= p
->FindOrAddControl(pControl
, true)))
219 if (pControl
->GetParentControl() == m_pControl
)
220 return AddControl(pControl
);
225 CGUIControlProfiler::CGUIControlProfiler(void)
226 : m_ItemHead(NULL
, NULL
, NULL
), m_pLastItem(NULL
)
227 // m_bIsRunning(false), no isRunning because it is static
229 m_fPerfScale
= 100000.0f
/ CurrentHostFrequency();
232 CGUIControlProfiler
&CGUIControlProfiler::Instance(void)
234 static CGUIControlProfiler _instance
;
238 bool CGUIControlProfiler::IsRunning(void)
243 void CGUIControlProfiler::Start(void)
248 m_ItemHead
.Reset(this);
251 void CGUIControlProfiler::BeginVisibility(CGUIControl
*pControl
)
253 CGUIControlProfilerItem
*item
= FindOrAddControl(pControl
);
254 item
->BeginVisibility();
257 void CGUIControlProfiler::EndVisibility(CGUIControl
*pControl
)
259 CGUIControlProfilerItem
*item
= FindOrAddControl(pControl
);
260 item
->EndVisibility();
263 void CGUIControlProfiler::BeginRender(CGUIControl
*pControl
)
265 CGUIControlProfilerItem
*item
= FindOrAddControl(pControl
);
269 void CGUIControlProfiler::EndRender(CGUIControl
*pControl
)
271 CGUIControlProfilerItem
*item
= FindOrAddControl(pControl
);
275 CGUIControlProfilerItem
*CGUIControlProfiler::FindOrAddControl(CGUIControl
*pControl
)
279 // Typically calls come in pairs so the last control we found is probably
280 // the one we want again next time
281 if (m_pLastItem
->m_pControl
== pControl
)
283 // If that control is not a match, usually the one we want is the next
284 // sibling of that control, or the parent of that control so check
285 // the parent first as it is more convenient
286 m_pLastItem
= m_pLastItem
->m_pParent
;
287 if (m_pLastItem
&& m_pLastItem
->m_pControl
== pControl
)
289 // continued from above, this searches the original control's siblings
291 m_pLastItem
= m_pLastItem
->FindOrAddControl(pControl
, false);
296 m_pLastItem
= m_ItemHead
.FindOrAddControl(pControl
, true);
298 m_pLastItem
= m_ItemHead
.AddControl(pControl
);
303 void CGUIControlProfiler::EndFrame(void)
306 if (m_iFrameCount
>= m_iMaxFrameCount
)
308 const unsigned int dwSize
= m_ItemHead
.m_vecChildren
.size();
309 for (unsigned int i
=0; i
<dwSize
; ++i
)
311 CGUIControlProfilerItem
*p
= m_ItemHead
.m_vecChildren
[i
];
312 m_ItemHead
.m_visTime
+= p
->m_visTime
;
313 m_ItemHead
.m_renderTime
+= p
->m_renderTime
;
316 m_bIsRunning
= false;
318 m_ItemHead
.Reset(this);
322 bool CGUIControlProfiler::SaveResults(void)
324 if (m_strOutputFile
.empty())
328 TiXmlDeclaration
decl("1.0", "", "yes");
329 doc
.InsertEndChild(decl
);
331 TiXmlElement
*root
= new TiXmlElement("guicontrolprofiler");
332 std::string str
= std::to_string(m_iFrameCount
);
333 root
->SetAttribute("framecount", str
.c_str());
334 root
->SetAttribute("timeunit", "ms");
335 doc
.LinkEndChild(root
);
337 m_ItemHead
.SaveToXML(root
);
338 return doc
.SaveFile(m_strOutputFile
);