This page has been translated automatically.
Video Tutorials
Interface
Essentials
Advanced
How To
Basics
Rendering
Professional (SIM)
UnigineEditor
Interface Overview
Assets Workflow
Version Control
Settings and Preferences
Working With Projects
Adjusting Node Parameters
Setting Up Materials
Setting Up Properties
Lighting
Sandworm
Using Editor Tools for Specific Tasks
Extending Editor Functionality
Built-in Node Types
Nodes
Objects
Effects
Decals
Light Sources
Geodetics
World Nodes
Sound Objects
Pathfinding Objects
Players
Programming
Fundamentals
Setting Up Development Environment
Usage Examples
C++
C#
UnigineScript
UUSL (Unified UNIGINE Shader Language)
Plugins
File Formats
Materials and Shaders
Rebuilding the Engine Tools
GUI
Double Precision Coordinates
API
Animations-Related Classes
Containers
Common Functionality
Controls-Related Classes
Engine-Related Classes
Filesystem Functionality
GUI-Related Classes
Math Functionality
Node-Related Classes
Objects-Related Classes
Networking Functionality
Pathfinding-Related Classes
Physics-Related Classes
Plugins-Related Classes
IG Plugin
CIGIConnector Plugin
Rendering-Related Classes
VR-Related Classes
Content Creation
Content Optimization
Materials
Material Nodes Library
Miscellaneous
Input
Math
Matrix
Textures
Art Samples
Tutorials

Microprofile

UNIGINE has support for Microprofile, an advanced external embeddable CPU/GPU profiler with support for per-frame inspection.

Microprofile Tool

The profiler features the following:

  • Profiling operations performed by the engine on CPU and GPU
  • Profiling the engine threads
  • Profiling up to 1000 frames
  • The performance data output to a local web server or to an HTML file

Running Microprofile#

The Microprofile tool is available only for the Development builds of UNIGINE Engine: it won't be compiled for the Debug and Release ones. You can use the microprofile_info console command to check if the Microprofile is compiled.

The performance data obtained by the Microprofile can be output to a local web server or to an HTML file.

Notice
Microprofile shows valid information only after the first 1000 frames are rendered (e.g. at the framerate of 60 FPS, such "warmup" time comprises about 16 seconds).

Enabling and Disabling Microprofile#

Microprofile is performance-consuming, that's why we recommend you to enable it only when you work with it and keep disabled otherwise.

One way to disable Microprofile is to untick the corresponding option before running UnigineEditor or the application:

Disabling Microprofile via SDK Browser

Another way is to use the microprofile_enabled console command.

Notice
If you change the Microprofile status via the console, this setting is saved in the <Project_Name>/data/configs/default.user file. The state set in the user configuration file will override the state defined via SDK Browser.

Saving Performance Data to File#

Microprofile allows saving the performance data to an HTML file and then analyzing it offline.

To output the performance data to the HTML file, perform the following:

  1. In the console, set the the number of frames to be profiled via the microprofile_dump_frames console command. You can skip this step: by default, 500 frames will be profiled.
  2. Run the microprofile_dump_html console command.

The performance data will be saved to the specified HTML file.

Notice
If the path isn't specified, the dump is saved to data/microprofile_dump_html folder.

Using profiling dumps simplifies capturing performance "spikes": the engine continues rendering the application in the background even when it is out of focus, so the frame where the spike has occurred can be overwritten in case of using the Web server for performance data visualization. Also it can be used to estimate the optimization results: you can dump frames before and after optimization and compare them.

Visualization Using Built-In Server#

To visualize the performance data using the local web server, perform the following:

  1. In the console, set the the number of frames to be profiled via the microprofile_webserver_frames console command. You can skip this step: by default, 200 frames will be profiled.
  2. On the Menu Bar of UnigineEditor, choose Tools -> Microprofile.

The performance data will be displayed in your Web browser.

Notice
  • You can display only a part of the profiled frames: in the Web browser address bar, add /<number_of_frames> to the current URL.
  • Don't forget to refresh (F5) the page in the Web browser while the profiling data is collected as it is not performed automatically.

For example, if you specify localhost:1337/100, only the first 100 frames will be displayed.

Notice
All available console commands can be found in the Performance Profiling section of the article on Console.

Performance Data#

The Microprofile visualizes the detailed per frame performance data on the operations performed by the engine on CPU and GPU and on the engine threads. In the Microprofile main menu, you can change the visualization mode: click Mode and choose the required one. By default, the Detailed mode is set.

Profiling Groups Displayed in Detailed Mode

In the Detailed mode, each operation (function) and thread is displayed as a separate colored region. The regions are hierarchical: the function called by the other function is displayed under the last one. The size of the region is determined by the time the corresponding operation takes.

In the picture below, the Engine::do_render() function calls the RenderRenderer::renderWorld() functions and so on:

To view the data on a certain operation or a thread, point to the corresponding region. To zoom in/out the displayed regions, scroll the mouse wheel.

CPU Data#

In the Main group of the performance data, the call stack of the operations (e.g., update, rendering, etc.) performed by the engine on CPU is displayed.

Performance Data on World Update Function

GPU Data#

In the GPU group of the performance data, the call stack of the operations performed by the engine on GPU is displayed. In addition to the main performance data, for each function (e.g. environment rendering, post materials rendering and so on), the number of DIP calls and rendered triangles is shown. Also there can be the number of surfaces, lights, shadows rendered by this function, the number of materials and shaders used; the information on the node or material for which the function is called (identifier, name, etc.).

Performance Data on Deferred Lighting Rendering

When the region that corresponds to the certain function is pointed, the Microprofile displays when this function is called on CPU and how much time is spent on its performing.

Vulkan or DirectX commands can be combined into GPU Debug groups that are created automatically when defining a profiling scope. All graphic resources loaded from external files, such as textures, shaders, static or skinned meshes, as well as the Engine's internal resources, have their own debug names to simplify identification. This information can be useful when using Graphics API debuggers, such as NVIDIA Nsight or RenderDoc.

Example of debug data viewed in RenderDoc

Engine Threads Data#

The performance data on the engine threads is visualized in the CPUThread, SoundThread, AsyncQueueThread, WorldSpawnMeshClutterThread, WorldSpawnGrassThread groups.

Performance Data on Physics Thread

Using Microprofile For Application Logic#

You can use the Microprofile to inspect performance of your application logic.

  1. Open the source code of your application.
  2. Include the UnigineProfiler.h file to get access to methods of the Profiler class.

    AppWorldLogic.h
    #include <UnigineProfiler.h>
    
    using namespace Unigine;
  3. Find a function or a scope in the code you want to inspect.
  4. In the beginning of the function (or the scope), call Profiler::begin(). Specify a name for the capture to be displayed in the Microprofile.

    Notice
    You can specify the __FUNCTION__ macro to automatically use the class and the function name as the capture.
  5. In the end of the function (scope), call Profiler::end().

    AppWorldLogic.cpp
    int AppWorldLogic::update()
    {
    
    	// start profiling
    	Profiler::begin("AppWorldLogic::update");
    
    	float time = Game::getTime();
    	float angle_0 = time * 1.0f;
    	float angle_1 = time * 1.5f;
    	float angle_2 = time * 2.0f;
    
    	light_0->setWorldTransform(translate(Unigine::Math::Vec3(sinf(angle_0), cosf(angle_0), 1.0f) * 20.0f));
    
    	light_1->setWorldTransform(translate(Unigine::Math::Vec3(sinf(angle_1), cosf(angle_1), 1.0f) * 20.0f));
    
    	light_2->setWorldTransform(translate(Unigine::Math::Vec3(sinf(angle_2), cosf(angle_2), 1.0f) * 20.0f));
    
    	// stop profiling
    	Profiler::end();
    
    	return 1;
    }
  6. Run the project.
  7. Open the console and run the microprofile_enabled 1 command.
  8. Go to the Microprofile and find the region with the specified name.

The begin() and end() functions make the profiling scope available for both the Profiler and Microprofile.

If you want to use Microprofile only, create the counter via the beginMicro() and endMicro() functions.

Notice
beginMicro() returns an identifier that should be passed to endMicro(). Thus, several nested counters can be created.
AppWorldLogic.cpp
int AppWorldLogic::update()
{

	// start profiling
	int id = Profiler::beginMicro("AppWorldLogic::update");

	float time = Game::getTime();
	float angle_0 = time * 1.0f;
	float angle_1 = time * 1.5f;
	float angle_2 = time * 2.0f;

	light_0->setWorldTransform(translate(Unigine::Math::Vec3(sinf(angle_0), cosf(angle_0), 1.0f) * 20.0f));

	light_1->setWorldTransform(translate(Unigine::Math::Vec3(sinf(angle_1), cosf(angle_1), 1.0f) * 20.0f));

	light_2->setWorldTransform(translate(Unigine::Math::Vec3(sinf(angle_2), cosf(angle_2), 1.0f) * 20.0f));

	// stop profiling
	Profiler::endMicro(id);

	return 1;
}

Creating Nested Counters for Profiling#

To create several nested counters, you should use the beginMicro() and endMicro() functions. beginMicro() returns an identifier that should be passed to endMicro(). This enables to create nested and intersecting profiler counters.

In the following example, combination of begin()/end() and beginMicro()/endMicro() is used. So, profiling of the AppWorldLogic::update() function will be available in both the Profiler and the Microprofile.

AppWorldLogic.cpp
int AppWorldLogic::update()
{

	// start profiling
	Profiler::begin("AppWorldLogic::update");

	float time = Game::getTime();
	float angle_0 = time * 1.0f;
	float angle_1 = time * 1.5f;
	float angle_2 = time * 2.0f;

	// start profiling of the first light source (available in the Microprofile only)
	int id_0 = Profiler::beginMicro("1st Light Update");

	light_0->setWorldTransform(translate(Unigine::Math::Vec3(sinf(angle_0), cosf(angle_0), 1.0f) * 20.0f));

	// stop profiling of the first light source
	Profiler::endMicro(id_0);

	// start profiling of the second light source (available in the Microprofile only)
	int id_1 = Profiler::beginMicro("2nd Light Update");

	light_1->setWorldTransform(translate(Unigine::Math::Vec3(sinf(angle_1), cosf(angle_1), 1.0f) * 20.0f));

	// stop profiling of the second light source
	Profiler::endMicro(id_1);

	light_2->setWorldTransform(translate(Unigine::Math::Vec3(sinf(angle_2), cosf(angle_2), 1.0f) * 20.0f));

	// stop profiling
	Profiler::end();

	return 1;
}

Notice
Use only beginMicro()/endMicro(), if you don't need the Profiler tool.

Profiling Logic Using Macros#

There are special macros to mark fragments of your code that should be inspected. They can be used instead of the beginMicro() and endMicro() functions:

  • UNIGINE_PROFILER_FUNCTION to inspect performance of the function.

    Using Macro Using Functions
    Source code (C++)
    void myFunction()
    {
    	UNIGINE_PROFILER_FUNCTION;
    	// your function code
    }
    Source code (C++)
    void myFunction()
    {
    	int id = Profiler::beginMicro(__FUNCTION__);
    	// your function code
    	Profiler::endMicro(id);
    }
  • UNIGINE_PROFILER_SCOPED to inspect only a certain part of the code.

    Using Macro Using Functions
    Source code (C++)
    void myFunction()
    {
    	// your function code
    	{
    		UNIGINE_PROFILER_SCOPED("Scope name");
    		// your function code
    	}
    }
    Source code (C++)
    void myFunction()
    {
    	// your function code
    	{
    		int id = Profiler::beginMicro("Scope name");
    		// your function code
    		Profiler::endMicro(id);
    	}
    }

Video Tutorial: Performance Inspection with Microprofile#

Last update: 2024-08-16
Build: ()