Skip to content

Usage: A coding tutorial

Nils Brinkmann edited this page Apr 25, 2014 · 3 revisions

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 entire main takes
  • CXXPROF_ACTIVITY(__FUNCTION__); in printSomething just 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 the printSomething function
  • The CXXPROF_ACTIVITY("someLongFunction"); got its own scope around the call to someLongFunction. 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.

##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.

##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;
    }

Clone this wiki locally