-
Notifications
You must be signed in to change notification settings - Fork 5
Usage: A coding tutorial
This tutorial should show how you can use CxxProf in your code. If you want to learn how you can integrate CxxProf into your project in general, see our Integration guide for more information.
In this tutorial we're using a made up example code as base and enhance it step by step with CxxProf macros. There also is a usage example available with cxxprof_howto. It is rather longer than our example here, but shows the features in more variety and depth.
##The base program So let's begin with a very simple application:
#include <iostream>
void printSomething(unsigned int numberOfPrints)
{
for(unsigned int index = 0; index < numberOfPrints; ++index)
{
std::cout << "Hello World #" << index << std::endl;
}
}
void someLongFunction()
{
std::cout << "Some long function, what a ressource hogger!" << std::endl;
}
int main()
{
printSomething(1);
printSomething(5);
someLongFunction();
return 0;
}This application does not do much, it contains two functions which in reality could take a lot of ressources and time. For simplicity's sake they're just printing something onto the screen. The printSomething allows the user to control how many times something should be printed.
##Add and initialize CxxProf
To add CxxProf we just need to include the cxxprof_static/CxxProf.h header. It defines the macros which we'll use to do all the magic.
We should also initialize CxxProf, this is done by calling the CXXPROF_INIT macro. This macro should be called at the very first opportunity, as it takes some time to load the dynamic plugin and get everything up and running. You do not want to let the initialization of CxxProf sabotage your measurements.
In order to ease up the analysis of our recorded data we can define our own process and thread aliases. This is done by calling CXXPROF_PROCESS_ALIAS and CXXPROF_THREAD_ALIAS. We do not have to call them, CxxProf will find names for them automatically. But often it's easier to have our own names for those things. Calling these macros will change the alias of the scope they're called from. It is important to call them before you start measuring anything, so I'd suggest to use them directly after the initialization.
After everything is initialized our code looks like the following:
#include <iostream>
#include <cxxprof_static/CxxProf.h>
void printSomething(unsigned int numberOfPrints)
{
for(unsigned int index = 0; index < numberOfPrints; ++index)
{
std::cout << "Hello World #" << index << std::endl;
}
}
void someLongFunction()
{
std::cout << "Some long function, what a ressource hogger!" << std::endl;
}
int main()
{
CXXPROF_INIT();
CXXPROF_PROCESS_ALIAS("TutorialApp");
CXXPROF_THREAD_ALIAS("MainThread");
printSomething(1);
printSomething(5);
someLongFunction();
return 0;
}##Activities Activities are the heart of CxxProf. They measure the time it takes until their scope is left. So if you're adding one Activity to a function it measures how long it takes until the function is done. You can also use any other scope or create scopes by yourself.
When we add Activities to our sample code it looks like the following:
#include <iostream>
#include <cxxprof_static/CxxProf.h>
void printSomething(unsigned int numberOfPrints)
{
CXXPROF_ACTIVITY(__FUNCTION__);
for(unsigned int index = 0; index < numberOfPrints; ++index)
{
std::cout << "Hello World #" << index << std::endl;
}
}
void someLongFunction()
{
std::cout << "Some long function, what a ressource hogger!" << std::endl;
}
int main()
{
CXXPROF_INIT();
CXXPROF_PROCESS_ALIAS("TutorialApp");
CXXPROF_THREAD_ALIAS("MainThread");
CXXPROF_ACTIVITY("This is the main function");
printSomething(1);
printSomething(5);
{ //let's create our own scope here
CXXPROF_ACTIVITY("someLongFunction");
someLongFunction();
}
return 0;
}We added 3 Activities:
-
CXXPROF_ACTIVITY("This is the main function");will measure how long the entiremaintakes -
CXXPROF_ACTIVITY(__FUNCTION__);inprintSomethingjust takes the__FUNCTION__keyword, which means that the compiler will later fill in the correct function name by itself. It measures how long it takes to execute theprintSomethingfunction - The
CXXPROF_ACTIVITY("someLongFunction");got its own scope around the call tosomeLongFunction. By doing this we can measure how long the function takes without changing it internally. This is useful if we want to measure Thirdparty calls where we don't have the rights to change sources.
Note: It is also possible to create conditional Activities by using CXXPROF_ACTIVITY_COND(NAME, COND). You can put any bool expression as COND. These can be useful to limit the amount of data that is generated and just profile the important parts of your application.
Example:
CXXPROF_ACTIVITY_COND("MyActivity", units.size() > 10);##Marks and Plots By adding Marks and Plots to your code, you add context that later helps you analyze the recorded data.
Marks define specific points during your application where the state changes. This could perhaps mean that your initialization is finished and your application starts running its main task. Or it could mean that something bad happened and you need to switch to an alternative execution path.
Plots show how values changed over time. It's for example useful to track the number of entities you're dealing with in a game engine to see how certain Activities change their execution time. So if your updating function messes up as soon as you have more than 50 entities, you can easily see this.
Here is the new code:
#include <iostream>
#include <cxxprof_static/CxxProf.h>
void printSomething(unsigned int numberOfPrints)
{
CXXPROF_PLOT("numberOfPrints", numberOfPrints);
CXXPROF_ACTIVITY(__FUNCTION__);
for(unsigned int index = 0; index < numberOfPrints; ++index)
{
std::cout << "Hello World #" << index << std::endl;
}
}
void someLongFunction()
{
std::cout << "Some long function, what a ressource hogger!" << std::endl;
}
int main()
{
CXXPROF_INIT();
CXXPROF_PROCESS_ALIAS("TutorialApp");
CXXPROF_THREAD_ALIAS("MainThread");
CXXPROF_ACTIVITY("This is the main function");
CXXPROF_MARK("PrintSomething tests");
printSomething(1);
printSomething(5);
CXXPROF_MARK("someLongFunction tests");
{ //let's create our own scope here
CXXPROF_ACTIVITY("someLongFunction");
someLongFunction();
}
return 0;
}Two Marks have been added before the different parts of our tests. There is also 1 Plot added in the printSomething method. It later will show how many times something should be printed, there we'll see why the second call will take 5 times longer than the first.
Note: As with Activities it is possible to define Marks and Plots with a Condition. It helps handling the amount of data being generated:
CXXPROF_MARK_COND("MyMark", isDataReceived);
CXXPROF_PLOT_COND("PlayerCounter", session.isLive() && playercount() > 2);##Clean Shutdown
To ensure that everything shuts down gracefully, we have to call CXXPROF_SHUTDOWN(); at the very end of our application. This cancels all Activities that are still running and sends the data to the network. The final version looks like the following:
#include <iostream>
#include <cxxprof_static/CxxProf.h>
void printSomething(unsigned int numberOfPrints)
{
CXXPROF_PLOT("numberOfPrints", numberOfPrints);
CXXPROF_ACTIVITY(__FUNCTION__);
for(unsigned int index = 0; index < numberOfPrints; ++index)
{
std::cout << "Hello World #" << index << std::endl;
}
}
void someLongFunction()
{
std::cout << "Some long function, what a ressource hogger!" << std::endl;
}
int main()
{
CXXPROF_INIT();
CXXPROF_PROCESS_ALIAS("TutorialApp");
CXXPROF_THREAD_ALIAS("MainThread");
CXXPROF_ACTIVITY("This is the main function");
CXXPROF_MARK("PrintSomething tests");
printSomething(1);
printSomething(5);
CXXPROF_MARK("someLongFunction tests");
{ //let's create our own scope here
CXXPROF_ACTIVITY("someLongFunction");
someLongFunction();
}
CXXPROF_SHUTDOWN();
return 0;
}##Results
The final tutorial application is in the source repository. It will compile alongside the other components if you call build.py and provides a start-script to easily get it running.
Here is how the output with Chromes trace-viewer looks like:
Link to image
You can get the data in SQLite and JSON format to play around with it.
##Removing CxxProf
Keep in mind that in order to remove CxxProf from your code you do not need to do something more than undefine USECXXPROF from your project. This will void the macros and your compiler removes them automatically.
##What's next?
- There are some other tutorials regarding the Integration, the Tracing interface or Compilation available.
- Take a look at the Examples
- CxxProf is work in progress, so it won't hurt to have a look at the Open Issues and if they would inflict your usage of CxxProf
- There are also some GoodFirstIssues if you want to help the project getting bigger and better
If there is something unclear to you or you have some interesting data give us notice. Feel free to open issues for everything you find useful.