From b101edc0f60bfc44e41eeaeaf95e317941aa073b Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Thu, 16 Apr 2026 15:22:42 -0500 Subject: [PATCH 01/33] add c++ wrapper --- cpp/include/ittapi.hpp | 17 ++++++ cpp/include/ittapi_collection_control.hpp | 66 +++++++++++++++++++++ cpp/include/ittapi_domain.hpp | 67 +++++++++++++++++++++ cpp/include/ittapi_frame.hpp | 67 +++++++++++++++++++++ cpp/include/ittapi_region.hpp | 72 +++++++++++++++++++++++ cpp/include/ittapi_string_handle.hpp | 30 ++++++++++ cpp/include/ittapi_task.hpp | 70 ++++++++++++++++++++++ cpp/include/ittapi_thread_naming.hpp | 22 +++++++ cpp/include/ittapi_utils.hpp | 46 +++++++++++++++ 9 files changed, 457 insertions(+) create mode 100644 cpp/include/ittapi.hpp create mode 100644 cpp/include/ittapi_collection_control.hpp create mode 100644 cpp/include/ittapi_domain.hpp create mode 100644 cpp/include/ittapi_frame.hpp create mode 100644 cpp/include/ittapi_region.hpp create mode 100644 cpp/include/ittapi_string_handle.hpp create mode 100644 cpp/include/ittapi_task.hpp create mode 100644 cpp/include/ittapi_thread_naming.hpp create mode 100644 cpp/include/ittapi_utils.hpp diff --git a/cpp/include/ittapi.hpp b/cpp/include/ittapi.hpp new file mode 100644 index 0000000..67d6557 --- /dev/null +++ b/cpp/include/ittapi.hpp @@ -0,0 +1,17 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#ifndef ITTAPI_HPP +#define ITTAPI_HPP + +#include "ittapi_collection_control.hpp" +#include "ittapi_domain.hpp" +#include "ittapi_frame.hpp" +#include "ittapi_region.hpp" +#include "ittapi_string_handle.hpp" +#include "ittapi_task.hpp" +#include "ittapi_thread_naming.hpp" + +#endif // ITTAPI_HPP diff --git a/cpp/include/ittapi_collection_control.hpp b/cpp/include/ittapi_collection_control.hpp new file mode 100644 index 0000000..8bc7d94 --- /dev/null +++ b/cpp/include/ittapi_collection_control.hpp @@ -0,0 +1,66 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#ifndef ITTAPI_COLLECTION_CONTROL_HPP +#define ITTAPI_COLLECTION_CONTROL_HPP + +#include + +namespace ittapi { + +inline void pause() noexcept { + __itt_pause(); +} + +inline void resume() noexcept { + __itt_resume(); +} + +class ScopedPause { +public: + ScopedPause() noexcept : active_(true) { + __itt_pause(); + } + + ScopedPause(const ScopedPause&) = delete; + ScopedPause& operator=(const ScopedPause&) = delete; + + ScopedPause(ScopedPause&& other) noexcept : active_(other.active_) { + other.active_ = false; + } + + ScopedPause& operator=(ScopedPause&& other) noexcept { + if (this != &other) { + if (active_) { + __itt_resume(); + } + active_ = other.active_; + other.active_ = false; + } + return *this; + } + + ~ScopedPause() noexcept { + if (active_) { + __itt_resume(); + } + } + + void resume_now() noexcept { + if (active_) { + __itt_resume(); + active_ = false; + } + } + + bool active() const noexcept { return active_; } + +private: + bool active_ = false; +}; + +} // namespace ittapi + +#endif // ITTAPI_COLLECTION_CONTROL_HPP diff --git a/cpp/include/ittapi_domain.hpp b/cpp/include/ittapi_domain.hpp new file mode 100644 index 0000000..1ff5482 --- /dev/null +++ b/cpp/include/ittapi_domain.hpp @@ -0,0 +1,67 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#ifndef ITTAPI_DOMAIN_HPP +#define ITTAPI_DOMAIN_HPP + +#include +#include + +#include "ittapi_utils.hpp" +#include "ittapi_string_handle.hpp" +#include "ittapi_task.hpp" +#include "ittapi_region.hpp" +#include "ittapi_frame.hpp" + +namespace ittapi { + +class Domain { +public: + explicit Domain(std::string_view name) + : handle_(detail::create_domain(std::string(name).c_str())) {} + + __itt_domain* native_handle() const noexcept { return handle_; } + bool valid() const noexcept { return handle_ != nullptr; } + + ScopedTask task(std::string_view name) const { + return ScopedTask(handle_, name); + } + + ScopedTask task(const StringHandle& name) const noexcept { + return ScopedTask(handle_, name); + } + + void task_begin(std::string_view name) const { + __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); + __itt_task_begin(handle_, detail::make_null_id(), detail::make_null_id(), h); + } + + void task_begin(const StringHandle& name) const noexcept { + __itt_task_begin(handle_, detail::make_null_id(), detail::make_null_id(), name.native_handle()); + } + + void task_end() const noexcept { + __itt_task_end(handle_); + } + + ScopedRegion region(std::string_view name) const { + return ScopedRegion(handle_, name); + } + + ScopedRegion region(const StringHandle& name) const noexcept { + return ScopedRegion(handle_, name); + } + + ScopedFrame frame() const noexcept { + return ScopedFrame(handle_); + } + +private: + __itt_domain* handle_ = nullptr; +}; + +} // namespace ittapi + +#endif // ITTAPI_DOMAIN_HPP diff --git a/cpp/include/ittapi_frame.hpp b/cpp/include/ittapi_frame.hpp new file mode 100644 index 0000000..2647837 --- /dev/null +++ b/cpp/include/ittapi_frame.hpp @@ -0,0 +1,67 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#ifndef ITTAPI_FRAME_HPP +#define ITTAPI_FRAME_HPP + +#include "ittapi_utils.hpp" + +namespace ittapi { + +class Domain; + +class ScopedFrame { +public: + explicit ScopedFrame(const __itt_domain* domain) noexcept + : domain_(domain), id_(detail::make_null_id()), active_(true) { + __itt_frame_begin_v3(domain_, &id_); + } + + ScopedFrame(const ScopedFrame&) = delete; + ScopedFrame& operator=(const ScopedFrame&) = delete; + + ScopedFrame(ScopedFrame&& other) noexcept + : domain_(other.domain_), id_(other.id_), active_(other.active_) { + other.active_ = false; + } + + ScopedFrame& operator=(ScopedFrame&& other) noexcept { + if (this != &other) { + end(); + domain_ = other.domain_; + id_ = other.id_; + active_ = other.active_; + other.active_ = false; + } + return *this; + } + + ~ScopedFrame() noexcept { + end(); + } + + void end() noexcept { + if (active_) { + __itt_frame_end_v3(domain_, &id_); + active_ = false; + } + } + + bool active() const noexcept { return active_; } + + static void submit(const __itt_domain* domain, __itt_timestamp begin, __itt_timestamp end) noexcept { + __itt_id id = detail::make_null_id(); + __itt_frame_submit_v3(domain, &id, begin, end); + } + +private: + const __itt_domain* domain_ = nullptr; + __itt_id id_{}; + bool active_ = false; +}; + +} // namespace ittapi + +#endif // ITTAPI_FRAME_HPP diff --git a/cpp/include/ittapi_region.hpp b/cpp/include/ittapi_region.hpp new file mode 100644 index 0000000..019f7b7 --- /dev/null +++ b/cpp/include/ittapi_region.hpp @@ -0,0 +1,72 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#ifndef ITTAPI_REGION_HPP +#define ITTAPI_REGION_HPP + +#include +#include + +#include "ittapi_utils.hpp" +#include "ittapi_string_handle.hpp" + +namespace ittapi { + +class Domain; + +class ScopedRegion { +public: + ScopedRegion(const __itt_domain* domain, std::string_view name) + : domain_(domain), id_(detail::make_null_id()), active_(true) { + __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); + __itt_region_begin(domain_, id_, detail::make_null_id(), h); + } + + ScopedRegion(const __itt_domain* domain, const StringHandle& name) noexcept + : domain_(domain), id_(detail::make_null_id()), active_(true) { + __itt_region_begin(domain_, id_, detail::make_null_id(), name.native_handle()); + } + + ScopedRegion(const ScopedRegion&) = delete; + ScopedRegion& operator=(const ScopedRegion&) = delete; + + ScopedRegion(ScopedRegion&& other) noexcept + : domain_(other.domain_), id_(other.id_), active_(other.active_) { + other.active_ = false; + } + + ScopedRegion& operator=(ScopedRegion&& other) noexcept { + if (this != &other) { + end(); + domain_ = other.domain_; + id_ = other.id_; + active_ = other.active_; + other.active_ = false; + } + return *this; + } + + ~ScopedRegion() noexcept { + end(); + } + + void end() noexcept { + if (active_) { + __itt_region_end(domain_, id_); + active_ = false; + } + } + + bool active() const noexcept { return active_; } + +private: + const __itt_domain* domain_ = nullptr; + __itt_id id_{}; + bool active_ = false; +}; + +} // namespace ittapi + +#endif // ITTAPI_REGION_HPP diff --git a/cpp/include/ittapi_string_handle.hpp b/cpp/include/ittapi_string_handle.hpp new file mode 100644 index 0000000..b3520df --- /dev/null +++ b/cpp/include/ittapi_string_handle.hpp @@ -0,0 +1,30 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#ifndef ITTAPI_STRING_HANDLE_HPP +#define ITTAPI_STRING_HANDLE_HPP + +#include +#include + +#include "ittapi_utils.hpp" + +namespace ittapi { + +class StringHandle { +public: + explicit StringHandle(std::string_view name) + : handle_(detail::create_string_handle(std::string(name).c_str())) {} + + __itt_string_handle* native_handle() const noexcept { return handle_; } + bool valid() const noexcept { return handle_ != nullptr; } + +private: + __itt_string_handle* handle_ = nullptr; +}; + +} // namespace ittapi + +#endif // ITTAPI_STRING_HANDLE_HPP diff --git a/cpp/include/ittapi_task.hpp b/cpp/include/ittapi_task.hpp new file mode 100644 index 0000000..420f3e2 --- /dev/null +++ b/cpp/include/ittapi_task.hpp @@ -0,0 +1,70 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#ifndef ITTAPI_TASK_HPP +#define ITTAPI_TASK_HPP + +#include +#include + +#include "ittapi_utils.hpp" +#include "ittapi_string_handle.hpp" + +namespace ittapi { + +class Domain; + +class ScopedTask { +public: + ScopedTask(const __itt_domain* domain, std::string_view name) + : domain_(domain), active_(true) { + __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); + __itt_task_begin(domain_, detail::make_null_id(), detail::make_null_id(), h); + } + + ScopedTask(const __itt_domain* domain, const StringHandle& name) noexcept + : domain_(domain), active_(true) { + __itt_task_begin(domain_, detail::make_null_id(), detail::make_null_id(), name.native_handle()); + } + + ScopedTask(const ScopedTask&) = delete; + ScopedTask& operator=(const ScopedTask&) = delete; + + ScopedTask(ScopedTask&& other) noexcept + : domain_(other.domain_), active_(other.active_) { + other.active_ = false; + } + + ScopedTask& operator=(ScopedTask&& other) noexcept { + if (this != &other) { + end(); + domain_ = other.domain_; + active_ = other.active_; + other.active_ = false; + } + return *this; + } + + ~ScopedTask() noexcept { + end(); + } + + void end() noexcept { + if (active_) { + __itt_task_end(domain_); + active_ = false; + } + } + + bool active() const noexcept { return active_; } + +private: + const __itt_domain* domain_ = nullptr; + bool active_ = false; +}; + +} // namespace ittapi + +#endif // ITTAPI_TASK_HPP diff --git a/cpp/include/ittapi_thread_naming.hpp b/cpp/include/ittapi_thread_naming.hpp new file mode 100644 index 0000000..946128a --- /dev/null +++ b/cpp/include/ittapi_thread_naming.hpp @@ -0,0 +1,22 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#ifndef ITTAPI_THREAD_NAMING_HPP +#define ITTAPI_THREAD_NAMING_HPP + +#include +#include + +#include "ittapi_utils.hpp" + +namespace ittapi { + +inline void set_thread_name(std::string_view name) { + detail::thread_set_name(std::string(name).c_str()); +} + +} // namespace ittapi + +#endif // ITTAPI_THREAD_NAMING_HPP diff --git a/cpp/include/ittapi_utils.hpp b/cpp/include/ittapi_utils.hpp new file mode 100644 index 0000000..ec834cc --- /dev/null +++ b/cpp/include/ittapi_utils.hpp @@ -0,0 +1,46 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#ifndef ITTAPI_UTILS_HPP +#define ITTAPI_UTILS_HPP + +#include + +namespace ittapi { +namespace detail { + +inline __itt_domain* create_domain(const char* name) noexcept { +#if ITT_PLATFORM == ITT_PLATFORM_WIN + return __itt_domain_createA(name); +#else + return __itt_domain_create(name); +#endif +} + +inline __itt_string_handle* create_string_handle(const char* name) noexcept { +#if ITT_PLATFORM == ITT_PLATFORM_WIN + return __itt_string_handle_createA(name); +#else + return __itt_string_handle_create(name); +#endif +} + +inline void thread_set_name(const char* name) noexcept { +#if ITT_PLATFORM == ITT_PLATFORM_WIN + __itt_thread_set_nameA(name); +#else + __itt_thread_set_name(name); +#endif +} + +inline __itt_id make_null_id() noexcept { + __itt_id id = __itt_null; + return id; +} + +} // namespace detail +} // namespace ittapi + +#endif // ITTAPI_UTILS_HPP From c2f4d71e3272e93373d29ec7d32802f82a7fe162 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 05:35:42 -0500 Subject: [PATCH 02/33] add support for wchar_t* --- cpp/include/ittapi_collection_control.hpp | 56 ++++++++++++------ cpp/include/ittapi_domain.hpp | 70 ++++++++++++++++------- cpp/include/ittapi_frame.hpp | 61 +++++++++++++------- cpp/include/ittapi_region.hpp | 65 +++++++++++++-------- cpp/include/ittapi_string_handle.hpp | 32 ++++++++--- cpp/include/ittapi_task.hpp | 58 ++++++++++++------- cpp/include/ittapi_thread_naming.hpp | 13 ++++- cpp/include/ittapi_utils.hpp | 37 ++++++++++-- 8 files changed, 270 insertions(+), 122 deletions(-) diff --git a/cpp/include/ittapi_collection_control.hpp b/cpp/include/ittapi_collection_control.hpp index 8bc7d94..787947d 100644 --- a/cpp/include/ittapi_collection_control.hpp +++ b/cpp/include/ittapi_collection_control.hpp @@ -8,57 +8,75 @@ #include -namespace ittapi { +namespace ittapi +{ -inline void pause() noexcept { +inline void pause() noexcept +{ __itt_pause(); } -inline void resume() noexcept { +inline void resume() noexcept +{ __itt_resume(); } -class ScopedPause { +class ScopedPause +{ public: - ScopedPause() noexcept : active_(true) { + ScopedPause() noexcept + : m_active(true) + { __itt_pause(); } ScopedPause(const ScopedPause&) = delete; ScopedPause& operator=(const ScopedPause&) = delete; - ScopedPause(ScopedPause&& other) noexcept : active_(other.active_) { - other.active_ = false; + ScopedPause(ScopedPause&& other) noexcept + : m_active(other.m_active) + { + other.m_active = false; } - ScopedPause& operator=(ScopedPause&& other) noexcept { - if (this != &other) { - if (active_) { + ScopedPause& operator=(ScopedPause&& other) noexcept + { + if (this != &other) + { + if (m_active) + { __itt_resume(); } - active_ = other.active_; - other.active_ = false; + m_active = other.m_active; + other.m_active = false; } return *this; } - ~ScopedPause() noexcept { - if (active_) { + ~ScopedPause() noexcept + { + if (m_active) + { __itt_resume(); } } - void resume_now() noexcept { - if (active_) { + void resume_now() noexcept + { + if (m_active) + { __itt_resume(); - active_ = false; + m_active = false; } } - bool active() const noexcept { return active_; } + bool active() const noexcept + { + return m_active; + } private: - bool active_ = false; + bool m_active = false; }; } // namespace ittapi diff --git a/cpp/include/ittapi_domain.hpp b/cpp/include/ittapi_domain.hpp index 1ff5482..8fe0b19 100644 --- a/cpp/include/ittapi_domain.hpp +++ b/cpp/include/ittapi_domain.hpp @@ -15,51 +15,77 @@ #include "ittapi_region.hpp" #include "ittapi_frame.hpp" -namespace ittapi { +namespace ittapi +{ -class Domain { +class Domain +{ public: explicit Domain(std::string_view name) - : handle_(detail::create_domain(std::string(name).c_str())) {} + : m_handle(detail::create_domain(std::string(name).c_str())) + { + } + +#if ITT_PLATFORM == ITT_PLATFORM_WIN + explicit Domain(std::wstring_view name) + : m_handle(detail::create_domain(std::wstring(name).c_str())) + { + } +#endif - __itt_domain* native_handle() const noexcept { return handle_; } - bool valid() const noexcept { return handle_ != nullptr; } + __itt_domain* native_handle() const noexcept + { + return m_handle; + } + + bool valid() const noexcept + { + return m_handle != nullptr; + } - ScopedTask task(std::string_view name) const { - return ScopedTask(handle_, name); + ScopedTask task(std::string_view name) const + { + return ScopedTask(m_handle, name); } - ScopedTask task(const StringHandle& name) const noexcept { - return ScopedTask(handle_, name); + ScopedTask task(const StringHandle& name) const noexcept + { + return ScopedTask(m_handle, name); } - void task_begin(std::string_view name) const { + void task_begin(std::string_view name) const + { __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); - __itt_task_begin(handle_, detail::make_null_id(), detail::make_null_id(), h); + __itt_task_begin(m_handle, detail::make_null_id(), detail::make_null_id(), h); } - void task_begin(const StringHandle& name) const noexcept { - __itt_task_begin(handle_, detail::make_null_id(), detail::make_null_id(), name.native_handle()); + void task_begin(const StringHandle& name) const noexcept + { + __itt_task_begin(m_handle, detail::make_null_id(), detail::make_null_id(), name.native_handle()); } - void task_end() const noexcept { - __itt_task_end(handle_); + void task_end() const noexcept + { + __itt_task_end(m_handle); } - ScopedRegion region(std::string_view name) const { - return ScopedRegion(handle_, name); + ScopedRegion region(std::string_view name) const + { + return ScopedRegion(m_handle, name); } - ScopedRegion region(const StringHandle& name) const noexcept { - return ScopedRegion(handle_, name); + ScopedRegion region(const StringHandle& name) const noexcept + { + return ScopedRegion(m_handle, name); } - ScopedFrame frame() const noexcept { - return ScopedFrame(handle_); + ScopedFrame frame() const noexcept + { + return ScopedFrame(m_handle); } private: - __itt_domain* handle_ = nullptr; + __itt_domain* m_handle = nullptr; }; } // namespace ittapi diff --git a/cpp/include/ittapi_frame.hpp b/cpp/include/ittapi_frame.hpp index 2647837..c7ef62a 100644 --- a/cpp/include/ittapi_frame.hpp +++ b/cpp/include/ittapi_frame.hpp @@ -8,58 +8,75 @@ #include "ittapi_utils.hpp" -namespace ittapi { +namespace ittapi +{ class Domain; -class ScopedFrame { +class ScopedFrame +{ public: explicit ScopedFrame(const __itt_domain* domain) noexcept - : domain_(domain), id_(detail::make_null_id()), active_(true) { - __itt_frame_begin_v3(domain_, &id_); + : m_domain(domain) + , m_id(detail::make_null_id()) + , m_active(true) + { + __itt_frame_begin_v3(m_domain, &m_id); } ScopedFrame(const ScopedFrame&) = delete; ScopedFrame& operator=(const ScopedFrame&) = delete; ScopedFrame(ScopedFrame&& other) noexcept - : domain_(other.domain_), id_(other.id_), active_(other.active_) { - other.active_ = false; + : m_domain(other.m_domain) + , m_id(other.m_id) + , m_active(other.m_active) + { + other.m_active = false; } - ScopedFrame& operator=(ScopedFrame&& other) noexcept { - if (this != &other) { + ScopedFrame& operator=(ScopedFrame&& other) noexcept + { + if (this != &other) + { end(); - domain_ = other.domain_; - id_ = other.id_; - active_ = other.active_; - other.active_ = false; + m_domain = other.m_domain; + m_id = other.m_id; + m_active = other.m_active; + other.m_active = false; } return *this; } - ~ScopedFrame() noexcept { + ~ScopedFrame() noexcept + { end(); } - void end() noexcept { - if (active_) { - __itt_frame_end_v3(domain_, &id_); - active_ = false; + void end() noexcept + { + if (m_active) + { + __itt_frame_end_v3(m_domain, &m_id); + m_active = false; } } - bool active() const noexcept { return active_; } + bool active() const noexcept + { + return m_active; + } - static void submit(const __itt_domain* domain, __itt_timestamp begin, __itt_timestamp end) noexcept { + static void submit(const __itt_domain* domain, __itt_timestamp begin, __itt_timestamp end) noexcept + { __itt_id id = detail::make_null_id(); __itt_frame_submit_v3(domain, &id, begin, end); } private: - const __itt_domain* domain_ = nullptr; - __itt_id id_{}; - bool active_ = false; + const __itt_domain* m_domain = nullptr; + __itt_id m_id{}; + bool m_active = false; }; } // namespace ittapi diff --git a/cpp/include/ittapi_region.hpp b/cpp/include/ittapi_region.hpp index 019f7b7..403b9ae 100644 --- a/cpp/include/ittapi_region.hpp +++ b/cpp/include/ittapi_region.hpp @@ -12,59 +12,78 @@ #include "ittapi_utils.hpp" #include "ittapi_string_handle.hpp" -namespace ittapi { +namespace ittapi +{ class Domain; -class ScopedRegion { +class ScopedRegion +{ public: ScopedRegion(const __itt_domain* domain, std::string_view name) - : domain_(domain), id_(detail::make_null_id()), active_(true) { + : m_domain(domain) + , m_id(detail::make_null_id()) + , m_active(true) + { __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); - __itt_region_begin(domain_, id_, detail::make_null_id(), h); + __itt_region_begin(m_domain, m_id, detail::make_null_id(), h); } ScopedRegion(const __itt_domain* domain, const StringHandle& name) noexcept - : domain_(domain), id_(detail::make_null_id()), active_(true) { - __itt_region_begin(domain_, id_, detail::make_null_id(), name.native_handle()); + : m_domain(domain) + , m_id(detail::make_null_id()) + , m_active(true) + { + __itt_region_begin(m_domain, m_id, detail::make_null_id(), name.native_handle()); } ScopedRegion(const ScopedRegion&) = delete; ScopedRegion& operator=(const ScopedRegion&) = delete; ScopedRegion(ScopedRegion&& other) noexcept - : domain_(other.domain_), id_(other.id_), active_(other.active_) { - other.active_ = false; + : m_domain(other.m_domain) + , m_id(other.m_id) + , m_active(other.m_active) + { + other.m_active = false; } - ScopedRegion& operator=(ScopedRegion&& other) noexcept { - if (this != &other) { + ScopedRegion& operator=(ScopedRegion&& other) noexcept + { + if (this != &other) + { end(); - domain_ = other.domain_; - id_ = other.id_; - active_ = other.active_; - other.active_ = false; + m_domain = other.m_domain; + m_id = other.m_id; + m_active = other.m_active; + other.m_active = false; } return *this; } - ~ScopedRegion() noexcept { + ~ScopedRegion() noexcept + { end(); } - void end() noexcept { - if (active_) { - __itt_region_end(domain_, id_); - active_ = false; + void end() noexcept + { + if (m_active) + { + __itt_region_end(m_domain, m_id); + m_active = false; } } - bool active() const noexcept { return active_; } + bool active() const noexcept + { + return m_active; + } private: - const __itt_domain* domain_ = nullptr; - __itt_id id_{}; - bool active_ = false; + const __itt_domain* m_domain = nullptr; + __itt_id m_id{}; + bool m_active = false; }; } // namespace ittapi diff --git a/cpp/include/ittapi_string_handle.hpp b/cpp/include/ittapi_string_handle.hpp index b3520df..5af6b2f 100644 --- a/cpp/include/ittapi_string_handle.hpp +++ b/cpp/include/ittapi_string_handle.hpp @@ -11,18 +11,36 @@ #include "ittapi_utils.hpp" -namespace ittapi { +namespace ittapi +{ -class StringHandle { +class StringHandle +{ public: explicit StringHandle(std::string_view name) - : handle_(detail::create_string_handle(std::string(name).c_str())) {} - - __itt_string_handle* native_handle() const noexcept { return handle_; } - bool valid() const noexcept { return handle_ != nullptr; } + : m_handle(detail::create_string_handle(std::string(name).c_str())) + { + } + +#if ITT_PLATFORM == ITT_PLATFORM_WIN + explicit StringHandle(std::wstring_view name) + : m_handle(detail::create_string_handle(std::wstring(name).c_str())) + { + } +#endif + + __itt_string_handle* native_handle() const noexcept + { + return m_handle; + } + + bool valid() const noexcept + { + return m_handle != nullptr; + } private: - __itt_string_handle* handle_ = nullptr; + __itt_string_handle* m_handle = nullptr; }; } // namespace ittapi diff --git a/cpp/include/ittapi_task.hpp b/cpp/include/ittapi_task.hpp index 420f3e2..a52dfb1 100644 --- a/cpp/include/ittapi_task.hpp +++ b/cpp/include/ittapi_task.hpp @@ -12,57 +12,73 @@ #include "ittapi_utils.hpp" #include "ittapi_string_handle.hpp" -namespace ittapi { +namespace ittapi +{ class Domain; -class ScopedTask { +class ScopedTask +{ public: ScopedTask(const __itt_domain* domain, std::string_view name) - : domain_(domain), active_(true) { + : m_domain(domain) + , m_active(true) + { __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); - __itt_task_begin(domain_, detail::make_null_id(), detail::make_null_id(), h); + __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), h); } ScopedTask(const __itt_domain* domain, const StringHandle& name) noexcept - : domain_(domain), active_(true) { - __itt_task_begin(domain_, detail::make_null_id(), detail::make_null_id(), name.native_handle()); + : m_domain(domain) + , m_active(true) + { + __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), name.native_handle()); } ScopedTask(const ScopedTask&) = delete; ScopedTask& operator=(const ScopedTask&) = delete; ScopedTask(ScopedTask&& other) noexcept - : domain_(other.domain_), active_(other.active_) { - other.active_ = false; + : m_domain(other.m_domain) + , m_active(other.m_active) + { + other.m_active = false; } - ScopedTask& operator=(ScopedTask&& other) noexcept { - if (this != &other) { + ScopedTask& operator=(ScopedTask&& other) noexcept + { + if (this != &other) + { end(); - domain_ = other.domain_; - active_ = other.active_; - other.active_ = false; + m_domain = other.m_domain; + m_active = other.m_active; + other.m_active = false; } return *this; } - ~ScopedTask() noexcept { + ~ScopedTask() noexcept + { end(); } - void end() noexcept { - if (active_) { - __itt_task_end(domain_); - active_ = false; + void end() noexcept + { + if (m_active) + { + __itt_task_end(m_domain); + m_active = false; } } - bool active() const noexcept { return active_; } + bool active() const noexcept + { + return m_active; + } private: - const __itt_domain* domain_ = nullptr; - bool active_ = false; + const __itt_domain* m_domain = nullptr; + bool m_active = false; }; } // namespace ittapi diff --git a/cpp/include/ittapi_thread_naming.hpp b/cpp/include/ittapi_thread_naming.hpp index 946128a..699c78d 100644 --- a/cpp/include/ittapi_thread_naming.hpp +++ b/cpp/include/ittapi_thread_naming.hpp @@ -11,12 +11,21 @@ #include "ittapi_utils.hpp" -namespace ittapi { +namespace ittapi +{ -inline void set_thread_name(std::string_view name) { +inline void set_thread_name(std::string_view name) +{ detail::thread_set_name(std::string(name).c_str()); } +#if ITT_PLATFORM == ITT_PLATFORM_WIN +inline void set_thread_name(std::wstring_view name) +{ + detail::thread_set_name(std::wstring(name).c_str()); +} +#endif + } // namespace ittapi #endif // ITTAPI_THREAD_NAMING_HPP diff --git a/cpp/include/ittapi_utils.hpp b/cpp/include/ittapi_utils.hpp index ec834cc..39d02f4 100644 --- a/cpp/include/ittapi_utils.hpp +++ b/cpp/include/ittapi_utils.hpp @@ -8,10 +8,13 @@ #include -namespace ittapi { -namespace detail { +namespace ittapi +{ +namespace detail +{ -inline __itt_domain* create_domain(const char* name) noexcept { +inline __itt_domain* create_domain(const char* name) noexcept +{ #if ITT_PLATFORM == ITT_PLATFORM_WIN return __itt_domain_createA(name); #else @@ -19,7 +22,8 @@ inline __itt_domain* create_domain(const char* name) noexcept { #endif } -inline __itt_string_handle* create_string_handle(const char* name) noexcept { +inline __itt_string_handle* create_string_handle(const char* name) noexcept +{ #if ITT_PLATFORM == ITT_PLATFORM_WIN return __itt_string_handle_createA(name); #else @@ -27,7 +31,8 @@ inline __itt_string_handle* create_string_handle(const char* name) noexcept { #endif } -inline void thread_set_name(const char* name) noexcept { +inline void thread_set_name(const char* name) noexcept +{ #if ITT_PLATFORM == ITT_PLATFORM_WIN __itt_thread_set_nameA(name); #else @@ -35,7 +40,27 @@ inline void thread_set_name(const char* name) noexcept { #endif } -inline __itt_id make_null_id() noexcept { +#if ITT_PLATFORM == ITT_PLATFORM_WIN + +inline __itt_domain* create_domain(const wchar_t* name) noexcept +{ + return __itt_domain_createW(name); +} + +inline __itt_string_handle* create_string_handle(const wchar_t* name) noexcept +{ + return __itt_string_handle_createW(name); +} + +inline void thread_set_name(const wchar_t* name) noexcept +{ + __itt_thread_set_nameW(name); +} + +#endif // ITT_PLATFORM == ITT_PLATFORM_WIN + +inline __itt_id make_null_id() noexcept +{ __itt_id id = __itt_null; return id; } From 269978102424f70f724cd39e3811af67b5585e9f Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 07:18:09 -0500 Subject: [PATCH 03/33] fix task/frame/region apis --- cpp/include/ittapi_collection_control.hpp | 15 +------------- cpp/include/ittapi_domain.hpp | 22 ++++++++++++++++++++ cpp/include/ittapi_frame.hpp | 14 +------------ cpp/include/ittapi_region.hpp | 25 +++++++++++------------ cpp/include/ittapi_task.hpp | 23 ++++++++++----------- 5 files changed, 47 insertions(+), 52 deletions(-) diff --git a/cpp/include/ittapi_collection_control.hpp b/cpp/include/ittapi_collection_control.hpp index 787947d..a6da28d 100644 --- a/cpp/include/ittapi_collection_control.hpp +++ b/cpp/include/ittapi_collection_control.hpp @@ -32,6 +32,7 @@ class ScopedPause ScopedPause(const ScopedPause&) = delete; ScopedPause& operator=(const ScopedPause&) = delete; + ScopedPause& operator=(ScopedPause&&) = delete; ScopedPause(ScopedPause&& other) noexcept : m_active(other.m_active) @@ -39,20 +40,6 @@ class ScopedPause other.m_active = false; } - ScopedPause& operator=(ScopedPause&& other) noexcept - { - if (this != &other) - { - if (m_active) - { - __itt_resume(); - } - m_active = other.m_active; - other.m_active = false; - } - return *this; - } - ~ScopedPause() noexcept { if (m_active) diff --git a/cpp/include/ittapi_domain.hpp b/cpp/include/ittapi_domain.hpp index 8fe0b19..e2ec020 100644 --- a/cpp/include/ittapi_domain.hpp +++ b/cpp/include/ittapi_domain.hpp @@ -48,6 +48,13 @@ class Domain return ScopedTask(m_handle, name); } +#if ITT_PLATFORM == ITT_PLATFORM_WIN + ScopedTask task(std::wstring_view name) const + { + return ScopedTask(m_handle, name); + } +#endif + ScopedTask task(const StringHandle& name) const noexcept { return ScopedTask(m_handle, name); @@ -59,6 +66,14 @@ class Domain __itt_task_begin(m_handle, detail::make_null_id(), detail::make_null_id(), h); } +#if ITT_PLATFORM == ITT_PLATFORM_WIN + void task_begin(std::wstring_view name) const + { + __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); + __itt_task_begin(m_handle, detail::make_null_id(), detail::make_null_id(), h); + } +#endif + void task_begin(const StringHandle& name) const noexcept { __itt_task_begin(m_handle, detail::make_null_id(), detail::make_null_id(), name.native_handle()); @@ -74,6 +89,13 @@ class Domain return ScopedRegion(m_handle, name); } +#if ITT_PLATFORM == ITT_PLATFORM_WIN + ScopedRegion region(std::wstring_view name) const + { + return ScopedRegion(m_handle, name); + } +#endif + ScopedRegion region(const StringHandle& name) const noexcept { return ScopedRegion(m_handle, name); diff --git a/cpp/include/ittapi_frame.hpp b/cpp/include/ittapi_frame.hpp index c7ef62a..f2af84e 100644 --- a/cpp/include/ittapi_frame.hpp +++ b/cpp/include/ittapi_frame.hpp @@ -26,6 +26,7 @@ class ScopedFrame ScopedFrame(const ScopedFrame&) = delete; ScopedFrame& operator=(const ScopedFrame&) = delete; + ScopedFrame& operator=(ScopedFrame&&) = delete; ScopedFrame(ScopedFrame&& other) noexcept : m_domain(other.m_domain) @@ -35,19 +36,6 @@ class ScopedFrame other.m_active = false; } - ScopedFrame& operator=(ScopedFrame&& other) noexcept - { - if (this != &other) - { - end(); - m_domain = other.m_domain; - m_id = other.m_id; - m_active = other.m_active; - other.m_active = false; - } - return *this; - } - ~ScopedFrame() noexcept { end(); diff --git a/cpp/include/ittapi_region.hpp b/cpp/include/ittapi_region.hpp index 403b9ae..576623c 100644 --- a/cpp/include/ittapi_region.hpp +++ b/cpp/include/ittapi_region.hpp @@ -29,6 +29,17 @@ class ScopedRegion __itt_region_begin(m_domain, m_id, detail::make_null_id(), h); } +#if ITT_PLATFORM == ITT_PLATFORM_WIN + ScopedRegion(const __itt_domain* domain, std::wstring_view name) + : m_domain(domain) + , m_id(detail::make_null_id()) + , m_active(true) + { + __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); + __itt_region_begin(m_domain, m_id, detail::make_null_id(), h); + } +#endif + ScopedRegion(const __itt_domain* domain, const StringHandle& name) noexcept : m_domain(domain) , m_id(detail::make_null_id()) @@ -39,6 +50,7 @@ class ScopedRegion ScopedRegion(const ScopedRegion&) = delete; ScopedRegion& operator=(const ScopedRegion&) = delete; + ScopedRegion& operator=(ScopedRegion&&) = delete; ScopedRegion(ScopedRegion&& other) noexcept : m_domain(other.m_domain) @@ -48,19 +60,6 @@ class ScopedRegion other.m_active = false; } - ScopedRegion& operator=(ScopedRegion&& other) noexcept - { - if (this != &other) - { - end(); - m_domain = other.m_domain; - m_id = other.m_id; - m_active = other.m_active; - other.m_active = false; - } - return *this; - } - ~ScopedRegion() noexcept { end(); diff --git a/cpp/include/ittapi_task.hpp b/cpp/include/ittapi_task.hpp index a52dfb1..7aedbc5 100644 --- a/cpp/include/ittapi_task.hpp +++ b/cpp/include/ittapi_task.hpp @@ -28,6 +28,16 @@ class ScopedTask __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), h); } +#if ITT_PLATFORM == ITT_PLATFORM_WIN + ScopedTask(const __itt_domain* domain, std::wstring_view name) + : m_domain(domain) + , m_active(true) + { + __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); + __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), h); + } +#endif + ScopedTask(const __itt_domain* domain, const StringHandle& name) noexcept : m_domain(domain) , m_active(true) @@ -37,6 +47,7 @@ class ScopedTask ScopedTask(const ScopedTask&) = delete; ScopedTask& operator=(const ScopedTask&) = delete; + ScopedTask& operator=(ScopedTask&&) = delete; ScopedTask(ScopedTask&& other) noexcept : m_domain(other.m_domain) @@ -45,18 +56,6 @@ class ScopedTask other.m_active = false; } - ScopedTask& operator=(ScopedTask&& other) noexcept - { - if (this != &other) - { - end(); - m_domain = other.m_domain; - m_active = other.m_active; - other.m_active = false; - } - return *this; - } - ~ScopedTask() noexcept { end(); From 8c8ce26b3d19a9cec20e0d50bb17b23ed830b14e Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 07:39:02 -0500 Subject: [PATCH 04/33] add id support --- cpp/include/ittapi_domain.hpp | 47 +++++++++++++++++++++++++++++++++++ cpp/include/ittapi_region.hpp | 29 +++++++++++++++++++++ cpp/include/ittapi_task.hpp | 26 +++++++++++++++++++ 3 files changed, 102 insertions(+) diff --git a/cpp/include/ittapi_domain.hpp b/cpp/include/ittapi_domain.hpp index e2ec020..c4546af 100644 --- a/cpp/include/ittapi_domain.hpp +++ b/cpp/include/ittapi_domain.hpp @@ -48,11 +48,21 @@ class Domain return ScopedTask(m_handle, name); } + ScopedTask task(std::string_view name, __itt_id taskid, __itt_id parentid) const + { + return ScopedTask(m_handle, name, taskid, parentid); + } + #if ITT_PLATFORM == ITT_PLATFORM_WIN ScopedTask task(std::wstring_view name) const { return ScopedTask(m_handle, name); } + + ScopedTask task(std::wstring_view name, __itt_id taskid, __itt_id parentid) const + { + return ScopedTask(m_handle, name, taskid, parentid); + } #endif ScopedTask task(const StringHandle& name) const noexcept @@ -60,18 +70,35 @@ class Domain return ScopedTask(m_handle, name); } + ScopedTask task(const StringHandle& name, __itt_id taskid, __itt_id parentid) const noexcept + { + return ScopedTask(m_handle, name, taskid, parentid); + } + void task_begin(std::string_view name) const { __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); __itt_task_begin(m_handle, detail::make_null_id(), detail::make_null_id(), h); } + void task_begin(std::string_view name, __itt_id taskid, __itt_id parentid) const + { + __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); + __itt_task_begin(m_handle, taskid, parentid, h); + } + #if ITT_PLATFORM == ITT_PLATFORM_WIN void task_begin(std::wstring_view name) const { __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); __itt_task_begin(m_handle, detail::make_null_id(), detail::make_null_id(), h); } + + void task_begin(std::wstring_view name, __itt_id taskid, __itt_id parentid) const + { + __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); + __itt_task_begin(m_handle, taskid, parentid, h); + } #endif void task_begin(const StringHandle& name) const noexcept @@ -79,6 +106,11 @@ class Domain __itt_task_begin(m_handle, detail::make_null_id(), detail::make_null_id(), name.native_handle()); } + void task_begin(const StringHandle& name, __itt_id taskid, __itt_id parentid) const noexcept + { + __itt_task_begin(m_handle, taskid, parentid, name.native_handle()); + } + void task_end() const noexcept { __itt_task_end(m_handle); @@ -89,11 +121,21 @@ class Domain return ScopedRegion(m_handle, name); } + ScopedRegion region(std::string_view name, __itt_id id, __itt_id parentid) const + { + return ScopedRegion(m_handle, name, id, parentid); + } + #if ITT_PLATFORM == ITT_PLATFORM_WIN ScopedRegion region(std::wstring_view name) const { return ScopedRegion(m_handle, name); } + + ScopedRegion region(std::wstring_view name, __itt_id id, __itt_id parentid) const + { + return ScopedRegion(m_handle, name, id, parentid); + } #endif ScopedRegion region(const StringHandle& name) const noexcept @@ -101,6 +143,11 @@ class Domain return ScopedRegion(m_handle, name); } + ScopedRegion region(const StringHandle& name, __itt_id id, __itt_id parentid) const noexcept + { + return ScopedRegion(m_handle, name, id, parentid); + } + ScopedFrame frame() const noexcept { return ScopedFrame(m_handle); diff --git a/cpp/include/ittapi_region.hpp b/cpp/include/ittapi_region.hpp index 576623c..3c85585 100644 --- a/cpp/include/ittapi_region.hpp +++ b/cpp/include/ittapi_region.hpp @@ -29,6 +29,16 @@ class ScopedRegion __itt_region_begin(m_domain, m_id, detail::make_null_id(), h); } + ScopedRegion(const __itt_domain* domain, std::string_view name, + __itt_id id, __itt_id parentid) + : m_domain(domain) + , m_id(id) + , m_active(true) + { + __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); + __itt_region_begin(m_domain, m_id, parentid, h); + } + #if ITT_PLATFORM == ITT_PLATFORM_WIN ScopedRegion(const __itt_domain* domain, std::wstring_view name) : m_domain(domain) @@ -38,6 +48,16 @@ class ScopedRegion __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); __itt_region_begin(m_domain, m_id, detail::make_null_id(), h); } + + ScopedRegion(const __itt_domain* domain, std::wstring_view name, + __itt_id id, __itt_id parentid) + : m_domain(domain) + , m_id(id) + , m_active(true) + { + __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); + __itt_region_begin(m_domain, m_id, parentid, h); + } #endif ScopedRegion(const __itt_domain* domain, const StringHandle& name) noexcept @@ -48,6 +68,15 @@ class ScopedRegion __itt_region_begin(m_domain, m_id, detail::make_null_id(), name.native_handle()); } + ScopedRegion(const __itt_domain* domain, const StringHandle& name, + __itt_id id, __itt_id parentid) noexcept + : m_domain(domain) + , m_id(id) + , m_active(true) + { + __itt_region_begin(m_domain, m_id, parentid, name.native_handle()); + } + ScopedRegion(const ScopedRegion&) = delete; ScopedRegion& operator=(const ScopedRegion&) = delete; ScopedRegion& operator=(ScopedRegion&&) = delete; diff --git a/cpp/include/ittapi_task.hpp b/cpp/include/ittapi_task.hpp index 7aedbc5..2460c92 100644 --- a/cpp/include/ittapi_task.hpp +++ b/cpp/include/ittapi_task.hpp @@ -28,6 +28,15 @@ class ScopedTask __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), h); } + ScopedTask(const __itt_domain* domain, std::string_view name, + __itt_id taskid, __itt_id parentid) + : m_domain(domain) + , m_active(true) + { + __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); + __itt_task_begin(m_domain, taskid, parentid, h); + } + #if ITT_PLATFORM == ITT_PLATFORM_WIN ScopedTask(const __itt_domain* domain, std::wstring_view name) : m_domain(domain) @@ -36,6 +45,15 @@ class ScopedTask __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), h); } + + ScopedTask(const __itt_domain* domain, std::wstring_view name, + __itt_id taskid, __itt_id parentid) + : m_domain(domain) + , m_active(true) + { + __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); + __itt_task_begin(m_domain, taskid, parentid, h); + } #endif ScopedTask(const __itt_domain* domain, const StringHandle& name) noexcept @@ -45,6 +63,14 @@ class ScopedTask __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), name.native_handle()); } + ScopedTask(const __itt_domain* domain, const StringHandle& name, + __itt_id taskid, __itt_id parentid) noexcept + : m_domain(domain) + , m_active(true) + { + __itt_task_begin(m_domain, taskid, parentid, name.native_handle()); + } + ScopedTask(const ScopedTask&) = delete; ScopedTask& operator=(const ScopedTask&) = delete; ScopedTask& operator=(ScopedTask&&) = delete; From b7f4cca3a0d45f2b007394c90b4e0c4a170e25f3 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 07:42:39 -0500 Subject: [PATCH 05/33] add cmake build and tests --- CMakeLists.txt | 11 +++ buildall.py | 5 +- cpp/CMakeLists.txt | 48 +++++++++++ cpp/tests/test_collection_control.cpp | 53 ++++++++++++ cpp/tests/test_domain.cpp | 66 ++++++++++++++ cpp/tests/test_frame.cpp | 58 +++++++++++++ cpp/tests/test_ittapi.cpp | 49 +++++++++++ cpp/tests/test_region.cpp | 89 +++++++++++++++++++ cpp/tests/test_string_handle.cpp | 41 +++++++++ cpp/tests/test_task.cpp | 118 ++++++++++++++++++++++++++ cpp/tests/test_thread_naming.cpp | 17 ++++ 11 files changed, 554 insertions(+), 1 deletion(-) create mode 100644 cpp/CMakeLists.txt create mode 100644 cpp/tests/test_collection_control.cpp create mode 100644 cpp/tests/test_domain.cpp create mode 100644 cpp/tests/test_frame.cpp create mode 100644 cpp/tests/test_ittapi.cpp create mode 100644 cpp/tests/test_region.cpp create mode 100644 cpp/tests/test_string_handle.cpp create mode 100644 cpp/tests/test_task.cpp create mode 100644 cpp/tests/test_thread_naming.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b56b06..a084274 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ project(ittapi) option(FORCE_32 "Force a 32-bit compile on 64-bit" OFF) option(ITT_API_IPT_SUPPORT "ptmarks support" OFF) option(ITT_API_FORTRAN_SUPPORT "fortran support" OFF) +option(ITT_API_CPP_SUPPORT "C++ wrapper support" OFF) if(FORCE_32 AND UNIX) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") @@ -168,12 +169,22 @@ target_include_directories(jitprofiling PRIVATE src/ittnotify ) +# C++ wrapper +if(ITT_API_CPP_SUPPORT) + add_subdirectory(cpp) +endif() + # install include(CMakePackageConfigHelpers) include(GNUInstallDirs) install(TARGETS ittnotify EXPORT ittapi-targets INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +if(ITT_API_CPP_SUPPORT) + install(TARGETS ittapi-cpp EXPORT ittapi-targets) + install(DIRECTORY cpp/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.hpp") +endif() install(EXPORT ittapi-targets NAMESPACE ittapi:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ittapi) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h" diff --git a/buildall.py b/buildall.py index a85cb7f..fb64c39 100755 --- a/buildall.py +++ b/buildall.py @@ -117,6 +117,8 @@ def main(): "-pt", "--ptmark", help="enable anomaly detection support", action="store_true") parser.add_argument( "-ft", "--fortran", help="enable fortran support", action="store_true") + parser.add_argument( + "--cpp", help="enable C++ wrapper support", action="store_true") parser.add_argument( "--force_bits", choices=["32", "64"], help="specify bit version for the target") if sys.platform == 'win32' and vs_versions: @@ -177,7 +179,8 @@ def main(): ("-DCMAKE_BUILD_TYPE=Debug" if args.debug else ""), ('-DCMAKE_VERBOSE_MAKEFILE:BOOL=ON' if args.verbose else ''), ("-DITT_API_IPT_SUPPORT=1" if args.ptmark else ""), - ("-DITT_API_FORTRAN_SUPPORT=1" if args.fortran else "") + ("-DITT_API_FORTRAN_SUPPORT=1" if args.fortran else ""), + ("-DITT_API_CPP_SUPPORT=ON" if args.cpp else "") ]))) if sys.platform == 'win32': diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt new file mode 100644 index 0000000..c017368 --- /dev/null +++ b/cpp/CMakeLists.txt @@ -0,0 +1,48 @@ +# +# Copyright (C) 2026 Intel Corporation +# SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +# + +add_library(ittapi-cpp INTERFACE) +add_library(ittapi::cxx ALIAS ittapi-cpp) + +target_include_directories(ittapi-cpp + INTERFACE + $ + $ +) + +target_link_libraries(ittapi-cpp INTERFACE ittnotify) +target_compile_features(ittapi-cpp INTERFACE cxx_std_17) + +find_package(Threads REQUIRED) + +# Sample +add_executable(task_sample samples/task_sample.cpp) +target_link_libraries(task_sample PRIVATE ittapi-cpp) +if(NOT WIN32) + target_link_libraries(task_sample PRIVATE ${CMAKE_DL_LIBS} Threads::Threads) +endif() + +# Tests +enable_testing() + +set(CPP_TESTS + test_string_handle + test_domain + test_task + test_region + test_frame + test_collection_control + test_thread_naming + test_ittapi +) + +foreach(test_name ${CPP_TESTS}) + add_executable(${test_name} tests/${test_name}.cpp) + target_link_libraries(${test_name} PRIVATE ittapi-cpp) + if(NOT WIN32) + target_link_libraries(${test_name} PRIVATE ${CMAKE_DL_LIBS} Threads::Threads) + endif() + add_test(NAME cpp_${test_name} COMMAND ${test_name}) +endforeach() diff --git a/cpp/tests/test_collection_control.cpp b/cpp/tests/test_collection_control.cpp new file mode 100644 index 0000000..daaec6a --- /dev/null +++ b/cpp/tests/test_collection_control.cpp @@ -0,0 +1,53 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#include + +#include +#include + +static void test_pause_resume() +{ + ittapi::pause(); + ittapi::resume(); +} + +static void test_scoped_pause_resumes_on_destruction() +{ + + { + ittapi::ScopedPause sp; + assert(sp.active()); + } + // destructor should have called resume() +} + +static void test_resume_now_disables_destructor() +{ + ittapi::ScopedPause sp; + assert(sp.active()); + sp.resume_now(); + assert(!sp.active()); + // destructor should not call resume() again +} + +static void test_move_construction() +{ + ittapi::ScopedPause sp1; + assert(sp1.active()); + + auto sp2 = std::move(sp1); + assert(!sp1.active()); + assert(sp2.active()); +} + +int main() +{ + test_pause_resume(); + test_scoped_pause_resumes_on_destruction(); + test_resume_now_disables_destructor(); + test_move_construction(); + return 0; +} diff --git a/cpp/tests/test_domain.cpp b/cpp/tests/test_domain.cpp new file mode 100644 index 0000000..b06f331 --- /dev/null +++ b/cpp/tests/test_domain.cpp @@ -0,0 +1,66 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#include + +#include + +static void test_construct_domain() +{ + ittapi::Domain d{"test.domain"}; + (void)d.valid(); + (void)d.native_handle(); +} + +static void test_create_task_from_domain() +{ + ittapi::Domain d{"test.domain.task"}; + + { + auto task = d.task("my_task"); + assert(task.active()); + } +} + +static void test_create_task_with_string_handle() +{ + ittapi::Domain d{"test.domain.task_sh"}; + ittapi::StringHandle name{"my_task"}; + + { + auto task = d.task(name); + assert(task.active()); + } +} + +static void test_create_region_from_domain() +{ + ittapi::Domain d{"test.domain.region"}; + + { + auto region = d.region("my_region"); + assert(region.active()); + } +} + +static void test_create_frame_from_domain() +{ + ittapi::Domain d{"test.domain.frame"}; + + { + auto frame = d.frame(); + assert(frame.active()); + } +} + +int main() +{ + test_construct_domain(); + test_create_task_from_domain(); + test_create_task_with_string_handle(); + test_create_region_from_domain(); + test_create_frame_from_domain(); + return 0; +} diff --git a/cpp/tests/test_frame.cpp b/cpp/tests/test_frame.cpp new file mode 100644 index 0000000..fc90247 --- /dev/null +++ b/cpp/tests/test_frame.cpp @@ -0,0 +1,58 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#include +#include + +#include +#include + +static void test_scoped_frame_lifecycle() +{ + ittapi::Domain d{"test.frame.lifecycle"}; + + { + auto frame = d.frame(); + assert(frame.active()); + } +} + +static void test_explicit_end_is_idempotent() +{ + ittapi::Domain d{"test.frame.end"}; + auto frame = d.frame(); + assert(frame.active()); + frame.end(); + assert(!frame.active()); + frame.end(); + assert(!frame.active()); +} + +static void test_move_construction() +{ + ittapi::Domain d{"test.frame.move"}; + auto f1 = d.frame(); + assert(f1.active()); + + auto f2 = std::move(f1); + assert(!f1.active()); + assert(f2.active()); +} + +static void test_submit() +{ + ittapi::Domain d{"test.frame.submit"}; + // Just verify it compiles and runs without a collector + ittapi::ScopedFrame::submit(d.native_handle(), 0, 100); +} + +int main() +{ + test_scoped_frame_lifecycle(); + test_explicit_end_is_idempotent(); + test_move_construction(); + test_submit(); + return 0; +} diff --git a/cpp/tests/test_ittapi.cpp b/cpp/tests/test_ittapi.cpp new file mode 100644 index 0000000..548f1d1 --- /dev/null +++ b/cpp/tests/test_ittapi.cpp @@ -0,0 +1,49 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#include + +#include + +static void test_umbrella_header_compiles() +{ + ittapi::Domain d{"test.umbrella"}; + ittapi::StringHandle sh{"umbrella_handle"}; + + ittapi::set_thread_name("umbrella_thread"); + ittapi::pause(); + ittapi::resume(); + + { + auto task = d.task("umbrella_task"); + assert(task.active()); + } + + { + auto region = d.region(sh); + assert(region.active()); + } + + { + auto frame = d.frame(); + assert(frame.active()); + } + + { + ittapi::ScopedPause sp; + assert(sp.active()); + sp.resume_now(); + assert(!sp.active()); + } + + d.task_begin("manual"); + d.task_end(); +} + +int main() +{ + test_umbrella_header_compiles(); + return 0; +} diff --git a/cpp/tests/test_region.cpp b/cpp/tests/test_region.cpp new file mode 100644 index 0000000..ba07217 --- /dev/null +++ b/cpp/tests/test_region.cpp @@ -0,0 +1,89 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#include +#include + +#include +#include + +static void test_scoped_region_lifecycle() +{ + ittapi::Domain d{"test.region.lifecycle"}; + + { + auto region = d.region("lifecycle_region"); + assert(region.active()); + } +} + +static void test_explicit_end_is_idempotent() +{ + ittapi::Domain d{"test.region.end"}; + auto region = d.region("end_region"); + assert(region.active()); + region.end(); + assert(!region.active()); + region.end(); + assert(!region.active()); +} + +static void test_move_construction() +{ + ittapi::Domain d{"test.region.move"}; + auto r1 = d.region("move_region"); + assert(r1.active()); + + auto r2 = std::move(r1); + assert(!r1.active()); + assert(r2.active()); +} + +static void test_string_handle_overload() +{ + ittapi::Domain d{"test.region.sh"}; + ittapi::StringHandle name{"sh_region"}; + + { + auto region = d.region(name); + assert(region.active()); + } +} + +static void test_scoped_region_with_ids() +{ + ittapi::Domain d{"test.region.ids"}; + __itt_id id = __itt_id_make(nullptr, 10); + __itt_id parentid = __itt_null; + + { + auto region = d.region("region_with_ids", id, parentid); + assert(region.active()); + } +} + +static void test_scoped_region_with_ids_string_handle() +{ + ittapi::Domain d{"test.region.ids_sh"}; + ittapi::StringHandle name{"sh_region_ids"}; + __itt_id id = __itt_id_make(nullptr, 11); + __itt_id parentid = __itt_null; + + { + auto region = d.region(name, id, parentid); + assert(region.active()); + } +} + +int main() +{ + test_scoped_region_lifecycle(); + test_explicit_end_is_idempotent(); + test_move_construction(); + test_string_handle_overload(); + test_scoped_region_with_ids(); + test_scoped_region_with_ids_string_handle(); + return 0; +} diff --git a/cpp/tests/test_string_handle.cpp b/cpp/tests/test_string_handle.cpp new file mode 100644 index 0000000..4afe3f8 --- /dev/null +++ b/cpp/tests/test_string_handle.cpp @@ -0,0 +1,41 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#include + +#include +#include +#include + +static void test_construct_from_literal() +{ + ittapi::StringHandle h{"test_handle"}; + // valid() may be false if no collector is attached; just verify it compiles and runs + (void)h.valid(); + (void)h.native_handle(); +} + +static void test_construct_from_string_view() +{ + std::string_view sv = "test_sv_handle"; + ittapi::StringHandle h{sv}; + (void)h.valid(); + (void)h.native_handle(); +} + +static void test_construct_from_std_string() +{ + std::string s = "test_string_handle"; + ittapi::StringHandle h{std::string_view(s)}; + (void)h.valid(); +} + +int main() +{ + test_construct_from_literal(); + test_construct_from_string_view(); + test_construct_from_std_string(); + return 0; +} diff --git a/cpp/tests/test_task.cpp b/cpp/tests/test_task.cpp new file mode 100644 index 0000000..1fa52a4 --- /dev/null +++ b/cpp/tests/test_task.cpp @@ -0,0 +1,118 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#include +#include + +#include +#include + +static void test_scoped_task_lifecycle() +{ + ittapi::Domain d{"test.task.lifecycle"}; + + { + auto task = d.task("lifecycle_task"); + assert(task.active()); + } + // destructor should have ended the task +} + +static void test_explicit_end_is_idempotent() +{ + ittapi::Domain d{"test.task.end"}; + auto task = d.task("end_task"); + assert(task.active()); + task.end(); + assert(!task.active()); + task.end(); // second call should be safe + assert(!task.active()); +} + +static void test_move_construction() +{ + ittapi::Domain d{"test.task.move"}; + auto task1 = d.task("move_task"); + assert(task1.active()); + + auto task2 = std::move(task1); + assert(!task1.active()); + assert(task2.active()); +} + +static void test_string_handle_overload() +{ + ittapi::Domain d{"test.task.sh"}; + ittapi::StringHandle name{"sh_task"}; + + { + auto task = d.task(name); + assert(task.active()); + } +} + +static void test_manual_task_begin_end() +{ + ittapi::Domain d{"test.task.manual"}; + d.task_begin("manual_task"); + d.task_end(); +} + +static void test_manual_task_begin_end_string_handle() +{ + ittapi::Domain d{"test.task.manual_sh"}; + ittapi::StringHandle name{"manual_sh_task"}; + d.task_begin(name); + d.task_end(); +} + +static void test_scoped_task_with_ids() +{ + ittapi::Domain d{"test.task.ids"}; + __itt_id taskid = __itt_id_make(nullptr, 1); + __itt_id parentid = __itt_null; + + { + auto task = d.task("task_with_ids", taskid, parentid); + assert(task.active()); + } +} + +static void test_scoped_task_with_ids_string_handle() +{ + ittapi::Domain d{"test.task.ids_sh"}; + ittapi::StringHandle name{"sh_task_ids"}; + __itt_id taskid = __itt_id_make(nullptr, 2); + __itt_id parentid = __itt_null; + + { + auto task = d.task(name, taskid, parentid); + assert(task.active()); + } +} + +static void test_manual_task_begin_end_with_ids() +{ + ittapi::Domain d{"test.task.manual_ids"}; + __itt_id taskid = __itt_id_make(nullptr, 3); + __itt_id parentid = __itt_null; + + d.task_begin("manual_ids_task", taskid, parentid); + d.task_end(); +} + +int main() +{ + test_scoped_task_lifecycle(); + test_explicit_end_is_idempotent(); + test_move_construction(); + test_string_handle_overload(); + test_manual_task_begin_end(); + test_manual_task_begin_end_string_handle(); + test_scoped_task_with_ids(); + test_scoped_task_with_ids_string_handle(); + test_manual_task_begin_end_with_ids(); + return 0; +} diff --git a/cpp/tests/test_thread_naming.cpp b/cpp/tests/test_thread_naming.cpp new file mode 100644 index 0000000..36a0732 --- /dev/null +++ b/cpp/tests/test_thread_naming.cpp @@ -0,0 +1,17 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#include + +static void test_set_thread_name() +{ + ittapi::set_thread_name("test_thread"); +} + +int main() +{ + test_set_thread_name(); + return 0; +} From a0352b80598785e1af20b555859c5336cd7ebab3 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 07:44:13 -0500 Subject: [PATCH 06/33] add readme and samples --- cpp/README.md | 186 ++++++++++++++++++++++++++++++++++++ cpp/samples/task_sample.cpp | 33 +++++++ 2 files changed, 219 insertions(+) create mode 100644 cpp/README.md create mode 100644 cpp/samples/task_sample.cpp diff --git a/cpp/README.md b/cpp/README.md new file mode 100644 index 0000000..3631174 --- /dev/null +++ b/cpp/README.md @@ -0,0 +1,186 @@ +# 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 library from this repository + +## Including the Wrapper + +Use the umbrella header to get the full API: + +```cpp +#include +``` + +Or include individual headers: + +```cpp +#include +#include +#include +``` + +## Example: Task Instrumentation + +```cpp +#include + +#include +#include + +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/include \ + app.cpp \ + /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 helper 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 +``` + +## 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.native_handle(); // 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 begin +d.task_end(); // manual end +``` + +#### `ittapi::ScopedTask` + +RAII wrapper for task begin/end. Move-only. + +```cpp +{ + auto task = domain.task("work"); + // ... do work ... + task.end(); // optional early end (idempotent) +} // destructor ends task if still active +``` + +For manual (non-RAII) control: + +```cpp +domain.task_begin("work"); +// ... do work ... +domain.task_end(); +``` + +#### `ittapi::ScopedRegion` + +RAII wrapper for region begin/end. Move-only. + +#### `ittapi::ScopedFrame` + +RAII wrapper for frame begin/end. Move-only. Supports explicit timestamp submission. + +```cpp +ittapi::ScopedFrame::submit(domain.native_handle(), 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 +} +``` diff --git a/cpp/samples/task_sample.cpp b/cpp/samples/task_sample.cpp new file mode 100644 index 0000000..cba1ad1 --- /dev/null +++ b/cpp/samples/task_sample.cpp @@ -0,0 +1,33 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#include + +#include +#include + +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)); + } + + + { + auto task = domain.task("startup"); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + + return 0; +} From 8ec95450fc7c18799a1d26cbcd7c27a9d37ddb54 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 07:47:37 -0500 Subject: [PATCH 07/33] add gh action --- .github/workflows/main.yml | 19 +++++++++++++++++++ README.md | 12 +++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 2fb2be5..d9deb5b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -39,6 +39,25 @@ jobs: # doesn't work in case of CMake + VS (https://github.com/fortran-lang/setup-fortran/issues/45) run: python buildall.py --force_bits 64 -ft ${{ matrix.optional_args }} + cpp_wrapper: + name: Check C++ wrapper + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + - os: windows-latest + steps: + - name: Checkout sources + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Configure + run: cmake -B build -DCMAKE_BUILD_TYPE=Release -DITT_API_CPP_SUPPORT=ON + - name: Build + run: cmake --build build --config Release + - name: Test + run: ctest --test-dir build/cpp --build-config Release --output-on-failure + rust_format: name: Check Rust formatting runs-on: ubuntu-latest diff --git a/README.md b/README.md index 37ea32f..0489441 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ To build the library: - To list available build options execute: `python buildall.py -h` ``` -usage: buildall.py [-h] [-d] [-c] [-v] [-pt] [-ft] [--force_bits] +usage: buildall.py [-h] [-d] [-c] [-v] [-pt] [-ft] [--cpp] [--force_bits] optional arguments: -h, --help show this help message and exit @@ -50,6 +50,7 @@ optional arguments: -v, --verbose enable verbose output from build process -pt, --ptmark enable anomaly detection support -ft, --fortran enable fortran support + --cpp enable C++ wrapper support --force_bits specify bit version for the target --vs specify visual studio version (Windows only) --cmake_gen specify cmake build generator (Windows only) @@ -60,6 +61,15 @@ optional arguments: Find complete documentation for ITT/JIT APIs on the [ITT/JIT APIs Documentation Page](https://intel.github.io/ittapi) +### Language Bindings + +| Language | Directory | Description | +|----------|-----------|-------------| +| C | `include/`, `src/` | Native C API headers and static library source | +| C++ | [`cpp/`](cpp/README.md) | Header-only C++17 wrapper with RAII scoped helpers | +| Python | [`python/`](python/README.md) | Python bindings | +| Rust | [`rust/`](rust/README.md) | Rust crate | + ### License All code in the repo is dual licensed under GPLv2 and 3-Clause BSD licenses From 6a263027b8b66d5236dc2363048d9648cc463f48 Mon Sep 17 00:00:00 2001 From: Evgeny Parshutin Date: Fri, 17 Apr 2026 15:23:03 +0200 Subject: [PATCH 08/33] update README.md --- cpp/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cpp/README.md b/cpp/README.md index 3631174..b4c59fd 100644 --- a/cpp/README.md +++ b/cpp/README.md @@ -17,7 +17,7 @@ A modern, header-only C++ wrapper for the [ITT API](https://github.com/intel/itt ## Requirements - C++17 or later -- The existing `ittnotify` static library from this repository +- The existing `ittnotify` static C-library ## Including the Wrapper @@ -93,7 +93,7 @@ cmake --build build The `ITT_API_CPP_SUPPORT` option is `OFF` by default. -You can also build with the helper script: +You can also build with the build script: ```bash python buildall.py --cpp @@ -135,7 +135,7 @@ Lightweight wrapper around `__itt_domain*` with convenience factories. 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 +auto frame = d.frame(); // returns ScopedFrame d.task_begin("work"); // manual begin d.task_end(); // manual end @@ -143,7 +143,7 @@ d.task_end(); // manual end #### `ittapi::ScopedTask` -RAII wrapper for task begin/end. Move-only. +RAII wrapper for task begin/end. ```cpp { @@ -163,11 +163,11 @@ domain.task_end(); #### `ittapi::ScopedRegion` -RAII wrapper for region begin/end. Move-only. +RAII wrapper for region begin/end. #### `ittapi::ScopedFrame` -RAII wrapper for frame begin/end. Move-only. Supports explicit timestamp submission. +RAII wrapper for frame begin/end. Supports explicit timestamp submission. ```cpp ittapi::ScopedFrame::submit(domain.native_handle(), begin_ts, end_ts); From fe9d1fc9646764398768976d2b42ef51335d4657 Mon Sep 17 00:00:00 2001 From: Evgeny Parshutin Date: Fri, 17 Apr 2026 15:27:32 +0200 Subject: [PATCH 09/33] cleanup --- README.md | 9 --------- 1 file changed, 9 deletions(-) diff --git a/README.md b/README.md index 0489441..7f9cc56 100644 --- a/README.md +++ b/README.md @@ -61,15 +61,6 @@ optional arguments: Find complete documentation for ITT/JIT APIs on the [ITT/JIT APIs Documentation Page](https://intel.github.io/ittapi) -### Language Bindings - -| Language | Directory | Description | -|----------|-----------|-------------| -| C | `include/`, `src/` | Native C API headers and static library source | -| C++ | [`cpp/`](cpp/README.md) | Header-only C++17 wrapper with RAII scoped helpers | -| Python | [`python/`](python/README.md) | Python bindings | -| Rust | [`rust/`](rust/README.md) | Rust crate | - ### License All code in the repo is dual licensed under GPLv2 and 3-Clause BSD licenses From a2fe2803f0fec671ae5cdb05769e126b5809f08c Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 08:20:27 -0500 Subject: [PATCH 10/33] improve tests --- cpp/tests/test_collection_control.cpp | 14 ++--- cpp/tests/test_domain.cpp | 18 +++--- cpp/tests/test_frame.cpp | 17 ++--- cpp/tests/test_helpers.hpp | 91 +++++++++++++++++++++++++++ cpp/tests/test_ittapi.cpp | 16 ++--- cpp/tests/test_region.cpp | 28 +++++---- cpp/tests/test_string_handle.cpp | 11 ++-- cpp/tests/test_task.cpp | 27 ++++---- 8 files changed, 163 insertions(+), 59 deletions(-) create mode 100644 cpp/tests/test_helpers.hpp diff --git a/cpp/tests/test_collection_control.cpp b/cpp/tests/test_collection_control.cpp index daaec6a..8fff79b 100644 --- a/cpp/tests/test_collection_control.cpp +++ b/cpp/tests/test_collection_control.cpp @@ -4,8 +4,8 @@ */ #include +#include "test_helpers.hpp" -#include #include static void test_pause_resume() @@ -19,7 +19,7 @@ static void test_scoped_pause_resumes_on_destruction() { ittapi::ScopedPause sp; - assert(sp.active()); + ITT_CHECK(sp.active()); } // destructor should have called resume() } @@ -27,20 +27,20 @@ static void test_scoped_pause_resumes_on_destruction() static void test_resume_now_disables_destructor() { ittapi::ScopedPause sp; - assert(sp.active()); + ITT_CHECK(sp.active()); sp.resume_now(); - assert(!sp.active()); + ITT_CHECK(!sp.active()); // destructor should not call resume() again } static void test_move_construction() { ittapi::ScopedPause sp1; - assert(sp1.active()); + ITT_CHECK(sp1.active()); auto sp2 = std::move(sp1); - assert(!sp1.active()); - assert(sp2.active()); + ITT_CHECK(!sp1.active()); + ITT_CHECK(sp2.active()); } int main() diff --git a/cpp/tests/test_domain.cpp b/cpp/tests/test_domain.cpp index b06f331..5e7e68e 100644 --- a/cpp/tests/test_domain.cpp +++ b/cpp/tests/test_domain.cpp @@ -4,23 +4,22 @@ */ #include - -#include +#include "test_helpers.hpp" static void test_construct_domain() { ittapi::Domain d{"test.domain"}; - (void)d.valid(); - (void)d.native_handle(); + ittapi::test::check_domain_name(d, "test.domain"); } static void test_create_task_from_domain() { ittapi::Domain d{"test.domain.task"}; + ittapi::test::check_domain_name(d, "test.domain.task"); { auto task = d.task("my_task"); - assert(task.active()); + ITT_CHECK(task.active()); } } @@ -28,30 +27,33 @@ static void test_create_task_with_string_handle() { ittapi::Domain d{"test.domain.task_sh"}; ittapi::StringHandle name{"my_task"}; + ittapi::test::check_string_handle_name(name, "my_task"); { auto task = d.task(name); - assert(task.active()); + ITT_CHECK(task.active()); } } static void test_create_region_from_domain() { ittapi::Domain d{"test.domain.region"}; + ittapi::test::check_domain_name(d, "test.domain.region"); { auto region = d.region("my_region"); - assert(region.active()); + ITT_CHECK(region.active()); } } static void test_create_frame_from_domain() { ittapi::Domain d{"test.domain.frame"}; + ittapi::test::check_domain_name(d, "test.domain.frame"); { auto frame = d.frame(); - assert(frame.active()); + ITT_CHECK(frame.active()); } } diff --git a/cpp/tests/test_frame.cpp b/cpp/tests/test_frame.cpp index fc90247..fcb8dfe 100644 --- a/cpp/tests/test_frame.cpp +++ b/cpp/tests/test_frame.cpp @@ -5,17 +5,18 @@ #include #include +#include "test_helpers.hpp" -#include #include static void test_scoped_frame_lifecycle() { ittapi::Domain d{"test.frame.lifecycle"}; + ittapi::test::check_domain_name(d, "test.frame.lifecycle"); { auto frame = d.frame(); - assert(frame.active()); + ITT_CHECK(frame.active()); } } @@ -23,22 +24,22 @@ static void test_explicit_end_is_idempotent() { ittapi::Domain d{"test.frame.end"}; auto frame = d.frame(); - assert(frame.active()); + ITT_CHECK(frame.active()); frame.end(); - assert(!frame.active()); + ITT_CHECK(!frame.active()); frame.end(); - assert(!frame.active()); + ITT_CHECK(!frame.active()); } static void test_move_construction() { ittapi::Domain d{"test.frame.move"}; auto f1 = d.frame(); - assert(f1.active()); + ITT_CHECK(f1.active()); auto f2 = std::move(f1); - assert(!f1.active()); - assert(f2.active()); + ITT_CHECK(!f1.active()); + ITT_CHECK(f2.active()); } static void test_submit() diff --git a/cpp/tests/test_helpers.hpp b/cpp/tests/test_helpers.hpp new file mode 100644 index 0000000..577f665 --- /dev/null +++ b/cpp/tests/test_helpers.hpp @@ -0,0 +1,91 @@ +/* + Copyright (C) 2026 Intel Corporation + SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0-only) +*/ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +// --------------------------------------------------------------------------- +// Assertion macros with file/line diagnostics +// --------------------------------------------------------------------------- + +#define ITT_CHECK(expr) \ + do \ + { \ + if (!(expr)) \ + { \ + std::fprintf(stderr, "FAIL %s:%d: %s\n", \ + __FILE__, __LINE__, #expr); \ + std::abort(); \ + } \ + } while (0) + +#define ITT_CHECK_STR_EQ(actual, expected) \ + do \ + { \ + const char* a_ = (actual); \ + const char* e_ = (expected); \ + if (std::strcmp(a_, e_) != 0) \ + { \ + std::fprintf(stderr, "FAIL %s:%d: expected \"%s\", got \"%s\"\n", \ + __FILE__, __LINE__, e_, a_); \ + std::abort(); \ + } \ + } while (0) + +// --------------------------------------------------------------------------- +// Domain / StringHandle / ID verification helpers +// --------------------------------------------------------------------------- + +namespace ittapi +{ +namespace test +{ + +inline void check_domain_name(const Domain& domain, const char* expected) +{ + if (domain.native_handle() == nullptr) + { + return; // no collector attached — nothing to verify + } + ITT_CHECK_STR_EQ(domain.native_handle()->nameA, expected); +} + +inline void check_string_handle_name(const StringHandle& handle, const char* expected) +{ + if (handle.native_handle() == nullptr) + { + return; // no collector attached — nothing to verify + } + ITT_CHECK_STR_EQ(handle.native_handle()->strA, expected); +} + +inline void check_id_fields(const __itt_id& id, + unsigned long long d1, + unsigned long long d2, + unsigned long long d3) +{ + if (id.d1 != d1 || id.d2 != d2 || id.d3 != d3) + { + std::fprintf(stderr, + "FAIL: id {%llu,%llu,%llu} != expected {%llu,%llu,%llu}\n", + id.d1, id.d2, id.d3, d1, d2, d3); + std::abort(); + } +} + +inline void check_id_is_null(const __itt_id& id) +{ + check_id_fields(id, 0, 0, 0); +} + +} // namespace test +} // namespace ittapi diff --git a/cpp/tests/test_ittapi.cpp b/cpp/tests/test_ittapi.cpp index 548f1d1..329d783 100644 --- a/cpp/tests/test_ittapi.cpp +++ b/cpp/tests/test_ittapi.cpp @@ -4,38 +4,40 @@ */ #include - -#include +#include "test_helpers.hpp" static void test_umbrella_header_compiles() { ittapi::Domain d{"test.umbrella"}; ittapi::StringHandle sh{"umbrella_handle"}; + ittapi::test::check_domain_name(d, "test.umbrella"); + ittapi::test::check_string_handle_name(sh, "umbrella_handle"); + ittapi::set_thread_name("umbrella_thread"); ittapi::pause(); ittapi::resume(); { auto task = d.task("umbrella_task"); - assert(task.active()); + ITT_CHECK(task.active()); } { auto region = d.region(sh); - assert(region.active()); + ITT_CHECK(region.active()); } { auto frame = d.frame(); - assert(frame.active()); + ITT_CHECK(frame.active()); } { ittapi::ScopedPause sp; - assert(sp.active()); + ITT_CHECK(sp.active()); sp.resume_now(); - assert(!sp.active()); + ITT_CHECK(!sp.active()); } d.task_begin("manual"); diff --git a/cpp/tests/test_region.cpp b/cpp/tests/test_region.cpp index ba07217..8287a5d 100644 --- a/cpp/tests/test_region.cpp +++ b/cpp/tests/test_region.cpp @@ -5,17 +5,18 @@ #include #include +#include "test_helpers.hpp" -#include #include static void test_scoped_region_lifecycle() { ittapi::Domain d{"test.region.lifecycle"}; + ittapi::test::check_domain_name(d, "test.region.lifecycle"); { auto region = d.region("lifecycle_region"); - assert(region.active()); + ITT_CHECK(region.active()); } } @@ -23,44 +24,48 @@ static void test_explicit_end_is_idempotent() { ittapi::Domain d{"test.region.end"}; auto region = d.region("end_region"); - assert(region.active()); + ITT_CHECK(region.active()); region.end(); - assert(!region.active()); + ITT_CHECK(!region.active()); region.end(); - assert(!region.active()); + ITT_CHECK(!region.active()); } static void test_move_construction() { ittapi::Domain d{"test.region.move"}; auto r1 = d.region("move_region"); - assert(r1.active()); + ITT_CHECK(r1.active()); auto r2 = std::move(r1); - assert(!r1.active()); - assert(r2.active()); + ITT_CHECK(!r1.active()); + ITT_CHECK(r2.active()); } static void test_string_handle_overload() { ittapi::Domain d{"test.region.sh"}; ittapi::StringHandle name{"sh_region"}; + ittapi::test::check_string_handle_name(name, "sh_region"); { auto region = d.region(name); - assert(region.active()); + ITT_CHECK(region.active()); } } static void test_scoped_region_with_ids() { ittapi::Domain d{"test.region.ids"}; + ittapi::test::check_domain_name(d, "test.region.ids"); __itt_id id = __itt_id_make(nullptr, 10); __itt_id parentid = __itt_null; + ittapi::test::check_id_is_null(parentid); + { auto region = d.region("region_with_ids", id, parentid); - assert(region.active()); + ITT_CHECK(region.active()); } } @@ -68,12 +73,13 @@ static void test_scoped_region_with_ids_string_handle() { ittapi::Domain d{"test.region.ids_sh"}; ittapi::StringHandle name{"sh_region_ids"}; + ittapi::test::check_string_handle_name(name, "sh_region_ids"); __itt_id id = __itt_id_make(nullptr, 11); __itt_id parentid = __itt_null; { auto region = d.region(name, id, parentid); - assert(region.active()); + ITT_CHECK(region.active()); } } diff --git a/cpp/tests/test_string_handle.cpp b/cpp/tests/test_string_handle.cpp index 4afe3f8..608372a 100644 --- a/cpp/tests/test_string_handle.cpp +++ b/cpp/tests/test_string_handle.cpp @@ -4,32 +4,29 @@ */ #include +#include "test_helpers.hpp" -#include #include #include static void test_construct_from_literal() { ittapi::StringHandle h{"test_handle"}; - // valid() may be false if no collector is attached; just verify it compiles and runs - (void)h.valid(); - (void)h.native_handle(); + ittapi::test::check_string_handle_name(h, "test_handle"); } static void test_construct_from_string_view() { std::string_view sv = "test_sv_handle"; ittapi::StringHandle h{sv}; - (void)h.valid(); - (void)h.native_handle(); + ittapi::test::check_string_handle_name(h, "test_sv_handle"); } static void test_construct_from_std_string() { std::string s = "test_string_handle"; ittapi::StringHandle h{std::string_view(s)}; - (void)h.valid(); + ittapi::test::check_string_handle_name(h, "test_string_handle"); } int main() diff --git a/cpp/tests/test_task.cpp b/cpp/tests/test_task.cpp index 1fa52a4..350729e 100644 --- a/cpp/tests/test_task.cpp +++ b/cpp/tests/test_task.cpp @@ -5,17 +5,18 @@ #include #include +#include "test_helpers.hpp" -#include #include static void test_scoped_task_lifecycle() { ittapi::Domain d{"test.task.lifecycle"}; + ittapi::test::check_domain_name(d, "test.task.lifecycle"); { auto task = d.task("lifecycle_task"); - assert(task.active()); + ITT_CHECK(task.active()); } // destructor should have ended the task } @@ -24,32 +25,33 @@ static void test_explicit_end_is_idempotent() { ittapi::Domain d{"test.task.end"}; auto task = d.task("end_task"); - assert(task.active()); + ITT_CHECK(task.active()); task.end(); - assert(!task.active()); + ITT_CHECK(!task.active()); task.end(); // second call should be safe - assert(!task.active()); + ITT_CHECK(!task.active()); } static void test_move_construction() { ittapi::Domain d{"test.task.move"}; auto task1 = d.task("move_task"); - assert(task1.active()); + ITT_CHECK(task1.active()); auto task2 = std::move(task1); - assert(!task1.active()); - assert(task2.active()); + ITT_CHECK(!task1.active()); + ITT_CHECK(task2.active()); } static void test_string_handle_overload() { ittapi::Domain d{"test.task.sh"}; ittapi::StringHandle name{"sh_task"}; + ittapi::test::check_string_handle_name(name, "sh_task"); { auto task = d.task(name); - assert(task.active()); + ITT_CHECK(task.active()); } } @@ -74,9 +76,11 @@ static void test_scoped_task_with_ids() __itt_id taskid = __itt_id_make(nullptr, 1); __itt_id parentid = __itt_null; + ittapi::test::check_id_is_null(parentid); + { auto task = d.task("task_with_ids", taskid, parentid); - assert(task.active()); + ITT_CHECK(task.active()); } } @@ -84,12 +88,13 @@ static void test_scoped_task_with_ids_string_handle() { ittapi::Domain d{"test.task.ids_sh"}; ittapi::StringHandle name{"sh_task_ids"}; + ittapi::test::check_string_handle_name(name, "sh_task_ids"); __itt_id taskid = __itt_id_make(nullptr, 2); __itt_id parentid = __itt_null; { auto task = d.task(name, taskid, parentid); - assert(task.active()); + ITT_CHECK(task.active()); } } From 55ba11e5054989d0d04ba348dc8051165a122d2d Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 08:36:06 -0500 Subject: [PATCH 11/33] rename test check define --- cpp/tests/test_collection_control.cpp | 12 ++++++------ cpp/tests/test_domain.cpp | 8 ++++---- cpp/tests/test_frame.cpp | 14 +++++++------- cpp/tests/test_helpers.hpp | 8 ++++---- cpp/tests/test_ittapi.cpp | 10 +++++----- cpp/tests/test_region.cpp | 20 ++++++++++---------- cpp/tests/test_task.cpp | 20 ++++++++++---------- 7 files changed, 46 insertions(+), 46 deletions(-) diff --git a/cpp/tests/test_collection_control.cpp b/cpp/tests/test_collection_control.cpp index 8fff79b..d0abdea 100644 --- a/cpp/tests/test_collection_control.cpp +++ b/cpp/tests/test_collection_control.cpp @@ -19,7 +19,7 @@ static void test_scoped_pause_resumes_on_destruction() { ittapi::ScopedPause sp; - ITT_CHECK(sp.active()); + CHECK(sp.active()); } // destructor should have called resume() } @@ -27,20 +27,20 @@ static void test_scoped_pause_resumes_on_destruction() static void test_resume_now_disables_destructor() { ittapi::ScopedPause sp; - ITT_CHECK(sp.active()); + CHECK(sp.active()); sp.resume_now(); - ITT_CHECK(!sp.active()); + CHECK(!sp.active()); // destructor should not call resume() again } static void test_move_construction() { ittapi::ScopedPause sp1; - ITT_CHECK(sp1.active()); + CHECK(sp1.active()); auto sp2 = std::move(sp1); - ITT_CHECK(!sp1.active()); - ITT_CHECK(sp2.active()); + CHECK(!sp1.active()); + CHECK(sp2.active()); } int main() diff --git a/cpp/tests/test_domain.cpp b/cpp/tests/test_domain.cpp index 5e7e68e..66371df 100644 --- a/cpp/tests/test_domain.cpp +++ b/cpp/tests/test_domain.cpp @@ -19,7 +19,7 @@ static void test_create_task_from_domain() { auto task = d.task("my_task"); - ITT_CHECK(task.active()); + CHECK(task.active()); } } @@ -31,7 +31,7 @@ static void test_create_task_with_string_handle() { auto task = d.task(name); - ITT_CHECK(task.active()); + CHECK(task.active()); } } @@ -42,7 +42,7 @@ static void test_create_region_from_domain() { auto region = d.region("my_region"); - ITT_CHECK(region.active()); + CHECK(region.active()); } } @@ -53,7 +53,7 @@ static void test_create_frame_from_domain() { auto frame = d.frame(); - ITT_CHECK(frame.active()); + CHECK(frame.active()); } } diff --git a/cpp/tests/test_frame.cpp b/cpp/tests/test_frame.cpp index fcb8dfe..12d68f9 100644 --- a/cpp/tests/test_frame.cpp +++ b/cpp/tests/test_frame.cpp @@ -16,7 +16,7 @@ static void test_scoped_frame_lifecycle() { auto frame = d.frame(); - ITT_CHECK(frame.active()); + CHECK(frame.active()); } } @@ -24,22 +24,22 @@ static void test_explicit_end_is_idempotent() { ittapi::Domain d{"test.frame.end"}; auto frame = d.frame(); - ITT_CHECK(frame.active()); + CHECK(frame.active()); frame.end(); - ITT_CHECK(!frame.active()); + CHECK(!frame.active()); frame.end(); - ITT_CHECK(!frame.active()); + CHECK(!frame.active()); } static void test_move_construction() { ittapi::Domain d{"test.frame.move"}; auto f1 = d.frame(); - ITT_CHECK(f1.active()); + CHECK(f1.active()); auto f2 = std::move(f1); - ITT_CHECK(!f1.active()); - ITT_CHECK(f2.active()); + CHECK(!f1.active()); + CHECK(f2.active()); } static void test_submit() diff --git a/cpp/tests/test_helpers.hpp b/cpp/tests/test_helpers.hpp index 577f665..2c78a95 100644 --- a/cpp/tests/test_helpers.hpp +++ b/cpp/tests/test_helpers.hpp @@ -17,7 +17,7 @@ // Assertion macros with file/line diagnostics // --------------------------------------------------------------------------- -#define ITT_CHECK(expr) \ +#define CHECK(expr) \ do \ { \ if (!(expr)) \ @@ -28,7 +28,7 @@ } \ } while (0) -#define ITT_CHECK_STR_EQ(actual, expected) \ +#define CHECK_STR_EQ(actual, expected) \ do \ { \ const char* a_ = (actual); \ @@ -56,7 +56,7 @@ inline void check_domain_name(const Domain& domain, const char* expected) { return; // no collector attached — nothing to verify } - ITT_CHECK_STR_EQ(domain.native_handle()->nameA, expected); + CHECK_STR_EQ(domain.native_handle()->nameA, expected); } inline void check_string_handle_name(const StringHandle& handle, const char* expected) @@ -65,7 +65,7 @@ inline void check_string_handle_name(const StringHandle& handle, const char* exp { return; // no collector attached — nothing to verify } - ITT_CHECK_STR_EQ(handle.native_handle()->strA, expected); + CHECK_STR_EQ(handle.native_handle()->strA, expected); } inline void check_id_fields(const __itt_id& id, diff --git a/cpp/tests/test_ittapi.cpp b/cpp/tests/test_ittapi.cpp index 329d783..5d1d92a 100644 --- a/cpp/tests/test_ittapi.cpp +++ b/cpp/tests/test_ittapi.cpp @@ -20,24 +20,24 @@ static void test_umbrella_header_compiles() { auto task = d.task("umbrella_task"); - ITT_CHECK(task.active()); + CHECK(task.active()); } { auto region = d.region(sh); - ITT_CHECK(region.active()); + CHECK(region.active()); } { auto frame = d.frame(); - ITT_CHECK(frame.active()); + CHECK(frame.active()); } { ittapi::ScopedPause sp; - ITT_CHECK(sp.active()); + CHECK(sp.active()); sp.resume_now(); - ITT_CHECK(!sp.active()); + CHECK(!sp.active()); } d.task_begin("manual"); diff --git a/cpp/tests/test_region.cpp b/cpp/tests/test_region.cpp index 8287a5d..1e6a653 100644 --- a/cpp/tests/test_region.cpp +++ b/cpp/tests/test_region.cpp @@ -16,7 +16,7 @@ static void test_scoped_region_lifecycle() { auto region = d.region("lifecycle_region"); - ITT_CHECK(region.active()); + CHECK(region.active()); } } @@ -24,22 +24,22 @@ static void test_explicit_end_is_idempotent() { ittapi::Domain d{"test.region.end"}; auto region = d.region("end_region"); - ITT_CHECK(region.active()); + CHECK(region.active()); region.end(); - ITT_CHECK(!region.active()); + CHECK(!region.active()); region.end(); - ITT_CHECK(!region.active()); + CHECK(!region.active()); } static void test_move_construction() { ittapi::Domain d{"test.region.move"}; auto r1 = d.region("move_region"); - ITT_CHECK(r1.active()); + CHECK(r1.active()); auto r2 = std::move(r1); - ITT_CHECK(!r1.active()); - ITT_CHECK(r2.active()); + CHECK(!r1.active()); + CHECK(r2.active()); } static void test_string_handle_overload() @@ -50,7 +50,7 @@ static void test_string_handle_overload() { auto region = d.region(name); - ITT_CHECK(region.active()); + CHECK(region.active()); } } @@ -65,7 +65,7 @@ static void test_scoped_region_with_ids() { auto region = d.region("region_with_ids", id, parentid); - ITT_CHECK(region.active()); + CHECK(region.active()); } } @@ -79,7 +79,7 @@ static void test_scoped_region_with_ids_string_handle() { auto region = d.region(name, id, parentid); - ITT_CHECK(region.active()); + CHECK(region.active()); } } diff --git a/cpp/tests/test_task.cpp b/cpp/tests/test_task.cpp index 350729e..9e10a18 100644 --- a/cpp/tests/test_task.cpp +++ b/cpp/tests/test_task.cpp @@ -16,7 +16,7 @@ static void test_scoped_task_lifecycle() { auto task = d.task("lifecycle_task"); - ITT_CHECK(task.active()); + CHECK(task.active()); } // destructor should have ended the task } @@ -25,22 +25,22 @@ static void test_explicit_end_is_idempotent() { ittapi::Domain d{"test.task.end"}; auto task = d.task("end_task"); - ITT_CHECK(task.active()); + CHECK(task.active()); task.end(); - ITT_CHECK(!task.active()); + CHECK(!task.active()); task.end(); // second call should be safe - ITT_CHECK(!task.active()); + CHECK(!task.active()); } static void test_move_construction() { ittapi::Domain d{"test.task.move"}; auto task1 = d.task("move_task"); - ITT_CHECK(task1.active()); + CHECK(task1.active()); auto task2 = std::move(task1); - ITT_CHECK(!task1.active()); - ITT_CHECK(task2.active()); + CHECK(!task1.active()); + CHECK(task2.active()); } static void test_string_handle_overload() @@ -51,7 +51,7 @@ static void test_string_handle_overload() { auto task = d.task(name); - ITT_CHECK(task.active()); + CHECK(task.active()); } } @@ -80,7 +80,7 @@ static void test_scoped_task_with_ids() { auto task = d.task("task_with_ids", taskid, parentid); - ITT_CHECK(task.active()); + CHECK(task.active()); } } @@ -94,7 +94,7 @@ static void test_scoped_task_with_ids_string_handle() { auto task = d.task(name, taskid, parentid); - ITT_CHECK(task.active()); + CHECK(task.active()); } } From 309cdee714a0a5dea4cda3058f8897a13bd4a463 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 10:41:14 -0500 Subject: [PATCH 12/33] added back copy and move assignment operators. --- cpp/include/ittapi_domain.hpp | 42 +++++++++++++++++++--------- cpp/include/ittapi_string_handle.hpp | 16 +++++++++++ 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/cpp/include/ittapi_domain.hpp b/cpp/include/ittapi_domain.hpp index c4546af..e34b8ab 100644 --- a/cpp/include/ittapi_domain.hpp +++ b/cpp/include/ittapi_domain.hpp @@ -43,34 +43,50 @@ class Domain return m_handle != nullptr; } - ScopedTask task(std::string_view name) const + Domain(const Domain&) = default; + Domain& operator=(const Domain&) = default; + + Domain(Domain&& other) noexcept + : m_handle(other.m_handle) + { + other.m_handle = nullptr; + } + + Domain& operator=(Domain&& other) noexcept + { + m_handle = other.m_handle; + other.m_handle = nullptr; + return *this; + } + + [[nodiscard]] ScopedTask task(std::string_view name) const { return ScopedTask(m_handle, name); } - ScopedTask task(std::string_view name, __itt_id taskid, __itt_id parentid) const + [[nodiscard]] ScopedTask task(std::string_view name, __itt_id taskid, __itt_id parentid) const { return ScopedTask(m_handle, name, taskid, parentid); } #if ITT_PLATFORM == ITT_PLATFORM_WIN - ScopedTask task(std::wstring_view name) const + [[nodiscard]] ScopedTask task(std::wstring_view name) const { return ScopedTask(m_handle, name); } - ScopedTask task(std::wstring_view name, __itt_id taskid, __itt_id parentid) const + [[nodiscard]] ScopedTask task(std::wstring_view name, __itt_id taskid, __itt_id parentid) const { return ScopedTask(m_handle, name, taskid, parentid); } #endif - ScopedTask task(const StringHandle& name) const noexcept + [[nodiscard]] ScopedTask task(const StringHandle& name) const noexcept { return ScopedTask(m_handle, name); } - ScopedTask task(const StringHandle& name, __itt_id taskid, __itt_id parentid) const noexcept + [[nodiscard]] ScopedTask task(const StringHandle& name, __itt_id taskid, __itt_id parentid) const noexcept { return ScopedTask(m_handle, name, taskid, parentid); } @@ -116,39 +132,39 @@ class Domain __itt_task_end(m_handle); } - ScopedRegion region(std::string_view name) const + [[nodiscard]] ScopedRegion region(std::string_view name) const { return ScopedRegion(m_handle, name); } - ScopedRegion region(std::string_view name, __itt_id id, __itt_id parentid) const + [[nodiscard]] ScopedRegion region(std::string_view name, __itt_id id, __itt_id parentid) const { return ScopedRegion(m_handle, name, id, parentid); } #if ITT_PLATFORM == ITT_PLATFORM_WIN - ScopedRegion region(std::wstring_view name) const + [[nodiscard]] ScopedRegion region(std::wstring_view name) const { return ScopedRegion(m_handle, name); } - ScopedRegion region(std::wstring_view name, __itt_id id, __itt_id parentid) const + [[nodiscard]] ScopedRegion region(std::wstring_view name, __itt_id id, __itt_id parentid) const { return ScopedRegion(m_handle, name, id, parentid); } #endif - ScopedRegion region(const StringHandle& name) const noexcept + [[nodiscard]] ScopedRegion region(const StringHandle& name) const noexcept { return ScopedRegion(m_handle, name); } - ScopedRegion region(const StringHandle& name, __itt_id id, __itt_id parentid) const noexcept + [[nodiscard]] ScopedRegion region(const StringHandle& name, __itt_id id, __itt_id parentid) const noexcept { return ScopedRegion(m_handle, name, id, parentid); } - ScopedFrame frame() const noexcept + [[nodiscard]] ScopedFrame frame() const noexcept { return ScopedFrame(m_handle); } diff --git a/cpp/include/ittapi_string_handle.hpp b/cpp/include/ittapi_string_handle.hpp index 5af6b2f..d40f45e 100644 --- a/cpp/include/ittapi_string_handle.hpp +++ b/cpp/include/ittapi_string_handle.hpp @@ -39,6 +39,22 @@ class StringHandle return m_handle != nullptr; } + StringHandle(const StringHandle&) = default; + StringHandle& operator=(const StringHandle&) = default; + + StringHandle(StringHandle&& other) noexcept + : m_handle(other.m_handle) + { + other.m_handle = nullptr; + } + + StringHandle& operator=(StringHandle&& other) noexcept + { + m_handle = other.m_handle; + other.m_handle = nullptr; + return *this; + } + private: __itt_string_handle* m_handle = nullptr; }; From c5f7d4cdd640f96abe2cfd035427e7069bc78127 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 10:52:16 -0500 Subject: [PATCH 13/33] cleanup cmake --- CMakeLists.txt | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a084274..7b56b06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,6 @@ project(ittapi) option(FORCE_32 "Force a 32-bit compile on 64-bit" OFF) option(ITT_API_IPT_SUPPORT "ptmarks support" OFF) option(ITT_API_FORTRAN_SUPPORT "fortran support" OFF) -option(ITT_API_CPP_SUPPORT "C++ wrapper support" OFF) if(FORCE_32 AND UNIX) SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32") @@ -169,22 +168,12 @@ target_include_directories(jitprofiling PRIVATE src/ittnotify ) -# C++ wrapper -if(ITT_API_CPP_SUPPORT) - add_subdirectory(cpp) -endif() - # install include(CMakePackageConfigHelpers) include(GNUInstallDirs) install(TARGETS ittnotify EXPORT ittapi-targets INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -if(ITT_API_CPP_SUPPORT) - install(TARGETS ittapi-cpp EXPORT ittapi-targets) - install(DIRECTORY cpp/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} - FILES_MATCHING PATTERN "*.hpp") -endif() install(EXPORT ittapi-targets NAMESPACE ittapi:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ittapi) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h" From 00cab166e0a823c9021b223e607f54edb050fd05 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 10:56:48 -0500 Subject: [PATCH 14/33] apply CMakefile changes back --- CMakeLists.txt | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 443ad93..8c97cf9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,6 +26,7 @@ project(ittapi) option(FORCE_32 "Force a 32-bit compile on 64-bit" OFF) option(ITT_API_IPT_SUPPORT "ptmarks support" OFF) option(ITT_API_FORTRAN_SUPPORT "fortran support" OFF) +option(ITT_API_CPP_SUPPORT "C++ wrapper support" OFF) option(ITT_API_INSTALL "Enable ITT API installation rules" ON) if(FORCE_32 AND UNIX) @@ -171,6 +172,11 @@ target_include_directories(jitprofiling PRIVATE src/ittnotify ) +# C++ wrapper +if(ITT_API_CPP_SUPPORT) + add_subdirectory(cpp) +endif() + # install include(CMakePackageConfigHelpers) @@ -178,6 +184,11 @@ include(GNUInstallDirs) if(ITT_API_INSTALL) install(TARGETS ittnotify EXPORT ittapi-targets INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + if(ITT_API_CPP_SUPPORT) + install(TARGETS ittapi-cpp EXPORT ittapi-targets) + install(DIRECTORY cpp/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.hpp") + endif() install(EXPORT ittapi-targets NAMESPACE ittapi:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/ittapi) install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h" From 29ce15246146a2c4b63b1260daa3ef81b6ba171f Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 10:58:54 -0500 Subject: [PATCH 15/33] trigger ci --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d9deb5b..ddda754 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [ master ] + branches: [ master, cpp_wrapper ] pull_request: branches: [ master ] From e212b7d23b5d7d47afb9922c1a4c129b4ec07af4 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 11:02:40 -0500 Subject: [PATCH 16/33] cleanup --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ddda754..d9deb5b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [ master, cpp_wrapper ] + branches: [ master ] pull_request: branches: [ master ] From 7d7848d8d2ae2e9d5c9aa0396aeea853679274b8 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 11:14:29 -0500 Subject: [PATCH 17/33] minor fixes --- .github/workflows/main.yml | 2 +- README.md | 2 +- buildall.py | 2 +- cpp/CMakeLists.txt | 14 +++++++++++--- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d9deb5b..ddda754 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [ master ] + branches: [ master, cpp_wrapper ] pull_request: branches: [ master ] diff --git a/README.md b/README.md index 7f9cc56..8151c78 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ optional arguments: -v, --verbose enable verbose output from build process -pt, --ptmark enable anomaly detection support -ft, --fortran enable fortran support - --cpp enable C++ wrapper support + -cpp, --cpp enable C++ wrapper support --force_bits specify bit version for the target --vs specify visual studio version (Windows only) --cmake_gen specify cmake build generator (Windows only) diff --git a/buildall.py b/buildall.py index fb64c39..180f7fe 100755 --- a/buildall.py +++ b/buildall.py @@ -118,7 +118,7 @@ def main(): parser.add_argument( "-ft", "--fortran", help="enable fortran support", action="store_true") parser.add_argument( - "--cpp", help="enable C++ wrapper support", action="store_true") + "-cpp", "--cpp", help="enable C++ wrapper support", action="store_true") parser.add_argument( "--force_bits", choices=["32", "64"], help="specify bit version for the target") if sys.platform == 'win32' and vs_versions: diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index c017368..56141d5 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -15,13 +15,18 @@ target_include_directories(ittapi-cpp target_link_libraries(ittapi-cpp INTERFACE ittnotify) target_compile_features(ittapi-cpp INTERFACE cxx_std_17) -find_package(Threads REQUIRED) +if(NOT WIN32) + find_package(Threads) +endif() # Sample add_executable(task_sample samples/task_sample.cpp) target_link_libraries(task_sample PRIVATE ittapi-cpp) if(NOT WIN32) - target_link_libraries(task_sample PRIVATE ${CMAKE_DL_LIBS} Threads::Threads) + target_link_libraries(task_sample PRIVATE ${CMAKE_DL_LIBS}) + if(Threads_FOUND) + target_link_libraries(task_sample PRIVATE Threads::Threads) + endif() endif() # Tests @@ -42,7 +47,10 @@ foreach(test_name ${CPP_TESTS}) add_executable(${test_name} tests/${test_name}.cpp) target_link_libraries(${test_name} PRIVATE ittapi-cpp) if(NOT WIN32) - target_link_libraries(${test_name} PRIVATE ${CMAKE_DL_LIBS} Threads::Threads) + target_link_libraries(${test_name} PRIVATE ${CMAKE_DL_LIBS}) + if(Threads_FOUND) + target_link_libraries(${test_name} PRIVATE Threads::Threads) + endif() endif() add_test(NAME cpp_${test_name} COMMAND ${test_name}) endforeach() From f6235a492245189988078dc089ea31fa406439e9 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 11:24:57 -0500 Subject: [PATCH 18/33] cleanup gh action --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ddda754..d9deb5b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [ master, cpp_wrapper ] + branches: [ master ] pull_request: branches: [ master ] From caaf0c7045393ab3403baab113aa88eea3673ff6 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 11:27:06 -0500 Subject: [PATCH 19/33] update main README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8151c78..0176d25 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ To build the library: - To list available build options execute: `python buildall.py -h` ``` -usage: buildall.py [-h] [-d] [-c] [-v] [-pt] [-ft] [--cpp] [--force_bits] +usage: buildall.py [-h] [-d] [-c] [-v] [-pt] [-ft] [-cpp] [--force_bits] optional arguments: -h, --help show this help message and exit From 1ec6e8962d521ee45e4edd25f12b2af10342aeed Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 11:37:57 -0500 Subject: [PATCH 20/33] simplify gh action --- .github/workflows/main.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index d9deb5b..7f52d4c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [ master ] + branches: [ master , cpp_wrapper ] pull_request: branches: [ master ] @@ -51,12 +51,14 @@ jobs: steps: - name: Checkout sources uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Configure - run: cmake -B build -DCMAKE_BUILD_TYPE=Release -DITT_API_CPP_SUPPORT=ON - - name: Build - run: cmake --build build --config Release - - name: Test - run: ctest --test-dir build/cpp --build-config Release --output-on-failure + - name: Build C++ wrapper + run: python buildall.py --force_bits 64 -cpp + - name: Test (Linux) + run: ctest --test-dir build_linux/64/cpp --build-config Release --output-on-failure + if: runner.os == 'Linux' + - name: Test (Windows) + run: ctest --test-dir build_win/64/cpp --build-config Release --output-on-failure + if: runner.os == 'Windows' rust_format: name: Check Rust formatting From 92f7a693eb2180901adc316843ac637f9521e133 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 17 Apr 2026 11:41:08 -0500 Subject: [PATCH 21/33] ready to merge --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 7f52d4c..659c1d6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [ master , cpp_wrapper ] + branches: [ master ] pull_request: branches: [ master ] From 4a9ec991caf66dd3f94238b8f6dae69c34cc43b9 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Mon, 20 Apr 2026 08:43:35 -0500 Subject: [PATCH 22/33] add new docomuntation page --- docs/src/api-support.rst | 1 + docs/src/itt-api-cpp-wrapper.rst | 221 +++++++++++++++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 docs/src/itt-api-cpp-wrapper.rst diff --git a/docs/src/api-support.rst b/docs/src/api-support.rst index 57c7890..3bc233b 100644 --- a/docs/src/api-support.rst +++ b/docs/src/api-support.rst @@ -28,6 +28,7 @@ Other Language API Bindings: :maxdepth: 1 + itt-api-cpp-wrapper Rust ITT API Bindings Python ITT API Bindings diff --git a/docs/src/itt-api-cpp-wrapper.rst b/docs/src/itt-api-cpp-wrapper.rst new file mode 100644 index 0000000..0fd6c4f --- /dev/null +++ b/docs/src/itt-api-cpp-wrapper.rst @@ -0,0 +1,221 @@ +.. _itt-api-cpp-wrapper: + +ITT API C++ Wrapper +=================== + +A modern, header-only C++ wrapper for the `ITT API `_ +instrumentation library. The wrapper provides RAII-based scoped helpers and type-safe +C++ abstractions over the existing C API. + +Supported APIs +-------------- + +.. list-table:: + :header-rows: 1 + :widths: 30 70 + + * - 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: + +.. code-block:: cpp + + #include + +Or include individual headers: + +.. code-block:: cpp + + #include + #include + #include + +Example: Task Instrumentation +----------------------------- + +.. code-block:: cpp + + #include + + #include + #include + + 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 +^^^^^^^^^^^^^^ + +.. code-block:: 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) +^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: bash + + g++ -std=c++17 -O2 \ + -I/include \ + app.cpp \ + /lib/libittnotify.a \ + -ldl -pthread \ + -o app + +Building with CMake +------------------- + +From the repository root: + +.. code-block:: 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: + +.. code-block:: bash + + python buildall.py --cpp + +Running Tests +------------- + +Tests are registered inside the ``cpp/`` subdirectory. After building: + +.. code-block:: bash + + ctest --test-dir build/cpp --output-on-failure + +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*``. + +.. code-block:: cpp + + ittapi::StringHandle h{"my_handle"}; + h.valid(); // true if handle was created + h.native_handle(); // underlying __itt_string_handle* + +ittapi::Domain +"""""""""""""" + +Lightweight wrapper around ``__itt_domain*`` with convenience factories. + +.. code-block:: 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 begin + d.task_end(); // manual end + +ittapi::ScopedTask +"""""""""""""""""" + +RAII wrapper for task begin/end. + +.. code-block:: cpp + + { + auto task = domain.task("work"); + // ... do work ... + task.end(); // optional early end (idempotent) + } // destructor ends task if still active + +For manual (non-RAII) control: + +.. code-block:: cpp + + domain.task_begin("work"); + // ... do work ... + domain.task_end(); + +ittapi::ScopedRegion +"""""""""""""""""""" + +RAII wrapper for region begin/end. + +ittapi::ScopedFrame +""""""""""""""""""" + +RAII wrapper for frame begin/end. Supports explicit timestamp submission. + +.. code-block:: cpp + + ittapi::ScopedFrame::submit(domain.native_handle(), begin_ts, end_ts); + +ittapi::ScopedPause +""""""""""""""""""" + +RAII wrapper for pause/resume. Constructor pauses, destructor resumes. + +.. code-block:: cpp + + { + ittapi::ScopedPause sp; + // collection is paused + sp.resume_now(); // optional early resume + } From 3fc05dfcb59544a0ff56680b2b16526b22215182 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Mon, 20 Apr 2026 09:19:40 -0500 Subject: [PATCH 23/33] update documentation copyrigth year --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 831c7b9..0bc4225 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -12,7 +12,7 @@ # -- Project information ----------------------------------------------------- project = 'ITT/JIT APIs Documentation' -copyright = '2025 Intel Corporation' +copyright = '2026 Intel Corporation' author = 'Intel Corporation' # -- General configuration --------------------------------------------------- From 593328a82395f0f15765c44e3aa4f54949c05de4 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Tue, 21 Apr 2026 08:28:13 -0500 Subject: [PATCH 24/33] add thread-local cache for string handle lookups --- cpp/include/ittapi_domain.hpp | 8 ++++---- cpp/include/ittapi_region.hpp | 8 ++++---- cpp/include/ittapi_task.hpp | 8 ++++---- cpp/include/ittapi_utils.hpp | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 47 insertions(+), 12 deletions(-) diff --git a/cpp/include/ittapi_domain.hpp b/cpp/include/ittapi_domain.hpp index e34b8ab..32d483b 100644 --- a/cpp/include/ittapi_domain.hpp +++ b/cpp/include/ittapi_domain.hpp @@ -93,26 +93,26 @@ class Domain void task_begin(std::string_view name) const { - __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); + __itt_string_handle* h = detail::get_or_create_string_handle(name); __itt_task_begin(m_handle, detail::make_null_id(), detail::make_null_id(), h); } void task_begin(std::string_view name, __itt_id taskid, __itt_id parentid) const { - __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); + __itt_string_handle* h = detail::get_or_create_string_handle(name); __itt_task_begin(m_handle, taskid, parentid, h); } #if ITT_PLATFORM == ITT_PLATFORM_WIN void task_begin(std::wstring_view name) const { - __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); + __itt_string_handle* h = detail::get_or_create_string_handle(name); __itt_task_begin(m_handle, detail::make_null_id(), detail::make_null_id(), h); } void task_begin(std::wstring_view name, __itt_id taskid, __itt_id parentid) const { - __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); + __itt_string_handle* h = detail::get_or_create_string_handle(name); __itt_task_begin(m_handle, taskid, parentid, h); } #endif diff --git a/cpp/include/ittapi_region.hpp b/cpp/include/ittapi_region.hpp index 3c85585..d15b50c 100644 --- a/cpp/include/ittapi_region.hpp +++ b/cpp/include/ittapi_region.hpp @@ -25,7 +25,7 @@ class ScopedRegion , m_id(detail::make_null_id()) , m_active(true) { - __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); + __itt_string_handle* h = detail::get_or_create_string_handle(name); __itt_region_begin(m_domain, m_id, detail::make_null_id(), h); } @@ -35,7 +35,7 @@ class ScopedRegion , m_id(id) , m_active(true) { - __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); + __itt_string_handle* h = detail::get_or_create_string_handle(name); __itt_region_begin(m_domain, m_id, parentid, h); } @@ -45,7 +45,7 @@ class ScopedRegion , m_id(detail::make_null_id()) , m_active(true) { - __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); + __itt_string_handle* h = detail::get_or_create_string_handle(name); __itt_region_begin(m_domain, m_id, detail::make_null_id(), h); } @@ -55,7 +55,7 @@ class ScopedRegion , m_id(id) , m_active(true) { - __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); + __itt_string_handle* h = detail::get_or_create_string_handle(name); __itt_region_begin(m_domain, m_id, parentid, h); } #endif diff --git a/cpp/include/ittapi_task.hpp b/cpp/include/ittapi_task.hpp index 2460c92..70b58cc 100644 --- a/cpp/include/ittapi_task.hpp +++ b/cpp/include/ittapi_task.hpp @@ -24,7 +24,7 @@ class ScopedTask : m_domain(domain) , m_active(true) { - __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); + __itt_string_handle* h = detail::get_or_create_string_handle(name); __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), h); } @@ -33,7 +33,7 @@ class ScopedTask : m_domain(domain) , m_active(true) { - __itt_string_handle* h = detail::create_string_handle(std::string(name).c_str()); + __itt_string_handle* h = detail::get_or_create_string_handle(name); __itt_task_begin(m_domain, taskid, parentid, h); } @@ -42,7 +42,7 @@ class ScopedTask : m_domain(domain) , m_active(true) { - __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); + __itt_string_handle* h = detail::get_or_create_string_handle(name); __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), h); } @@ -51,7 +51,7 @@ class ScopedTask : m_domain(domain) , m_active(true) { - __itt_string_handle* h = detail::create_string_handle(std::wstring(name).c_str()); + __itt_string_handle* h = detail::get_or_create_string_handle(name); __itt_task_begin(m_domain, taskid, parentid, h); } #endif diff --git a/cpp/include/ittapi_utils.hpp b/cpp/include/ittapi_utils.hpp index 39d02f4..9a2219e 100644 --- a/cpp/include/ittapi_utils.hpp +++ b/cpp/include/ittapi_utils.hpp @@ -8,6 +8,9 @@ #include +#include +#include + namespace ittapi { namespace detail @@ -31,6 +34,22 @@ inline __itt_string_handle* create_string_handle(const char* name) noexcept #endif } +inline __itt_string_handle* get_or_create_string_handle(std::string_view name) +{ + thread_local std::unordered_map cache; + auto it = cache.find(name); + if (it != cache.end()) + { + return it->second; + } + __itt_string_handle* h = create_string_handle(std::string(name).c_str()); + if (h != nullptr) + { + cache.emplace(h->strA, h); + } + return h; +} + inline void thread_set_name(const char* name) noexcept { #if ITT_PLATFORM == ITT_PLATFORM_WIN @@ -52,6 +71,22 @@ inline __itt_string_handle* create_string_handle(const wchar_t* name) noexcept return __itt_string_handle_createW(name); } +inline __itt_string_handle* get_or_create_string_handle(std::wstring_view name) +{ + thread_local std::unordered_map cache; + auto it = cache.find(name); + if (it != cache.end()) + { + return it->second; + } + __itt_string_handle* h = create_string_handle(std::wstring(name).c_str()); + if (h != nullptr) + { + cache.emplace(h->strW, h); + } + return h; +} + inline void thread_set_name(const wchar_t* name) noexcept { __itt_thread_set_nameW(name); From 5666ea05993defc3deacda7505051509c8ce0153 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Tue, 21 Apr 2026 08:33:05 -0500 Subject: [PATCH 25/33] rename Domain class member --- cpp/include/ittapi_domain.hpp | 58 +++++++++++++++++------------------ 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/cpp/include/ittapi_domain.hpp b/cpp/include/ittapi_domain.hpp index 32d483b..bdcb498 100644 --- a/cpp/include/ittapi_domain.hpp +++ b/cpp/include/ittapi_domain.hpp @@ -22,155 +22,155 @@ class Domain { public: explicit Domain(std::string_view name) - : m_handle(detail::create_domain(std::string(name).c_str())) + : m_domain(detail::create_domain(std::string(name).c_str())) { } #if ITT_PLATFORM == ITT_PLATFORM_WIN explicit Domain(std::wstring_view name) - : m_handle(detail::create_domain(std::wstring(name).c_str())) + : m_domain(detail::create_domain(std::wstring(name).c_str())) { } #endif __itt_domain* native_handle() const noexcept { - return m_handle; + return m_domain; } bool valid() const noexcept { - return m_handle != nullptr; + return m_domain != nullptr; } Domain(const Domain&) = default; Domain& operator=(const Domain&) = default; Domain(Domain&& other) noexcept - : m_handle(other.m_handle) + : m_domain(other.m_domain) { - other.m_handle = nullptr; + other.m_domain = nullptr; } Domain& operator=(Domain&& other) noexcept { - m_handle = other.m_handle; - other.m_handle = nullptr; + m_domain = other.m_domain; + other.m_domain = nullptr; return *this; } [[nodiscard]] ScopedTask task(std::string_view name) const { - return ScopedTask(m_handle, name); + return ScopedTask(m_domain, name); } [[nodiscard]] ScopedTask task(std::string_view name, __itt_id taskid, __itt_id parentid) const { - return ScopedTask(m_handle, name, taskid, parentid); + return ScopedTask(m_domain, name, taskid, parentid); } #if ITT_PLATFORM == ITT_PLATFORM_WIN [[nodiscard]] ScopedTask task(std::wstring_view name) const { - return ScopedTask(m_handle, name); + return ScopedTask(m_domain, name); } [[nodiscard]] ScopedTask task(std::wstring_view name, __itt_id taskid, __itt_id parentid) const { - return ScopedTask(m_handle, name, taskid, parentid); + return ScopedTask(m_domain, name, taskid, parentid); } #endif [[nodiscard]] ScopedTask task(const StringHandle& name) const noexcept { - return ScopedTask(m_handle, name); + return ScopedTask(m_domain, name); } [[nodiscard]] ScopedTask task(const StringHandle& name, __itt_id taskid, __itt_id parentid) const noexcept { - return ScopedTask(m_handle, name, taskid, parentid); + return ScopedTask(m_domain, name, taskid, parentid); } void task_begin(std::string_view name) const { __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_task_begin(m_handle, detail::make_null_id(), detail::make_null_id(), h); + __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), h); } void task_begin(std::string_view name, __itt_id taskid, __itt_id parentid) const { __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_task_begin(m_handle, taskid, parentid, h); + __itt_task_begin(m_domain, taskid, parentid, h); } #if ITT_PLATFORM == ITT_PLATFORM_WIN void task_begin(std::wstring_view name) const { __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_task_begin(m_handle, detail::make_null_id(), detail::make_null_id(), h); + __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), h); } void task_begin(std::wstring_view name, __itt_id taskid, __itt_id parentid) const { __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_task_begin(m_handle, taskid, parentid, h); + __itt_task_begin(m_domain, taskid, parentid, h); } #endif void task_begin(const StringHandle& name) const noexcept { - __itt_task_begin(m_handle, detail::make_null_id(), detail::make_null_id(), name.native_handle()); + __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), name.native_handle()); } void task_begin(const StringHandle& name, __itt_id taskid, __itt_id parentid) const noexcept { - __itt_task_begin(m_handle, taskid, parentid, name.native_handle()); + __itt_task_begin(m_domain, taskid, parentid, name.native_handle()); } void task_end() const noexcept { - __itt_task_end(m_handle); + __itt_task_end(m_domain); } [[nodiscard]] ScopedRegion region(std::string_view name) const { - return ScopedRegion(m_handle, name); + return ScopedRegion(m_domain, name); } [[nodiscard]] ScopedRegion region(std::string_view name, __itt_id id, __itt_id parentid) const { - return ScopedRegion(m_handle, name, id, parentid); + return ScopedRegion(m_domain, name, id, parentid); } #if ITT_PLATFORM == ITT_PLATFORM_WIN [[nodiscard]] ScopedRegion region(std::wstring_view name) const { - return ScopedRegion(m_handle, name); + return ScopedRegion(m_domain, name); } [[nodiscard]] ScopedRegion region(std::wstring_view name, __itt_id id, __itt_id parentid) const { - return ScopedRegion(m_handle, name, id, parentid); + return ScopedRegion(m_domain, name, id, parentid); } #endif [[nodiscard]] ScopedRegion region(const StringHandle& name) const noexcept { - return ScopedRegion(m_handle, name); + return ScopedRegion(m_domain, name); } [[nodiscard]] ScopedRegion region(const StringHandle& name, __itt_id id, __itt_id parentid) const noexcept { - return ScopedRegion(m_handle, name, id, parentid); + return ScopedRegion(m_domain, name, id, parentid); } [[nodiscard]] ScopedFrame frame() const noexcept { - return ScopedFrame(m_handle); + return ScopedFrame(m_domain); } private: - __itt_domain* m_handle = nullptr; + __itt_domain* m_domain = nullptr; }; } // namespace ittapi From be229858097eb037bc3e6fccdc4dc579066d54aa Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Tue, 21 Apr 2026 08:42:57 -0500 Subject: [PATCH 26/33] update the sample with more usage examples --- cpp/README.md | 4 +- cpp/include/ittapi_domain.hpp | 6 +-- cpp/include/ittapi_region.hpp | 4 +- cpp/include/ittapi_string_handle.hpp | 2 +- cpp/include/ittapi_task.hpp | 4 +- cpp/samples/task_sample.cpp | 69 ++++++++++++++++++++++++++-- cpp/tests/test_frame.cpp | 2 +- cpp/tests/test_helpers.hpp | 8 ++-- docs/src/itt-api-cpp-wrapper.rst | 6 +-- 9 files changed, 82 insertions(+), 23 deletions(-) diff --git a/cpp/README.md b/cpp/README.md index b4c59fd..653c069 100644 --- a/cpp/README.md +++ b/cpp/README.md @@ -124,7 +124,7 @@ Lightweight wrapper around `__itt_string_handle*`. ```cpp ittapi::StringHandle h{"my_handle"}; h.valid(); // true if handle was created -h.native_handle(); // underlying __itt_string_handle* +h.get(); // underlying __itt_string_handle* ``` #### `ittapi::Domain` @@ -170,7 +170,7 @@ RAII wrapper for region begin/end. RAII wrapper for frame begin/end. Supports explicit timestamp submission. ```cpp -ittapi::ScopedFrame::submit(domain.native_handle(), begin_ts, end_ts); +ittapi::ScopedFrame::submit(domain.get(), begin_ts, end_ts); ``` #### `ittapi::ScopedPause` diff --git a/cpp/include/ittapi_domain.hpp b/cpp/include/ittapi_domain.hpp index bdcb498..456cd36 100644 --- a/cpp/include/ittapi_domain.hpp +++ b/cpp/include/ittapi_domain.hpp @@ -33,7 +33,7 @@ class Domain } #endif - __itt_domain* native_handle() const noexcept + __itt_domain* get() const noexcept { return m_domain; } @@ -119,12 +119,12 @@ class Domain void task_begin(const StringHandle& name) const noexcept { - __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), name.native_handle()); + __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), name.get()); } void task_begin(const StringHandle& name, __itt_id taskid, __itt_id parentid) const noexcept { - __itt_task_begin(m_domain, taskid, parentid, name.native_handle()); + __itt_task_begin(m_domain, taskid, parentid, name.get()); } void task_end() const noexcept diff --git a/cpp/include/ittapi_region.hpp b/cpp/include/ittapi_region.hpp index d15b50c..10ba040 100644 --- a/cpp/include/ittapi_region.hpp +++ b/cpp/include/ittapi_region.hpp @@ -65,7 +65,7 @@ class ScopedRegion , m_id(detail::make_null_id()) , m_active(true) { - __itt_region_begin(m_domain, m_id, detail::make_null_id(), name.native_handle()); + __itt_region_begin(m_domain, m_id, detail::make_null_id(), name.get()); } ScopedRegion(const __itt_domain* domain, const StringHandle& name, @@ -74,7 +74,7 @@ class ScopedRegion , m_id(id) , m_active(true) { - __itt_region_begin(m_domain, m_id, parentid, name.native_handle()); + __itt_region_begin(m_domain, m_id, parentid, name.get()); } ScopedRegion(const ScopedRegion&) = delete; diff --git a/cpp/include/ittapi_string_handle.hpp b/cpp/include/ittapi_string_handle.hpp index d40f45e..533407a 100644 --- a/cpp/include/ittapi_string_handle.hpp +++ b/cpp/include/ittapi_string_handle.hpp @@ -29,7 +29,7 @@ class StringHandle } #endif - __itt_string_handle* native_handle() const noexcept + __itt_string_handle* get() const noexcept { return m_handle; } diff --git a/cpp/include/ittapi_task.hpp b/cpp/include/ittapi_task.hpp index 70b58cc..820778c 100644 --- a/cpp/include/ittapi_task.hpp +++ b/cpp/include/ittapi_task.hpp @@ -60,7 +60,7 @@ class ScopedTask : m_domain(domain) , m_active(true) { - __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), name.native_handle()); + __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), name.get()); } ScopedTask(const __itt_domain* domain, const StringHandle& name, @@ -68,7 +68,7 @@ class ScopedTask : m_domain(domain) , m_active(true) { - __itt_task_begin(m_domain, taskid, parentid, name.native_handle()); + __itt_task_begin(m_domain, taskid, parentid, name.get()); } ScopedTask(const ScopedTask&) = delete; diff --git a/cpp/samples/task_sample.cpp b/cpp/samples/task_sample.cpp index cba1ad1..5c78240 100644 --- a/cpp/samples/task_sample.cpp +++ b/cpp/samples/task_sample.cpp @@ -8,25 +8,84 @@ #include #include +static void simulate_work(int ms) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(ms)); +} + int main() { + // Thread naming ittapi::set_thread_name("main"); - ittapi::Domain domain{"example.task"}; + + // Domain and string handle creation + ittapi::Domain domain{"example.app"}; ittapi::StringHandle task_name{"process"}; + // Collection control — pause/resume ittapi::pause(); ittapi::resume(); - + // Scoped task with pre-created StringHandle (zero-overhead path) { auto task = domain.task(task_name); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + simulate_work(10); } - + // Scoped task with inline string (convenience path) { auto task = domain.task("startup"); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + simulate_work(10); + } + + // Scoped task with early end + { + auto task = domain.task("partial_work"); + simulate_work(5); + task.end(); // end early, destructor is a no-op + } + + // Scoped task with IDs for parent-child relationships + { + __itt_id parent_id = __itt_id_make(nullptr, 1); + auto parent = domain.task("parent_task", parent_id, __itt_null); + + __itt_id child_id = __itt_id_make(nullptr, 2); + auto child = domain.task("child_task", child_id, parent_id); + simulate_work(5); + } + + // Manual task begin/end (non-RAII) + domain.task_begin("manual_work"); + simulate_work(5); + domain.task_end(); + + // Scoped region + { + auto region = domain.region("init_phase"); + simulate_work(10); + } + + // Scoped frame + { + auto frame = domain.frame(); + simulate_work(10); + } + + // Frame submit with explicit timestamps + { + __itt_timestamp begin = __itt_get_timestamp(); + simulate_work(10); + __itt_timestamp end = __itt_get_timestamp(); + ittapi::ScopedFrame::submit(domain.get(), begin, end); + } + + // Scoped pause — collection paused within scope + { + ittapi::ScopedPause sp; + simulate_work(10); // not collected + sp.resume_now(); // resume early + simulate_work(10); // collected } return 0; diff --git a/cpp/tests/test_frame.cpp b/cpp/tests/test_frame.cpp index 12d68f9..2868e20 100644 --- a/cpp/tests/test_frame.cpp +++ b/cpp/tests/test_frame.cpp @@ -46,7 +46,7 @@ static void test_submit() { ittapi::Domain d{"test.frame.submit"}; // Just verify it compiles and runs without a collector - ittapi::ScopedFrame::submit(d.native_handle(), 0, 100); + ittapi::ScopedFrame::submit(d.get(), 0, 100); } int main() diff --git a/cpp/tests/test_helpers.hpp b/cpp/tests/test_helpers.hpp index 2c78a95..d852642 100644 --- a/cpp/tests/test_helpers.hpp +++ b/cpp/tests/test_helpers.hpp @@ -52,20 +52,20 @@ namespace test inline void check_domain_name(const Domain& domain, const char* expected) { - if (domain.native_handle() == nullptr) + if (domain.get() == nullptr) { return; // no collector attached — nothing to verify } - CHECK_STR_EQ(domain.native_handle()->nameA, expected); + CHECK_STR_EQ(domain.get()->nameA, expected); } inline void check_string_handle_name(const StringHandle& handle, const char* expected) { - if (handle.native_handle() == nullptr) + if (handle.get() == nullptr) { return; // no collector attached — nothing to verify } - CHECK_STR_EQ(handle.native_handle()->strA, expected); + CHECK_STR_EQ(handle.get()->strA, expected); } inline void check_id_fields(const __itt_id& id, diff --git a/docs/src/itt-api-cpp-wrapper.rst b/docs/src/itt-api-cpp-wrapper.rst index 0fd6c4f..3a76f33 100644 --- a/docs/src/itt-api-cpp-wrapper.rst +++ b/docs/src/itt-api-cpp-wrapper.rst @@ -154,8 +154,8 @@ Lightweight wrapper around ``__itt_string_handle*``. .. code-block:: cpp ittapi::StringHandle h{"my_handle"}; - h.valid(); // true if handle was created - h.native_handle(); // underlying __itt_string_handle* + h.valid(); // true if handle was created + h.get(); // underlying __itt_string_handle* ittapi::Domain """""""""""""" @@ -205,7 +205,7 @@ RAII wrapper for frame begin/end. Supports explicit timestamp submission. .. code-block:: cpp - ittapi::ScopedFrame::submit(domain.native_handle(), begin_ts, end_ts); + ittapi::ScopedFrame::submit(domain.get(), begin_ts, end_ts); ittapi::ScopedPause """"""""""""""""""" From 847404a7d49cd15846664c336e79e44563d90bae Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Tue, 21 Apr 2026 10:22:36 -0500 Subject: [PATCH 27/33] fix windows build --- cpp/include/ittapi_utils.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/include/ittapi_utils.hpp b/cpp/include/ittapi_utils.hpp index 9a2219e..7dfe7a6 100644 --- a/cpp/include/ittapi_utils.hpp +++ b/cpp/include/ittapi_utils.hpp @@ -82,7 +82,7 @@ inline __itt_string_handle* get_or_create_string_handle(std::wstring_view name) __itt_string_handle* h = create_string_handle(std::wstring(name).c_str()); if (h != nullptr) { - cache.emplace(h->strW, h); + cache.emplace(static_cast(h->strW), h); } return h; } From ecf663034a35d5cc7e3e3f48695da7cc1bfa4e97 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Thu, 23 Apr 2026 05:09:20 -0500 Subject: [PATCH 28/33] add overlapped task api support --- cpp/README.md | 29 +++++++++++++++++++++++-- cpp/include/ittapi_domain.hpp | 11 +++++++--- cpp/include/ittapi_task.hpp | 31 ++++++++++++++++++++++---- cpp/samples/task_sample.cpp | 18 +++++++++++++--- cpp/tests/test_task.cpp | 37 +++++++++++++++++++++++++++++++- docs/src/itt-api-cpp-wrapper.rst | 30 ++++++++++++++++++++++++-- 6 files changed, 141 insertions(+), 15 deletions(-) diff --git a/cpp/README.md b/cpp/README.md index 653c069..1c63f67 100644 --- a/cpp/README.md +++ b/cpp/README.md @@ -137,15 +137,20 @@ 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 begin +d.task_begin("work"); // manual begin (stack-based) d.task_end(); // manual end + +__itt_id id = __itt_id_make(nullptr, 1); +d.task_begin("overlapped", id, __itt_null); // manual begin (overlapped) +d.task_end(id); // manual end by ID ``` #### `ittapi::ScopedTask` -RAII wrapper for task begin/end. +RAII wrapper for task begin/end. Without IDs, uses stack-based task API. With IDs, uses overlapped task API (tasks can end in any order). ```cpp +// Stack-based task (no ID) { auto task = domain.task("work"); // ... do work ... @@ -153,12 +158,32 @@ RAII wrapper for task begin/end. } // destructor ends task if still active ``` +Overlapped tasks with IDs — safe to end in any order: + +```cpp +{ + __itt_id parent_id = __itt_id_make(nullptr, 1); + auto parent = domain.task("parent", parent_id, __itt_null); + + __itt_id child_id = __itt_id_make(nullptr, 2); + auto child = domain.task("child", child_id, parent_id); + + parent.end(); // end parent while child is still running +} // child ends here via destructor +``` + For manual (non-RAII) control: ```cpp domain.task_begin("work"); // ... do work ... domain.task_end(); + +// Or with 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` diff --git a/cpp/include/ittapi_domain.hpp b/cpp/include/ittapi_domain.hpp index 456cd36..376a075 100644 --- a/cpp/include/ittapi_domain.hpp +++ b/cpp/include/ittapi_domain.hpp @@ -100,7 +100,7 @@ class Domain void task_begin(std::string_view name, __itt_id taskid, __itt_id parentid) const { __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_task_begin(m_domain, taskid, parentid, h); + __itt_task_begin_overlapped(m_domain, taskid, parentid, h); } #if ITT_PLATFORM == ITT_PLATFORM_WIN @@ -113,7 +113,7 @@ class Domain void task_begin(std::wstring_view name, __itt_id taskid, __itt_id parentid) const { __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_task_begin(m_domain, taskid, parentid, h); + __itt_task_begin_overlapped(m_domain, taskid, parentid, h); } #endif @@ -124,7 +124,7 @@ class Domain void task_begin(const StringHandle& name, __itt_id taskid, __itt_id parentid) const noexcept { - __itt_task_begin(m_domain, taskid, parentid, name.get()); + __itt_task_begin_overlapped(m_domain, taskid, parentid, name.get()); } void task_end() const noexcept @@ -132,6 +132,11 @@ class Domain __itt_task_end(m_domain); } + void task_end(__itt_id taskid) const noexcept + { + __itt_task_end_overlapped(m_domain, taskid); + } + [[nodiscard]] ScopedRegion region(std::string_view name) const { return ScopedRegion(m_domain, name); diff --git a/cpp/include/ittapi_task.hpp b/cpp/include/ittapi_task.hpp index 820778c..5ddb9d8 100644 --- a/cpp/include/ittapi_task.hpp +++ b/cpp/include/ittapi_task.hpp @@ -22,6 +22,8 @@ class ScopedTask public: ScopedTask(const __itt_domain* domain, std::string_view name) : m_domain(domain) + , m_taskid(detail::make_null_id()) + , m_overlapped(false) , m_active(true) { __itt_string_handle* h = detail::get_or_create_string_handle(name); @@ -31,15 +33,19 @@ class ScopedTask ScopedTask(const __itt_domain* domain, std::string_view name, __itt_id taskid, __itt_id parentid) : m_domain(domain) + , m_taskid(taskid) + , m_overlapped(true) , m_active(true) { __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_task_begin(m_domain, taskid, parentid, h); + __itt_task_begin_overlapped(m_domain, m_taskid, parentid, h); } #if ITT_PLATFORM == ITT_PLATFORM_WIN ScopedTask(const __itt_domain* domain, std::wstring_view name) : m_domain(domain) + , m_taskid(detail::make_null_id()) + , m_overlapped(false) , m_active(true) { __itt_string_handle* h = detail::get_or_create_string_handle(name); @@ -49,15 +55,19 @@ class ScopedTask ScopedTask(const __itt_domain* domain, std::wstring_view name, __itt_id taskid, __itt_id parentid) : m_domain(domain) + , m_taskid(taskid) + , m_overlapped(true) , m_active(true) { __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_task_begin(m_domain, taskid, parentid, h); + __itt_task_begin_overlapped(m_domain, m_taskid, parentid, h); } #endif ScopedTask(const __itt_domain* domain, const StringHandle& name) noexcept : m_domain(domain) + , m_taskid(detail::make_null_id()) + , m_overlapped(false) , m_active(true) { __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), name.get()); @@ -66,9 +76,11 @@ class ScopedTask ScopedTask(const __itt_domain* domain, const StringHandle& name, __itt_id taskid, __itt_id parentid) noexcept : m_domain(domain) + , m_taskid(taskid) + , m_overlapped(true) , m_active(true) { - __itt_task_begin(m_domain, taskid, parentid, name.get()); + __itt_task_begin_overlapped(m_domain, m_taskid, parentid, name.get()); } ScopedTask(const ScopedTask&) = delete; @@ -77,6 +89,8 @@ class ScopedTask ScopedTask(ScopedTask&& other) noexcept : m_domain(other.m_domain) + , m_taskid(other.m_taskid) + , m_overlapped(other.m_overlapped) , m_active(other.m_active) { other.m_active = false; @@ -91,7 +105,14 @@ class ScopedTask { if (m_active) { - __itt_task_end(m_domain); + if (m_overlapped) + { + __itt_task_end_overlapped(m_domain, m_taskid); + } + else + { + __itt_task_end(m_domain); + } m_active = false; } } @@ -103,6 +124,8 @@ class ScopedTask private: const __itt_domain* m_domain = nullptr; + __itt_id m_taskid{}; + bool m_overlapped = false; bool m_active = false; }; diff --git a/cpp/samples/task_sample.cpp b/cpp/samples/task_sample.cpp index 5c78240..c8cc371 100644 --- a/cpp/samples/task_sample.cpp +++ b/cpp/samples/task_sample.cpp @@ -45,21 +45,33 @@ int main() task.end(); // end early, destructor is a no-op } - // Scoped task with IDs for parent-child relationships + // Overlapped tasks with IDs — parent and child can end in any order { __itt_id parent_id = __itt_id_make(nullptr, 1); auto parent = domain.task("parent_task", parent_id, __itt_null); + simulate_work(3); __itt_id child_id = __itt_id_make(nullptr, 2); auto child = domain.task("child_task", child_id, parent_id); simulate_work(5); - } - // Manual task begin/end (non-RAII) + parent.end(); // end parent while child is still running + simulate_work(2); + } // child ends here via destructor + + // Manual task begin/end (non-RAII, stack-based) domain.task_begin("manual_work"); simulate_work(5); domain.task_end(); + // Manual overlapped task begin/end (ID-based) + { + __itt_id id = __itt_id_make(nullptr, 3); + domain.task_begin("overlapped_manual", id, __itt_null); + simulate_work(5); + domain.task_end(id); + } + // Scoped region { auto region = domain.region("init_phase"); diff --git a/cpp/tests/test_task.cpp b/cpp/tests/test_task.cpp index 9e10a18..c13f868 100644 --- a/cpp/tests/test_task.cpp +++ b/cpp/tests/test_task.cpp @@ -105,7 +105,40 @@ static void test_manual_task_begin_end_with_ids() __itt_id parentid = __itt_null; d.task_begin("manual_ids_task", taskid, parentid); - d.task_end(); + d.task_end(taskid); +} + +static void test_overlapped_tasks_interleaved() +{ + ittapi::Domain d{"test.task.overlapped"}; + __itt_id id1 = __itt_id_make(nullptr, 100); + __itt_id id2 = __itt_id_make(nullptr, 200); + + // Start parent, start child, end parent, end child — only valid with overlapped + auto parent = d.task("parent", id1, __itt_null); + auto child = d.task("child", id2, id1); + + CHECK(parent.active()); + CHECK(child.active()); + + parent.end(); + CHECK(!parent.active()); + CHECK(child.active()); + + child.end(); + CHECK(!child.active()); +} + +static void test_overlapped_manual_interleaved() +{ + ittapi::Domain d{"test.task.overlapped_manual"}; + __itt_id id1 = __itt_id_make(nullptr, 300); + __itt_id id2 = __itt_id_make(nullptr, 400); + + d.task_begin("first", id1, __itt_null); + d.task_begin("second", id2, __itt_null); + d.task_end(id1); + d.task_end(id2); } int main() @@ -119,5 +152,7 @@ int main() test_scoped_task_with_ids(); test_scoped_task_with_ids_string_handle(); test_manual_task_begin_end_with_ids(); + test_overlapped_tasks_interleaved(); + test_overlapped_manual_interleaved(); return 0; } diff --git a/docs/src/itt-api-cpp-wrapper.rst b/docs/src/itt-api-cpp-wrapper.rst index 3a76f33..fb96177 100644 --- a/docs/src/itt-api-cpp-wrapper.rst +++ b/docs/src/itt-api-cpp-wrapper.rst @@ -169,22 +169,42 @@ Lightweight wrapper around ``__itt_domain*`` with convenience factories. auto region = d.region("region_name"); // returns ScopedRegion auto frame = d.frame(); // returns ScopedFrame - d.task_begin("work"); // manual begin + d.task_begin("work"); // manual begin (stack-based) d.task_end(); // manual end + __itt_id id = __itt_id_make(nullptr, 1); + d.task_begin("overlapped", id, __itt_null); // manual begin (overlapped) + d.task_end(id); // manual end by ID + ittapi::ScopedTask """""""""""""""""" -RAII wrapper for task begin/end. +RAII wrapper for task begin/end. Without IDs, uses stack-based task API. +With IDs, uses overlapped task API (tasks can end in any order). .. code-block:: cpp + // Stack-based task (no ID) { auto task = domain.task("work"); // ... do work ... task.end(); // optional early end (idempotent) } // destructor ends task if still active +Overlapped tasks with IDs — safe to end in any order: + +.. code-block:: cpp + + { + __itt_id parent_id = __itt_id_make(nullptr, 1); + auto parent = domain.task("parent", parent_id, __itt_null); + + __itt_id child_id = __itt_id_make(nullptr, 2); + auto child = domain.task("child", child_id, parent_id); + + parent.end(); // end parent while child is still running + } // child ends here via destructor + For manual (non-RAII) control: .. code-block:: cpp @@ -193,6 +213,12 @@ For manual (non-RAII) control: // ... do work ... domain.task_end(); + // Or with 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 """""""""""""""""""" From acec3f4c115b14d663f3f0ad6be9b8a9785fcb89 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Thu, 23 Apr 2026 05:26:03 -0500 Subject: [PATCH 29/33] improve documentation --- cpp/README.md | 32 ++++++++++++++++++++-------- cpp/samples/task_sample.cpp | 2 +- docs/src/itt-api-cpp-wrapper.rst | 36 ++++++++++++++++++++++++++------ 3 files changed, 54 insertions(+), 16 deletions(-) diff --git a/cpp/README.md b/cpp/README.md index 1c63f67..9e3222a 100644 --- a/cpp/README.md +++ b/cpp/README.md @@ -107,6 +107,20 @@ Tests are registered inside the `cpp/` subdirectory. After building: 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 @@ -123,8 +137,8 @@ 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* +h.valid(); // true if handle was created +h.get(); // underlying __itt_string_handle* ``` #### `ittapi::Domain` @@ -137,20 +151,20 @@ 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 begin (stack-based) -d.task_end(); // manual end +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 begin (overlapped) -d.task_end(id); // manual end by ID +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. Without IDs, uses stack-based task API. With IDs, uses overlapped task API (tasks can end in any order). +RAII wrapper for task begin/end. Without IDs, uses simple stack-based task API. With IDs, uses overlapped task API (tasks can end in any order). ```cpp -// Stack-based task (no ID) +// Simple task { auto task = domain.task("work"); // ... do work ... @@ -179,7 +193,7 @@ domain.task_begin("work"); // ... do work ... domain.task_end(); -// Or with overlapped tasks: +// overlapped tasks: __itt_id id = __itt_id_make(nullptr, 1); domain.task_begin("overlapped_work", id, __itt_null); // ... do work ... diff --git a/cpp/samples/task_sample.cpp b/cpp/samples/task_sample.cpp index c8cc371..aa8d2b6 100644 --- a/cpp/samples/task_sample.cpp +++ b/cpp/samples/task_sample.cpp @@ -59,7 +59,7 @@ int main() simulate_work(2); } // child ends here via destructor - // Manual task begin/end (non-RAII, stack-based) + // Manual task begin/end (non-RAII, simple task) domain.task_begin("manual_work"); simulate_work(5); domain.task_end(); diff --git a/docs/src/itt-api-cpp-wrapper.rst b/docs/src/itt-api-cpp-wrapper.rst index fb96177..2975cf9 100644 --- a/docs/src/itt-api-cpp-wrapper.rst +++ b/docs/src/itt-api-cpp-wrapper.rst @@ -133,6 +133,30 @@ Tests are registered inside the ``cpp/`` subdirectory. After building: 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. + + .. code-block:: 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 ------------- @@ -169,22 +193,22 @@ Lightweight wrapper around ``__itt_domain*`` with convenience factories. auto region = d.region("region_name"); // returns ScopedRegion auto frame = d.frame(); // returns ScopedFrame - d.task_begin("work"); // manual begin (stack-based) - d.task_end(); // manual end + d.task_begin("work"); // manual task begin (simple stack-based) + d.task_end(); // manual task end __itt_id id = __itt_id_make(nullptr, 1); - d.task_begin("overlapped", id, __itt_null); // manual begin (overlapped) - d.task_end(id); // manual end by ID + d.task_begin("overlapped", id, __itt_null); // manual task begin (overlapped) + d.task_end(id); // manual task end by ID ittapi::ScopedTask """""""""""""""""" -RAII wrapper for task begin/end. Without IDs, uses stack-based task API. +RAII wrapper for task begin/end. Without IDs, uses simple stack-based task API. With IDs, uses overlapped task API (tasks can end in any order). .. code-block:: cpp - // Stack-based task (no ID) + // Simple task { auto task = domain.task("work"); // ... do work ... From 062e2625ba4a5267855401a9ad781086f55ef64a Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Thu, 23 Apr 2026 07:28:21 -0500 Subject: [PATCH 30/33] add itt id auto generation --- cpp/README.md | 16 ++++---- cpp/include/ittapi_domain.hpp | 24 +++++++++-- cpp/include/ittapi_frame.hpp | 4 +- cpp/include/ittapi_region.hpp | 12 +++--- cpp/include/ittapi_task.hpp | 70 +++++++++++++++++++++++++++++--- cpp/include/ittapi_utils.hpp | 9 +++- cpp/samples/task_sample.cpp | 10 ++--- cpp/tests/test_task.cpp | 38 +++++++++++++++++ docs/src/itt-api-cpp-wrapper.rst | 18 ++++++-- 9 files changed, 165 insertions(+), 36 deletions(-) diff --git a/cpp/README.md b/cpp/README.md index 9e3222a..e36cc41 100644 --- a/cpp/README.md +++ b/cpp/README.md @@ -161,7 +161,7 @@ d.task_end(id); // manual task end by ID #### `ittapi::ScopedTask` -RAII wrapper for task begin/end. Without IDs, uses simple stack-based task API. With IDs, uses overlapped task API (tasks can end in any order). +RAII wrapper for task begin/end. Pass `true` as the second argument to create an overlapped task (tasks that can end in any order). The `id()` method returns the task's auto-generated `__itt_id`. ```cpp // Simple task @@ -172,18 +172,16 @@ RAII wrapper for task begin/end. Without IDs, uses simple stack-based task API. } // destructor ends task if still active ``` -Overlapped tasks with IDs — safe to end in any order: +Overlapped tasks — pass `true` to enable, optionally pass a parent ID: ```cpp { - __itt_id parent_id = __itt_id_make(nullptr, 1); - auto parent = domain.task("parent", parent_id, __itt_null); + auto parent = domain.task("parent", true); // overlapped, no parent + auto child = domain.task("child", true, parent.id()); // overlapped, child of parent - __itt_id child_id = __itt_id_make(nullptr, 2); - auto child = domain.task("child", child_id, parent_id); - - parent.end(); // end parent while child is still running -} // child ends here via destructor + parent.end(); // end parent task while child is still running + child.end(); // child task ends +} ``` For manual (non-RAII) control: diff --git a/cpp/include/ittapi_domain.hpp b/cpp/include/ittapi_domain.hpp index 376a075..5a14cb0 100644 --- a/cpp/include/ittapi_domain.hpp +++ b/cpp/include/ittapi_domain.hpp @@ -64,6 +64,12 @@ class Domain return ScopedTask(m_domain, name); } + [[nodiscard]] ScopedTask task(std::string_view name, + bool overlapped, __itt_id parentid = detail::get_null_id()) const + { + return ScopedTask(m_domain, name, overlapped, parentid); + } + [[nodiscard]] ScopedTask task(std::string_view name, __itt_id taskid, __itt_id parentid) const { return ScopedTask(m_domain, name, taskid, parentid); @@ -75,6 +81,12 @@ class Domain return ScopedTask(m_domain, name); } + [[nodiscard]] ScopedTask task(std::wstring_view name, + bool overlapped, __itt_id parentid = detail::get_null_id()) const + { + return ScopedTask(m_domain, name, overlapped, parentid); + } + [[nodiscard]] ScopedTask task(std::wstring_view name, __itt_id taskid, __itt_id parentid) const { return ScopedTask(m_domain, name, taskid, parentid); @@ -86,6 +98,12 @@ class Domain return ScopedTask(m_domain, name); } + [[nodiscard]] ScopedTask task(const StringHandle& name, + bool overlapped, __itt_id parentid = detail::get_null_id()) const noexcept + { + return ScopedTask(m_domain, name, overlapped, parentid); + } + [[nodiscard]] ScopedTask task(const StringHandle& name, __itt_id taskid, __itt_id parentid) const noexcept { return ScopedTask(m_domain, name, taskid, parentid); @@ -94,7 +112,7 @@ class Domain void task_begin(std::string_view name) const { __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), h); + __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), h); } void task_begin(std::string_view name, __itt_id taskid, __itt_id parentid) const @@ -107,7 +125,7 @@ class Domain void task_begin(std::wstring_view name) const { __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), h); + __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), h); } void task_begin(std::wstring_view name, __itt_id taskid, __itt_id parentid) const @@ -119,7 +137,7 @@ class Domain void task_begin(const StringHandle& name) const noexcept { - __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), name.get()); + __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), name.get()); } void task_begin(const StringHandle& name, __itt_id taskid, __itt_id parentid) const noexcept diff --git a/cpp/include/ittapi_frame.hpp b/cpp/include/ittapi_frame.hpp index f2af84e..8fecc2f 100644 --- a/cpp/include/ittapi_frame.hpp +++ b/cpp/include/ittapi_frame.hpp @@ -18,7 +18,7 @@ class ScopedFrame public: explicit ScopedFrame(const __itt_domain* domain) noexcept : m_domain(domain) - , m_id(detail::make_null_id()) + , m_id(detail::get_null_id()) , m_active(true) { __itt_frame_begin_v3(m_domain, &m_id); @@ -57,7 +57,7 @@ class ScopedFrame static void submit(const __itt_domain* domain, __itt_timestamp begin, __itt_timestamp end) noexcept { - __itt_id id = detail::make_null_id(); + __itt_id id = detail::get_null_id(); __itt_frame_submit_v3(domain, &id, begin, end); } diff --git a/cpp/include/ittapi_region.hpp b/cpp/include/ittapi_region.hpp index 10ba040..41f071f 100644 --- a/cpp/include/ittapi_region.hpp +++ b/cpp/include/ittapi_region.hpp @@ -22,11 +22,11 @@ class ScopedRegion public: ScopedRegion(const __itt_domain* domain, std::string_view name) : m_domain(domain) - , m_id(detail::make_null_id()) + , m_id(detail::get_null_id()) , m_active(true) { __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_region_begin(m_domain, m_id, detail::make_null_id(), h); + __itt_region_begin(m_domain, m_id, detail::get_null_id(), h); } ScopedRegion(const __itt_domain* domain, std::string_view name, @@ -42,11 +42,11 @@ class ScopedRegion #if ITT_PLATFORM == ITT_PLATFORM_WIN ScopedRegion(const __itt_domain* domain, std::wstring_view name) : m_domain(domain) - , m_id(detail::make_null_id()) + , m_id(detail::get_null_id()) , m_active(true) { __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_region_begin(m_domain, m_id, detail::make_null_id(), h); + __itt_region_begin(m_domain, m_id, detail::get_null_id(), h); } ScopedRegion(const __itt_domain* domain, std::wstring_view name, @@ -62,10 +62,10 @@ class ScopedRegion ScopedRegion(const __itt_domain* domain, const StringHandle& name) noexcept : m_domain(domain) - , m_id(detail::make_null_id()) + , m_id(detail::get_null_id()) , m_active(true) { - __itt_region_begin(m_domain, m_id, detail::make_null_id(), name.get()); + __itt_region_begin(m_domain, m_id, detail::get_null_id(), name.get()); } ScopedRegion(const __itt_domain* domain, const StringHandle& name, diff --git a/cpp/include/ittapi_task.hpp b/cpp/include/ittapi_task.hpp index 5ddb9d8..c33657a 100644 --- a/cpp/include/ittapi_task.hpp +++ b/cpp/include/ittapi_task.hpp @@ -22,12 +22,30 @@ class ScopedTask public: ScopedTask(const __itt_domain* domain, std::string_view name) : m_domain(domain) - , m_taskid(detail::make_null_id()) + , m_taskid(detail::get_null_id()) , m_overlapped(false) , m_active(true) { __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), h); + __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), h); + } + + ScopedTask(const __itt_domain* domain, std::string_view name, + bool overlapped, __itt_id parentid = detail::get_null_id()) + : m_domain(domain) + , m_taskid(overlapped ? detail::gen_id() : detail::get_null_id()) + , m_overlapped(overlapped) + , m_active(true) + { + __itt_string_handle* h = detail::get_or_create_string_handle(name); + if (m_overlapped) + { + __itt_task_begin_overlapped(m_domain, m_taskid, parentid, h); + } + else + { + __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), h); + } } ScopedTask(const __itt_domain* domain, std::string_view name, @@ -44,12 +62,30 @@ class ScopedTask #if ITT_PLATFORM == ITT_PLATFORM_WIN ScopedTask(const __itt_domain* domain, std::wstring_view name) : m_domain(domain) - , m_taskid(detail::make_null_id()) + , m_taskid(detail::get_null_id()) , m_overlapped(false) , m_active(true) { __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), h); + __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), h); + } + + ScopedTask(const __itt_domain* domain, std::wstring_view name, + bool overlapped, __itt_id parentid = detail::get_null_id()) + : m_domain(domain) + , m_taskid(overlapped ? detail::gen_id() : detail::get_null_id()) + , m_overlapped(overlapped) + , m_active(true) + { + __itt_string_handle* h = detail::get_or_create_string_handle(name); + if (m_overlapped) + { + __itt_task_begin_overlapped(m_domain, m_taskid, parentid, h); + } + else + { + __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), h); + } } ScopedTask(const __itt_domain* domain, std::wstring_view name, @@ -66,11 +102,28 @@ class ScopedTask ScopedTask(const __itt_domain* domain, const StringHandle& name) noexcept : m_domain(domain) - , m_taskid(detail::make_null_id()) + , m_taskid(detail::get_null_id()) , m_overlapped(false) , m_active(true) { - __itt_task_begin(m_domain, detail::make_null_id(), detail::make_null_id(), name.get()); + __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), name.get()); + } + + ScopedTask(const __itt_domain* domain, const StringHandle& name, + bool overlapped, __itt_id parentid = detail::get_null_id()) noexcept + : m_domain(domain) + , m_taskid(overlapped ? detail::gen_id() : detail::get_null_id()) + , m_overlapped(overlapped) + , m_active(true) + { + if (m_overlapped) + { + __itt_task_begin_overlapped(m_domain, m_taskid, parentid, name.get()); + } + else + { + __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), name.get()); + } } ScopedTask(const __itt_domain* domain, const StringHandle& name, @@ -122,6 +175,11 @@ class ScopedTask return m_active; } + __itt_id id() const noexcept + { + return m_taskid; + } + private: const __itt_domain* m_domain = nullptr; __itt_id m_taskid{}; diff --git a/cpp/include/ittapi_utils.hpp b/cpp/include/ittapi_utils.hpp index 7dfe7a6..2bdd7bb 100644 --- a/cpp/include/ittapi_utils.hpp +++ b/cpp/include/ittapi_utils.hpp @@ -8,6 +8,7 @@ #include +#include #include #include @@ -94,12 +95,18 @@ inline void thread_set_name(const wchar_t* name) noexcept #endif // ITT_PLATFORM == ITT_PLATFORM_WIN -inline __itt_id make_null_id() noexcept +inline __itt_id get_null_id() noexcept { __itt_id id = __itt_null; return id; } +inline __itt_id gen_id() noexcept +{ + static std::atomic counter{1}; + return __itt_id_make(nullptr, counter.fetch_add(1, std::memory_order_relaxed)); +} + } // namespace detail } // namespace ittapi diff --git a/cpp/samples/task_sample.cpp b/cpp/samples/task_sample.cpp index aa8d2b6..49724c0 100644 --- a/cpp/samples/task_sample.cpp +++ b/cpp/samples/task_sample.cpp @@ -47,16 +47,14 @@ int main() // Overlapped tasks with IDs — parent and child can end in any order { - __itt_id parent_id = __itt_id_make(nullptr, 1); - auto parent = domain.task("parent_task", parent_id, __itt_null); - simulate_work(3); + auto parent = domain.task("parent_task", true); + simulate_work(5); - __itt_id child_id = __itt_id_make(nullptr, 2); - auto child = domain.task("child_task", child_id, parent_id); + auto child = domain.task("child_task", true, parent.id()); simulate_work(5); parent.end(); // end parent while child is still running - simulate_work(2); + simulate_work(5); } // child ends here via destructor // Manual task begin/end (non-RAII, simple task) diff --git a/cpp/tests/test_task.cpp b/cpp/tests/test_task.cpp index c13f868..a4a2562 100644 --- a/cpp/tests/test_task.cpp +++ b/cpp/tests/test_task.cpp @@ -141,6 +141,41 @@ static void test_overlapped_manual_interleaved() d.task_end(id2); } +static void test_overlapped_auto_id() +{ + ittapi::Domain d{"test.task.auto_id"}; + auto task = d.task("work", true); + CHECK(task.active()); + __itt_id tid = task.id(); + CHECK(tid.d2 != 0); +} + +static void test_overlapped_auto_id_parent_child() +{ + ittapi::Domain d{"test.task.auto_parent_child"}; + auto parent = d.task("parent", true); + auto child = d.task("child", true, parent.id()); + + CHECK(parent.active()); + CHECK(child.active()); + CHECK(parent.id().d2 != child.id().d2); + + parent.end(); + CHECK(!parent.active()); + CHECK(child.active()); + + child.end(); + CHECK(!child.active()); +} + +static void test_non_overlapped_id_is_null() +{ + ittapi::Domain d{"test.task.non_overlapped_id"}; + auto task = d.task("simple"); + __itt_id tid = task.id(); + CHECK(tid.d1 == 0 && tid.d2 == 0 && tid.d3 == 0); +} + int main() { test_scoped_task_lifecycle(); @@ -154,5 +189,8 @@ int main() test_manual_task_begin_end_with_ids(); test_overlapped_tasks_interleaved(); test_overlapped_manual_interleaved(); + test_overlapped_auto_id(); + test_overlapped_auto_id_parent_child(); + test_non_overlapped_id_is_null(); return 0; } diff --git a/docs/src/itt-api-cpp-wrapper.rst b/docs/src/itt-api-cpp-wrapper.rst index 2975cf9..b61aa03 100644 --- a/docs/src/itt-api-cpp-wrapper.rst +++ b/docs/src/itt-api-cpp-wrapper.rst @@ -203,8 +203,9 @@ Lightweight wrapper around ``__itt_domain*`` with convenience factories. ittapi::ScopedTask """""""""""""""""" -RAII wrapper for task begin/end. Without IDs, uses simple stack-based task API. -With IDs, uses overlapped task API (tasks can end in any order). +RAII wrapper for task begin/end. Pass ``true`` as the second argument to create +an overlapped task (tasks that can end in any order). The ``id()`` method returns +the task's auto-generated ``__itt_id``. .. code-block:: cpp @@ -215,7 +216,18 @@ With IDs, uses overlapped task API (tasks can end in any order). task.end(); // optional early end (idempotent) } // destructor ends task if still active -Overlapped tasks with IDs — safe to end in any order: +Overlapped tasks — pass ``true`` to enable, optionally pass a parent ID: + +.. code-block:: cpp + + { + auto parent = domain.task("parent", true); // overlapped, no parent + auto child = domain.task("child", true, parent.id()); // overlapped, child of parent + + parent.end(); // end parent while child is still running + } // child ends here via destructor + +Overlapped tasks with explicit IDs (advanced): .. code-block:: cpp From 9bbc142abd8bb1368300ced40c0a429cd72604c7 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Thu, 23 Apr 2026 14:20:29 -0500 Subject: [PATCH 31/33] add new overlapped_task() api in domain --- cpp/README.md | 8 ++--- cpp/include/ittapi_domain.hpp | 18 +++++------ cpp/include/ittapi_task.hpp | 53 -------------------------------- cpp/samples/task_sample.cpp | 6 ++-- cpp/tests/test_task.cpp | 6 ++-- docs/src/itt-api-cpp-wrapper.rst | 8 ++--- 6 files changed, 23 insertions(+), 76 deletions(-) diff --git a/cpp/README.md b/cpp/README.md index e36cc41..49cdf38 100644 --- a/cpp/README.md +++ b/cpp/README.md @@ -161,7 +161,7 @@ d.task_end(id); // manual task end by ID #### `ittapi::ScopedTask` -RAII wrapper for task begin/end. Pass `true` as the second argument to create an overlapped task (tasks that can end in any order). The `id()` method returns the task's auto-generated `__itt_id`. +RAII wrapper for task begin/end. Use `domain.overlapped_task()` to create an overlapped task (tasks that can end in any order). The `id()` method returns the task's auto-generated `__itt_id`. ```cpp // Simple task @@ -172,12 +172,12 @@ RAII wrapper for task begin/end. Pass `true` as the second argument to create an } // destructor ends task if still active ``` -Overlapped tasks — pass `true` to enable, optionally pass a parent ID: +Overlapped tasks — use `overlapped_task()`, optionally pass a parent ID: ```cpp { - auto parent = domain.task("parent", true); // overlapped, no parent - auto child = domain.task("child", true, parent.id()); // overlapped, child of parent + 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 diff --git a/cpp/include/ittapi_domain.hpp b/cpp/include/ittapi_domain.hpp index 5a14cb0..6f62bb5 100644 --- a/cpp/include/ittapi_domain.hpp +++ b/cpp/include/ittapi_domain.hpp @@ -64,10 +64,10 @@ class Domain return ScopedTask(m_domain, name); } - [[nodiscard]] ScopedTask task(std::string_view name, - bool overlapped, __itt_id parentid = detail::get_null_id()) const + [[nodiscard]] ScopedTask overlapped_task(std::string_view name, + __itt_id parentid = detail::get_null_id()) const { - return ScopedTask(m_domain, name, overlapped, parentid); + return ScopedTask(m_domain, name, detail::gen_id(), parentid); } [[nodiscard]] ScopedTask task(std::string_view name, __itt_id taskid, __itt_id parentid) const @@ -81,10 +81,10 @@ class Domain return ScopedTask(m_domain, name); } - [[nodiscard]] ScopedTask task(std::wstring_view name, - bool overlapped, __itt_id parentid = detail::get_null_id()) const + [[nodiscard]] ScopedTask overlapped_task(std::wstring_view name, + __itt_id parentid = detail::get_null_id()) const { - return ScopedTask(m_domain, name, overlapped, parentid); + return ScopedTask(m_domain, name, detail::gen_id(), parentid); } [[nodiscard]] ScopedTask task(std::wstring_view name, __itt_id taskid, __itt_id parentid) const @@ -98,10 +98,10 @@ class Domain return ScopedTask(m_domain, name); } - [[nodiscard]] ScopedTask task(const StringHandle& name, - bool overlapped, __itt_id parentid = detail::get_null_id()) const noexcept + [[nodiscard]] ScopedTask overlapped_task(const StringHandle& name, + __itt_id parentid = detail::get_null_id()) const noexcept { - return ScopedTask(m_domain, name, overlapped, parentid); + return ScopedTask(m_domain, name, detail::gen_id(), parentid); } [[nodiscard]] ScopedTask task(const StringHandle& name, __itt_id taskid, __itt_id parentid) const noexcept diff --git a/cpp/include/ittapi_task.hpp b/cpp/include/ittapi_task.hpp index c33657a..e7b58f8 100644 --- a/cpp/include/ittapi_task.hpp +++ b/cpp/include/ittapi_task.hpp @@ -30,24 +30,6 @@ class ScopedTask __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), h); } - ScopedTask(const __itt_domain* domain, std::string_view name, - bool overlapped, __itt_id parentid = detail::get_null_id()) - : m_domain(domain) - , m_taskid(overlapped ? detail::gen_id() : detail::get_null_id()) - , m_overlapped(overlapped) - , m_active(true) - { - __itt_string_handle* h = detail::get_or_create_string_handle(name); - if (m_overlapped) - { - __itt_task_begin_overlapped(m_domain, m_taskid, parentid, h); - } - else - { - __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), h); - } - } - ScopedTask(const __itt_domain* domain, std::string_view name, __itt_id taskid, __itt_id parentid) : m_domain(domain) @@ -70,24 +52,6 @@ class ScopedTask __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), h); } - ScopedTask(const __itt_domain* domain, std::wstring_view name, - bool overlapped, __itt_id parentid = detail::get_null_id()) - : m_domain(domain) - , m_taskid(overlapped ? detail::gen_id() : detail::get_null_id()) - , m_overlapped(overlapped) - , m_active(true) - { - __itt_string_handle* h = detail::get_or_create_string_handle(name); - if (m_overlapped) - { - __itt_task_begin_overlapped(m_domain, m_taskid, parentid, h); - } - else - { - __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), h); - } - } - ScopedTask(const __itt_domain* domain, std::wstring_view name, __itt_id taskid, __itt_id parentid) : m_domain(domain) @@ -109,23 +73,6 @@ class ScopedTask __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), name.get()); } - ScopedTask(const __itt_domain* domain, const StringHandle& name, - bool overlapped, __itt_id parentid = detail::get_null_id()) noexcept - : m_domain(domain) - , m_taskid(overlapped ? detail::gen_id() : detail::get_null_id()) - , m_overlapped(overlapped) - , m_active(true) - { - if (m_overlapped) - { - __itt_task_begin_overlapped(m_domain, m_taskid, parentid, name.get()); - } - else - { - __itt_task_begin(m_domain, detail::get_null_id(), detail::get_null_id(), name.get()); - } - } - ScopedTask(const __itt_domain* domain, const StringHandle& name, __itt_id taskid, __itt_id parentid) noexcept : m_domain(domain) diff --git a/cpp/samples/task_sample.cpp b/cpp/samples/task_sample.cpp index 49724c0..4fec496 100644 --- a/cpp/samples/task_sample.cpp +++ b/cpp/samples/task_sample.cpp @@ -45,12 +45,12 @@ int main() task.end(); // end early, destructor is a no-op } - // Overlapped tasks with IDs — parent and child can end in any order + // Overlapped tasks — parent and child can end in any order { - auto parent = domain.task("parent_task", true); + auto parent = domain.overlapped_task("parent_task"); simulate_work(5); - auto child = domain.task("child_task", true, parent.id()); + auto child = domain.overlapped_task("child_task", parent.id()); simulate_work(5); parent.end(); // end parent while child is still running diff --git a/cpp/tests/test_task.cpp b/cpp/tests/test_task.cpp index a4a2562..ed76a3e 100644 --- a/cpp/tests/test_task.cpp +++ b/cpp/tests/test_task.cpp @@ -144,7 +144,7 @@ static void test_overlapped_manual_interleaved() static void test_overlapped_auto_id() { ittapi::Domain d{"test.task.auto_id"}; - auto task = d.task("work", true); + auto task = d.overlapped_task("work"); CHECK(task.active()); __itt_id tid = task.id(); CHECK(tid.d2 != 0); @@ -153,8 +153,8 @@ static void test_overlapped_auto_id() static void test_overlapped_auto_id_parent_child() { ittapi::Domain d{"test.task.auto_parent_child"}; - auto parent = d.task("parent", true); - auto child = d.task("child", true, parent.id()); + auto parent = d.overlapped_task("parent"); + auto child = d.overlapped_task("child", parent.id()); CHECK(parent.active()); CHECK(child.active()); diff --git a/docs/src/itt-api-cpp-wrapper.rst b/docs/src/itt-api-cpp-wrapper.rst index b61aa03..80224d4 100644 --- a/docs/src/itt-api-cpp-wrapper.rst +++ b/docs/src/itt-api-cpp-wrapper.rst @@ -203,7 +203,7 @@ Lightweight wrapper around ``__itt_domain*`` with convenience factories. ittapi::ScopedTask """""""""""""""""" -RAII wrapper for task begin/end. Pass ``true`` as the second argument to create +RAII wrapper for task begin/end. Use ``domain.overlapped_task()`` to create an overlapped task (tasks that can end in any order). The ``id()`` method returns the task's auto-generated ``__itt_id``. @@ -216,13 +216,13 @@ the task's auto-generated ``__itt_id``. task.end(); // optional early end (idempotent) } // destructor ends task if still active -Overlapped tasks — pass ``true`` to enable, optionally pass a parent ID: +Overlapped tasks — use ``overlapped_task()``, optionally pass a parent ID: .. code-block:: cpp { - auto parent = domain.task("parent", true); // overlapped, no parent - auto child = domain.task("child", true, parent.id()); // overlapped, child of parent + 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 while child is still running } // child ends here via destructor From 851291264561e4c9bd159485b07c6ce36eae03f1 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Thu, 23 Apr 2026 15:19:04 -0500 Subject: [PATCH 32/33] add cache for overlapped task id storing --- cpp/README.md | 2 +- cpp/include/ittapi_domain.hpp | 9 ++++++--- cpp/include/ittapi_task.hpp | 10 ++++++++++ cpp/include/ittapi_utils.hpp | 14 ++++++++++++++ cpp/tests/test_task.cpp | 13 ++++++++++++- docs/src/itt-api-cpp-wrapper.rst | 5 +++-- 6 files changed, 46 insertions(+), 7 deletions(-) diff --git a/cpp/README.md b/cpp/README.md index 49cdf38..a8ab014 100644 --- a/cpp/README.md +++ b/cpp/README.md @@ -161,7 +161,7 @@ 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). The `id()` method returns the task's auto-generated `__itt_id`. +RAII wrapper for task begin/end. Use `domain.overlapped_task()` to create an overlapped task (tasks that can end in any order). Overlapped tasks with the same name on the same thread share a single `__itt_id`, generated automatically on first use. The `id()` method returns this ID. ```cpp // Simple task diff --git a/cpp/include/ittapi_domain.hpp b/cpp/include/ittapi_domain.hpp index 6f62bb5..6b9d09e 100644 --- a/cpp/include/ittapi_domain.hpp +++ b/cpp/include/ittapi_domain.hpp @@ -67,7 +67,8 @@ class Domain [[nodiscard]] ScopedTask overlapped_task(std::string_view name, __itt_id parentid = detail::get_null_id()) const { - return ScopedTask(m_domain, name, detail::gen_id(), parentid); + __itt_string_handle* h = detail::get_or_create_string_handle(name); + return ScopedTask(m_domain, h, detail::get_or_create_task_id(h), parentid); } [[nodiscard]] ScopedTask task(std::string_view name, __itt_id taskid, __itt_id parentid) const @@ -84,7 +85,8 @@ class Domain [[nodiscard]] ScopedTask overlapped_task(std::wstring_view name, __itt_id parentid = detail::get_null_id()) const { - return ScopedTask(m_domain, name, detail::gen_id(), parentid); + __itt_string_handle* h = detail::get_or_create_string_handle(name); + return ScopedTask(m_domain, h, detail::get_or_create_task_id(h), parentid); } [[nodiscard]] ScopedTask task(std::wstring_view name, __itt_id taskid, __itt_id parentid) const @@ -101,7 +103,8 @@ class Domain [[nodiscard]] ScopedTask overlapped_task(const StringHandle& name, __itt_id parentid = detail::get_null_id()) const noexcept { - return ScopedTask(m_domain, name, detail::gen_id(), parentid); + __itt_string_handle* h = name.get(); + return ScopedTask(m_domain, h, detail::get_or_create_task_id(h), parentid); } [[nodiscard]] ScopedTask task(const StringHandle& name, __itt_id taskid, __itt_id parentid) const noexcept diff --git a/cpp/include/ittapi_task.hpp b/cpp/include/ittapi_task.hpp index e7b58f8..62e4fc0 100644 --- a/cpp/include/ittapi_task.hpp +++ b/cpp/include/ittapi_task.hpp @@ -41,6 +41,16 @@ class ScopedTask __itt_task_begin_overlapped(m_domain, m_taskid, parentid, h); } + ScopedTask(const __itt_domain* domain, __itt_string_handle* name, + __itt_id taskid, __itt_id parentid) noexcept + : m_domain(domain) + , m_taskid(taskid) + , m_overlapped(true) + , m_active(true) + { + __itt_task_begin_overlapped(m_domain, m_taskid, parentid, name); + } + #if ITT_PLATFORM == ITT_PLATFORM_WIN ScopedTask(const __itt_domain* domain, std::wstring_view name) : m_domain(domain) diff --git a/cpp/include/ittapi_utils.hpp b/cpp/include/ittapi_utils.hpp index 2bdd7bb..20b9b03 100644 --- a/cpp/include/ittapi_utils.hpp +++ b/cpp/include/ittapi_utils.hpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -107,6 +108,19 @@ inline __itt_id gen_id() noexcept return __itt_id_make(nullptr, counter.fetch_add(1, std::memory_order_relaxed)); } +inline __itt_id get_or_create_task_id(__itt_string_handle* h) noexcept +{ + thread_local std::unordered_map<__itt_string_handle*, __itt_id> cache; + auto it = cache.find(h); + if (it != cache.end()) + { + return it->second; + } + __itt_id id = gen_id(); + cache.emplace(h, id); + return id; +} + } // namespace detail } // namespace ittapi diff --git a/cpp/tests/test_task.cpp b/cpp/tests/test_task.cpp index ed76a3e..f527ac8 100644 --- a/cpp/tests/test_task.cpp +++ b/cpp/tests/test_task.cpp @@ -158,7 +158,6 @@ static void test_overlapped_auto_id_parent_child() CHECK(parent.active()); CHECK(child.active()); - CHECK(parent.id().d2 != child.id().d2); parent.end(); CHECK(!parent.active()); @@ -176,6 +175,17 @@ static void test_non_overlapped_id_is_null() CHECK(tid.d1 == 0 && tid.d2 == 0 && tid.d3 == 0); } +static void test_overlapped_same_name_same_id() +{ + ittapi::Domain d{"test.task.same_name_id"}; + auto task1 = d.overlapped_task("work"); + auto task2 = d.overlapped_task("work"); + + // Same name on the same thread must produce the same task ID + CHECK(task1.id().d2 == task2.id().d2); + CHECK(task1.id().d2 != 0); +} + int main() { test_scoped_task_lifecycle(); @@ -192,5 +202,6 @@ int main() test_overlapped_auto_id(); test_overlapped_auto_id_parent_child(); test_non_overlapped_id_is_null(); + test_overlapped_same_name_same_id(); return 0; } diff --git a/docs/src/itt-api-cpp-wrapper.rst b/docs/src/itt-api-cpp-wrapper.rst index 80224d4..c4ff077 100644 --- a/docs/src/itt-api-cpp-wrapper.rst +++ b/docs/src/itt-api-cpp-wrapper.rst @@ -204,8 +204,9 @@ ittapi::ScopedTask """""""""""""""""" RAII wrapper for task begin/end. Use ``domain.overlapped_task()`` to create -an overlapped task (tasks that can end in any order). The ``id()`` method returns -the task's auto-generated ``__itt_id``. +an overlapped task (tasks that can end in any order). Overlapped tasks with the +same name on the same thread share a single ``__itt_id``, generated automatically +on first use. The ``id()`` method returns this ID. .. code-block:: cpp From 5ccf4c5eb82c62b0abe573627c0e955b8e8664f5 Mon Sep 17 00:00:00 2001 From: "Parshutin, Eugeny" Date: Fri, 24 Apr 2026 09:31:16 -0500 Subject: [PATCH 33/33] fix id generation logic, cover more overlapped scenarios --- cpp/README.md | 2 +- cpp/include/ittapi_domain.hpp | 27 ++++++++++---- cpp/include/ittapi_task.hpp | 61 ++++++++++++++++++++++---------- cpp/include/ittapi_utils.hpp | 19 ++-------- cpp/tests/test_task.cpp | 20 ++--------- docs/src/itt-api-cpp-wrapper.rst | 6 ++-- 6 files changed, 72 insertions(+), 63 deletions(-) diff --git a/cpp/README.md b/cpp/README.md index a8ab014..71bf5c3 100644 --- a/cpp/README.md +++ b/cpp/README.md @@ -161,7 +161,7 @@ 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). Overlapped tasks with the same name on the same thread share a single `__itt_id`, generated automatically on first use. The `id()` method returns this ID. +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 diff --git a/cpp/include/ittapi_domain.hpp b/cpp/include/ittapi_domain.hpp index 6b9d09e..86d1746 100644 --- a/cpp/include/ittapi_domain.hpp +++ b/cpp/include/ittapi_domain.hpp @@ -67,8 +67,13 @@ class Domain [[nodiscard]] ScopedTask overlapped_task(std::string_view name, __itt_id parentid = detail::get_null_id()) const { - __itt_string_handle* h = detail::get_or_create_string_handle(name); - return ScopedTask(m_domain, h, detail::get_or_create_task_id(h), parentid); + return ScopedTask(m_domain, name, detail::get_null_id(), parentid, true); + } + + [[nodiscard]] ScopedTask overlapped_task(std::string_view name, + __itt_id taskid, __itt_id parentid) const + { + return ScopedTask(m_domain, name, taskid, parentid, true); } [[nodiscard]] ScopedTask task(std::string_view name, __itt_id taskid, __itt_id parentid) const @@ -85,8 +90,13 @@ class Domain [[nodiscard]] ScopedTask overlapped_task(std::wstring_view name, __itt_id parentid = detail::get_null_id()) const { - __itt_string_handle* h = detail::get_or_create_string_handle(name); - return ScopedTask(m_domain, h, detail::get_or_create_task_id(h), parentid); + return ScopedTask(m_domain, name, detail::get_null_id(), parentid, true); + } + + [[nodiscard]] ScopedTask overlapped_task(std::wstring_view name, + __itt_id taskid, __itt_id parentid) const + { + return ScopedTask(m_domain, name, taskid, parentid, true); } [[nodiscard]] ScopedTask task(std::wstring_view name, __itt_id taskid, __itt_id parentid) const @@ -103,8 +113,13 @@ class Domain [[nodiscard]] ScopedTask overlapped_task(const StringHandle& name, __itt_id parentid = detail::get_null_id()) const noexcept { - __itt_string_handle* h = name.get(); - return ScopedTask(m_domain, h, detail::get_or_create_task_id(h), parentid); + return ScopedTask(m_domain, name, detail::get_null_id(), parentid, true); + } + + [[nodiscard]] ScopedTask overlapped_task(const StringHandle& name, + __itt_id taskid, __itt_id parentid) const noexcept + { + return ScopedTask(m_domain, name, taskid, parentid, true); } [[nodiscard]] ScopedTask task(const StringHandle& name, __itt_id taskid, __itt_id parentid) const noexcept diff --git a/cpp/include/ittapi_task.hpp b/cpp/include/ittapi_task.hpp index 62e4fc0..7697d68 100644 --- a/cpp/include/ittapi_task.hpp +++ b/cpp/include/ittapi_task.hpp @@ -31,24 +31,25 @@ class ScopedTask } ScopedTask(const __itt_domain* domain, std::string_view name, - __itt_id taskid, __itt_id parentid) + __itt_id taskid, __itt_id parentid, bool overlapped = false) : m_domain(domain) , m_taskid(taskid) - , m_overlapped(true) + , m_overlapped(overlapped) , m_active(true) { + if (m_overlapped && detail::is_null_id(m_taskid)) + { + m_taskid = __itt_id_make(this, 0); + } __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_task_begin_overlapped(m_domain, m_taskid, parentid, h); - } - - ScopedTask(const __itt_domain* domain, __itt_string_handle* name, - __itt_id taskid, __itt_id parentid) noexcept - : m_domain(domain) - , m_taskid(taskid) - , m_overlapped(true) - , m_active(true) - { - __itt_task_begin_overlapped(m_domain, m_taskid, parentid, name); + if (m_overlapped) + { + __itt_task_begin_overlapped(m_domain, m_taskid, parentid, h); + } + else + { + __itt_task_begin(m_domain, m_taskid, parentid, h); + } } #if ITT_PLATFORM == ITT_PLATFORM_WIN @@ -63,14 +64,25 @@ class ScopedTask } ScopedTask(const __itt_domain* domain, std::wstring_view name, - __itt_id taskid, __itt_id parentid) + __itt_id taskid, __itt_id parentid, bool overlapped = false) : m_domain(domain) , m_taskid(taskid) - , m_overlapped(true) + , m_overlapped(overlapped) , m_active(true) { + if (m_overlapped && detail::is_null_id(m_taskid)) + { + m_taskid = __itt_id_make(this, 0); + } __itt_string_handle* h = detail::get_or_create_string_handle(name); - __itt_task_begin_overlapped(m_domain, m_taskid, parentid, h); + if (m_overlapped) + { + __itt_task_begin_overlapped(m_domain, m_taskid, parentid, h); + } + else + { + __itt_task_begin(m_domain, m_taskid, parentid, h); + } } #endif @@ -84,13 +96,24 @@ class ScopedTask } ScopedTask(const __itt_domain* domain, const StringHandle& name, - __itt_id taskid, __itt_id parentid) noexcept + __itt_id taskid, __itt_id parentid, bool overlapped = false) noexcept : m_domain(domain) , m_taskid(taskid) - , m_overlapped(true) + , m_overlapped(overlapped) , m_active(true) { - __itt_task_begin_overlapped(m_domain, m_taskid, parentid, name.get()); + if (m_overlapped && detail::is_null_id(m_taskid)) + { + m_taskid = __itt_id_make(this, 0); + } + if (m_overlapped) + { + __itt_task_begin_overlapped(m_domain, m_taskid, parentid, name.get()); + } + else + { + __itt_task_begin(m_domain, m_taskid, parentid, name.get()); + } } ScopedTask(const ScopedTask&) = delete; diff --git a/cpp/include/ittapi_utils.hpp b/cpp/include/ittapi_utils.hpp index 20b9b03..345239a 100644 --- a/cpp/include/ittapi_utils.hpp +++ b/cpp/include/ittapi_utils.hpp @@ -8,7 +8,6 @@ #include -#include #include #include #include @@ -102,23 +101,9 @@ inline __itt_id get_null_id() noexcept return id; } -inline __itt_id gen_id() noexcept +inline bool is_null_id(const __itt_id& id) noexcept { - static std::atomic counter{1}; - return __itt_id_make(nullptr, counter.fetch_add(1, std::memory_order_relaxed)); -} - -inline __itt_id get_or_create_task_id(__itt_string_handle* h) noexcept -{ - thread_local std::unordered_map<__itt_string_handle*, __itt_id> cache; - auto it = cache.find(h); - if (it != cache.end()) - { - return it->second; - } - __itt_id id = gen_id(); - cache.emplace(h, id); - return id; + return id.d1 == 0 && id.d2 == 0 && id.d3 == 0; } } // namespace detail diff --git a/cpp/tests/test_task.cpp b/cpp/tests/test_task.cpp index f527ac8..0d4785b 100644 --- a/cpp/tests/test_task.cpp +++ b/cpp/tests/test_task.cpp @@ -111,12 +111,10 @@ static void test_manual_task_begin_end_with_ids() static void test_overlapped_tasks_interleaved() { ittapi::Domain d{"test.task.overlapped"}; - __itt_id id1 = __itt_id_make(nullptr, 100); - __itt_id id2 = __itt_id_make(nullptr, 200); // Start parent, start child, end parent, end child — only valid with overlapped - auto parent = d.task("parent", id1, __itt_null); - auto child = d.task("child", id2, id1); + auto parent = d.overlapped_task("parent"); + auto child = d.overlapped_task("child", parent.id()); CHECK(parent.active()); CHECK(child.active()); @@ -147,7 +145,7 @@ static void test_overlapped_auto_id() auto task = d.overlapped_task("work"); CHECK(task.active()); __itt_id tid = task.id(); - CHECK(tid.d2 != 0); + CHECK(tid.d1 != 0); } static void test_overlapped_auto_id_parent_child() @@ -175,17 +173,6 @@ static void test_non_overlapped_id_is_null() CHECK(tid.d1 == 0 && tid.d2 == 0 && tid.d3 == 0); } -static void test_overlapped_same_name_same_id() -{ - ittapi::Domain d{"test.task.same_name_id"}; - auto task1 = d.overlapped_task("work"); - auto task2 = d.overlapped_task("work"); - - // Same name on the same thread must produce the same task ID - CHECK(task1.id().d2 == task2.id().d2); - CHECK(task1.id().d2 != 0); -} - int main() { test_scoped_task_lifecycle(); @@ -202,6 +189,5 @@ int main() test_overlapped_auto_id(); test_overlapped_auto_id_parent_child(); test_non_overlapped_id_is_null(); - test_overlapped_same_name_same_id(); return 0; } diff --git a/docs/src/itt-api-cpp-wrapper.rst b/docs/src/itt-api-cpp-wrapper.rst index c4ff077..313fd3b 100644 --- a/docs/src/itt-api-cpp-wrapper.rst +++ b/docs/src/itt-api-cpp-wrapper.rst @@ -204,9 +204,9 @@ ittapi::ScopedTask """""""""""""""""" RAII wrapper for task begin/end. Use ``domain.overlapped_task()`` to create -an overlapped task (tasks that can end in any order). Overlapped tasks with the -same name on the same thread share a single ``__itt_id``, generated automatically -on first use. The ``id()`` method returns this ID. +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. .. code-block:: cpp