|
| 1 | +# ITT API C++ Wrapper |
| 2 | + |
| 3 | +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. |
| 4 | + |
| 5 | +## Supported APIs |
| 6 | + |
| 7 | +| API | C++ Wrapper | |
| 8 | +|-----|------------| |
| 9 | +| String Handle | `ittapi::StringHandle` | |
| 10 | +| Domain | `ittapi::Domain` | |
| 11 | +| Task | `ittapi::ScopedTask`, `Domain::task_begin()` / `Domain::task_end()` | |
| 12 | +| Region | `ittapi::ScopedRegion` | |
| 13 | +| Frame | `ittapi::ScopedFrame` | |
| 14 | +| Collection Control | `ittapi::pause()`, `ittapi::resume()`, `ittapi::ScopedPause` | |
| 15 | +| Thread Naming | `ittapi::set_thread_name()` | |
| 16 | + |
| 17 | +## Requirements |
| 18 | + |
| 19 | +- C++17 or later |
| 20 | +- The existing `ittnotify` static C-library |
| 21 | + |
| 22 | +## Including the Wrapper |
| 23 | + |
| 24 | +Use the umbrella header to get the full API: |
| 25 | + |
| 26 | +```cpp |
| 27 | +#include <ittapi.hpp> |
| 28 | +``` |
| 29 | + |
| 30 | +Or include individual headers: |
| 31 | + |
| 32 | +```cpp |
| 33 | +#include <ittapi_domain.hpp> |
| 34 | +#include <ittapi_task.hpp> |
| 35 | +#include <ittapi_collection_control.hpp> |
| 36 | +``` |
| 37 | + |
| 38 | +## Example: Task Instrumentation |
| 39 | + |
| 40 | +```cpp |
| 41 | +#include <ittapi.hpp> |
| 42 | + |
| 43 | +#include <chrono> |
| 44 | +#include <thread> |
| 45 | + |
| 46 | +int main() { |
| 47 | + ittapi::set_thread_name("main"); |
| 48 | + ittapi::Domain domain{"example.task"}; |
| 49 | + ittapi::StringHandle task_name{"process"}; |
| 50 | + |
| 51 | + ittapi::pause(); |
| 52 | + ittapi::resume(); |
| 53 | + |
| 54 | + { |
| 55 | + auto task = domain.task(task_name); |
| 56 | + std::this_thread::sleep_for(std::chrono::milliseconds(10)); |
| 57 | + } |
| 58 | + |
| 59 | + return 0; |
| 60 | +} |
| 61 | +``` |
| 62 | + |
| 63 | +## Linking |
| 64 | + |
| 65 | +### CMake Consumer |
| 66 | + |
| 67 | +```cmake |
| 68 | +find_package(ittapi CONFIG REQUIRED) |
| 69 | +target_link_libraries(my_app PRIVATE ittapi::cxx) |
| 70 | +``` |
| 71 | + |
| 72 | +The `ittapi::cxx` target is an `INTERFACE` library that transitively links the existing `ittnotify` static library and adds the C++ wrapper include directories. |
| 73 | + |
| 74 | +### Manual GCC/G++ (Linux) |
| 75 | + |
| 76 | +```bash |
| 77 | +g++ -std=c++17 -O2 \ |
| 78 | + -I<ittapi-install-prefix>/include \ |
| 79 | + app.cpp \ |
| 80 | + <ittapi-install-prefix>/lib/libittnotify.a \ |
| 81 | + -ldl -pthread \ |
| 82 | + -o app |
| 83 | +``` |
| 84 | + |
| 85 | +## Building with CMake |
| 86 | + |
| 87 | +From the repository root: |
| 88 | + |
| 89 | +```bash |
| 90 | +cmake -B build -DCMAKE_BUILD_TYPE=Release -DITT_API_CPP_SUPPORT=ON |
| 91 | +cmake --build build |
| 92 | +``` |
| 93 | + |
| 94 | +The `ITT_API_CPP_SUPPORT` option is `OFF` by default. |
| 95 | + |
| 96 | +You can also build with the build script: |
| 97 | + |
| 98 | +```bash |
| 99 | +python buildall.py --cpp |
| 100 | +``` |
| 101 | + |
| 102 | +## Running Tests |
| 103 | + |
| 104 | +Tests are registered inside the `cpp/` subdirectory. After building: |
| 105 | + |
| 106 | +```bash |
| 107 | +ctest --test-dir build/cpp --output-on-failure |
| 108 | +``` |
| 109 | + |
| 110 | +## Performance Tips |
| 111 | + |
| 112 | +- **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. |
| 113 | + ```cpp |
| 114 | + // Do this once at startup: |
| 115 | + ittapi::StringHandle name{"compute"}; |
| 116 | + |
| 117 | + // Then in hot code: |
| 118 | + auto task = domain.task(name); // no allocation, no lock |
| 119 | + ``` |
| 120 | +- **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. |
| 121 | +- **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. |
| 122 | +- **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. |
| 123 | +
|
| 124 | +## API Reference |
| 125 | +
|
| 126 | +### Free Functions |
| 127 | +
|
| 128 | +- `ittapi::pause()` — Pause collection. |
| 129 | +- `ittapi::resume()` — Resume collection. |
| 130 | +- `ittapi::set_thread_name(std::string_view name)` — Set the current thread's name. |
| 131 | +
|
| 132 | +### Classes |
| 133 | +
|
| 134 | +#### `ittapi::StringHandle` |
| 135 | +
|
| 136 | +Lightweight wrapper around `__itt_string_handle*`. |
| 137 | +
|
| 138 | +```cpp |
| 139 | +ittapi::StringHandle h{"my_handle"}; |
| 140 | +h.valid(); // true if handle was created |
| 141 | +h.get(); // underlying __itt_string_handle* |
| 142 | +``` |
| 143 | + |
| 144 | +#### `ittapi::Domain` |
| 145 | + |
| 146 | +Lightweight wrapper around `__itt_domain*` with convenience factories. |
| 147 | + |
| 148 | +```cpp |
| 149 | +ittapi::Domain d{"my.domain"}; |
| 150 | +auto task = d.task("task_name"); // returns ScopedTask (RAII) |
| 151 | +auto region = d.region("region_name"); // returns ScopedRegion |
| 152 | +auto frame = d.frame(); // returns ScopedFrame |
| 153 | + |
| 154 | +d.task_begin("work"); // manual task begin (simple stack-based task) |
| 155 | +d.task_end(); // manual task end |
| 156 | + |
| 157 | +__itt_id id = __itt_id_make(nullptr, 1); |
| 158 | +d.task_begin("overlapped", id, __itt_null); // manual task begin (overlapped task) |
| 159 | +d.task_end(id); // manual task end by ID |
| 160 | +``` |
| 161 | +
|
| 162 | +#### `ittapi::ScopedTask` |
| 163 | +
|
| 164 | +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. |
| 165 | +
|
| 166 | +```cpp |
| 167 | +// Simple task |
| 168 | +{ |
| 169 | + auto task = domain.task("work"); |
| 170 | + // ... do work ... |
| 171 | + task.end(); // optional early end (idempotent) |
| 172 | +} // destructor ends task if still active |
| 173 | +``` |
| 174 | + |
| 175 | +Overlapped tasks — use `overlapped_task()`, optionally pass a parent ID: |
| 176 | + |
| 177 | +```cpp |
| 178 | +{ |
| 179 | + auto parent = domain.overlapped_task("parent"); // overlapped, no parent |
| 180 | + auto child = domain.overlapped_task("child", parent.id()); // overlapped, child of parent |
| 181 | + |
| 182 | + parent.end(); // end parent task while child is still running |
| 183 | + child.end(); // child task ends |
| 184 | +} |
| 185 | +``` |
| 186 | + |
| 187 | +For manual (non-RAII) control: |
| 188 | + |
| 189 | +```cpp |
| 190 | +domain.task_begin("work"); |
| 191 | +// ... do work ... |
| 192 | +domain.task_end(); |
| 193 | + |
| 194 | +// overlapped tasks: |
| 195 | +__itt_id id = __itt_id_make(nullptr, 1); |
| 196 | +domain.task_begin("overlapped_work", id, __itt_null); |
| 197 | +// ... do work ... |
| 198 | +domain.task_end(id); |
| 199 | +``` |
| 200 | + |
| 201 | +#### `ittapi::ScopedRegion` |
| 202 | + |
| 203 | +RAII wrapper for region begin/end. |
| 204 | + |
| 205 | +#### `ittapi::ScopedFrame` |
| 206 | + |
| 207 | +RAII wrapper for frame begin/end. Supports explicit timestamp submission. |
| 208 | + |
| 209 | +```cpp |
| 210 | +ittapi::ScopedFrame::submit(domain.get(), begin_ts, end_ts); |
| 211 | +``` |
| 212 | +
|
| 213 | +#### `ittapi::ScopedPause` |
| 214 | +
|
| 215 | +RAII wrapper for pause/resume. Constructor pauses, destructor resumes. |
| 216 | +
|
| 217 | +```cpp |
| 218 | +{ |
| 219 | + ittapi::ScopedPause sp; |
| 220 | + // collection is paused |
| 221 | + sp.resume_now(); // optional early resume |
| 222 | +} |
| 223 | +``` |
0 commit comments