Zakero's C++ Header Libraries
A collection of reusable C++ libraries
|
Zakero Profiler. More...
Go to the source code of this file.
Macros | |
#define | ZAKERO_PROFILER_INIT(output_) |
Initialize the profiler. More... | |
#define | ZAKERO_PROFILER_INIT_METADATA(output_, meta_data_) |
Initialize the profiler. More... | |
#define | ZAKERO_PROFILER_ACTIVATE |
Activate Profiling. More... | |
#define | ZAKERO_PROFILER_DEACTIVATE |
Deactivate Profiling. More... | |
#define | ZAKERO_PROFILER_DURATION(category_, name_) |
Generate profiler data. More... | |
#define | ZAKERO_PROFILER_INSTANT(category_, name_) |
Generate profiler data. More... | |
#define | ZAKERO_PROFILER_ENABLE |
Enable the profiler. More... | |
#define | ZAKERO_PROFILER_IMPLEMENTATION |
Activate the implementation code. More... | |
This library will generate profiling data while your application is running.
To use, add the implementation to a source code file:
Next, add the library to the source code where it is "always enabled"
Or. enable the profiler at compile time. Only include the library in the source code:
Then use a compiler flag when building:
Profiling a program helps you determine how much time is being used by different sections of code. This information can be used to determine where code optimizations will have the most pay-off or help locate an area that does not perform consistently.
If your program is crashing or has some other catastrophic bug, profiling will not help you.
The Zakero Profiler is an "internal" profiler that can be added to your C++ code. An "internal" profiler has a few advantages over "external" profilers, such as "gprof". These advantages include:
The disadvantage of "internal" profilers is code-clutter. You must litter your code with profiler stuff which can make code harder to read. This implementation is no different, but it does try to keep the mess to a minimum by using a few macros.
The first benefit is the generated profiler output is JSON formatted. There are many JSON parsers available allowing you to parse and use the data easily. Which leads into the main benefit...
The main benefit of using the Zakero Profiler is that you can visualize the profiler data in Google Chrome and Chromium. No need to write your own visualization code.
And the final reason to use the Zakero Profiler is that it is a "Single Header Library". Just include the header file where ever you need or want to add profiling.
Step 0
Your compiler must support at least the C++20 standard.
Step 1
The first step is to select which C++ source code file will contain the Zakero Profiler implementation. Once the location has been determined, add the following to that file:
The macro ZAKERO_PROFILER_IMPLEMENTATION tells the header file to include the implementation of the profiler.
In all other files that will use the Zakero Profiler, they need to include the header. In addition to including the header, the profiler must be enabled by defining the ZAKERO_PROFILER_ENABLE macro.
The easiest way to do this is to always have the Zakero_Profiler enabled:
This, however, is not very realistic. A better solution is to configure your build system to define ZAKERO_PROFILER_ENABLE when needed and add the Zakero Profiler header and macros where desired.
And if your "build system" is the command-line, the following will turn on profiling:
If the ZAKERO_PROFILER_ENABLE macro is not defined, all the other marcos in this library will be disabled. With compiler optimizations turned on, -O2, the unused profiler code should be removed from the resulting executable.
Step 2
Next, is to initialize the Zakero Profiler. Somewhere in your code, before any profiling is done (such as in main()) add one of the initializer macros (ZAKERO_PROFILER_INIT(), ZAKERO_PROFILER_INIT_METADATA()).
The following example will have the Zakero Profiler write to a file and include information about the application.
Step 3
All the prep work is done, now it is time to generate some profiling data.
To do this use one of these macros:
The ZAKERO_PROFILER_DURATION() macro is best used at the start of a code block. Remember you do not have to put this macro after every '{', only add the macros where you need to capture data.
For example:
Step 4
The program ran and you have profile data. It's time to look at it. Fire up one of the following browsers and...
Google Chrome
Open a new tab and enter chrome://tracing for the URL.
Chromium
Open a new tab enter about:tracing for the URL.
Next, drag the Zakero Profiler output file into the tab to see your data.
Add meta data to ZAKERO_PROFILER_DURATION
Add meta data to ZAKERO_PROFILER_INSTANT
Add support for std::filesystem
Add error handling
Look into converting Duration to use a "Complete" event (phase = 'X').
#define ZAKERO_PROFILER_INIT | ( | output_ | ) |
The profiler must be initialized before any of the other macros are used.
The output_
can be a file name or a std::ostream object. If a std::ostream object is used, the profiler will use a pointer to that stream. This means the provided output_
stream must remain valid for the life of the profiler.
However, if a file name is given, then the profiler will maintain the life-span of the file. Behavior is undefined (i.e. expect a crash) if the provided file name is not writable.
output_ | Where to stream the profile data. |
#define ZAKERO_PROFILER_INIT_METADATA | ( | output_, | |
meta_data_ | |||
) |
The profiler must be initialized before any of the other macros are used.
The output_
can be a file name or a std::ostream object. If a std::ostream object is used, the profiler will use a pointer to that stream. This means the provided output_
stream must remain valid for the life of the profiler.
However, if a file name is given, then the profiler will maintain the life-span of the file. Behavior is undefined (i.e. expect a crash) if the provided file name is not writable.
Any extra data that should appear in the profiler output can be added using the meta_data_
. meta_data_
is a map of std::string/std::string key/value pairs. The "date" key will be automatically added if not already present. The following keys will be over written if used:
output_ | Where to stream the profile data |
meta_data_ | Extra data |
#define ZAKERO_PROFILER_ACTIVATE |
This macro will reactivate the generation of profiling data.
The use of ZAKERO_PROFILER_ACTIVATE and ZAKERO_PROFILER_DEACTIVATE macros allows the control of when profiling happens. Instead of having profiling data being generated for the entire runtime of an application, an event can be used to call these macros so that only the profiling data of the area of interest is generated.
If Zakero Profiler has been enabled at compile-time, by defining the ZAKERO_PROFILER_ENABLE macro, then profiling is automatically active. To have the profiler manually/programmatically activated, call ZAKERO_PROFILER_DEACTIVATE immediately after initialization.
#define ZAKERO_PROFILER_DEACTIVATE |
The generation of profiling data can be temporarily stopped with this macro.
#define ZAKERO_PROFILER_DURATION | ( | category_, | |
name_ | |||
) |
This macro will generate a "duration" profiler event, meaning that the time when the macro was executed is recorded and the time when current code block goes out-of-scope is also recorded.
The category_
can be used to group together related name_
data. For example, profiling a C++ class could use the class name for the category and the name_
would be the part of the class being profiled.
category_ | The category of the data |
name_ | The name of the data |
#define ZAKERO_PROFILER_INSTANT | ( | category_, | |
name_ | |||
) |
This macro will generate an "instant" event. These events are useful to mark something in the timeline.
The category_
and name_
serve the same function as in ZAKERO_PROFILER_DURATION().
category_ | The category of the data |
name_ | The name of the data |
#define ZAKERO_PROFILER_ENABLE |
The Zakero Profiler is a macro based system. When this macro is defined, the macros will be replaced with code. If this macro is not defined, the macros will be removed at compile time.
#define ZAKERO_PROFILER_IMPLEMENTATION |
Defining this macro will cause the Zakero Profiler implementation to be included. This should only be done once, since compiler and/or linker errors will typically be generated if more than a single implementation is found.