0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-25 23:40:51 +08:00
easy_profiler/README.md

332 lines
12 KiB
Markdown
Raw Permalink Normal View History

2024-09-20 19:16:39 +03:00
# easy_profiler [![2.1.0](https://img.shields.io/badge/stable-2.1.0-009688.svg)](https://github.com/yse/easy_profiler/releases/tag/v2.1.0) [![3.x.x](https://img.shields.io/badge/latest-3.x.x-f57f17.svg)](https://github.com/yse/easy_profiler)
2016-11-13 17:34:19 +03:00
2017-08-30 00:41:27 +04:00
[![Build Status](https://ci.appveyor.com/api/projects/status/github/yse/easy_profiler?branch=develop&svg=true)](https://ci.appveyor.com/project/yse/easy-profiler/branch/develop)
2016-11-13 17:34:19 +03:00
2017-03-30 06:30:11 +03:00
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
2016-11-13 16:31:27 +03:00
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0)
2017-03-30 06:28:30 +03:00
2016-08-31 22:47:17 +03:00
1. [About](#about)
2017-03-01 11:40:47 +03:00
2. [Key features](#key-features)
3. [Usage](#usage)
2018-05-28 20:39:16 +03:00
- [Integration](#integration)
2017-02-07 06:22:34 +03:00
- [General build system](#general)
2018-05-28 20:39:16 +03:00
- [CMake](#if-using-cmake)
- [Inserting blocks](#inserting-blocks)
- [Storing variables](#storing-variables)
- [Collect profiling data](#collect-profiling-data)
- [Streaming over network](#streaming-over-network)
- [Dump to file](#dump-to-file)
- [Note about thread context-switch events](#note-about-thread-context-switch-events)
- [Profiling application startup](#profiling-application-startup)
2017-03-01 11:40:47 +03:00
4. [Build](#build)
2016-08-31 22:47:17 +03:00
- [Linux](#linux)
2018-02-22 00:10:01 +03:00
- [MacOS](#macos)
2016-08-31 22:47:17 +03:00
- [Windows](#windows)
2019-01-15 23:10:11 +03:00
- [QNX](#qnx)
2019-01-15 23:22:41 +03:00
- [Android](#android)
2024-09-20 19:16:39 +03:00
5. [Notes about major release 1.x -> 2.x and 2.x -> 3.x](#status)
2018-04-28 00:31:38 +03:00
6. [License](#license)
2016-08-31 22:47:17 +03:00
# About
2016-09-26 22:00:22 +03:00
Lightweight cross-platform profiler library for c++
2016-06-29 06:47:50 +04:00
2016-09-15 00:08:53 +03:00
You can profile any function in you code. Furthermore this library provide measuring time of any block of code.
2016-09-15 00:33:47 +03:00
For example, information for 12 millions of blocks is using less than 300Mb of memory.
Working profiler slows your application execution for only 1-2%.
2016-12-25 13:03:47 +03:00
![Block time](https://hsto.org/files/3e4/afe/8b7/3e4afe8b77ac4ad3a6f8c805be4b7f13.png)
2016-12-27 21:01:12 +03:00
_Average overhead per block is about 15ns/block (tested on Intel Core i7-5930K 3.5GHz, Win7)_
2016-12-25 13:03:47 +03:00
2016-09-15 00:33:47 +03:00
Disabled profiler will not affect your application execution in any way. You can leave it in your Release build
2016-11-13 15:54:06 +03:00
and enable it at run-time at any moment during application launch to see what is happening at the moment.
2016-09-15 00:33:47 +03:00
Also the library can capture system's context switch events between threads. Context switch information includes
duration, target thread id, thread owner process id, thread owner process name.
2016-09-15 00:08:53 +03:00
You can see the results of measuring in simple GUI application which provides full statistics and renders beautiful time-line.
2016-06-29 06:47:50 +04:00
2017-04-10 11:14:09 +03:00
![GUI screenshot](https://cloud.githubusercontent.com/assets/1775230/24852044/a0b1edd0-1dde-11e7-8736-7052b840ad06.png)
2017-05-07 13:40:23 +03:00
_Profiling CryEngine SDK example_
2016-11-05 19:24:12 +03:00
2018-06-03 22:41:54 +03:00
![New UI Style](https://user-images.githubusercontent.com/10530007/40890463-0ab378f8-677f-11e8-9b10-9c62ffb7d5b8.png)
2018-04-27 14:20:07 +03:00
_New UI style in version 2.0_
2017-03-01 11:40:47 +03:00
# Key features
- Extremely low overhead
- Low additional memory usage
- Cross-platform
2018-05-28 20:39:16 +03:00
- Profiling over network
2017-03-01 11:40:47 +03:00
- Capture thread context-switch events
2018-05-28 20:39:16 +03:00
- Store user variables (both single values and arrays)
2017-04-07 23:51:34 +03:00
- GUI could be connected to an application which is already profiling (so you can profile initialization of your application)
2018-05-28 20:39:16 +03:00
- Monitor main thread fps at real-time in GUI even if profiling is disabled or draw your own HUD/fps-plot directly in your application using data provided by profiler
2018-06-14 03:23:39 +03:00
- Save a snapshot (selected area) of profiled data from file
- Add bookmarks at any place on the timeline
2018-05-28 20:39:16 +03:00
- Configurable timer type with CMakeLists or preprocessor macros
2017-03-01 11:40:47 +03:00
2016-08-31 22:47:17 +03:00
# Usage
2018-05-28 20:39:16 +03:00
## Integration
2017-02-07 06:22:34 +03:00
### General
2017-01-21 01:25:06 +04:00
2016-09-30 00:12:36 +04:00
First of all you can specify path to include directory which contains `include/profiler` directory and define macro `BUILD_WITH_EASY_PROFILER`.
2016-09-15 00:08:53 +03:00
For linking with easy_profiler you can specify path to library.
2016-08-31 22:47:17 +03:00
2018-05-28 20:39:16 +03:00
### If using CMake
2017-02-07 06:22:34 +03:00
2018-05-28 20:39:16 +03:00
If you are using `cmake` set `CMAKE_PREFIX_PATH` to `lib/cmake/easy_profiler` directory (from [release](https://github.com/yse/easy_profiler/releases) package) and use function `find_package(easy_profiler)` with `target_link_libraries(... easy_profiler)`.
2017-02-07 06:22:34 +03:00
2018-05-28 20:39:16 +03:00
Example:
2017-02-07 06:22:34 +03:00
``` cmake
2018-05-28 20:39:16 +03:00
project(my_application)
2017-02-07 06:22:34 +03:00
set(SOURCES
main.cpp
)
2018-05-28 20:39:16 +03:00
# CMAKE_PREFIX_PATH should be set to <easy_profiler-release_dir>/lib/cmake/easy_profiler
find_package(easy_profiler REQUIRED) # STEP 1 #########################
2017-02-07 06:22:34 +03:00
2018-05-28 20:39:16 +03:00
add_executable(my_application ${SOURCES})
2017-02-07 06:22:34 +03:00
2018-05-28 20:39:16 +03:00
target_link_libraries(my_application easy_profiler) # STEP 2 ##########
2017-02-07 06:22:34 +03:00
```
2018-05-28 20:39:16 +03:00
## Inserting blocks
2017-02-07 06:22:34 +03:00
2016-06-29 06:47:50 +04:00
Example of usage.
```cpp
2016-10-21 22:21:25 +03:00
#include <easy/profiler.h>
2016-08-31 22:47:17 +03:00
2016-11-06 03:56:30 +03:00
void foo() {
2018-05-28 20:39:16 +03:00
EASY_FUNCTION(profiler::colors::Magenta); // Magenta block with name "foo"
EASY_BLOCK("Calculating sum"); // Begin block with default color == Amber100
2016-09-15 00:08:53 +03:00
int sum = 0;
2016-11-06 03:56:30 +03:00
for (int i = 0; i < 10; ++i) {
EASY_BLOCK("Addition", profiler::colors::Red); // Scoped red block (no EASY_END_BLOCK needed)
2016-09-07 22:12:25 +03:00
sum += i;
2016-11-06 03:56:30 +03:00
}
2018-05-28 20:39:16 +03:00
EASY_END_BLOCK; // End of "Calculating sum" block
2016-09-07 22:12:25 +03:00
2016-09-15 00:33:47 +03:00
EASY_BLOCK("Calculating multiplication", profiler::colors::Blue500); // Blue block
2016-09-15 00:08:53 +03:00
int mul = 1;
for (int i = 1; i < 11; ++i)
2016-09-07 22:12:25 +03:00
mul *= i;
2016-11-06 03:56:30 +03:00
//EASY_END_BLOCK; // This is not needed because all blocks are ended on destructor when closing braces met
2016-06-29 06:47:50 +04:00
}
2018-05-28 20:39:16 +03:00
void bar() {
EASY_FUNCTION(0xfff080aa); // Function block with custom ARGB color
}
void baz() {
EASY_FUNCTION(); // Function block with default color == Amber100
}
2016-06-29 06:47:50 +04:00
```
2016-09-15 00:08:53 +03:00
2018-05-28 20:39:16 +03:00
EasyProfiler is using Google Material-Design colors palette, but you can use custom colors in ARGB format (like shown in example above).
The default color is `Amber100` (it is used when you do not specify color explicitly).
## Storing variables
Example of storing variables:
2016-09-15 00:08:53 +03:00
```cpp
2016-10-21 22:21:25 +03:00
#include <easy/profiler.h>
2018-05-28 20:39:16 +03:00
#include <easy/arbitrary_value.h> // EASY_VALUE, EASY_ARRAY are defined here
2016-09-15 00:08:53 +03:00
2018-05-28 20:39:16 +03:00
class Object {
Vector3 m_position; // Let's suppose Vector3 is a struct { float x, y, z; };
unsigned int m_id;
public:
void act() {
EASY_FUNCTION(profiler::colors::Cyan);
// Dump variables values
constexpr auto Size = sizeof(Vector3) / sizeof(float);
EASY_VALUE("id", m_id);
EASY_ARRAY("position", &m_position.x, Size, profiler::color::Red);
// Do something ...
}
void loop(uint32_t N) {
EASY_FUNCTION();
EASY_VALUE("N", N, EASY_VIN("N")); /* EASY_VIN is used here to ensure
that this value id will always be
the same, because the address of N
can change */
for (uint32_t i = 0; i < N; ++i) {
// Do something
}
}
};
2016-09-15 00:08:53 +03:00
```
2017-01-21 01:25:06 +04:00
2018-05-28 20:39:16 +03:00
## Collect profiling data
There are two ways to collect profiling data: streaming over network and dumping data to file.
2017-03-01 12:02:22 +03:00
2018-05-28 20:39:16 +03:00
### Streaming over network
2017-03-01 12:02:22 +03:00
2018-05-28 20:39:16 +03:00
This is the most preferred and convenient method in many cases.
2017-03-01 12:02:22 +03:00
2018-05-28 20:39:16 +03:00
1. (In profiled app) Invoke `profiler::startListen()`. This will start new thread to listen `28077` port for the start-capture-signal from profiler_gui.
2. (In UI) Connect profiler_gui to your application using `hostname` or `IP-address`.
3. (In UI) Press `Start capture` button in profiler_gui.
4. (In UI) Press `Stop capture` button in profiler_gui to stop capturing and wait until profiled data will be passed over network.
5. (Optional step)(In profiled app) Invoke `profiler::stopListen()` to stop listening.
Example:
```cpp
void main() {
profiler::startListen();
/* do work */
}
```
2017-03-01 12:02:22 +03:00
2018-05-28 20:39:16 +03:00
### Dump to file
2017-03-01 12:02:22 +03:00
2018-05-28 20:39:16 +03:00
1. (Profiled application) Start capturing by putting `EASY_PROFILER_ENABLE` macro somewhere into the code.
2. (Profiled application) Dump profiled data to file in any place you want by `profiler::dumpBlocksToFile("test_profile.prof")` function.
2017-03-01 12:02:22 +03:00
Example:
```cpp
2018-05-28 20:39:16 +03:00
void main() {
2017-03-01 12:02:22 +03:00
EASY_PROFILER_ENABLE;
2018-05-28 20:39:16 +03:00
/* do work */
2017-03-01 12:02:22 +03:00
profiler::dumpBlocksToFile("test_profile.prof");
}
```
2016-09-15 00:08:53 +03:00
2018-05-28 20:39:16 +03:00
### Note about thread context-switch events
2017-03-01 13:20:51 +03:00
2018-05-28 20:39:16 +03:00
To capture a thread context-switch events you need:
2017-03-01 13:20:51 +03:00
2018-05-28 20:39:16 +03:00
- On Windows: launch your application "as Administrator"
- On Linux: you can launch special `systemtap` script with root privileges as follow (example on Fedora):
2017-03-01 13:20:51 +03:00
```bash
#stap -o /tmp/cs_profiling_info.log scripts/context_switch_logger.stp name APPLICATION_NAME
```
2018-05-28 20:39:16 +03:00
APPLICATION_NAME - name of your application
2017-03-01 13:20:51 +03:00
2018-01-08 01:22:27 +03:00
There are some known issues on a linux based systems (for more information see [wiki](https://github.com/yse/easy_profiler/wiki/Known-bugs-and-issues))
2018-01-07 02:10:57 +03:00
2018-05-28 20:39:16 +03:00
### Profiling application startup
To profile your application startup (when using [network](#streaming-over-network) method) add `EASY_PROFILER_ENABLE` macro into the code together with `profiler::startListen()`.
Example:
```cpp
void main() {
EASY_PROFILER_ENABLE;
profiler::startListen();
/* do work */
}
```
This will allow you to collect profiling data before profiler_gui connection. profiler_gui will automatically display capturing dialog window after successful connection to the profiled application.
2016-09-26 22:00:22 +03:00
# Build
## Prerequisites
* CMake 3.0 or higher
* Compiler with c++11 support
2017-10-02 21:25:41 +03:00
* for Unix systems: compiler with `thread_local` support is **highly recommended**: _GCC >=4.8_, _Clang >=3.3_
2016-09-26 22:00:22 +03:00
Additional requirements for GUI:
2016-11-13 15:54:06 +03:00
* Qt 5.3.0 or higher
2016-09-26 22:00:22 +03:00
## Linux
```bash
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE="Release" ..
2016-09-26 22:00:22 +03:00
$ make
```
2018-02-22 00:10:01 +03:00
## MacOS
```bash
$ mkdir build
$ cd build
$ cmake -DCMAKE_CXX_COMPILER=g++-5 -DCMAKE_C_COMPILER=gcc-5 -DCMAKE_BUILD_TYPE="Release" ..
$ make
```
2016-09-26 22:00:22 +03:00
## Windows
If you are using QtCreator IDE you can just open `CMakeLists.txt` file in root directory.
If you are using Visual Studio you can generate solution by cmake generator command.
2016-11-13 15:54:06 +03:00
Examples shows how to generate Win64 solution for Visual Studio 2013. To generate for another version use proper cmake generator (-G "name of generator").
2016-09-26 22:00:22 +03:00
### Way 1
2024-09-20 18:58:21 +03:00
Specify path to cmake scripts in Qt6 dir (usually in lib/cmake subdir) and execute cmake generator command,
2016-09-26 22:00:22 +03:00
for example:
```batch
$ mkdir build
$ cd build
2024-09-20 18:58:21 +03:00
$ cmake -DCMAKE_PREFIX_PATH="C:\Qt\6.7.2\msvc2013_64\lib\cmake" .. -G "Visual Studio 12 2013 Win64"
2016-09-26 22:00:22 +03:00
```
### Way 2
2024-09-20 18:58:21 +03:00
Create system variable "Qt6Widgets_DIR" and set it's value to "[path-to-Qt6-binaries]\lib\cmake\Qt6Widgets".
For example, "C:\Qt\5.3\msvc2013_64\lib\cmake\Qt6Widgets".
2016-09-26 22:00:22 +03:00
And then run cmake generator as follows:
```batch
$ mkdir build
$ cd build
$ cmake .. -G "Visual Studio 12 2013 Win64"
```
2017-03-30 06:19:45 +03:00
2019-01-15 23:10:11 +03:00
## QNX
```bash
$ souce $QNX_ENVIRONMENT
$ mkdir build
$ cd build
$ cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/QNXToolchain.cmake ..
```
2019-01-15 23:11:52 +03:00
For more information and example for `QNXToolchain.cmake` see [this PR](https://github.com/yse/easy_profiler/pull/145)
2019-01-15 23:10:11 +03:00
2019-01-15 23:22:41 +03:00
## Android
You can build native library for android by using NDK and standalone toolchain. See [comment for this PR](https://github.com/yse/easy_profiler/pull/137#issuecomment-436167127) to get a more detailed instruction.
2018-04-28 00:31:38 +03:00
# Status
2024-09-20 19:16:39 +03:00
## Migration 1.x --> 2.x
2018-05-28 20:39:16 +03:00
Branch `develop` contains all v2.0.0 features and new UI style.
Please, note that .prof file header has changed in v2.0.0:
2018-04-28 00:31:38 +03:00
```cpp
2018-05-28 20:39:16 +03:00
struct EasyFileHeader {
2018-04-28 00:31:38 +03:00
uint32_t signature = 0;
uint32_t version = 0;
profiler::processid_t pid = 0;
int64_t cpu_frequency = 0;
profiler::timestamp_t begin_time = 0;
profiler::timestamp_t end_time = 0;
// Changed order of memory_size and blocks_number relative to v1.3.0
uint64_t memory_size = 0;
uint64_t descriptors_memory_size = 0;
uint32_t total_blocks_number = 0;
uint32_t total_descriptors_number = 0;
};
```
2024-09-20 19:16:39 +03:00
## Migration 2.x --> 3.x
There are some functions in the 2.x release that conflicts with system functions, for example `now()`. You can find more details in the related [issue](https://github.com/yse/easy_profiler/issues/215) and [PR](https://github.com/yse/easy_profiler/pull/188)
2017-03-30 06:20:25 +03:00
# License
2017-03-30 06:19:45 +03:00
Licensed under either of
2021-06-06 14:52:13 +03:00
- MIT license ([mit.lic](mit.lic) or http://opensource.org/licenses/MIT)
- Apache License, Version 2.0 ([apache.lic](apache.lic) or http://www.apache.org/licenses/LICENSE-2.0)
2017-03-30 06:25:07 +03:00
2017-03-30 06:19:45 +03:00
at your option.