Skip to content
Victor Zarubkin edited this page Apr 15, 2017 · 6 revisions

This page contains description of basic easy_profiler API.

General

enum EasyBlockStatus

Enumeration type to control profiled blocks on/off statuses. This is optional feature (all blocks are ON by default). You can always change status of a block at run-time with GUI client, you don't need to change your source code.

Possible values:

  • OFF = The block is OFF (block will not be profiled, but it's children would).
  • ON = The block is ON (but if it's parent block is off recursively then this block will be off too).
  • FORCE_ON = The block is ALWAYS ON (even if it's parent has turned off all children).
  • OFF_RECURSIVE = The block is OFF and all of it's children (by call-stack) are also OFF.
  • ON_WITHOUT_CHILDREN = The block is ON but all of it's children are OFF.
  • FORCE_ON_WITHOUT_CHILDREN = The block is ALWAYS ON but all of it's children are OFF.

enum Duration

Enumeration type used for convertion of FPS value (see Getting FPS)

Possible values:

  • TICKS = FPS value in CPU ticks
  • MICROSECONDS = FPS value in microseconds

EASY_PROFILER_ENABLE and EASY_PROFILER_DISABLE

Use these macros to enable/disable profiling. Profiling information stored only when profiler is enabled. EasyProfiler is disabled by default. Using these macros is optional because you can always start/stop profiling session via EasyProfiler GUI.

Remote control

Instead of enabling/disabling profiler manually you can do this via remote GUI. In the profiled application you need to put profiler::startListen() or profiler::startListen(<port number>) to start listening network commands from GUI. In GUI you need to connect to the profiled application using IP-address (or computer name) and port number passed to startListen() function. Default port number is 28077.

Inserting blocks

EASY_END_BLOCK;

Ends last opened block. If last block is OFF then do nothing.

EASY_BLOCK(name, . . .);

Opens new profiler block. The block will be ended on it's destructor when closing brace will be met or it can be ended manually using EASY_END_BLOCK macro.

It's 1st parameter is block name. It accepts C-strings and std::string. Compile-time strings are inserted into block description (only once per application launch) and not included into every profiled block. Run-time strings are serialized together with every profiled block, so it is much more efficient to use compile-time strings if block name does not change at run-time.

Rest two optional parameters are (their order is not strict):

  • block color in 32-bit ARGB integer format (you can use one of predefined colors from profiler::colors namespace or create your own custom color);
  • block activity status (see enum EasyBlockStatus). All block statuses could be changed dynamically at run-time from EasyProfiler GUI. Default status is profiler::ON

Example:

#include <easy/profiler.h>

void foo(const char* loopName) {
    EASY_BLOCK("Red block", profiler::colors::Red); // A
    // some code
    EASY_END_BLOCK; // A end

    EASY_BLOCK(loopName, profiler::ON_WITHOUT_CHILDREN, profiler::colors::Amber700); // B
    for (int i = 0; i < 100; ++i) {
        EASY_BLOCK("Loop body"); // This block is disabled by parent activity status and will not be profiled
        // some code
    }
    EASY_BLOCK("Child", profiler::FORCE_ON); // C . This block will be profiled forcedly.
    // some another code
    EASY_END_BLOCK; // C end. This will never affect block B even if C status will be profiler::OFF.
    EASY_END_BLOCK; // This always refer to block B even if it's status will be profiler::OFF

    // some code
}

EASY_FUNCTION(. . .);

This is just syntactic sugar for EASY_BLOCK(__FUNCTION__, ...); (for Windows) or EASY_BLOCK(__func__, ...); (for Linux).

Example:

#include <easy/profiler.h>

int bar() {
    EASY_FUNCTION(); // Block with name "bar" and default color
    // some code
    return 0;
}

EASY_EVENT(name, . . .);

Insert user defined mark into profiler timeline. This is same as EASY_BLOCK except such blocks has no duration (ends immidiately). Also, event markers are displayed on timeline under the blocks.

Example:

#include <easy/profiler.h>

bool ResourceManager::load() {
    EASY_FUNCTION(profiler::colors::Yellow500);
    // some code...
    EASY_EVENT("Resources loaded", profiler::colors::Magenta);
    return true;
}

Registering threads

EASY_THREAD_SCOPE(name);

Set name for current thread. Also creates scoped ThreadGuard object which marks current thread as expired and creates ThreadFinished event on it's destructor.

Notice: Please, insert this macro into the main thread function (which returns only on thread finish) or some errors may occur.

Only first invoke of the macro has an effect (setting a name). Using this macro is optional but without it you will see raw thread id in profiler timeline instead of human readable name.

Example:

#include <easy/profiler.h>

void workerThread(void* parameters) {
    EASY_THREAD_SCOPE("Worker"); // Setting name for current thread from a main worker function
    while (true) {
        EASY_BLOCK("Worker step");
        // main worker cycle
    }
}

int main() {
    int dummy1 = 1, dummy2 = 2;
    
    EASY_PROFILER_ENABLE;
    std::thread t1(workerThread, &dummy1);
    std::thread t2(workerThread, &dummy2);
    t1.join();
    t2.join();
    
    return 0;
}

EASY_THREAD(name);

Set name for current thread. Notice: This macro does not create a ThreadGuard and can be invoked from every function you want, but there is no ThreadFinished event.

Only first invoke of the macro has an effect (setting a name). Using this macro is optional but without it you will see raw thread id in profiler timeline instead of human readable name.

Example:

#include <easy/profiler.h>

void foo() {
    EASY_FUNCTION();
    // ...
}

void bar() {
    EASY_THREAD("Worker"); // Setting name for current thread from a custom worker function
                           // which may be invoked multiple times
    EASY_FUNCTION();
    // ...
}

void workerThread(void* parameters) {
    while (true) {
        EASY_BLOCK("Worker step");
        // main worker cycle
        foo();
        bar(); // Only first invoke will give this thread a name
        bar();
        bar();
    }
}

int main() {
    int dummy1 = 1, dummy2 = 2;
    
    EASY_PROFILER_ENABLE;
    std::thread t1(workerThread, &dummy1);
    std::thread t2(workerThread, &dummy2);
    t1.join();
    t2.join();
    
    return 0;
}

EASY_MAIN_THREAD;

This is syntactic sugar for EASY_THREAD("Main").

Note: EasyProfiler does not force you to mark main thread except the case if you want to get an FPS value.

Example:

#include <easy/profiler.h>

int main() {
    EASY_MAIN_THREAD;
    EASY_PROFILER_ENABLE;
    while (true) {
        // main application cycle
    }
    return 0;
}

Getting FPS

EasyProfiler calculates FPS value continually even if profiler is disabled. This is done to let you inspect your application frame rate and to let you enable profiler in proper time. EasyProfiler GUI has FPS Monitor widget so, in most cases, you do not need to use API functions directly to get FPS value. But if you want to, you can use API functions described below. Note: "Frame" means every top-level block (which has no parent).

Main thread FPS

To get main thread FPS you have to mark main thread first. Use EASY_MAIN_THREAD macro for that purpose. After that you can get FPS values using profiler::main_thread_frameTime... bunch of functions or profiler::main_thread:: namespace.

profiler::main_thread_frameTime() returns last frame duration.

profiler::main_thread_frameTimeLocalMax() returns frame local max duration which is max duration since last call of the function.

profiler::main_thread_frameTimeLocalAvg() same as local max, but returns local average duration.

All functions have one optional argument Duration _durationCast which could be used to convert result to CPU-ticks or microseconds. All functions have prototypes in profiler::main_thread:: namespace. For example, profiler::main_thread::frameTimeLocalMax().

Current thread FPS

This is almost the same like main thread functions, but used for current active thread. Use profiler::this_thread_... functions or profiler::this_thread:: namespace.