blob: 71bf5c35c575d6ff276e1704685f573d47dd3531 [file] [view] [edit]
# ITT API C++ Wrapper
A modern, header-only C++ wrapper for the [ITT API](https://github.com/intel/ittapi) instrumentation library. The wrapper provides RAII-based scoped helpers and type-safe C++ abstractions over the existing C API.
## Supported APIs
| API | C++ Wrapper |
|-----|------------|
| String Handle | `ittapi::StringHandle` |
| Domain | `ittapi::Domain` |
| Task | `ittapi::ScopedTask`, `Domain::task_begin()` / `Domain::task_end()` |
| Region | `ittapi::ScopedRegion` |
| Frame | `ittapi::ScopedFrame` |
| Collection Control | `ittapi::pause()`, `ittapi::resume()`, `ittapi::ScopedPause` |
| Thread Naming | `ittapi::set_thread_name()` |
## Requirements
- C++17 or later
- The existing `ittnotify` static C-library
## Including the Wrapper
Use the umbrella header to get the full API:
```cpp
#include <ittapi.hpp>
```
Or include individual headers:
```cpp
#include <ittapi_domain.hpp>
#include <ittapi_task.hpp>
#include <ittapi_collection_control.hpp>
```
## Example: Task Instrumentation
```cpp
#include <ittapi.hpp>
#include <chrono>
#include <thread>
int main() {
ittapi::set_thread_name("main");
ittapi::Domain domain{"example.task"};
ittapi::StringHandle task_name{"process"};
ittapi::pause();
ittapi::resume();
{
auto task = domain.task(task_name);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
return 0;
}
```
## Linking
### CMake Consumer
```cmake
find_package(ittapi CONFIG REQUIRED)
target_link_libraries(my_app PRIVATE ittapi::cxx)
```
The `ittapi::cxx` target is an `INTERFACE` library that transitively links the existing `ittnotify` static library and adds the C++ wrapper include directories.
### Manual GCC/G++ (Linux)
```bash
g++ -std=c++17 -O2 \
-I<ittapi-install-prefix>/include \
app.cpp \
<ittapi-install-prefix>/lib/libittnotify.a \
-ldl -pthread \
-o app
```
## Building with CMake
From the repository root:
```bash
cmake -B build -DCMAKE_BUILD_TYPE=Release -DITT_API_CPP_SUPPORT=ON
cmake --build build
```
The `ITT_API_CPP_SUPPORT` option is `OFF` by default.
You can also build with the build script:
```bash
python buildall.py --cpp
```
## Running Tests
Tests are registered inside the `cpp/` subdirectory. After building:
```bash
ctest --test-dir build/cpp --output-on-failure
```
## Performance Tips
- **Pre-create `StringHandle` objects** for task/region names used in hot paths. The `StringHandle` overloads pass a raw pointer with no locking — this is the zero-overhead path.
```cpp
// Do this once at startup:
ittapi::StringHandle name{"compute"};
// Then in hot code:
auto task = domain.task(name); // no allocation, no lock
```
- **The `string_view` overloads** are convenient but allocate a `std::string` on cache miss and acquire a lock in the C library. Use them for setup or infrequent tasks, not tight loops.
- **Create `Domain` objects once** and reuse them. Domain creation is a global lookup — store them as class members or globals, not as function locals called repeatedly.
- **Use overlapped tasks** (with IDs) only when you need tasks that end out of order. Stack-based tasks (without IDs) are simpler and carry less internal state.
## API Reference
### Free Functions
- `ittapi::pause()` — Pause collection.
- `ittapi::resume()` — Resume collection.
- `ittapi::set_thread_name(std::string_view name)` — Set the current thread's name.
### Classes
#### `ittapi::StringHandle`
Lightweight wrapper around `__itt_string_handle*`.
```cpp
ittapi::StringHandle h{"my_handle"};
h.valid(); // true if handle was created
h.get(); // underlying __itt_string_handle*
```
#### `ittapi::Domain`
Lightweight wrapper around `__itt_domain*` with convenience factories.
```cpp
ittapi::Domain d{"my.domain"};
auto task = d.task("task_name"); // returns ScopedTask (RAII)
auto region = d.region("region_name"); // returns ScopedRegion
auto frame = d.frame(); // returns ScopedFrame
d.task_begin("work"); // manual task begin (simple stack-based task)
d.task_end(); // manual task end
__itt_id id = __itt_id_make(nullptr, 1);
d.task_begin("overlapped", id, __itt_null); // manual task begin (overlapped task)
d.task_end(id); // manual task end by ID
```
#### `ittapi::ScopedTask`
RAII wrapper for task begin/end. Use `domain.overlapped_task()` to create an overlapped task (tasks that can end in any order). Each overlapped task instance gets a unique `__itt_id` derived from its object address. The `id()` method returns this ID.
```cpp
// Simple task
{
auto task = domain.task("work");
// ... do work ...
task.end(); // optional early end (idempotent)
} // destructor ends task if still active
```
Overlapped tasks — use `overlapped_task()`, optionally pass a parent ID:
```cpp
{
auto parent = domain.overlapped_task("parent"); // overlapped, no parent
auto child = domain.overlapped_task("child", parent.id()); // overlapped, child of parent
parent.end(); // end parent task while child is still running
child.end(); // child task ends
}
```
For manual (non-RAII) control:
```cpp
domain.task_begin("work");
// ... do work ...
domain.task_end();
// overlapped tasks:
__itt_id id = __itt_id_make(nullptr, 1);
domain.task_begin("overlapped_work", id, __itt_null);
// ... do work ...
domain.task_end(id);
```
#### `ittapi::ScopedRegion`
RAII wrapper for region begin/end.
#### `ittapi::ScopedFrame`
RAII wrapper for frame begin/end. Supports explicit timestamp submission.
```cpp
ittapi::ScopedFrame::submit(domain.get(), begin_ts, end_ts);
```
#### `ittapi::ScopedPause`
RAII wrapper for pause/resume. Constructor pauses, destructor resumes.
```cpp
{
ittapi::ScopedPause sp;
// collection is paused
sp.resume_now(); // optional early resume
}
```