Skip to content

Commit 15fdfc1

Browse files
authored
Add C++17 header-only wrapper for ITT API (#226)
* add c++ wrapper * add support for wchar_t* * fix task/frame/region apis * add id support * add cmake build and tests * add readme and samples * add gh action * update README.md * cleanup * improve tests * rename test check define * added back copy and move assignment operators. * cleanup cmake * trigger ci * cleanup * minor fixes * apply CMakefile changes back * cleanup gh action * update main README * simplify gh action * ready to merge * add new docomuntation page * update documentation copyrigth year * add thread-local cache for string handle lookups * rename Domain class member * update the sample with more usage examples * fix windows build * add overlapped task api support * improve documentation * add itt id auto generation * add new overlapped_task() api in domain * add cache for overlapped task id storing * fix id generation logic, cover more overlapped scenarios
1 parent 2369c7e commit 15fdfc1

28 files changed

Lines changed: 2247 additions & 3 deletions

.github/workflows/main.yml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,27 @@ jobs:
3939
# doesn't work in case of CMake + VS (https://github.com/fortran-lang/setup-fortran/issues/45)
4040
run: python buildall.py --force_bits 64 -ft ${{ matrix.optional_args }}
4141

42+
cpp_wrapper:
43+
name: Check C++ wrapper
44+
runs-on: ${{ matrix.os }}
45+
strategy:
46+
fail-fast: false
47+
matrix:
48+
include:
49+
- os: ubuntu-latest
50+
- os: windows-latest
51+
steps:
52+
- name: Checkout sources
53+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
54+
- name: Build C++ wrapper
55+
run: python buildall.py --force_bits 64 -cpp
56+
- name: Test (Linux)
57+
run: ctest --test-dir build_linux/64/cpp --build-config Release --output-on-failure
58+
if: runner.os == 'Linux'
59+
- name: Test (Windows)
60+
run: ctest --test-dir build_win/64/cpp --build-config Release --output-on-failure
61+
if: runner.os == 'Windows'
62+
4263
rust_format:
4364
name: Check Rust formatting
4465
runs-on: ubuntu-latest

CMakeLists.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ project(ittapi)
2626
option(FORCE_32 "Force a 32-bit compile on 64-bit" OFF)
2727
option(ITT_API_IPT_SUPPORT "ptmarks support" OFF)
2828
option(ITT_API_FORTRAN_SUPPORT "fortran support" OFF)
29+
option(ITT_API_CPP_SUPPORT "C++ wrapper support" OFF)
2930
option(ITT_API_INSTALL "Enable ITT API installation rules" ON)
3031

3132
if(FORCE_32 AND UNIX)
@@ -171,13 +172,23 @@ target_include_directories(jitprofiling
171172
PRIVATE src/ittnotify
172173
)
173174

175+
# C++ wrapper
176+
if(ITT_API_CPP_SUPPORT)
177+
add_subdirectory(cpp)
178+
endif()
179+
174180
# install
175181

176182
include(CMakePackageConfigHelpers)
177183
include(GNUInstallDirs)
178184

179185
if(ITT_API_INSTALL)
180186
install(TARGETS ittnotify EXPORT ittapi-targets INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
187+
if(ITT_API_CPP_SUPPORT)
188+
install(TARGETS ittapi-cpp EXPORT ittapi-targets)
189+
install(DIRECTORY cpp/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
190+
FILES_MATCHING PATTERN "*.hpp")
191+
endif()
181192
install(EXPORT ittapi-targets NAMESPACE ittapi:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ittapi)
182193
install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
183194
FILES_MATCHING PATTERN "*.h"

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ To build the library:
4141
- To list available build options execute: `python buildall.py -h`
4242

4343
```
44-
usage: buildall.py [-h] [-d] [-c] [-v] [-pt] [-ft] [--force_bits]
44+
usage: buildall.py [-h] [-d] [-c] [-v] [-pt] [-ft] [-cpp] [--force_bits]
4545
4646
optional arguments:
4747
-h, --help show this help message and exit
@@ -50,6 +50,7 @@ optional arguments:
5050
-v, --verbose enable verbose output from build process
5151
-pt, --ptmark enable anomaly detection support
5252
-ft, --fortran enable fortran support
53+
-cpp, --cpp enable C++ wrapper support
5354
--force_bits specify bit version for the target
5455
--vs specify visual studio version (Windows only)
5556
--cmake_gen specify cmake build generator (Windows only)

buildall.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ def main():
117117
"-pt", "--ptmark", help="enable anomaly detection support", action="store_true")
118118
parser.add_argument(
119119
"-ft", "--fortran", help="enable fortran support", action="store_true")
120+
parser.add_argument(
121+
"-cpp", "--cpp", help="enable C++ wrapper support", action="store_true")
120122
parser.add_argument(
121123
"--force_bits", choices=["32", "64"], help="specify bit version for the target")
122124
if sys.platform == 'win32' and vs_versions:
@@ -177,7 +179,8 @@ def main():
177179
("-DCMAKE_BUILD_TYPE=Debug" if args.debug else ""),
178180
('-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON' if args.verbose else ''),
179181
("-DITT_API_IPT_SUPPORT=1" if args.ptmark else ""),
180-
("-DITT_API_FORTRAN_SUPPORT=1" if args.fortran else "")
182+
("-DITT_API_FORTRAN_SUPPORT=1" if args.fortran else ""),
183+
("-DITT_API_CPP_SUPPORT=ON" if args.cpp else "")
181184
])))
182185

183186
if sys.platform == 'win32':

cpp/CMakeLists.txt

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#
2+
# Copyright (C) 2026 Intel Corporation
3+
# SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
4+
#
5+
6+
add_library(ittapi-cpp INTERFACE)
7+
add_library(ittapi::cxx ALIAS ittapi-cpp)
8+
9+
target_include_directories(ittapi-cpp
10+
INTERFACE
11+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
12+
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
13+
)
14+
15+
target_link_libraries(ittapi-cpp INTERFACE ittnotify)
16+
target_compile_features(ittapi-cpp INTERFACE cxx_std_17)
17+
18+
if(NOT WIN32)
19+
find_package(Threads)
20+
endif()
21+
22+
# Sample
23+
add_executable(task_sample samples/task_sample.cpp)
24+
target_link_libraries(task_sample PRIVATE ittapi-cpp)
25+
if(NOT WIN32)
26+
target_link_libraries(task_sample PRIVATE ${CMAKE_DL_LIBS})
27+
if(Threads_FOUND)
28+
target_link_libraries(task_sample PRIVATE Threads::Threads)
29+
endif()
30+
endif()
31+
32+
# Tests
33+
enable_testing()
34+
35+
set(CPP_TESTS
36+
test_string_handle
37+
test_domain
38+
test_task
39+
test_region
40+
test_frame
41+
test_collection_control
42+
test_thread_naming
43+
test_ittapi
44+
)
45+
46+
foreach(test_name ${CPP_TESTS})
47+
add_executable(${test_name} tests/${test_name}.cpp)
48+
target_link_libraries(${test_name} PRIVATE ittapi-cpp)
49+
if(NOT WIN32)
50+
target_link_libraries(${test_name} PRIVATE ${CMAKE_DL_LIBS})
51+
if(Threads_FOUND)
52+
target_link_libraries(${test_name} PRIVATE Threads::Threads)
53+
endif()
54+
endif()
55+
add_test(NAME cpp_${test_name} COMMAND ${test_name})
56+
endforeach()

cpp/README.md

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
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+
```

cpp/include/ittapi.hpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
Copyright (C) 2026 Intel Corporation
3+
SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only)
4+
*/
5+
6+
#ifndef ITTAPI_HPP
7+
#define ITTAPI_HPP
8+
9+
#include "ittapi_collection_control.hpp"
10+
#include "ittapi_domain.hpp"
11+
#include "ittapi_frame.hpp"
12+
#include "ittapi_region.hpp"
13+
#include "ittapi_string_handle.hpp"
14+
#include "ittapi_task.hpp"
15+
#include "ittapi_thread_naming.hpp"
16+
17+
#endif // ITTAPI_HPP

0 commit comments

Comments
 (0)