# easy_profiler: an in-process C++ profiler with a GUI and a 28077 port

> easy_profiler is a lightweight cross-platform C++ profiling library that records function and block timings, streams them over a network port to a GUI, and can be left disabled in a release build. It suits engineers who want timeline data from a running binary rather than a sampling profiler attached from outside.

**yse/easy_profiler** — Lightweight profiler library for c++

- Repository: https://github.com/yse/easy_profiler
- Stars: 2,374 · Forks: 202
- Language: C++
- License: MIT
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/yse-easy-profiler

## What easy_profiler records that a sampling profiler cannot

easy_profiler is an instrumentation profiler. You mark regions of your own code with macros, and the library records when each region starts and ends. That gives you exact block boundaries and nesting rather than statistical samples, which matters when you want to know that a specific loop iteration took a specific amount of time. The README frames the target audience implicitly: C++ developers who can edit the source they want to measure. The library is cross-platform and works on Linux, macOS, Windows, QNX and Android according to the build section. Beyond timing, it stores user variables, both single values and arrays, so a timeline entry can carry the value of an id or the contents of a vector alongside its duration. It can also capture system context switch events between threads, including duration, target thread id, and the owning process id and name. That combination, block timings plus variable snapshots plus thread scheduling, is what separates it from a pure CPU sampler.

## How the instrumentation, buffering and transport fit together

The repository splits into easy_profiler_core, profiler_gui, easy_profiler_converter and reader directories, with a sample application alongside them. The core library is what you link into your binary. Macros such as EASY_FUNCTION and EASY_BLOCK open a block on entry and close it on scope exit, so a block is bounded by braces rather than by an explicit end call in the common case. The README notes that EASY_END_BLOCK is available for manual closing when you want a block to span a region that does not end with a closing brace. Values are attached with EASY_VALUE and EASY_ARRAY from easy/arbitrary_value.h. The README gives EASY_VIN as a way to pin a value id when the address of the variable can change, which is a real concern for parameters passed by value. Data leaves the process in one of two ways. The preferred path, per the README, is profiler::startListen(), which spawns a thread that listens on port 28077 for a start-capture signal from profiler_gui. The other path dumps to a file. The README also states that a disabled profiler does not affect execution, so the macros can stay in a release build and be switched on at run time.

## Installing easy_profiler and profiling your first block

There is no package manager step in the README. Integration is manual: point your build at the include directory containing include/profiler and define BUILD_WITH_EASY_PROFILER, then link against the library. If you use CMake, the README directs you to set CMAKE_PREFIX_PATH to the lib/cmake/easy_profiler directory from a release package and use find_package with target_link_libraries. The README gives this example.

```cmake
project(my_application)

set(SOURCES
    main.cpp
)

# CMAKE_PREFIX_PATH should be set to <easy_profiler-release_dir>/lib/cmake/easy_profiler
find_package(easy_profiler REQUIRED)  # STEP 1 #########################

add_executable(my_application ${SOURCES})

target_link_libraries(my_application easy_profiler)  # STEP 2 ##########
```

With that in place, instrument a function. The README shows EASY_FUNCTION taking an optional colour, with profiler::colors::Magenta as one of the Google Material-Design palette entries, and a raw ARGB value as an alternative. The default colour when you pass nothing is Amber100.

```cpp
#include <easy/profiler.h>

void foo() {
    EASY_FUNCTION(profiler::colors::Magenta); // Magenta block with name "foo"

    EASY_BLOCK("Calculating sum"); // Begin block with default color == Amber100
    int sum = 0;
    for (int i = 0; i < 10; ++i) {
        EASY_BLOCK("Addition", profiler::colors::Red); // Scoped red block (no EASY_END_BLOCK needed)
        sum += i;
    }
    EASY_END_BLOCK; // End of "Calculating sum" block
}
```

To collect the data, call profiler::startListen() in the profiled application before you want to capture. The README states this starts a new thread that listens on port 28077 for the start-capture signal from profiler_gui. You then connect profiler_gui to the application by hostname. The README notes that the GUI can connect to an application that is already profiling, which is how you capture initialization work that happens before you would otherwise be able to attach.

## The startup window problem and how the README solves it

Most profilers have a blind spot at process start. If your tool attaches after the process is running, you miss static initialization, plugin loading and the first frames of real work. easy_profiler addresses this by reversing the connection direction. The application calls profiler::startListen() and waits; the GUI initiates the capture. Because the listener is up as soon as you call it, the GUI can be connected before the interesting work begins, and the README lists this explicitly as a feature: the GUI can connect to an application which is already profiling, so you can profile initialization of your application. The same mechanism supports the fps monitoring feature, where the GUI can display main thread frames per second in real time even when profiling is disabled, or you can draw your own HUD using data the profiler provides. That is a narrower use of the library than full block capture, but it means the overhead of the listener thread is the price of admission for any of it.

## Where easy_profiler is the wrong tool

The library requires you to modify and recompile the target. If you are diagnosing a production binary you cannot rebuild, or a third-party library with no source access, easy_profiler cannot help and a sampling profiler is the correct choice. The README's own overhead figures are worth reading carefully: it states that 12 million blocks use less than 300 MB of memory and that a working profiler slows execution by 1 to 2 percent, with an average of about 15ns per block measured on an Intel Core i7-5930K at 3.5GHz on Windows 7. That is a per-block cost. A hot loop with millions of short iterations and an EASY_BLOCK inside it accumulates both time and memory in proportion to the number of blocks, not to the wall clock of the run. Instrumenting the innermost loop of a tight numeric kernel is the case where the measurement distorts what it measures. The README does not document a rollback or undo path for instrumentation, and it does not describe a sampling mode, so the only way to reduce overhead is to remove or disable the macros. The GUI is a separate build target, so using the library means building or obtaining profiler_gui as well as the core library.

## easy_profiler against gprof and Orbit

The two names that come up most often alongside easy_profiler are gprof and Orbit. gprof is a compiler-driven instrumenting profiler: you build with -pg, run the program, and get a flat profile plus a call graph after the run ends. The difference in approach is the feedback loop. gprof gives you a report after the fact and its instrumentation is inserted by the compiler at function granularity; easy_profiler gives you a live timeline at block granularity with colours, nesting and attached variable values, while the process runs. If you need a call graph of the whole program without touching the source, gprof is less invasive. If you need to see that one specific block inside one specific function is slow, and you want to watch it change as you edit, easy_profiler's model fits better. Orbit is a sampling profiler for Windows, and the README does not discuss it, so any comparison beyond the sampling-versus-instrumentation distinction is outside what the repository documents. The practical rule: sampling tools tell you where time goes across a binary you may not control; easy_profiler tells you what your own marked blocks did.

## Maintenance, releases and the 2.x to 3.x question

The last push to the develop branch was on 2026-08-05, so the repository is not dormant, but the release history is worth understanding before you pin a version. The most recent release is v2.1.0 from 2019-11-01. Before that, v2.0.1 in 2018 fixed Clang builds and high-dpi displays, and v2.0.0 in 2018 introduced arbitrary values and snapshots. The README badges mark 2.1.0 as stable and 3.x.x as latest, and the table of contents includes a section on notes about major releases from 1.x to 2.x and 2.x to 3.x. That section is where you should look before choosing a branch, because the README does not present 3.x.x as the stable line. If you take a release package, you are on 2.1.0 and its CMake config path. If you track develop, you are on code that the README distinguishes from the stable badge. Upgrade cost is dominated by the CMake integration step: the find_package call and the CMAKE_PREFIX_PATH pointing at lib/cmake/easy_profiler. The repository also contains an easy_profiler_converter directory, which suggests a path for converting captured data, though the README excerpt does not document its interface. On licensing, the repository ships both mit.lic and apache.lic and the README shows MIT and Apache 2.0 badges, so the terms you are actually under depend on which file governs your copy. Read both files rather than the badges.

## Conclusion

Adopt easy_profiler when you control the C++ source and want block-level timelines from a release build that you can enable at run time, and when you can accept a GUI tool whose stable release is v2.1.0 and whose 3.x.x line the README still labels as latest rather than stable. Do not adopt it for code you cannot recompile, for Python or Java work, or if you need a sampling profiler that attaches to an unmodified binary. Before committing, verify that your compiler and platform are covered by the build instructions in the README, confirm which branch you intend to track, and check that the port 28077 used by profiler::startListen() is reachable from the machine running profiler_gui.

## FAQ

### What is easy_profiler used for?

It measures the time taken by functions and arbitrary blocks of code in a C++ application, and can also store user variable values and capture thread context switch events. Results are viewed in a GUI that renders a timeline, either from a live network connection or from a dumped file.

### Is easy_profiler a good C++ profiling tool compared to others?

It is an instrumentation profiler, so it requires you to mark blocks in source and recompile, unlike sampling tools such as gprof or Orbit that work on a binary you may not control. The README reports roughly 15ns of overhead per block and a 1 to 2 percent slowdown while profiling is active, and states that a disabled profiler does not affect execution.

### What is an example of profiling with easy_profiler?

The README's example wraps a function with EASY_FUNCTION and marks an inner loop with EASY_BLOCK, then calls profiler::startListen() so profiler_gui can connect on port 28077 and start a capture. The GUI can also connect to an application that is already profiling, which is how initialization work gets captured.

### Does easy_profiler work with Python?

No. It is a C++ library, and integration means defining BUILD_WITH_EASY_PROFILER, pointing your build at include/profiler, and linking the library. There is no Python binding described in the README.

## Sources

- [Issues](https://github.com/yse/easy_profiler/issues)
- [License: MIT](https://github.com/yse/easy_profiler/blob/develop/LICENSE)
- [README](https://github.com/yse/easy_profiler/blob/develop/README.md)
- [Releases](https://github.com/yse/easy_profiler/releases)
- [yse/easy_profiler on GitHub](https://github.com/yse/easy_profiler)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/yse-easy-profiler
