mirror of
https://github.com/minetest/irrlicht.git
synced 2024-12-27 00:17:30 +01:00
c481179825
Add some for newer examples which didn't have those so far. Only updating this once now as some were broken. Next time on release. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@6204 dfc29bdd-3216-0410-991c-e03cc46cb475
210 lines
35 KiB
HTML
210 lines
35 KiB
HTML
<!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 <irrlicht.h></span></div><div class="line"><span class="preprocessor">#include "driverChoice.h"</span></div><div class="line"><span class="preprocessor">#include "exampleHelper.h"</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, "Irrlicht.lib")</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 class="keyword">public</span>:</div><div class="line"> <span class="comment">// constructor</span></div><div class="line"> MyEventReceiver(ISceneManager * smgr) : GuiProfiler(0), IncludeOverview(true), IgnoreUncalled(false), ActiveScene(ES_NONE), SceneManager(smgr) {}</div><div class="line"></div><div class="line"> <span class="keyword">virtual</span> <span class="keywordtype">bool</span> OnEvent(<span class="keyword">const</span> SEvent& event)</div><div class="line"> {</div><div class="line"> <span class="keywordflow">if</span> (event.EventType == EET_KEY_INPUT_EVENT)</div><div class="line"> {</div><div class="line"> <span class="keywordflow">if</span> ( event.KeyInput.PressedDown )</div><div class="line"> {</div></div><!-- fragment --><p> Catching keys to control the profiling display and the profiler itself </p><div class="fragment"><div class="line"><span class="keywordflow">switch</span> ( event.KeyInput.Key )</div><div class="line">{</div><div class="line"> <span class="keywordflow">case</span> KEY_F1:</div><div class="line"> GuiProfiler->setVisible( !GuiProfiler->isVisible() );</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_F2:</div><div class="line"> GuiProfiler->nextPage(IncludeOverview);</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_F3:</div><div class="line"> GuiProfiler->previousPage(IncludeOverview);</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_F4:</div><div class="line"> GuiProfiler->firstPage(IncludeOverview);</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_F5:</div><div class="line"> IncludeOverview = !IncludeOverview;</div><div class="line"> GuiProfiler->firstPage(IncludeOverview); <span class="comment">// not strictly needed, but otherwise the update won't update</span></div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_F6:</div></div><!-- fragment --><p> You can set more filters. This one filters out profile data which was never called. </p><div class="fragment"><div class="line"> IgnoreUncalled = !IgnoreUncalled;</div><div class="line"> GuiProfiler->setFilters(IgnoreUncalled ? 1 : 0, 0, 0.f, 0);</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_F7:</div><div class="line"> GuiProfiler->setShowGroupsTogether( !GuiProfiler->getShowGroupsTogether() );</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_F8:</div><div class="line"> NextScene();</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_F9:</div><div class="line"> {</div><div class="line"> u32 index = 0;</div><div class="line"> <span class="keywordflow">if</span> ( getProfiler().findGroupIndex(index, L<span class="stringliteral">"grp runtime"</span>) )</div><div class="line"> {</div><div class="line"> getProfiler().resetGroup(index);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_F10:</div><div class="line"> {</div><div class="line"> u32 index = 0;</div><div class="line"> <span class="keywordflow">if</span> ( getProfiler().findDataIndex(index, L<span class="stringliteral">"scope 3"</span>) )</div><div class="line"> {</div><div class="line"> getProfiler().resetDataByIndex(index);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_F11:</div><div class="line"> getProfiler().resetAll();</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">case</span> KEY_KEY_F:</div><div class="line"> GuiProfiler->setFrozen(!GuiProfiler->getFrozen());</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> <span class="keywordflow">default</span>:</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> <span class="keywordflow">return</span> <span class="keyword">false</span>;</div><div class="line">}</div></div><!-- fragment --><p> Some example scenes so we have something to profile </p><div class="fragment"><div class="line"><span class="keywordtype">void</span> NextScene()</div><div class="line">{</div><div class="line"> SceneManager->clear();</div><div class="line"> ActiveScene = (ActiveScene+1) % ES_COUNT;</div><div class="line"> <span class="keywordflow">if</span> ( ActiveScene == 0 )</div><div class="line"> ActiveScene = ActiveScene+1;</div><div class="line"></div><div class="line"> <span class="keywordflow">switch</span> ( ActiveScene )</div><div class="line"> {</div><div class="line"> <span class="keywordflow">case</span> ES_CUBE:</div><div class="line"> {</div></div><!-- fragment --><p> Simple scene with cube and light. </p><div class="fragment"><div class="line"> MY_PROFILE(CProfileScope p(L<span class="stringliteral">"cube"</span>, L<span class="stringliteral">"grp switch scene"</span>);)</div><div class="line"></div><div class="line"> SceneManager->addCameraSceneNode (0, core::vector3df(0, 0, 0),</div><div class="line"> core::vector3df(0, 0, 100),</div><div class="line"> -1);</div><div class="line"></div><div class="line"> SceneManager->addCubeSceneNode (30.0f, 0, -1,</div><div class="line"> core::vector3df(0, 20, 100),</div><div class="line"> core::vector3df(45, 45, 45),</div><div class="line"> core::vector3df(1.0f, 1.0f, 1.0f));</div><div class="line"></div><div class="line"> SceneManager->addLightSceneNode(0, core::vector3df(0, 0, 0),</div><div class="line"> video::SColorf(1.0f, 1.0f, 1.0f),</div><div class="line"> 100.0f);</div><div class="line">}</div><div class="line"><span class="keywordflow">break</span>;</div><div class="line"><span class="keywordflow">case</span> ES_QUAKE_MAP:</div><div class="line">{</div></div><!-- fragment --><p> Our typical Irrlicht example quake map. </p><div class="fragment"><div class="line"> MY_PROFILE(CProfileScope p(L<span class="stringliteral">"quake map"</span>, L<span class="stringliteral">"grp switch scene"</span>);)</div><div class="line"></div><div class="line"> scene::IAnimatedMesh* mesh = SceneManager->getMesh(<span class="stringliteral">"20kdm2.bsp"</span>);</div><div class="line"> scene::ISceneNode* node = 0;</div><div class="line"></div><div class="line"> <span class="keywordflow">if</span> (mesh)</div><div class="line"> node = SceneManager->addOctreeSceneNode(mesh->getMesh(0), 0, -1, 1024);</div><div class="line"> <span class="keywordflow">if</span> (node)</div><div class="line"> node->setPosition(core::vector3df(-1300,-144,-1249));</div><div class="line"> SceneManager->addCameraSceneNodeFPS();</div><div class="line">}</div><div class="line"><span class="keywordflow">break</span>;</div><div class="line"><span class="keywordflow">case</span> ES_DWARVES:</div><div class="line">{</div></div><!-- fragment --><p> Stress-test Irrlicht a little bit by creating many objects. </p><div class="fragment"><div class="line">MY_PROFILE(CProfileScope p(L<span class="stringliteral">"dwarfes"</span>, L<span class="stringliteral">"grp switch scene"</span>);)</div><div class="line"></div><div class="line">scene::IAnimatedMesh* aniMesh = SceneManager->getMesh( getExampleMediaPath() + <span class="stringliteral">"dwarf.x"</span> );</div><div class="line"><span class="keywordflow">if</span> (aniMesh)</div><div class="line">{</div><div class="line"> scene::IMesh * mesh = aniMesh->getMesh (0);</div><div class="line"> <span class="keywordflow">if</span> ( !mesh )</div><div class="line"> <span class="keywordflow">break</span>;</div></div><!-- fragment --><p> You can never have too many dwarves. So let's make some. </p><div class="fragment"><div class="line"> <span class="keyword">const</span> <span class="keywordtype">int</span> nodesX = 30;</div><div class="line"> <span class="keyword">const</span> <span class="keywordtype">int</span> nodesY = 5;</div><div class="line"> <span class="keyword">const</span> <span class="keywordtype">int</span> nodesZ = 30;</div><div class="line"></div><div class="line"> aabbox3df bbox = mesh->getBoundingBox();</div><div class="line"> vector3df extent = bbox.getExtent();</div><div class="line"> <span class="keyword">const</span> f32 GAP = 10.f;</div><div class="line"> f32 halfSizeX = 0.5f * (nodesX*extent.X + GAP*(nodesX-1));</div><div class="line"> f32 halfSizeY = 0.5f * (nodesY*extent.Y + GAP*(nodesY-1));</div><div class="line"> f32 halfSizeZ = 0.5f * (nodesZ*extent.Z + GAP*(nodesZ-1));</div><div class="line"></div><div class="line"> <span class="keywordflow">for</span> ( <span class="keywordtype">int</span> x = 0; x < nodesX; ++x )</div><div class="line"> {</div><div class="line"> irr::f32 gapX = x > 0 ? (x-1)*GAP : 0.f;</div><div class="line"> irr::f32 posX = -halfSizeX + x*extent.X + gapX;</div><div class="line"> <span class="keywordflow">for</span> ( <span class="keywordtype">int</span> y = 0; y < nodesY; ++y )</div><div class="line"> {</div><div class="line"> irr::f32 gapY = y > 0 ? (y-1)*GAP : 0.f;</div><div class="line"> irr::f32 posY = -halfSizeY + y*extent.Y + gapY;</div><div class="line"> <span class="keywordflow">for</span> ( <span class="keywordtype">int</span> z=0; z < nodesZ; ++z )</div><div class="line"> {</div><div class="line"> irr::f32 gapZ = z > 0 ? (z-1)*GAP : 0.f;</div><div class="line"> irr::f32 posZ = -halfSizeZ + z*extent.Z + gapZ;</div><div class="line"> scene::IAnimatedMeshSceneNode * node = SceneManager->addAnimatedMeshSceneNode(aniMesh, NULL, -1, vector3df(posX, posY, posZ) );</div><div class="line"> node->setMaterialFlag(video::EMF_LIGHTING, <span class="keyword">false</span>);</div><div class="line"> }</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> irr::scene::ICameraSceneNode * camera = SceneManager->addCameraSceneNodeFPS(0, 20.f, 0.1f );</div><div class="line"> camera->updateAbsolutePosition();</div><div class="line"> camera->setTarget( vector3df(0,0,0) );</div><div class="line"> camera->updateAbsolutePosition();</div><div class="line"> camera->setPosition(irr::core::vector3df(halfSizeX+extent.X, halfSizeY+extent.Y, halfSizeZ+extent.Z));</div><div class="line"> camera->updateAbsolutePosition();</div><div class="line"> }</div><div class="line"> }</div><div class="line"> <span class="keywordflow">break</span>;</div><div class="line"> }</div><div class="line"> }</div><div class="line"></div><div class="line"> IGUIProfiler * GuiProfiler;</div><div class="line"> <span class="keywordtype">bool</span> IncludeOverview;</div><div class="line"> <span class="keywordtype">bool</span> IgnoreUncalled;</div><div class="line"> u32 ActiveScene;</div><div class="line"> scene::ISceneManager* SceneManager;</div><div class="line">};</div><div class="line"></div><div class="line"><span class="keywordtype">void</span> recursive(<span class="keywordtype">int</span> recursion)</div><div class="line">{</div></div><!-- fragment --><p> As the profiler uses internally counters for start stop and only takes profile data when that counter is zero we count all recursions as a single call. If you want to profile each call on it's own you have to use explicit start/stop calls and stop the profile id right before the recursive call. </p><div class="fragment"><div class="line"> MY_PROFILE(CProfileScope p3(L<span class="stringliteral">"recursive"</span>, L<span class="stringliteral">"grp runtime"</span>);)</div><div class="line"> <span class="keywordflow">if</span> (recursion > 0 )</div><div class="line"> recursive(recursion-1);</div><div class="line">}</div><div class="line"></div><div class="line"><span class="keywordtype">int</span> main()</div><div class="line">{</div></div><!-- fragment --><p> Setup, nothing special here. </p><div class="fragment"><div class="line">video::E_DRIVER_TYPE driverType=driverChoiceConsole();</div><div class="line"><span class="keywordflow">if</span> (driverType==video::EDT_COUNT)</div><div class="line"> <span class="keywordflow">return</span> 1;</div></div><!-- fragment --><p> Profiler is independent of the device - so we can time the device setup </p><div class="fragment"><div class="line">MY_PROFILE(s32 pDev = getProfiler().add(L<span class="stringliteral">"createDevice"</span>, L<span class="stringliteral">"grp runtime"</span>);)</div><div class="line">MY_PROFILE(getProfiler().start(pDev);)</div><div class="line"></div><div class="line">IrrlichtDevice * device = createDevice(driverType, core::dimension2d<u32>(640, 480));</div><div class="line"><span class="keywordflow">if</span> (device == 0)</div><div class="line">{</div></div><!-- fragment --><p> When working with start/stop you should add a stop to all exit paths. Although in this case it wouldn't matter as we don't do anything with it when we quit here. </p><div class="fragment"><div class="line"> MY_PROFILE(getProfiler().stop(pDev);)</div><div class="line"> <span class="keywordflow">return</span> 1; <span class="comment">// could not create selected driver.</span></div><div class="line">}</div><div class="line">MY_PROFILE(getProfiler().stop(pDev);)</div><div class="line"></div><div class="line">video::IVideoDriver* driver = device->getVideoDriver();</div><div class="line">IGUIEnvironment* env = device->getGUIEnvironment();</div><div class="line">scene::ISceneManager* smgr = device->getSceneManager();</div><div class="line"></div><div class="line"><span class="keyword">const</span> io::path mediaPath = getExampleMediaPath();</div></div><!-- fragment --><p> A map we use for one of our test-scenes. </p><div class="fragment"><div class="line">device->getFileSystem()->addFileArchive(mediaPath + <span class="stringliteral">"map-20kdm2.pk3"</span>);</div><div class="line"></div><div class="line">MyEventReceiver receiver(smgr);</div><div class="line">device->setEventReceiver(&receiver);</div><div class="line">receiver.NextScene();</div></div><!-- fragment --><p> Show some info about the controls used in this example </p><div class="fragment"><div class="line">IGUIStaticText * staticText = env->addStaticText(</div><div class="line"> L<span class="stringliteral">"<F1> to show/hide the profiling display\n"</span></div><div class="line"> L<span class="stringliteral">"<F2> to show the next page\n"</span></div><div class="line"> L<span class="stringliteral">"<F3> to show the previous page\n"</span></div><div class="line"> L<span class="stringliteral">"<F4> to show the first page\n"</span></div><div class="line"> L<span class="stringliteral">"<F5> to flip between including the group overview\n"</span></div><div class="line"> L<span class="stringliteral">"<F6> to flip between ignoring and showing uncalled data\n"</span></div><div class="line"> L<span class="stringliteral">"<F7> to flip between showing 1 group per page or all together\n"</span></div><div class="line"> L<span class="stringliteral">"<F8> to change our scene\n"</span></div><div class="line"> L<span class="stringliteral">"<F9> to reset the \"grp runtime\" data\n"</span></div><div class="line"> L<span class="stringliteral">"<F10> to reset the scope 3 data\n"</span></div><div class="line"> L<span class="stringliteral">"<F11> to reset all data\n"</span></div><div class="line"> L<span class="stringliteral">"<f> to freeze/unfreeze the display\n"</span></div><div class="line"> , recti(10,10, 250, 140), <span class="keyword">true</span>, <span class="keyword">true</span>, 0, -1, <span class="keyword">true</span>);</div><div class="line">staticText->setWordWrap(<span class="keyword">false</span>);</div></div><!-- fragment --><p> IGUIProfiler is can be used to show active profiling data at runtime. </p><div class="fragment"><div class="line">receiver.GuiProfiler = env->addProfilerDisplay(core::recti(40, 140, 600, 470));</div><div class="line">receiver.GuiProfiler->setDrawBackground(<span class="keyword">true</span>);</div></div><!-- fragment --><p> Get a monospaced font - it's nicer when working with rows of numbers. </p><div class="fragment"><div class="line">IGUIFont* font = env->getFont(mediaPath + <span class="stringliteral">"fontcourier.bmp"</span>);</div><div class="line"><span class="keywordflow">if</span> (font)</div><div class="line"> receiver.GuiProfiler->setOverrideFont(font);</div></div><!-- fragment --><p> Adding ID's has to be done before the start/stop calls. This allows start/stop to be really fast and we still have nice information like names and groups. Groups are created automatically each time an ID with a new group-name is added. Groups exist to sort the display data in a nicer way. </p><div class="fragment"><div class="line">MY_PROFILE(</div><div class="line"> getProfiler().add(EP_APP_TIME_ONCE, L<span class="stringliteral">"full time"</span>, L<span class="stringliteral">"grp runtime"</span>);</div><div class="line"> getProfiler().add(EP_APP_TIME_UPDATED, L<span class="stringliteral">"full time updated"</span>, L<span class="stringliteral">"grp runtime"</span>);</div><div class="line"> getProfiler().add(EP_SCOPE1, L<span class="stringliteral">"scope 1"</span>, L<span class="stringliteral">"grp runtime"</span>);</div><div class="line"> getProfiler().add(EP_DRAW_SCENE, L<span class="stringliteral">"draw scene"</span>, L<span class="stringliteral">"grp runtime"</span>);</div><div class="line">)</div></div><!-- fragment --><p> Two timers which run the whole time. One will be continuously updated the other won't. </p><div class="fragment"><div class="line">MY_PROFILE(getProfiler().start(EP_APP_TIME_ONCE);)</div><div class="line">MY_PROFILE(getProfiler().start(EP_APP_TIME_UPDATED);)</div><div class="line"></div><div class="line">s32 lastFPS = -1;</div><div class="line"><span class="keywordflow">while</span>(device->run() && driver)</div><div class="line">{</div><div class="line"> <span class="keywordflow">if</span> (device->isWindowActive())</div><div class="line"> {</div></div><!-- fragment --><p> For comparison show the FPS in the title bar </p><div class="fragment"><div class="line">s32 fps = driver->getFPS();</div><div class="line"><span class="keywordflow">if</span> (lastFPS != fps)</div><div class="line">{</div><div class="line"> core::stringw str = L<span class="stringliteral">"FPS: "</span>;</div><div class="line"> str += fps;</div><div class="line"> device->setWindowCaption(str.c_str());</div><div class="line"> lastFPS = fps;</div><div class="line">}</div></div><!-- fragment --><p> Times are only updated on stop() calls. So if we want a long-running timer to update we have to stop() and start() it in between. Note that this will also update the call-counter and is rarely needed. </p><div class="fragment"><div class="line">MY_PROFILE(getProfiler().stop(EP_APP_TIME_UPDATED);)</div><div class="line">MY_PROFILE(getProfiler().start(EP_APP_TIME_UPDATED);)</div></div><!-- fragment --><p> The following CProfileScope's will all do the same thing: they measure the time this loop takes. They call start() when the object is created and call stop() when it is destroyed.</p>
|
|
<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">"scope 3"</span>, L<span class="stringliteral">"grp runtime"</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">"scope 2"</span>, L<span class="stringliteral">"grp runtime"</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->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->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">"draw env"</span>, L<span class="stringliteral">"grp runtime"</span>);)</div><div class="line"> MY_PROFILE(getProfiler().start(pEnv);)</div><div class="line"> env->drawAll();</div><div class="line"> MY_PROFILE(getProfiler().stop(pEnv);)</div><div class="line"></div><div class="line"> driver->endScene();</div><div class="line"> }</div><div class="line">}</div></div><!-- fragment --><p> Shutdown. </p><div class="fragment"><div class="line">device->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">"%s"</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> </p>
|
|
</body>
|
|
</html>
|