irrlicht/examples/30.Profiling/tutorial.html

210 lines
35 KiB
HTML
Raw Normal View History

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
<meta name="generator" content="Doxygen 1.8.13"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Tutorial 30: Profiling</title>
<html xmlns="http://www.w3.org/1999/xhtml">
<!-- Wanted to avoid copying .css to each folder, so copied default .css from doxyen in here, kicked out most stuff we don't need for examples and modified some a little bit.
Target was having a single html in each example folder which is created from the main.cpp files and needs no files besides some images below media folder.
Feel free to improve :)
-->
<style>
body, table, div, p, dl {
font: 400 14px/22px;
}
body {
background-color: #F0F0F0;
color: black;
margin-left: 5%;
margin-right: 5%;
}
p.reference, p.definition {
font: 400 14px/22px;
}
.title {
font: 400 14px/28px;
font-size: 150%;
font-weight: bold;
margin: 10px 2px;
}
h1, h2, h3, h4, h5, h6 {
-webkit-transition: text-shadow 0.5s linear;
-moz-transition: text-shadow 0.5s linear;
-ms-transition: text-shadow 0.5s linear;
-o-transition: text-shadow 0.5s linear;
transition: text-shadow 0.5s linear;
margin-right: 15px;
}
caption {
font-weight: bold;
}
h3.version {
font-size: 90%;
text-align: center;
}
a {
color: #3D578C;
font-weight: normal;
text-decoration: none;
}
.contents a:visited {
color: #4665A2;
}
a:hover {
text-decoration: underline;
}
a.el {
font-weight: bold;
}
a.code, a.code:visited, a.line, a.line:visited {
color: #4665A2;
}
a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
color: #4665A2;
}
pre.fragment {
border: 1px solid #C4CFE5;
background-color: #FBFCFD;
padding: 4px 6px;
margin: 4px 8px 4px 2px;
overflow: auto;
word-wrap: break-word;
font-size: 9pt;
line-height: 125%;
font-family: monospace, fixed;
font-size: 105%;
}
div.fragment {
padding: 0px;
margin: 4px 8px 4px 2px;
background-color: #FBFCFD;
border: 1px solid #C4CFE5;
}
div.line {
font-family: monospace, fixed;
font-size: 13px;
min-height: 13px;
line-height: 1.0;
text-wrap: unrestricted;
white-space: -moz-pre-wrap; /* Moz */
white-space: -pre-wrap; /* Opera 4-6 */
white-space: -o-pre-wrap; /* Opera 7 */
white-space: pre-wrap; /* CSS3 */
word-wrap: break-word; /* IE 5.5+ */
text-indent: -53px;
padding-left: 53px;
padding-bottom: 0px;
margin: 0px;
-webkit-transition-property: background-color, box-shadow;
-webkit-transition-duration: 0.5s;
-moz-transition-property: background-color, box-shadow;
-moz-transition-duration: 0.5s;
-ms-transition-property: background-color, box-shadow;
-ms-transition-duration: 0.5s;
-o-transition-property: background-color, box-shadow;
-o-transition-duration: 0.5s;
transition-property: background-color, box-shadow;
transition-duration: 0.5s;
}
div.contents {
margin-top: 10px;
margin-left: 12px;
margin-right: 8px;
}
div.center {
text-align: center;
margin-top: 0px;
margin-bottom: 0px;
padding: 0px;
}
div.center img {
border: 0px;
}
span.keyword {
color: #008000
}
span.keywordtype {
color: #604020
}
span.keywordflow {
color: #e08000
}
span.comment {
color: #800000
}
span.preprocessor {
color: #806020
}
span.stringliteral {
color: #002080
}
span.charliteral {
color: #008080
}
blockquote {
background-color: #F7F8FB;
border-left: 2px solid #9CAFD4;
margin: 0 24px 0 4px;
padding: 0 12px 0 16px;
}
hr {
height: 0px;
border: none;
border-top: 1px solid #4A6AAA;
}
address {
font-style: normal;
color: #2A3D61;
}
div.header {
background-image:url('nav_h.png');
background-repeat:repeat-x;
background-color: #F9FAFC;
margin: 0px;
border-bottom: 1px solid #C4CFE5;
}
div.headertitle {
padding: 5px 5px 5px 10px;
}
.image {
text-align: center;
}
.caption {
font-weight: bold;
}
div.zoom {
border: 1px solid #90A5CE;
}
tr.heading h2 {
margin-top: 12px;
margin-bottom: 4px;
}
</style>
</head>
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
<!--END TITLEAREA-->
<!-- end header part -->
<!-- Generated by Doxygen 1.8.13 -->
</div><!-- top -->
<div class="header">
<div class="headertitle">
<div class="title">Tutorial 30: Profiling </div> </div>
</div><!--header-->
<div class="contents">
<div class="textblock"><div class="image">
<img src="../../media/example_screenshots/030shot.jpg" alt="030shot.jpg"/>
</div>
<p>Profiling is used to get runtime information about code code.</p>
<p>There exist several independent profiling tools. Examples for free profilers are "gprof" for the GNU toolchain and "very sleepy" from codersnotes for Windows. Proprietary tools are for example "VTune" from Intel or "AMD APP Profiler". Those tools work by sampling the running application regularly to get statistic information about the called functions. The way to use them is to compile your application with special flags to include profiling information (some also work with debug information). They also might allow to profile only certain parts of the code, although most can't do that. The sampling is usually rather time-consuming which means the application will be very slow when collecting the profiling data. It's often useful to start with one of those tools to get an overview over the bottlenecks in your application. Those tools have the advantage that they don't need any modifications inside the code.</p>
<p>Once you need to dig deeper the Irrlicht profiler can help you. It works nearly like a stopwatch. You add start/stop blocks into the parts of your code which you need to check and the Irrlicht profiler will give you then the exact times of execution for those parts. And unlike general profiler tools you don't just get average information about the run-time but also worst-cases. Which tends to be information you really for a stable framerate. Also the Irrlicht profiler has a low overhead and affects only the areas which you want to time. So you can profile applications with nearly original speed.</p>
<p>Irrlicht itself has such profiling information, which is useful to figure out where the runtime inside the engine is spend. To get that profiling data you need to recompile Irrlicht with <em>IRR_COMPILE_WITH_PROFILING</em> enabled as collecting profiling information is disabled by default for speed reasons. </p><div class="fragment"></div><!-- fragment --><p> It's usually a good idea to wrap all your profile code with a define. That way you don't have to worry too much about the runtime profiling itself takes. You can remove the profiling code completely when you release the software by removing a single define.Or sometimes you might want to have several such defines for different areas of your application code. </p><div class="fragment"><div class="line"><span class="preprocessor">#define ENABLE_MY_PROFILE // comment out to remove the profiling code</span></div><div class="line"><span class="preprocessor">#ifdef ENABLE_MY_PROFILE</span></div><div class="line"> <span class="comment">// calls code X</span></div><div class="line"><span class="preprocessor"> #define MY_PROFILE(X) X</span></div><div class="line"><span class="preprocessor">#else</span></div><div class="line"> <span class="comment">// removes the code for X in the pre-processor</span></div><div class="line"><span class="preprocessor"> #define MY_PROFILE(X)</span></div><div class="line"><span class="preprocessor">#endif // IRR_PROFILE</span></div><div class="line"></div><div class="line"><span class="preprocessor">#include &lt;irrlicht.h&gt;</span></div><div class="line"><span class="preprocessor">#include &quot;driverChoice.h&quot;</span></div><div class="line"><span class="preprocessor">#include &quot;exampleHelper.h&quot;</span></div><div class="line"></div><div class="line"><span class="preprocessor">#ifdef _MSC_VER</span></div><div class="line"><span class="preprocessor">#pragma comment(lib, &quot;Irrlicht.lib&quot;)</span></div><div class="line"><span class="preprocessor">#endif</span></div><div class="line"></div><div class="line"></div><div class="line"><span class="keyword">using namespace </span>irr;</div><div class="line"><span class="keyword">using namespace </span>core;</div><div class="line"><span class="keyword">using namespace </span>scene;</div><div class="line"><span class="keyword">using namespace </span>video;</div><div class="line"><span class="keyword">using namespace </span>io;</div><div class="line"><span class="keyword">using namespace </span>gui;</div></div><!-- fragment --><p> We have the choice between working with fixed and with automatic profiling id's. Here are some fixed ID's we will be using. </p><div class="fragment"><div class="line"><span class="keyword">enum</span> EProfiles</div><div class="line">{</div><div class="line"> EP_APP_TIME_ONCE,</div><div class="line"> EP_APP_TIME_UPDATED,</div><div class="line"> EP_SCOPE1,</div><div class="line"> EP_SCOPE2,</div><div class="line"> EP_DRAW_SCENE</div><div class="line">};</div><div class="line"></div><div class="line"><span class="comment">// For our example scenes</span></div><div class="line"><span class="keyword">enum</span> EScenes</div><div class="line">{</div><div class="line"> ES_NONE, <span class="comment">// no scene set</span></div><div class="line"> ES_CUBE,</div><div class="line"> ES_QUAKE_MAP,</div><div class="line"> ES_DWARVES,</div><div class="line"></div><div class="line"> ES_COUNT <span class="comment">// counting how many scenes we have</span></div><div class="line">};</div></div><!-- fragment --><p> Controlling the profiling display is application specific behavior. We use function keys in our case and play around with all the parameters. In real applications you will likely only need something to make the profiling-display visible/invisible and switch pages while the parameters can be set to fixed values. </p><div class="fragment"><div class="line"><span class="keyword">class </span>MyEventReceiver : <span class="keyword">public</span> IEventReceiver</div><div class="line">{</div><div class="line"><span clas
<p>The first one creates an ID on it's first call and will do constant string-comparisons for the name. It's the slowest, but most comfortable solution. Use it when you just need to run a quick check without the hassle of setting up id's. </p><div class="fragment"><div class="line">MY_PROFILE(CProfileScope p3(L<span class="stringliteral">&quot;scope 3&quot;</span>, L<span class="stringliteral">&quot;grp runtime&quot;</span>);)</div></div><!-- fragment --><p> Second CProfileScope solution will create a data block on first call. So it's a little bit slower on the first run. But usually that's hardly noticeable. </p><div class="fragment"><div class="line">MY_PROFILE(CProfileScope p2(EP_SCOPE2, L<span class="stringliteral">&quot;scope 2&quot;</span>, L<span class="stringliteral">&quot;grp runtime&quot;</span>);)</div></div><!-- fragment --><p> Last CProfileScope solution is the fastest one. But you must add the id before you can use it like that. </p><div class="fragment"><div class="line">MY_PROFILE(CProfileScope p1(EP_SCOPE1));</div></div><!-- fragment --><p> Call a recursive function to show how profiler only counts it once. </p><div class="fragment"><div class="line">recursive(5);</div><div class="line"></div><div class="line">driver-&gt;beginScene(video::ECBF_COLOR | video::ECBF_DEPTH, SColor(0,200,200,200));</div></div><!-- fragment --><p> If you want to profile only some lines and not a complete scope then you have to work with start() and stop() calls. </p><div class="fragment"><div class="line">MY_PROFILE(getProfiler().start(EP_DRAW_SCENE);)</div><div class="line">smgr-&gt;drawAll();</div><div class="line">MY_PROFILE(getProfiler().stop(EP_DRAW_SCENE);)</div></div><!-- fragment --><p> If it doesn't matter if the profiler takes some time you can also be lazy and create id's automatically on the spot: </p><div class="fragment"><div class="line"> MY_PROFILE(s32 pEnv = getProfiler().add(L<span class="stringliteral">&quot;draw env&quot;</span>, L<span class="stringliteral">&quot;grp runtime&quot;</span>);)</div><div class="line"> MY_PROFILE(getProfiler().start(pEnv);)</div><div class="line"> env-&gt;drawAll();</div><div class="line"> MY_PROFILE(getProfiler().stop(pEnv);)</div><div class="line"></div><div class="line"> driver-&gt;endScene();</div><div class="line"> }</div><div class="line">}</div></div><!-- fragment --><p> Shutdown. </p><div class="fragment"><div class="line">device-&gt;drop();</div></div><!-- fragment --><p> The profiler is independent of an device - so we can still work with it. </p><div class="fragment"><div class="line">MY_PROFILE(getProfiler().stop(EP_APP_TIME_UPDATED));</div><div class="line">MY_PROFILE(getProfiler().stop(EP_APP_TIME_ONCE));</div></div><!-- fragment --><p> Print a complete overview of the profiling data to the console. </p><div class="fragment"><div class="line"> MY_PROFILE(core::stringw output);</div><div class="line"> MY_PROFILE(getProfiler().printAll(output));</div><div class="line"> MY_PROFILE(printf(<span class="stringliteral">&quot;%s&quot;</span>, core::stringc(output).c_str() ));</div><div class="line"></div><div class="line"> <span class="keywordflow">return</span> 0;</div><div class="line">}</div></div><!-- fragment --> </div></div><!-- contents -->
<!-- HTML footer for doxygen 1.8.13-->
<!-- start footer part -->
<p>&nbsp;</p>
</body>
</html>