|
|
|||
File indexing completed on 2026-05-10 08:45:13
0001 /* 0002 * SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. 0003 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 0004 * 0005 * Licensed under the Apache License, Version 2.0 (the "License"); 0006 * you may not use this file except in compliance with the License. 0007 * You may obtain a copy of the License at 0008 * 0009 * http://www.apache.org/licenses/LICENSE-2.0 0010 * 0011 * Unless required by applicable law or agreed to in writing, software 0012 * distributed under the License is distributed on an "AS IS" BASIS, 0013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0014 * See the License for the specific language governing permissions and 0015 * limitations under the License. 0016 * 0017 * Licensed under the Apache License v2.0 with LLVM Exceptions. 0018 * See https://nvidia.github.io/NVTX/LICENSE.txt for license information. 0019 */ 0020 0021 #if defined(NVTX_AS_SYSTEM_HEADER) 0022 #if defined(__clang__) 0023 #pragma clang system_header 0024 #elif defined(__GNUC__) || defined(__NVCOMPILER) 0025 #pragma GCC system_header 0026 #elif defined(_MSC_VER) 0027 #pragma system_header 0028 #endif 0029 #endif 0030 0031 /* Temporary helper #defines, #undef'ed at end of header */ 0032 #define NVTX3_CPP_VERSION_MAJOR 1 0033 #define NVTX3_CPP_VERSION_MINOR 1 0034 0035 /* This section handles the decision of whether to provide unversioned symbols. 0036 * If NVTX3_CPP_REQUIRE_EXPLICIT_VERSION is #defined, unversioned symbols are 0037 * not provided, and explicit-version symbols such as nvtx3::v1::scoped_range 0038 * and NVTX3_V1_FUNC_RANGE must be used. By default, the first #include of this 0039 * header will define the unversioned symbols such as nvtx3::scoped_range and 0040 * NVTX3_FUNC_RANGE. Subsequently including a different major version of this 0041 * header without #defining NVTX3_CPP_REQUIRE_EXPLICIT_VERSION triggers an error 0042 * since the symbols would conflict. Subsequently including of a different 0043 * minor version within the same major version is allowed. Functionality of 0044 * minor versions is cumulative, regardless of include order. 0045 * 0046 * Since NVTX3_CPP_REQUIRE_EXPLICIT_VERSION allows all combinations of versions 0047 * to coexist without problems within a translation unit, the recommended best 0048 * practice for instrumenting header-based libraries with NVTX C++ Wrappers is 0049 * is to #define NVTX3_CPP_REQUIRE_EXPLICIT_VERSION before including nvtx3.hpp, 0050 * #undef it afterward, and only use explicit-version symbols. This is not 0051 * necessary in common cases, such as instrumenting a standalone application, or 0052 * static/shared libraries in .cpp files or headers private to those projects. 0053 */ 0054 /* clang-format off */ 0055 #if !defined(NVTX3_CPP_REQUIRE_EXPLICIT_VERSION) 0056 /* Define macro used by all definitions in this header to indicate the 0057 * unversioned symbols should be defined in addition to the versioned ones. 0058 */ 0059 #define NVTX3_INLINE_THIS_VERSION 0060 0061 #if !defined(NVTX3_CPP_INLINED_VERSION_MAJOR) 0062 /* First occurrence of this header in the translation unit. Define macros 0063 * indicating which version shall be used for unversioned symbols. 0064 */ 0065 0066 /** 0067 * @brief Semantic major version number for NVTX C++ wrappers of unversioned symbols 0068 * 0069 * Breaking changes may occur between major versions, and different major versions 0070 * cannot provide unversioned symbols in the same translation unit (.cpp file). 0071 * 0072 * Note: If NVTX3_CPP_REQUIRE_EXPLICIT_VERSION is defined, this macro is not defined. 0073 * 0074 * Not to be confused with the version number of the NVTX core library. 0075 */ 0076 #define NVTX3_CPP_INLINED_VERSION_MAJOR 1 // NVTX3_CPP_VERSION_MAJOR 0077 0078 /** 0079 * @brief Semantic minor version number for NVTX C++ wrappers of unversioned symbols 0080 * 0081 * No breaking changes occur between minor versions -- minor version changes within 0082 * a major version are purely additive. 0083 * 0084 * Note: If NVTX3_CPP_REQUIRE_EXPLICIT_VERSION is defined, this macro is not defined. 0085 * 0086 * Not to be confused with the version number of the NVTX core library. 0087 */ 0088 #define NVTX3_CPP_INLINED_VERSION_MINOR 1 // NVTX3_CPP_VERSION_MINOR 0089 #elif NVTX3_CPP_INLINED_VERSION_MAJOR != NVTX3_CPP_VERSION_MAJOR 0090 /* Unsupported case -- cannot define unversioned symbols for different major versions 0091 * in the same translation unit. 0092 */ 0093 #error \ 0094 "Two different major versions of the NVTX C++ Wrappers are being included in a single .cpp file, with unversioned symbols enabled in both. Only one major version can enable unversioned symbols in a .cpp file. To disable unversioned symbols, #define NVTX3_CPP_REQUIRE_EXPLICIT_VERSION before #including nvtx3.hpp, and use the explicit-version symbols instead -- this is the preferred way to use nvtx3.hpp from a header file." 0095 #elif (NVTX3_CPP_INLINED_VERSION_MAJOR == NVTX3_CPP_VERSION_MAJOR) && \ 0096 (NVTX3_CPP_INLINED_VERSION_MINOR < NVTX3_CPP_VERSION_MINOR) 0097 /* An older minor version of the same major version already defined unversioned 0098 * symbols. The new features provided in this header will be inlined 0099 * redefine the minor version macro to this header's version. 0100 */ 0101 #undef NVTX3_CPP_INLINED_VERSION_MINOR 0102 #define NVTX3_CPP_INLINED_VERSION_MINOR 1 // NVTX3_CPP_VERSION_MINOR 0103 // else, already have this version or newer, nothing to do 0104 #endif 0105 #endif 0106 /* clang-format on */ 0107 0108 /** 0109 * @file nvtx3.hpp 0110 * 0111 * @brief Provides C++ constructs making the NVTX library safer and easier to 0112 * use with zero overhead. 0113 */ 0114 0115 /** 0116 * \mainpage 0117 * \tableofcontents 0118 * 0119 * \section QUICK_START Quick Start 0120 * 0121 * To add NVTX ranges to your code, use the `nvtx3::scoped_range` RAII object. A 0122 * range begins when the object is created, and ends when the object is 0123 * destroyed. 0124 * 0125 * \code{.cpp} 0126 * #include "nvtx3/nvtx3.hpp" 0127 * void some_function() { 0128 * // Begins a NVTX range with the message "some_function" 0129 * // The range ends when some_function() returns and `r` is destroyed 0130 * nvtx3::scoped_range r{"some_function"}; 0131 * 0132 * for(int i = 0; i < 5; ++i) { 0133 * nvtx3::scoped_range loop{"loop range"}; 0134 * std::this_thread::sleep_for(std::chrono::seconds{1}); 0135 * } 0136 * } // Range ends when `r` is destroyed 0137 * \endcode 0138 * 0139 * The example code above generates the following timeline view in Nsight 0140 * Systems: 0141 * 0142 * \image html 0143 * https://raw.githubusercontent.com/NVIDIA/NVTX/release-v3/docs/images/example_range.png 0144 * 0145 * Alternatively, use the \ref MACROS like `NVTX3_FUNC_RANGE()` to add 0146 * ranges to your code that automatically use the name of the enclosing function 0147 * as the range's message. 0148 * 0149 * \code{.cpp} 0150 * #include "nvtx3/nvtx3.hpp" 0151 * void some_function() { 0152 * // Creates a range with a message "some_function" that ends when the 0153 * // enclosing function returns 0154 * NVTX3_FUNC_RANGE(); 0155 * ... 0156 * } 0157 * \endcode 0158 * 0159 * 0160 * \section Overview 0161 * 0162 * The NVTX library provides a set of functions for users to annotate their code 0163 * to aid in performance profiling and optimization. These annotations provide 0164 * information to tools like Nsight Systems to improve visualization of 0165 * application timelines. 0166 * 0167 * \ref RANGES are one of the most commonly used NVTX constructs for annotating 0168 * a span of time. For example, imagine a user wanted to see every time a 0169 * function, `my_function`, is called and how long it takes to execute. This can 0170 * be accomplished with an NVTX range created on the entry to the function and 0171 * terminated on return from `my_function` using the push/pop C APIs: 0172 * 0173 * \code{.cpp} 0174 * void my_function(...) { 0175 * nvtxRangePushA("my_function"); // Begins NVTX range 0176 * // do work 0177 * nvtxRangePop(); // Ends NVTX range 0178 * } 0179 * \endcode 0180 * 0181 * One of the challenges with using the NVTX C API is that it requires manually 0182 * terminating the end of the range with `nvtxRangePop`. This can be challenging 0183 * if `my_function()` has multiple returns or can throw exceptions as it 0184 * requires calling `nvtxRangePop()` before all possible return points. 0185 * 0186 * NVTX C++ solves this inconvenience through the "RAII" technique by providing 0187 * a `nvtx3::scoped_range` class that begins a range at construction and ends 0188 * the range on destruction. The above example then becomes: 0189 * 0190 * \code{.cpp} 0191 * void my_function(...) { 0192 * nvtx3::scoped_range r{"my_function"}; // Begins NVTX range 0193 * // do work 0194 * } // Range ends on exit from `my_function` when `r` is destroyed 0195 * \endcode 0196 * 0197 * The range object `r` is deterministically destroyed whenever `my_function` 0198 * returns---ending the NVTX range without manual intervention. For more 0199 * information, see \ref RANGES and `nvtx3::scoped_range_in`. 0200 * 0201 * Another inconvenience of the NVTX C APIs are the several constructs where the 0202 * user is expected to initialize an object at the beginning of an application 0203 * and reuse that object throughout the lifetime of the application. For example 0204 * see domains, categories, and registered messages. 0205 * 0206 * Example: 0207 * \code{.cpp} 0208 * nvtxDomainHandle_t D = nvtxDomainCreateA("my domain"); 0209 * // Reuse `D` throughout the rest of the application 0210 * \endcode 0211 * 0212 * This can be problematic if the user application or library does not have an 0213 * explicit initialization function called before all other functions to 0214 * ensure that these long-lived objects are initialized before being used. 0215 * 0216 * NVTX C++ makes use of the "construct on first use" technique to alleviate 0217 * this inconvenience. In short, a function local static object is constructed 0218 * upon the first invocation of a function and returns a reference to that 0219 * object on all future invocations. See the documentation for `nvtx3::domain`, 0220 * `nvtx3::named_category`, `nvtx3::registered_string`, and 0221 * https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use for more 0222 * information. 0223 * 0224 * Using construct on first use, the above example becomes: 0225 * \code{.cpp} 0226 * struct my_domain{ static constexpr char const* name{"my domain"}; }; 0227 * 0228 * // The first invocation of `domain::get` for the type `my_domain` will 0229 * // construct a `nvtx3::domain` object and return a reference to it. Future 0230 * // invocations simply return a reference. 0231 * nvtx3::domain const& D = nvtx3::domain::get<my_domain>(); 0232 * \endcode 0233 * For more information about NVTX and how it can be used, see 0234 * https://docs.nvidia.com/cuda/profiler-users-guide/index.html#nvtx and 0235 * https://devblogs.nvidia.com/cuda-pro-tip-generate-custom-application-profile-timelines-nvtx/ 0236 * for more information. 0237 * 0238 * \section RANGES Ranges 0239 * 0240 * Ranges are used to describe a span of time during the execution of an 0241 * application. Common examples are using ranges to annotate the time it takes 0242 * to execute a function or an iteration of a loop. 0243 * 0244 * NVTX C++ uses RAII to automate the generation of ranges that are tied to the 0245 * lifetime of objects. Similar to `std::lock_guard` in the C++ Standard 0246 * Template Library. 0247 * 0248 * \subsection scoped_range Scoped Range 0249 * 0250 * `nvtx3::scoped_range_in` is a class that begins a range upon construction 0251 * and ends the range at destruction. This is one of the most commonly used 0252 * constructs in NVTX C++ and is useful for annotating spans of time on a 0253 * particular thread. These ranges can be nested to arbitrary depths. 0254 * 0255 * `nvtx3::scoped_range` is an alias for a `nvtx3::scoped_range_in` in the 0256 * global NVTX domain. For more information about Domains, see \ref DOMAINS. 0257 * 0258 * Various attributes of a range can be configured constructing a 0259 * `nvtx3::scoped_range_in` with a `nvtx3::event_attributes` object. For 0260 * more information, see \ref ATTRIBUTES. 0261 * 0262 * Example: 0263 * 0264 * \code{.cpp} 0265 * void some_function() { 0266 * // Creates a range for the duration of `some_function` 0267 * nvtx3::scoped_range r{}; 0268 * 0269 * while(true) { 0270 * // Creates a range for every loop iteration 0271 * // `loop_range` is nested inside `r` 0272 * nvtx3::scoped_range loop_range{}; 0273 * } 0274 * } 0275 * \endcode 0276 * 0277 * \subsection unique_range Unique Range 0278 * 0279 * `nvtx3::unique_range` is similar to `nvtx3::scoped_range`, with a few key differences: 0280 * - `unique_range` objects can be destroyed in any order whereas `scoped_range` objects must be 0281 * destroyed in exact reverse creation order 0282 * - `unique_range` can start and end on different threads 0283 * - `unique_range` is movable 0284 * - `unique_range` objects can be constructed as heap objects 0285 * 0286 * There is extra overhead associated with `unique_range` constructs and therefore use of 0287 * `nvtx3::scoped_range_in` should be preferred. 0288 * 0289 * \section MARKS Marks 0290 * 0291 * `nvtx3::mark` annotates an instantaneous point in time with a "marker". 0292 * 0293 * Unlike a "range" which has a beginning and an end, a marker is a single event 0294 * in an application, such as detecting a problem: 0295 * 0296 * \code{.cpp} 0297 * bool success = do_operation(...); 0298 * if (!success) { 0299 * nvtx3::mark("operation failed!"); 0300 * } 0301 * \endcode 0302 * 0303 * \section DOMAINS Domains 0304 * 0305 * Similar to C++ namespaces, domains allow for scoping NVTX events. By default, 0306 * all NVTX events belong to the "global" domain. Libraries and applications 0307 * should scope their events to use a custom domain to differentiate where the 0308 * events originate from. 0309 * 0310 * It is common for a library or application to have only a single domain and 0311 * for the name of that domain to be known at compile time. Therefore, Domains 0312 * in NVTX C++ are represented by _tag types_. 0313 * 0314 * For example, to define a custom domain, simply define a new concrete type 0315 * (a `class` or `struct`) with a `static` member called `name` that contains 0316 * the desired name of the domain. 0317 * 0318 * \code{.cpp} 0319 * struct my_domain{ static constexpr char const* name{"my domain"}; }; 0320 * \endcode 0321 * 0322 * For any NVTX C++ construct that can be scoped to a domain, the type 0323 * `my_domain` can be passed as an explicit template argument to scope it to 0324 * the custom domain. 0325 * 0326 * The tag type `nvtx3::domain::global` represents the global NVTX domain. 0327 * 0328 * \code{.cpp} 0329 * // By default, `scoped_range_in` belongs to the global domain 0330 * nvtx3::scoped_range_in<> r0{}; 0331 * 0332 * // Alias for a `scoped_range_in` in the global domain 0333 * nvtx3::scoped_range r1{}; 0334 * 0335 * // `r` belongs to the custom domain 0336 * nvtx3::scoped_range_in<my_domain> r{}; 0337 * \endcode 0338 * 0339 * When using a custom domain, it is recommended to define type aliases for NVTX 0340 * constructs in the custom domain. 0341 * \code{.cpp} 0342 * using my_scoped_range = nvtx3::scoped_range_in<my_domain>; 0343 * using my_registered_string = nvtx3::registered_string_in<my_domain>; 0344 * using my_named_category = nvtx3::named_category_in<my_domain>; 0345 * \endcode 0346 * 0347 * See `nvtx3::domain` for more information. 0348 * 0349 * \section ATTRIBUTES Event Attributes 0350 * 0351 * NVTX events can be customized with various attributes to provide additional 0352 * information (such as a custom message) or to control visualization of the 0353 * event (such as the color used). These attributes can be specified per-event 0354 * via arguments to a `nvtx3::event_attributes` object. 0355 * 0356 * NVTX events can be customized via five "attributes": 0357 * - \ref COLOR : color used to visualize the event in tools. 0358 * - \ref MESSAGES : Custom message string. 0359 * - \ref PAYLOAD : User-defined numerical value. 0360 * - \ref PAYLOAD_DATA : User-defined structured data (exclusive of payload). 0361 * - \ref CATEGORY : Intra-domain grouping. 0362 * 0363 * It is possible to construct a `nvtx3::event_attributes` from any number of 0364 * attribute objects (nvtx3::color, nvtx3::message, nvtx3::payload, 0365 * nvtx3::category, nvtx3::payload_data, or a container of nvtx3::payload_data) 0366 * in any order. If an attribute is not specified, a tool specific default value 0367 * is used. See `nvtx3::event_attributes` for more information. 0368 * 0369 * \code{.cpp} 0370 * // Set message, same as passing nvtx3::message{"message"} 0371 * nvtx3::event_attributes attr{"message"}; 0372 * 0373 * // Set message and color 0374 * nvtx3::event_attributes attr{"message", nvtx3::rgb{127, 255, 0}}; 0375 * 0376 * // Set message, color, payload, category 0377 * nvtx3::event_attributes attr{"message", 0378 * nvtx3::rgb{127, 255, 0}, 0379 * nvtx3::payload{42}, 0380 * nvtx3::category{1}}; 0381 * 0382 * // Same as above -- can use any order of arguments 0383 * nvtx3::event_attributes attr{nvtx3::payload{42}, 0384 * nvtx3::category{1}, 0385 * "message", 0386 * nvtx3::rgb{127, 255, 0}}; 0387 * 0388 * // Multiple arguments of the same type are allowed, but only the first is 0389 * // used -- in this example, payload is set to 42: 0390 * nvtx3::event_attributes attr{ nvtx3::payload{42}, nvtx3::payload{7} }; 0391 * // payload and payload_data should not be used together. 0392 * 0393 * // Using the nvtx3 namespace in a local scope makes the syntax more succinct: 0394 * using namespace nvtx3; 0395 * event_attributes attr{"message", rgb{127, 255, 0}, payload{42}, category{1}}; 0396 * \endcode 0397 * 0398 * \subsection MESSAGES message 0399 * 0400 * `nvtx3::message` sets the message string for an NVTX event. 0401 * 0402 * Example: 0403 * \code{.cpp} 0404 * // Create an `event_attributes` with the message "my message" 0405 * nvtx3::event_attributes attr{nvtx3::message{"my message"}}; 0406 * 0407 * // strings and string literals implicitly assumed to be a `nvtx3::message` 0408 * nvtx3::event_attributes attr{"my message"}; 0409 * \endcode 0410 * 0411 * \subsubsection REGISTERED_MESSAGE Registered Messages 0412 * 0413 * Associating a `nvtx3::message` with an event requires copying the contents of 0414 * the message every time the message is used, i.e., copying the entire message 0415 * string. This may cause non-trivial overhead in performance sensitive code. 0416 * 0417 * To eliminate this overhead, NVTX allows registering a message string, 0418 * yielding a "handle" that is inexpensive to copy that may be used in place of 0419 * a message string. When visualizing the events, tools such as Nsight Systems 0420 * will take care of mapping the message handle to its string. 0421 * 0422 * A message should be registered once and the handle reused throughout the rest 0423 * of the application. This can be done by either explicitly creating static 0424 * `nvtx3::registered_string` objects, or using the 0425 * `nvtx3::registered_string::get` construct on first use helper (recommended). 0426 * 0427 * Similar to \ref DOMAINS, `nvtx3::registered_string::get` requires defining a 0428 * custom tag type with a static `message` member whose value will be the 0429 * contents of the registered string. 0430 * 0431 * Example: 0432 * \code{.cpp} 0433 * // Explicitly constructed, static `registered_string` in my_domain: 0434 * static registered_string_in<my_domain> static_message{"my message"}; 0435 * 0436 * // Or use construct on first use: 0437 * // Define a tag type with a `message` member string to register 0438 * struct my_message{ static constexpr char const* message{ "my message" }; }; 0439 * 0440 * // Uses construct on first use to register the contents of 0441 * // `my_message::message` 0442 * auto& msg = nvtx3::registered_string_in<my_domain>::get<my_message>(); 0443 * \endcode 0444 * 0445 * A `nvtx3::registered_string_in` can also be used inside of a struct for 0446 * `nvtx3::payload_data` using `TYPE_NVTX_REGISTERED_STRING_HANDLE`. 0447 * 0448 * \code{.cpp} 0449 * 0450 * \endcode 0451 * 0452 * \subsection COLOR color 0453 * 0454 * Associating a `nvtx3::color` with an event allows controlling how the event 0455 * is visualized in a tool such as Nsight Systems. This is a convenient way to 0456 * visually differentiate among different events. 0457 * 0458 * \code{.cpp} 0459 * // Define a color via rgb color values 0460 * nvtx3::color c{nvtx3::rgb{127, 255, 0}}; 0461 * nvtx3::event_attributes attr{c}; 0462 * 0463 * // rgb color values can be passed directly to an `event_attributes` 0464 * nvtx3::event_attributes attr1{nvtx3::rgb{127,255,0}}; 0465 * \endcode 0466 * 0467 * \subsection CATEGORY category 0468 * 0469 * A `nvtx3::category` is simply an integer id that allows for fine-grain 0470 * grouping of NVTX events. For example, one might use separate categories for 0471 * IO, memory allocation, compute, etc. 0472 * 0473 * \code{.cpp} 0474 * nvtx3::event_attributes{nvtx3::category{1}}; 0475 * \endcode 0476 * 0477 * \subsubsection NAMED_CATEGORIES Named Categories 0478 * 0479 * Associates a `name` string with a category `id` to help differentiate among 0480 * categories. 0481 * 0482 * For any given category id `Id`, a `named_category{Id, "name"}` should only 0483 * be constructed once and reused throughout an application. This can be done by 0484 * either explicitly creating static `nvtx3::named_category` objects, or using 0485 * the `nvtx3::named_category::get` construct on first use helper (recommended). 0486 * 0487 * Similar to \ref DOMAINS, `nvtx3::named_category::get` requires defining a 0488 * custom tag type with static `name` and `id` members. 0489 * 0490 * \code{.cpp} 0491 * // Explicitly constructed, static `named_category` in my_domain: 0492 * static nvtx3::named_category_in<my_domain> static_category{42, "my category"}; 0493 * 0494 * // Or use construct on first use: 0495 * // Define a tag type with `name` and `id` members 0496 * struct my_category { 0497 * static constexpr char const* name{"my category"}; // category name 0498 * static constexpr uint32_t id{42}; // category id 0499 * }; 0500 * 0501 * // Use construct on first use to name the category id `42` 0502 * // with name "my category": 0503 * auto& cat = named_category_in<my_domain>::get<my_category>(); 0504 * 0505 * // Range `r` associated with category id `42` 0506 * nvtx3::event_attributes attr{cat}; 0507 * \endcode 0508 * 0509 * \subsection PAYLOAD payload 0510 * 0511 * Allows associating a user-defined numerical value with an event. 0512 * 0513 * \code{.cpp} 0514 * // Constructs a payload from the `int32_t` value 42 0515 * nvtx3:: event_attributes attr{nvtx3::payload{42}}; 0516 * \endcode 0517 * 0518 * \subsection PAYLOAD_DATA payload_data 0519 * 0520 * `nvtx3::payload_data` allows associating arbitrary structured data with an NVTX event. 0521 * 0522 * First, define a `struct` that is *standard-layout* and *trivially copyable*. 0523 * Then use `NVTX3_DEFINE_SCHEMA_GET` (`NVTX3_V1_DEFINE_SCHEMA_GET()`) to define the schema layout. 0524 * Finally you can use any such instance wrapped in `nvtx3::payload_data` in an 0525 * `nvtx3::event_attributes` object. 0526 * You can also pass containers (e.g., `std::vector`, `std::array`) of `payload_data` objects. 0527 * \note Constructing `nvtx3::payload_data` from temporaries or using tempoarary 0528 * `nvtx3::payload_data` objects is disabled to prevent dangling pointers. 0529 * 0530 * \section EXAMPLE Example 0531 * 0532 * Putting it all together: 0533 * \code{.cpp} 0534 * // Define a custom domain tag type 0535 * struct my_domain{ static constexpr char const* name{"my domain"}; }; 0536 * 0537 * // Define a named category tag type 0538 * struct my_category{ 0539 * static constexpr char const* name{"my category"}; 0540 * static constexpr uint32_t id{42}; 0541 * }; 0542 * 0543 * // Define a registered string tag type 0544 * struct my_message{ static constexpr char const* message{"my message"}; }; 0545 * 0546 * // For convenience, use aliases for domain scoped objects 0547 * using my_scoped_range = nvtx3::scoped_range_in<my_domain>; 0548 * using my_registered_string = nvtx3::registered_string_in<my_domain>; 0549 * using my_named_category = nvtx3::named_category_in<my_domain>; 0550 * 0551 * // Custom payload data 0552 * struct my_payload_data { 0553 * uint32_t iteration; 0554 * float temperature; 0555 * }; 0556 * NVTX3_DEFINE_SCHEMA_GET( 0557 * my_domain, 0558 * my_payload_data, 0559 * "MyPayloadData", 0560 * NVTX_PAYLOAD_ENTRIES((iteration, TYPE_UINT32, "Iteration Count"), 0561 * (temperature, TYPE_FLOAT, "Temperature")) 0562 * ) 0563 * 0564 * // Default values for all attributes 0565 * nvtx3::event_attributes attr{}; 0566 * my_scoped_range r0{attr}; 0567 * 0568 * // Custom (unregistered) message, and unnamed category 0569 * nvtx3::event_attributes attr1{"message", nvtx3::category{2}}; 0570 * my_scoped_range r1{attr1}; 0571 * 0572 * // Alternatively, pass arguments of `event_attributes` constructor directly 0573 * // to `my_scoped_range` 0574 * my_scoped_range r2{"message", nvtx3::category{2}}; 0575 * 0576 * // construct on first use a registered string 0577 * auto& msg = my_registered_string::get<my_message>(); 0578 * 0579 * // construct on first use a named category 0580 * auto& cat = my_named_category::get<my_category>(); 0581 * 0582 * // Use registered string and named category with a custom payload 0583 * my_scoped_range r3{msg, cat, nvtx3::payload{42}}; 0584 * 0585 * // Use custom payload data 0586 * my_payload_data extras{42, 0.7f}; 0587 * nvtx3::payload_data pd{extras}; 0588 * my_scoped_range r4{pd}; 0589 * 0590 * // Use a container of payload_data, can use different struct types 0591 * auto multiple = std::to_array({pd, pd2}); 0592 * my_scoped_range r5{multiple}; 0593 * 0594 * // Any number of arguments in any order 0595 * my_scoped_range r{nvtx3::rgb{127, 255, 0}, msg}; 0596 * 0597 * \endcode 0598 * \section MACROS Convenience Macros 0599 * 0600 * Oftentimes users want to quickly and easily add NVTX ranges to their library 0601 * or application to aid in profiling and optimization. 0602 * 0603 * A convenient way to do this is to use the \ref NVTX3_FUNC_RANGE and 0604 * \ref NVTX3_FUNC_RANGE_IN macros. These macros take care of constructing an 0605 * `nvtx3::scoped_range_in` with the name of the enclosing function as the 0606 * range's message. 0607 * 0608 * \code{.cpp} 0609 * void some_function() { 0610 * // Automatically generates an NVTX range for the duration of the function 0611 * // using "some_function" as the event's message. 0612 * NVTX3_FUNC_RANGE(); 0613 * } 0614 * \endcode 0615 * 0616 */ 0617 0618 /* Temporary helper #defines, removed with #undef at end of header */ 0619 0620 /* Some compilers do not correctly support SFINAE, which is used in this API 0621 * to detect common usage errors and provide clearer error messages (by using 0622 * static_assert) than the compiler would produce otherwise. These compilers 0623 * will generate errors while compiling this file such as: 0624 * 0625 * error: 'name' is not a member of 'nvtx3::v1::domain::global' 0626 * 0627 * The following compiler versions are known to have this problem, and so are 0628 * set by default to disable the SFINAE-based checks: 0629 * 0630 * - All MSVC versions prior to VS2017 Update 7 (15.7) 0631 * - GCC 8.1-8.3 (the problem was fixed in GCC 8.4) 0632 * 0633 * If you find your compiler hits this problem, you can work around it by 0634 * defining NVTX3_USE_CHECKED_OVERLOADS_FOR_GET to 0 before including this 0635 * header, or you can add a check for your compiler version to this #if. 0636 * Also, please report the issue on the NVTX GitHub page. 0637 */ 0638 #if !defined(NVTX3_USE_CHECKED_OVERLOADS_FOR_GET) 0639 #if defined(_MSC_VER) && _MSC_VER < 1914 \ 0640 || defined(__GNUC__) && __GNUC__ == 8 && __GNUC_MINOR__ < 4 0641 #define NVTX3_USE_CHECKED_OVERLOADS_FOR_GET 0 0642 #else 0643 #define NVTX3_USE_CHECKED_OVERLOADS_FOR_GET 1 0644 #endif 0645 #define NVTX3_USE_CHECKED_OVERLOADS_FOR_GET_DEFINED_HERE 0646 #endif 0647 0648 /* Within this header, nvtx3::NVTX3_VERSION_NAMESPACE resolves to nvtx3::vX, 0649 * where "X" is the major version number. */ 0650 #define NVTX3_CONCAT(A, B) A##B 0651 #define NVTX3_NAMESPACE_FOR(VERSION) NVTX3_CONCAT(v, VERSION) 0652 #define NVTX3_VERSION_NAMESPACE NVTX3_NAMESPACE_FOR(NVTX3_CPP_VERSION_MAJOR) 0653 /* We use a different prefix to avoid ambiguity with the version namespace */ 0654 #define NVTX3_MINOR_NAMESPACE_FOR(VERSION) NVTX3_CONCAT(mv, VERSION) 0655 #define NVTX3_MINOR_VERSION_NAMESPACE NVTX3_MINOR_NAMESPACE_FOR(NVTX3_CPP_VERSION_MINOR) 0656 0657 /* Avoid duplicating #if defined(NVTX3_INLINE_THIS_VERSION) for namespaces 0658 * in each minor version by making a macro to use unconditionally, which 0659 * resolves to "inline" or nothing as appropriate. */ 0660 #if defined(NVTX3_INLINE_THIS_VERSION) 0661 #define NVTX3_INLINE_IF_REQUESTED inline 0662 #else 0663 #define NVTX3_INLINE_IF_REQUESTED 0664 #endif 0665 0666 /* Enables the use of constexpr when support for C++14 constexpr is present. 0667 * 0668 * Initialization of a class member that is a union to a specific union member 0669 * can only be done in the body of a constructor, not in a member initializer 0670 * list. A constexpr constructor must have an empty body until C++14, so there 0671 * is no way to make an initializer of a member union constexpr in C++11. This 0672 * macro allows making functions constexpr in C++14 or newer, but non-constexpr 0673 * in C++11 compilation. It is used here on constructors that initialize their 0674 * member unions. 0675 */ 0676 #if __cpp_constexpr >= 201304L 0677 #define NVTX3_CONSTEXPR_IF_CPP14 constexpr 0678 #else 0679 #define NVTX3_CONSTEXPR_IF_CPP14 0680 #endif 0681 0682 /* Enables the use of constexpr when support for C++20 constexpr is present. 0683 */ 0684 #if __cplusplus >= 202002L 0685 #define NVTX3_CONSTEXPR_IF_CPP20 constexpr 0686 #else 0687 #define NVTX3_CONSTEXPR_IF_CPP20 0688 #endif 0689 0690 // Macro wrappers for C++ attributes 0691 #if !defined(__has_cpp_attribute) 0692 #define __has_cpp_attribute(x) 0 0693 #endif 0694 #if __has_cpp_attribute(maybe_unused) 0695 #define NVTX3_MAYBE_UNUSED [[maybe_unused]] 0696 #else 0697 #define NVTX3_MAYBE_UNUSED 0698 #endif 0699 #if __has_cpp_attribute(nodiscard) 0700 #define NVTX3_NO_DISCARD [[nodiscard]] 0701 #else 0702 #define NVTX3_NO_DISCARD 0703 #endif 0704 0705 /* Use a macro for static asserts, which defaults to static_assert, but that 0706 * testing tools can replace with a logging function. For example: 0707 * #define NVTX3_STATIC_ASSERT(c, m) \ 0708 * do { if (!(c)) printf("static_assert would fail: %s\n", m); } while (0) 0709 */ 0710 #if !defined(NVTX3_STATIC_ASSERT) 0711 #define NVTX3_STATIC_ASSERT(condition, message) static_assert(condition, message) 0712 #define NVTX3_STATIC_ASSERT_DEFINED_HERE 0713 #endif 0714 0715 /* Implementation sections, enclosed in guard macros for each minor version */ 0716 0717 #ifndef NVTX3_CPP_DEFINITIONS_V1_0 0718 #define NVTX3_CPP_DEFINITIONS_V1_0 0719 0720 #include "nvToolsExt.h" 0721 #include "nvToolsExtPayload.h" 0722 #include "nvToolsExtPayloadHelper.h" 0723 0724 #include <memory> 0725 #include <string> 0726 #include <type_traits> 0727 #include <utility> 0728 #include <cstddef> 0729 #include <cstdint> 0730 0731 namespace nvtx3 { 0732 0733 NVTX3_INLINE_IF_REQUESTED namespace NVTX3_VERSION_NAMESPACE 0734 { 0735 inline namespace NVTX3_MINOR_VERSION_NAMESPACE 0736 { 0737 0738 namespace detail { 0739 0740 template <typename Unused> 0741 struct always_false : std::false_type {}; 0742 0743 template <typename T, typename = void> 0744 struct has_name : std::false_type {}; 0745 template <typename T> 0746 struct has_name<T, decltype((void)T::name, void())> : std::true_type {}; 0747 0748 template <typename T, typename = void> 0749 struct has_id : std::false_type {}; 0750 template <typename T> 0751 struct has_id<T, decltype((void)T::id, void())> : std::true_type {}; 0752 0753 template <typename T, typename = void> 0754 struct has_message : std::false_type {}; 0755 template <typename T> 0756 struct has_message<T, decltype((void)T::message, void())> : std::true_type {}; 0757 0758 template <typename T, typename = void> 0759 struct is_c_string : std::false_type {}; 0760 template <typename T> 0761 struct is_c_string<T, typename std::enable_if< 0762 std::is_convertible<T, char const* >::value || 0763 std::is_convertible<T, wchar_t const*>::value 0764 >::type> : std::true_type {}; 0765 0766 template <typename T> 0767 using is_uint32 = std::is_same<typename std::decay<T>::type, uint32_t>; 0768 0769 template <typename... Args> 0770 static inline void silence_unused(Args const&...) noexcept {} 0771 0772 // Type trait to check for a .data() member returning T* or const T* 0773 // Some day, we can just use std::span 0774 template <typename T, typename TD> 0775 struct has_data_member 0776 { 0777 private: 0778 template <typename U> 0779 static auto test_data(int) -> decltype(std::declval<const U>().data()); 0780 template <typename> 0781 static auto test_data(...) -> void; 0782 using return_type = decltype(test_data<T>(0)); 0783 0784 public: 0785 static constexpr bool value = 0786 std::is_same<return_type, TD*>::value || std::is_same<return_type, TD const*>::value; 0787 }; 0788 0789 // Type trait to check for a .size() member returning something convertible to size_t 0790 template <typename T> 0791 struct has_size_member 0792 { 0793 private: 0794 template <typename U> 0795 static auto test_size(int) -> decltype(std::declval<const U>().size()); 0796 template <typename> 0797 static auto test_size(...) -> void; 0798 using return_type = decltype(test_size<T>(0)); 0799 0800 public: 0801 static constexpr bool value = !std::is_same<return_type, void>::value && 0802 std::is_convertible<return_type, size_t>::value; 0803 }; 0804 0805 /** 0806 * To ensure that we can "safely" use one type as another, for pointers, in 0807 * arrays or in structs. This is used for our wrappers around C-types so that 0808 * we can pass them back to C. 0809 * 0810 * This is by no means perfect and foolproof. 0811 * 0812 * @tparam W The wrapper type. 0813 * @tparam U The type it is wrapping. 0814 */ 0815 template <typename W, typename U, typename = void> 0816 struct is_safe_wrapper_of : std::false_type 0817 { 0818 }; 0819 0820 template <typename W, typename U> 0821 struct is_safe_wrapper_of< 0822 W, 0823 U, 0824 typename std::enable_if< 0825 std::is_standard_layout<W>::value && std::is_standard_layout<U>::value && 0826 std::is_trivially_copyable<W>::value && std::is_trivially_copyable<U>::value && 0827 sizeof(W) == sizeof(U)>::type> : std::true_type 0828 { 0829 }; 0830 } // namespace detail 0831 0832 /** 0833 * @brief `domain`s allow for grouping NVTX events into a single scope to 0834 * differentiate them from events in other `domain`s. 0835 * 0836 * By default, all NVTX constructs are placed in the "global" NVTX domain. 0837 * 0838 * A custom `domain` may be used in order to differentiate a library's or 0839 * application's NVTX events from other events. 0840 * 0841 * `domain`s are expected to be long-lived and unique to a library or 0842 * application. As such, it is assumed a domain's name is known at compile 0843 * time. Therefore, all NVTX constructs that can be associated with a domain 0844 * require the domain to be specified via a *type* `D` passed as an 0845 * explicit template parameter. 0846 * 0847 * The type `domain::global` may be used to indicate that the global NVTX 0848 * domain should be used. 0849 * 0850 * None of the C++ NVTX constructs require the user to manually construct a 0851 * `domain` object. Instead, if a custom domain is desired, the user is 0852 * expected to define a type `D` that contains a member 0853 * `D::name` which resolves to either a `char const*` or `wchar_t 0854 * const*`. The value of `D::name` is used to name and uniquely 0855 * identify the custom domain. 0856 * 0857 * Upon the first use of an NVTX construct associated with the type 0858 * `D`, the "construct on first use" pattern is used to construct a 0859 * function local static `domain` object. All future NVTX constructs 0860 * associated with `D` will use a reference to the previously 0861 * constructed `domain` object. See `domain::get`. 0862 * 0863 * Example: 0864 * \code{.cpp} 0865 * // The type `my_domain` defines a `name` member used to name and identify 0866 * // the `domain` object identified by `my_domain`. 0867 * struct my_domain{ static constexpr char const* name{"my_domain"}; }; 0868 * 0869 * // The NVTX range `r` will be grouped with all other NVTX constructs 0870 * // associated with `my_domain`. 0871 * nvtx3::scoped_range_in<my_domain> r{}; 0872 * 0873 * // An alias can be created for a `scoped_range_in` in the custom domain 0874 * using my_scoped_range = nvtx3::scoped_range_in<my_domain>; 0875 * my_scoped_range my_range{}; 0876 * 0877 * // `domain::global` indicates that the global NVTX domain is used 0878 * nvtx3::scoped_range_in<domain::global> r2{}; 0879 * 0880 * // For convenience, `nvtx3::scoped_range` is an alias for a range in the 0881 * // global domain 0882 * nvtx3::scoped_range r3{}; 0883 * \endcode 0884 */ 0885 class domain { 0886 public: 0887 domain(domain const&) = delete; 0888 domain& operator=(domain const&) = delete; 0889 domain(domain&&) = delete; 0890 domain& operator=(domain&&) = delete; 0891 0892 /** 0893 * @brief Tag type for the "global" NVTX domain. 0894 * 0895 * This type may be passed as a template argument to any function/class 0896 * expecting a type to identify a domain to indicate that the global domain 0897 * should be used. 0898 * 0899 * All NVTX events in the global domain across all libraries and 0900 * applications will be grouped together. 0901 * 0902 */ 0903 struct global { 0904 }; 0905 0906 #if NVTX3_USE_CHECKED_OVERLOADS_FOR_GET 0907 /** 0908 * @brief Returns reference to an instance of a function local static 0909 * `domain` object. 0910 * 0911 * Uses the "construct on first use" idiom to safely ensure the `domain` 0912 * object is initialized exactly once upon first invocation of 0913 * `domain::get<D>()`. All following invocations will return a 0914 * reference to the previously constructed `domain` object. See 0915 * https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use 0916 * 0917 * None of the constructs in this header require the user to directly invoke 0918 * `domain::get`. It is automatically invoked when constructing objects like 0919 * a `scoped_range_in` or `category`. Advanced users may wish to use 0920 * `domain::get` for the convenience of the "construct on first use" idiom 0921 * when using domains with their own use of the NVTX C API. 0922 * 0923 * This function is thread-safe as of C++11. If two or more threads call 0924 * `domain::get<D>` concurrently, exactly one of them is guaranteed 0925 * to construct the `domain` object and the other(s) will receive a 0926 * reference to the object after it is fully constructed. 0927 * 0928 * The domain's name is specified via the type `D` pass as an 0929 * explicit template parameter. `D` is required to contain a 0930 * member `D::name` that resolves to either a `char const*` or 0931 * `wchar_t const*`. The value of `D::name` is used to name and 0932 * uniquely identify the `domain`. 0933 * 0934 * Example: 0935 * \code{.cpp} 0936 * // The type `my_domain` defines a `name` member used to name and identify 0937 * // the `domain` object identified by `my_domain`. 0938 * struct my_domain{ static constexpr char const* name{"my domain"}; }; 0939 * 0940 * auto& D1 = domain::get<my_domain>(); // First invocation constructs a 0941 * // `domain` with the name "my domain" 0942 * 0943 * auto& D2 = domain::get<my_domain>(); // Quickly returns reference to 0944 * // previously constructed `domain`. 0945 * \endcode 0946 * 0947 * @tparam D Type that contains a `D::name` member used to 0948 * name the `domain` object. 0949 * @return Reference to the `domain` corresponding to the type `D`. 0950 */ 0951 template <typename D = global, 0952 typename std::enable_if< 0953 detail::is_c_string<decltype(D::name)>::value 0954 , int>::type = 0> 0955 NVTX3_NO_DISCARD static domain const& get() noexcept 0956 { 0957 static domain const d(D::name); 0958 return d; 0959 } 0960 0961 /** 0962 * @brief Overload of `domain::get` to provide a clear compile error when 0963 * `D` has a `name` member that is not directly convertible to either 0964 * `char const*` or `wchar_t const*`. 0965 */ 0966 template <typename D = global, 0967 typename std::enable_if< 0968 !detail::is_c_string<decltype(D::name)>::value 0969 , int>::type = 0> 0970 NVTX3_NO_DISCARD static domain const& get() noexcept 0971 { 0972 NVTX3_STATIC_ASSERT(detail::always_false<D>::value, 0973 "Type used to identify an NVTX domain must contain a static constexpr member " 0974 "called 'name' of type const char* or const wchar_t* -- 'name' member is not " 0975 "convertible to either of those types"); 0976 static domain const unused; 0977 return unused; // Function must compile for static_assert to be triggered 0978 } 0979 0980 /** 0981 * @brief Overload of `domain::get` to provide a clear compile error when 0982 * `D` does not have a `name` member. 0983 */ 0984 template <typename D = global, 0985 typename std::enable_if< 0986 !detail::has_name<D>::value 0987 , int>::type = 0> 0988 NVTX3_NO_DISCARD static domain const& get() noexcept 0989 { 0990 NVTX3_STATIC_ASSERT(detail::always_false<D>::value, 0991 "Type used to identify an NVTX domain must contain a static constexpr member " 0992 "called 'name' of type const char* or const wchar_t* -- 'name' member is missing"); 0993 static domain const unused; 0994 return unused; // Function must compile for static_assert to be triggered 0995 } 0996 #else 0997 template <typename D = global> 0998 NVTX3_NO_DISCARD static domain const& get() noexcept 0999 { 1000 static domain const d(D::name); 1001 return d; 1002 } 1003 #endif 1004 1005 /** 1006 * @brief Conversion operator to `nvtxDomainHandle_t`. 1007 * 1008 * Allows transparently passing a domain object into an API expecting a 1009 * native `nvtxDomainHandle_t` object. 1010 */ 1011 operator nvtxDomainHandle_t() const noexcept { return _domain; } 1012 1013 private: 1014 /** 1015 * @brief Construct a new domain with the specified `name`. 1016 * 1017 * This constructor is private as it is intended that `domain` objects only 1018 * be created through the `domain::get` function. 1019 * 1020 * @param name A unique name identifying the domain 1021 */ 1022 explicit domain(char const* name) noexcept : _domain{nvtxDomainCreateA(name)} {} 1023 1024 /** 1025 * @brief Construct a new domain with the specified `name`. 1026 * 1027 * This constructor is private as it is intended that `domain` objects only 1028 * be created through the `domain::get` function. 1029 * 1030 * @param name A unique name identifying the domain 1031 */ 1032 explicit domain(wchar_t const* name) noexcept : _domain{nvtxDomainCreateW(name)} {} 1033 1034 /** 1035 * @brief Construct a new domain with the specified `name`. 1036 * 1037 * This constructor is private as it is intended that `domain` objects only 1038 * be created through the `domain::get` function. 1039 * 1040 * @param name A unique name identifying the domain 1041 */ 1042 explicit domain(std::string const& name) noexcept : domain{name.c_str()} {} 1043 1044 /** 1045 * @brief Construct a new domain with the specified `name`. 1046 * 1047 * This constructor is private as it is intended that `domain` objects only 1048 * be created through the `domain::get` function. 1049 * 1050 * @param name A unique name identifying the domain 1051 */ 1052 explicit domain(std::wstring const& name) noexcept : domain{name.c_str()} {} 1053 1054 /** 1055 * @brief Default constructor creates a `domain` representing the 1056 * "global" NVTX domain. 1057 * 1058 * All events not associated with a custom `domain` are grouped in the 1059 * "global" NVTX domain. 1060 * 1061 */ 1062 constexpr domain() noexcept {} 1063 1064 /** 1065 * @brief Intentionally avoid calling nvtxDomainDestroy on the `domain` object. 1066 * 1067 * No currently-available tools attempt to free domain resources when the 1068 * nvtxDomainDestroy function is called, due to the thread-safety and 1069 * efficiency challenges of freeing thread-local storage for other threads. 1070 * Since libraries may be disallowed from introducing static destructors, 1071 * and destroying the domain is likely to have no effect, the destructor 1072 * for `domain` intentionally chooses to not destroy the domain. 1073 * 1074 * In a situation where domain destruction is necessary, either manually 1075 * call nvtxDomainDestroy on the domain's handle, or make a class that 1076 * derives from `domain` and calls nvtxDomainDestroy in its destructor. 1077 */ 1078 ~domain() = default; 1079 1080 private: 1081 nvtxDomainHandle_t const _domain{}; ///< The `domain`s NVTX handle 1082 }; 1083 1084 /** 1085 * @brief Returns reference to the `domain` object that represents the global 1086 * NVTX domain. 1087 * 1088 * This specialization for `domain::global` returns a default constructed, 1089 * `domain` object for use when the "global" domain is desired. 1090 * 1091 * All NVTX events in the global domain across all libraries and applications 1092 * will be grouped together. 1093 * 1094 * @return Reference to the `domain` corresponding to the global NVTX domain. 1095 * 1096 */ 1097 template <> 1098 NVTX3_NO_DISCARD inline domain const& domain::get<domain::global>() noexcept 1099 { 1100 static domain const d{}; 1101 return d; 1102 } 1103 1104 /** 1105 * @brief Indicates the values of the red, green, and blue color channels for 1106 * an RGB color to use as an event attribute (assumes no transparency). 1107 * 1108 */ 1109 struct rgb { 1110 /// Type used for component values 1111 using component_type = uint8_t; 1112 1113 /** 1114 * @brief Construct a rgb with red, green, and blue channels 1115 * specified by `red_`, `green_`, and `blue_`, respectively. 1116 * 1117 * Valid values are in the range `[0,255]`. 1118 * 1119 * @param red_ Value of the red channel 1120 * @param green_ Value of the green channel 1121 * @param blue_ Value of the blue channel 1122 */ 1123 constexpr rgb( 1124 component_type red_, 1125 component_type green_, 1126 component_type blue_) noexcept 1127 : red{red_}, green{green_}, blue{blue_} 1128 { 1129 } 1130 1131 component_type red{}; ///< Red channel value 1132 component_type green{}; ///< Green channel value 1133 component_type blue{}; ///< Blue channel value 1134 }; 1135 1136 /** 1137 * @brief Indicates the value of the alpha, red, green, and blue color 1138 * channels for an ARGB color to use as an event attribute. 1139 * 1140 */ 1141 struct argb final : rgb { 1142 /** 1143 * @brief Construct an argb with alpha, red, green, and blue channels 1144 * specified by `alpha_`, `red_`, `green_`, and `blue_`, respectively. 1145 * 1146 * Valid values are in the range `[0,255]`. 1147 * 1148 * @param alpha_ Value of the alpha channel (opacity) 1149 * @param red_ Value of the red channel 1150 * @param green_ Value of the green channel 1151 * @param blue_ Value of the blue channel 1152 * 1153 */ 1154 constexpr argb( 1155 component_type alpha_, 1156 component_type red_, 1157 component_type green_, 1158 component_type blue_) noexcept 1159 : rgb{red_, green_, blue_}, alpha{alpha_} 1160 { 1161 } 1162 1163 component_type alpha{}; ///< Alpha channel value 1164 }; 1165 1166 /** 1167 * @brief Represents a custom color that can be associated with an NVTX event 1168 * via its `event_attributes`. 1169 * 1170 * Specifying colors for NVTX events is a convenient way to visually 1171 * differentiate among different events in a visualization tool such as Nsight 1172 * Systems. 1173 * 1174 */ 1175 class color { 1176 public: 1177 /// Type used for the color's value 1178 using value_type = uint32_t; 1179 1180 /** 1181 * @brief Constructs a `color` using the value provided by `hex_code`. 1182 * 1183 * `hex_code` is expected to be a 4 byte argb hex code. 1184 * 1185 * The most significant byte indicates the value of the alpha channel 1186 * (opacity) (0-255) 1187 * 1188 * The next byte indicates the value of the red channel (0-255) 1189 * 1190 * The next byte indicates the value of the green channel (0-255) 1191 * 1192 * The least significant byte indicates the value of the blue channel 1193 * (0-255) 1194 * 1195 * @param hex_code The hex code used to construct the `color` 1196 */ 1197 constexpr explicit color(value_type hex_code) noexcept : _value{hex_code} {} 1198 1199 /** 1200 * @brief Construct a `color` using the alpha, red, green, blue components 1201 * in `argb`. 1202 * 1203 * @param argb_ The alpha, red, green, blue components of the desired `color` 1204 */ 1205 constexpr color(argb argb_) noexcept 1206 : color{from_bytes_msb_to_lsb(argb_.alpha, argb_.red, argb_.green, argb_.blue)} 1207 { 1208 } 1209 1210 /** 1211 * @brief Construct a `color` using the red, green, blue components in 1212 * `rgb`. 1213 * 1214 * Uses maximum value for the alpha channel (opacity) of the `color`. 1215 * 1216 * @param rgb_ The red, green, blue components of the desired `color` 1217 */ 1218 constexpr color(rgb rgb_) noexcept 1219 : color{from_bytes_msb_to_lsb(0xFF, rgb_.red, rgb_.green, rgb_.blue)} 1220 { 1221 } 1222 1223 /** 1224 * @brief Returns the `color`s argb hex code 1225 * 1226 */ 1227 constexpr value_type get_value() const noexcept { return _value; } 1228 1229 /** 1230 * @brief Return the NVTX color type of the color. 1231 * 1232 */ 1233 constexpr nvtxColorType_t get_type() const noexcept { return _type; } 1234 1235 color() = delete; 1236 ~color() = default; 1237 color(color const&) = default; 1238 color& operator=(color const&) = default; 1239 color(color&&) = default; 1240 color& operator=(color&&) = default; 1241 1242 private: 1243 /** 1244 * @brief Constructs an unsigned, 4B integer from the component bytes in 1245 * most to least significant byte order. 1246 * 1247 */ 1248 constexpr static value_type from_bytes_msb_to_lsb( 1249 uint8_t byte3, 1250 uint8_t byte2, 1251 uint8_t byte1, 1252 uint8_t byte0) noexcept 1253 { 1254 return uint32_t{byte3} << 24 | uint32_t{byte2} << 16 | uint32_t{byte1} << 8 | uint32_t{byte0}; 1255 } 1256 1257 value_type _value{}; ///< color's argb color code 1258 nvtxColorType_t _type{NVTX_COLOR_ARGB}; ///< NVTX color type code 1259 }; 1260 1261 /** 1262 * @brief Object for intra-domain grouping of NVTX events. 1263 * 1264 * A `category` is simply an integer id that allows for fine-grain grouping of 1265 * NVTX events. For example, one might use separate categories for IO, memory 1266 * allocation, compute, etc. 1267 * 1268 * Example: 1269 * \code{.cpp} 1270 * nvtx3::category cat1{1}; 1271 * 1272 * // Range `r1` belongs to the category identified by the value `1`. 1273 * nvtx3::scoped_range r1{cat1}; 1274 * 1275 * // Range `r2` belongs to the same category as `r1` 1276 * nvtx3::scoped_range r2{nvtx3::category{1}}; 1277 * \endcode 1278 * 1279 * To associate a name string with a category id, see `named_category`. 1280 * 1281 */ 1282 class category { 1283 public: 1284 /// Type used for `category`s integer id. 1285 using id_type = uint32_t; 1286 1287 /** 1288 * @brief Construct a `category` with the specified `id`. 1289 * 1290 * The `category` will be unnamed and identified only by its `id` value. 1291 * 1292 * All `category`s in a domain sharing the same `id` are equivalent. 1293 * 1294 * @param[in] id The `category`'s identifying value 1295 */ 1296 constexpr explicit category(id_type id) noexcept : id_{id} {} 1297 1298 /** 1299 * @brief Returns the id of the category. 1300 * 1301 */ 1302 constexpr id_type get_id() const noexcept { return id_; } 1303 1304 category() = delete; 1305 ~category() = default; 1306 category(category const&) = default; 1307 category& operator=(category const&) = default; 1308 category(category&&) = default; 1309 category& operator=(category&&) = default; 1310 1311 private: 1312 id_type id_{}; ///< category's unique identifier 1313 }; 1314 1315 /** 1316 * @brief A `category` with an associated name string. 1317 * 1318 * Associates a `name` string with a category `id` to help differentiate among 1319 * categories. 1320 * 1321 * For any given category id `Id`, a `named_category(Id, "name")` should only 1322 * be constructed once and reused throughout an application. This can be done 1323 * by either explicitly creating static `named_category` objects, or using the 1324 * `named_category::get` construct on first use helper (recommended). 1325 * 1326 * Creating two or more `named_category` objects with the same value for `id` 1327 * in the same domain results in undefined behavior. 1328 * 1329 * Similarly, behavior is undefined when a `named_category` and `category` 1330 * share the same value of `id`. 1331 * 1332 * Example: 1333 * \code{.cpp} 1334 * // Explicitly constructed, static `named_category` in global domain: 1335 * static nvtx3::named_category static_category{42, "my category"}; 1336 * 1337 * // Range `r` associated with category id `42` 1338 * nvtx3::scoped_range r{static_category}; 1339 * 1340 * // OR use construct on first use: 1341 * 1342 * // Define a type with `name` and `id` members 1343 * struct my_category { 1344 * static constexpr char const* name{"my category"}; // category name 1345 * static constexpr uint32_t id{42}; // category id 1346 * }; 1347 * 1348 * // Use construct on first use to name the category id `42` 1349 * // with name "my category" 1350 * auto& cat = named_category_in<my_domain>::get<my_category>(); 1351 * 1352 * // Range `r` associated with category id `42` 1353 * nvtx3::scoped_range r{cat}; 1354 * \endcode 1355 * 1356 * `named_category_in<D>`'s association of a name to a category id is local to 1357 * the domain specified by the type `D`. An id may have a different name in 1358 * another domain. 1359 * 1360 * @tparam D Type containing `name` member used to identify the `domain` to 1361 * which the `named_category_in` belongs. Else, `domain::global` to indicate 1362 * that the global NVTX domain should be used. 1363 */ 1364 template <typename D = domain::global> 1365 class named_category_in final : public category { 1366 public: 1367 #if NVTX3_USE_CHECKED_OVERLOADS_FOR_GET 1368 /** 1369 * @brief Returns a global instance of a `named_category_in` as a 1370 * function-local static. 1371 * 1372 * Creates a `named_category_in<D>` with name and id specified by the contents 1373 * of a type `C`. `C::name` determines the name and `C::id` determines the 1374 * category id. 1375 * 1376 * This function is useful for constructing a named `category` exactly once 1377 * and reusing the same instance throughout an application. 1378 * 1379 * Example: 1380 * \code{.cpp} 1381 * // Define a type with `name` and `id` members 1382 * struct my_category { 1383 * static constexpr char const* name{"my category"}; // category name 1384 * static constexpr uint32_t id{42}; // category id 1385 * }; 1386 * 1387 * // Use construct on first use to name the category id `42` 1388 * // with name "my category" 1389 * auto& cat = named_category_in<my_domain>::get<my_category>(); 1390 * 1391 * // Range `r` associated with category id `42` 1392 * nvtx3::scoped_range r{cat}; 1393 * \endcode 1394 * 1395 * Uses the "construct on first use" idiom to safely ensure the `category` 1396 * object is initialized exactly once. See 1397 * https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use 1398 * 1399 * @tparam C Type containing a member `C::name` that resolves to either a 1400 * `char const*` or `wchar_t const*` and `C::id`. 1401 */ 1402 template <typename C, 1403 typename std::enable_if< 1404 detail::is_c_string<decltype(C::name)>::value && 1405 detail::is_uint32<decltype(C::id)>::value 1406 , int>::type = 0> 1407 static named_category_in const& get() noexcept 1408 { 1409 static named_category_in const cat(C::id, C::name); 1410 return cat; 1411 } 1412 1413 /** 1414 * @brief Overload of `named_category_in::get` to provide a clear compile error 1415 * when `C` has the required `name` and `id` members, but they are not the 1416 * required types. `name` must be directly convertible to `char const*` or 1417 * `wchar_t const*`, and `id` must be `uint32_t`. 1418 */ 1419 template <typename C, 1420 typename std::enable_if< 1421 !detail::is_c_string<decltype(C::name)>::value || 1422 !detail::is_uint32<decltype(C::id)>::value 1423 , int>::type = 0> 1424 NVTX3_NO_DISCARD static named_category_in const& get() noexcept 1425 { 1426 NVTX3_STATIC_ASSERT(detail::is_c_string<decltype(C::name)>::value, 1427 "Type used to name an NVTX category must contain a static constexpr member " 1428 "called 'name' of type const char* or const wchar_t* -- 'name' member is not " 1429 "convertible to either of those types"); 1430 NVTX3_STATIC_ASSERT(detail::is_uint32<decltype(C::id)>::value, 1431 "Type used to name an NVTX category must contain a static constexpr member " 1432 "called 'id' of type uint32_t -- 'id' member is the wrong type"); 1433 static named_category_in const unused; 1434 return unused; // Function must compile for static_assert to be triggered 1435 } 1436 1437 /** 1438 * @brief Overload of `named_category_in::get` to provide a clear compile error 1439 * when `C` does not have the required `name` and `id` members. 1440 */ 1441 template <typename C, 1442 typename std::enable_if< 1443 !detail::has_name<C>::value || 1444 !detail::has_id<C>::value 1445 , int>::type = 0> 1446 NVTX3_NO_DISCARD static named_category_in const& get() noexcept 1447 { 1448 NVTX3_STATIC_ASSERT(detail::has_name<C>::value, 1449 "Type used to name an NVTX category must contain a static constexpr member " 1450 "called 'name' of type const char* or const wchar_t* -- 'name' member is missing"); 1451 NVTX3_STATIC_ASSERT(detail::has_id<C>::value, 1452 "Type used to name an NVTX category must contain a static constexpr member " 1453 "called 'id' of type uint32_t -- 'id' member is missing"); 1454 static named_category_in const unused; 1455 return unused; // Function must compile for static_assert to be triggered 1456 } 1457 #else 1458 template <typename C> 1459 NVTX3_NO_DISCARD static named_category_in const& get() noexcept 1460 { 1461 static named_category_in const cat(C::id, C::name); 1462 return cat; 1463 } 1464 #endif 1465 1466 private: 1467 // Default constructor is only used internally for static_assert(false) cases. 1468 named_category_in() noexcept : category{0} {} 1469 1470 public: 1471 /** 1472 * @brief Construct a `named_category_in` with the specified `id` and `name`. 1473 * 1474 * The name `name` will be registered with `id`. 1475 * 1476 * Every unique value of `id` should only be named once. 1477 * 1478 * @param[in] id The category id to name 1479 * @param[in] name The name to associated with `id` 1480 */ 1481 named_category_in(id_type id, char const* name) noexcept : category{id} 1482 { 1483 #ifndef NVTX_DISABLE 1484 nvtxDomainNameCategoryA(domain::get<D>(), get_id(), name); 1485 #else 1486 (void)id; 1487 (void)name; 1488 #endif 1489 } 1490 1491 /** 1492 * @brief Construct a `named_category_in` with the specified `id` and `name`. 1493 * 1494 * The name `name` will be registered with `id`. 1495 * 1496 * Every unique value of `id` should only be named once. 1497 * 1498 * @param[in] id The category id to name 1499 * @param[in] name The name to associated with `id` 1500 */ 1501 named_category_in(id_type id, wchar_t const* name) noexcept : category{id} 1502 { 1503 #ifndef NVTX_DISABLE 1504 nvtxDomainNameCategoryW(domain::get<D>(), get_id(), name); 1505 #else 1506 (void)id; 1507 (void)name; 1508 #endif 1509 } 1510 }; 1511 1512 /** 1513 * @brief Alias for a `named_category_in` in the global NVTX domain. 1514 * 1515 */ 1516 using named_category = named_category_in<domain::global>; 1517 1518 /** 1519 * @brief A message registered with NVTX. 1520 * 1521 * Normally, associating a `message` with an NVTX event requires copying the 1522 * contents of the message string. This may cause non-trivial overhead in 1523 * highly performance sensitive regions of code. 1524 * 1525 * message registration is an optimization to lower the overhead of 1526 * associating a message with an NVTX event. Registering a message yields a 1527 * handle that is inexpensive to copy that may be used in place of a message 1528 * string. 1529 * 1530 * A particular message should only be registered once and the handle 1531 * reused throughout the rest of the application. This can be done by either 1532 * explicitly creating static `registered_string_in` objects, or using the 1533 * `registered_string_in::get` construct on first use helper (recommended). 1534 * 1535 * Example: 1536 * \code{.cpp} 1537 * // Explicitly constructed, static `registered_string` in my_domain: 1538 * static registered_string_in<my_domain> static_message{"message"}; 1539 * 1540 * // "message" is associated with the range `r` 1541 * nvtx3::scoped_range r{static_message}; 1542 * 1543 * // Or use construct on first use: 1544 * 1545 * // Define a type with a `message` member that defines the contents of the 1546 * // registered string 1547 * struct my_message{ static constexpr char const* message{ "my message" }; }; 1548 * 1549 * // Uses construct on first use to register the contents of 1550 * // `my_message::message` 1551 * auto& msg = registered_string_in<my_domain>::get<my_message>(); 1552 * 1553 * // "my message" is associated with the range `r` 1554 * nvtx3::scoped_range r{msg}; 1555 * \endcode 1556 * 1557 * `registered_string_in`s are local to a particular domain specified via 1558 * the type `D`. 1559 * 1560 * @tparam D Type containing `name` member used to identify the `domain` to 1561 * which the `registered_string_in` belongs. Else, `domain::global` to indicate 1562 * that the global NVTX domain should be used. 1563 */ 1564 template <typename D = domain::global> 1565 class registered_string_in { 1566 public: 1567 #if NVTX3_USE_CHECKED_OVERLOADS_FOR_GET 1568 /** 1569 * @brief Returns a global instance of a `registered_string_in` as a function 1570 * local static. 1571 * 1572 * Provides a convenient way to register a message with NVTX without having 1573 * to explicitly register the message. 1574 * 1575 * Upon first invocation, constructs a `registered_string_in` whose contents 1576 * are specified by `message::message`. 1577 * 1578 * All future invocations will return a reference to the object constructed 1579 * in the first invocation. 1580 * 1581 * Example: 1582 * \code{.cpp} 1583 * // Define a type with a `message` member that defines the contents of the 1584 * // registered string 1585 * struct my_message{ static constexpr char const* message{ "my message" }; 1586 * }; 1587 * 1588 * // Uses construct on first use to register the contents of 1589 * // `my_message::message` 1590 * auto& msg = registered_string_in<my_domain>::get<my_message>(); 1591 * 1592 * // "my message" is associated with the range `r` 1593 * nvtx3::scoped_range r{msg}; 1594 * \endcode 1595 * 1596 * @tparam M Type required to contain a member `M::message` that 1597 * resolves to either a `char const*` or `wchar_t const*` used as the 1598 * registered string's contents. 1599 * @return Reference to a `registered_string_in` associated with the type `M`. 1600 */ 1601 template <typename M, 1602 typename std::enable_if< 1603 detail::is_c_string<decltype(M::message)>::value 1604 , int>::type = 0> 1605 NVTX3_NO_DISCARD static registered_string_in const& get() noexcept 1606 { 1607 static registered_string_in const regstr(M::message); 1608 return regstr; 1609 } 1610 1611 /** 1612 * @brief Overload of `registered_string_in::get` to provide a clear compile error 1613 * when `M` has a `message` member that is not directly convertible to either 1614 * `char const*` or `wchar_t const*`. 1615 */ 1616 template <typename M, 1617 typename std::enable_if< 1618 !detail::is_c_string<decltype(M::message)>::value 1619 , int>::type = 0> 1620 NVTX3_NO_DISCARD static registered_string_in const& get() noexcept 1621 { 1622 NVTX3_STATIC_ASSERT(detail::always_false<M>::value, 1623 "Type used to register an NVTX string must contain a static constexpr member " 1624 "called 'message' of type const char* or const wchar_t* -- 'message' member is " 1625 "not convertible to either of those types"); 1626 static registered_string_in const unused; 1627 return unused; // Function must compile for static_assert to be triggered 1628 } 1629 1630 /** 1631 * @brief Overload of `registered_string_in::get` to provide a clear compile error when 1632 * `M` does not have a `message` member. 1633 */ 1634 template <typename M, 1635 typename std::enable_if< 1636 !detail::has_message<M>::value 1637 , int>::type = 0> 1638 NVTX3_NO_DISCARD static registered_string_in const& get() noexcept 1639 { 1640 NVTX3_STATIC_ASSERT(detail::always_false<M>::value, 1641 "Type used to register an NVTX string must contain a static constexpr member " 1642 "called 'message' of type const char* or const wchar_t* -- 'message' member " 1643 "is missing"); 1644 static registered_string_in const unused; 1645 return unused; // Function must compile for static_assert to be triggered 1646 } 1647 #else 1648 template <typename M> 1649 NVTX3_NO_DISCARD static registered_string_in const& get() noexcept 1650 { 1651 static registered_string_in const regstr(M::message); 1652 return regstr; 1653 } 1654 #endif 1655 1656 /** 1657 * @brief Constructs a `registered_string_in` from the specified `msg` string. 1658 * 1659 * Registers `msg` with NVTX and associates a handle with the registered 1660 * message. 1661 * 1662 * A particular message should should only be registered once and the handle 1663 * reused throughout the rest of the application. 1664 * 1665 * @param msg The contents of the message 1666 */ 1667 explicit registered_string_in(char const* msg) noexcept 1668 : handle_{nvtxDomainRegisterStringA(domain::get<D>(), msg)} 1669 { 1670 } 1671 1672 /** 1673 * @brief Constructs a `registered_string_in` from the specified `msg` string. 1674 * 1675 * Registers `msg` with NVTX and associates a handle with the registered 1676 * message. 1677 * 1678 * A particular message should should only be registered once and the handle 1679 * reused throughout the rest of the application. 1680 * 1681 * @param msg The contents of the message 1682 */ 1683 explicit registered_string_in(std::string const& msg) noexcept 1684 : registered_string_in{msg.c_str()} {} 1685 1686 /** 1687 * @brief Constructs a `registered_string_in` from the specified `msg` string. 1688 * 1689 * Registers `msg` with NVTX and associates a handle with the registered 1690 * message. 1691 * 1692 * A particular message should should only be registered once and the handle 1693 * reused throughout the rest of the application. 1694 * 1695 * @param msg The contents of the message 1696 */ 1697 explicit registered_string_in(wchar_t const* msg) noexcept 1698 : handle_{nvtxDomainRegisterStringW(domain::get<D>(), msg)} 1699 { 1700 } 1701 1702 /** 1703 * @brief Constructs a `registered_string_in` from the specified `msg` string. 1704 * 1705 * Registers `msg` with NVTX and associates a handle with the registered 1706 * message. 1707 * 1708 * A particular message should only be registered once and the handle 1709 * reused throughout the rest of the application. 1710 * 1711 * @param msg The contents of the message 1712 */ 1713 explicit registered_string_in(std::wstring const& msg) noexcept 1714 : registered_string_in{msg.c_str()} {} 1715 1716 /** 1717 * @brief Returns the registered string's handle 1718 * 1719 */ 1720 nvtxStringHandle_t get_handle() const noexcept 1721 { 1722 // We want to ensure that we can use the registered_string in place of a handle 1723 // in a payload data struct. 1724 NVTX3_STATIC_ASSERT( 1725 (detail::is_safe_wrapper_of<registered_string_in<D>, nvtxStringHandle_t>::value), 1726 "Internal error! registered_string_in is potentially unsafe."); 1727 return handle_; 1728 } 1729 1730 private: 1731 // Default constructor is only used internally for static_assert(false) cases. 1732 registered_string_in() noexcept {} 1733 public: 1734 ~registered_string_in() = default; 1735 registered_string_in(registered_string_in const&) = default; 1736 registered_string_in& operator=(registered_string_in const&) = default; 1737 registered_string_in(registered_string_in&&) = default; 1738 registered_string_in& operator=(registered_string_in&&) = default; 1739 1740 private: 1741 nvtxStringHandle_t handle_{}; ///< The handle returned from 1742 ///< registering the message with NVTX 1743 }; 1744 1745 /** 1746 * @brief Alias for a `registered_string_in` in the global NVTX domain. 1747 * 1748 */ 1749 using registered_string = registered_string_in<domain::global>; 1750 1751 /** 1752 * @brief Allows associating a message string with an NVTX event via 1753 * its `EventAttribute`s. 1754 * 1755 * Associating a `message` with an NVTX event through its `event_attributes` 1756 * allows for naming events to easily differentiate them from other events. 1757 * 1758 * Every time an NVTX event is created with an associated `message`, the 1759 * contents of the message string must be copied. This may cause non-trivial 1760 * overhead in highly performance sensitive sections of code. Use of a 1761 * `nvtx3::registered_string` is recommended in these situations. 1762 * 1763 * Example: 1764 * \code{.cpp} 1765 * // Creates an `event_attributes` with message "message 0" 1766 * nvtx3::event_attributes attr0{nvtx3::message{"message 0"}}; 1767 * 1768 * // `range0` contains message "message 0" 1769 * nvtx3::scoped_range range0{attr0}; 1770 * 1771 * // `std::string` and string literals are implicitly assumed to be 1772 * // the contents of an `nvtx3::message` 1773 * // Creates an `event_attributes` with message "message 1" 1774 * nvtx3::event_attributes attr1{"message 1"}; 1775 * 1776 * // `range1` contains message "message 1" 1777 * nvtx3::scoped_range range1{attr1}; 1778 * 1779 * // `range2` contains message "message 2" 1780 * nvtx3::scoped_range range2{nvtx3::message{"message 2"}}; 1781 * 1782 * // `std::string` and string literals are implicitly assumed to be 1783 * // the contents of an `nvtx3::message` 1784 * // `range3` contains message "message 3" 1785 * nvtx3::scoped_range range3{"message 3"}; 1786 * \endcode 1787 */ 1788 class message { 1789 public: 1790 using value_type = nvtxMessageValue_t; 1791 1792 /** 1793 * @brief Construct a `message` whose contents are specified by `msg`. 1794 * 1795 * @param msg The contents of the message 1796 */ 1797 NVTX3_CONSTEXPR_IF_CPP14 message(char const* msg) noexcept : type_{NVTX_MESSAGE_TYPE_ASCII} 1798 { 1799 value_.ascii = msg; 1800 } 1801 1802 /** 1803 * @brief Construct a `message` whose contents are specified by `msg`. 1804 * 1805 * @param msg The contents of the message 1806 */ 1807 message(std::string const& msg) noexcept : message{msg.c_str()} {} 1808 1809 /** 1810 * @brief Disallow construction for `std::string` r-value 1811 * 1812 * `message` is a non-owning type and therefore cannot take ownership of an 1813 * r-value. Therefore, constructing from an r-value is disallowed to prevent 1814 * a dangling pointer. 1815 * 1816 */ 1817 #ifndef NVTX3_ALLOW_RVALUE_CONSTRUCTORS 1818 message(std::string&&) = delete; 1819 #endif 1820 1821 /** 1822 * @brief Construct a `message` whose contents are specified by `msg`. 1823 * 1824 * @param msg The contents of the message 1825 */ 1826 NVTX3_CONSTEXPR_IF_CPP14 message(wchar_t const* msg) noexcept : type_{NVTX_MESSAGE_TYPE_UNICODE} 1827 { 1828 value_.unicode = msg; 1829 } 1830 1831 /** 1832 * @brief Construct a `message` whose contents are specified by `msg`. 1833 * 1834 * @param msg The contents of the message 1835 */ 1836 message(std::wstring const& msg) noexcept : message{msg.c_str()} {} 1837 1838 /** 1839 * @brief Disallow construction for `std::wstring` r-value 1840 * 1841 * `message` is a non-owning type and therefore cannot take ownership of an 1842 * r-value. Therefore, constructing from an r-value is disallowed to prevent 1843 * a dangling pointer. 1844 * 1845 */ 1846 #ifndef NVTX3_ALLOW_RVALUE_CONSTRUCTORS 1847 message(std::wstring&&) = delete; 1848 #endif 1849 1850 /** 1851 * @brief Construct a `message` from a `registered_string_in`. 1852 * 1853 * @tparam D Type containing `name` member used to identify the `domain` 1854 * to which the `registered_string_in` belongs. Else, `domain::global` to 1855 * indicate that the global NVTX domain should be used. 1856 * @param msg The message that has already been registered with NVTX. 1857 */ 1858 template <typename D> 1859 NVTX3_CONSTEXPR_IF_CPP14 message(registered_string_in<D> const& msg) noexcept 1860 : type_{NVTX_MESSAGE_TYPE_REGISTERED} 1861 { 1862 value_.registered = msg.get_handle(); 1863 } 1864 1865 /** 1866 * @brief Construct a `message` from NVTX C API type and value. 1867 * 1868 * @param type nvtxMessageType_t enum value indicating type of the payload 1869 * @param value nvtxMessageValue_t union containing message 1870 */ 1871 constexpr message( 1872 nvtxMessageType_t const& type, 1873 nvtxMessageValue_t const& value) noexcept 1874 : type_{type}, value_(value) 1875 { 1876 } 1877 1878 /** 1879 * @brief Construct a `message` from NVTX C API registered string handle. 1880 * 1881 * @param handle nvtxStringHandle_t value of registered string handle 1882 */ 1883 NVTX3_CONSTEXPR_IF_CPP14 message(nvtxStringHandle_t handle) noexcept 1884 : type_{NVTX_MESSAGE_TYPE_REGISTERED} 1885 { 1886 value_.registered = handle; 1887 } 1888 1889 /** 1890 * @brief Return the union holding the value of the message. 1891 * 1892 */ 1893 constexpr value_type get_value() const noexcept { return value_; } 1894 1895 /** 1896 * @brief Return the type information about the value the union holds. 1897 * 1898 */ 1899 constexpr nvtxMessageType_t get_type() const noexcept { return type_; } 1900 1901 private: 1902 nvtxMessageType_t type_{}; ///< message type 1903 nvtxMessageValue_t value_{}; ///< message contents 1904 }; 1905 1906 /** 1907 * @brief A numerical value that can be associated with an NVTX event via 1908 * its `event_attributes`. 1909 * 1910 * Example: 1911 * \code{.cpp} 1912 * // Constructs a payload from the int32_t value 42 1913 * nvtx3:: event_attributes attr{nvtx3::payload{42}}; 1914 * 1915 * // `range0` will have an int32_t payload of 42 1916 * nvtx3::scoped_range range0{attr}; 1917 * 1918 * // range1 has double payload of 3.14 1919 * nvtx3::scoped_range range1{nvtx3::payload{3.14}}; 1920 * \endcode 1921 */ 1922 class payload { 1923 public: 1924 using value_type = typename nvtxEventAttributes_v2::payload_t; 1925 1926 /** 1927 * @brief Construct a `payload` from a signed, 8 byte integer. 1928 * 1929 * @param value Value to use as contents of the payload 1930 */ 1931 NVTX3_CONSTEXPR_IF_CPP14 explicit payload(int64_t value) noexcept 1932 : type_{NVTX_PAYLOAD_TYPE_INT64}, value_{} 1933 { 1934 value_.llValue = value; 1935 } 1936 1937 /** 1938 * @brief Construct a `payload` from a signed, 4 byte integer. 1939 * 1940 * @param value Value to use as contents of the payload 1941 */ 1942 NVTX3_CONSTEXPR_IF_CPP14 explicit payload(int32_t value) noexcept 1943 : type_{NVTX_PAYLOAD_TYPE_INT32}, value_{} 1944 { 1945 value_.iValue = value; 1946 } 1947 1948 /** 1949 * @brief Construct a `payload` from an unsigned, 8 byte integer. 1950 * 1951 * @param value Value to use as contents of the payload 1952 */ 1953 NVTX3_CONSTEXPR_IF_CPP14 explicit payload(uint64_t value) noexcept 1954 : type_{NVTX_PAYLOAD_TYPE_UNSIGNED_INT64}, value_{} 1955 { 1956 value_.ullValue = value; 1957 } 1958 1959 /** 1960 * @brief Construct a `payload` from an unsigned, 4 byte integer. 1961 * 1962 * @param value Value to use as contents of the payload 1963 */ 1964 NVTX3_CONSTEXPR_IF_CPP14 explicit payload(uint32_t value) noexcept 1965 : type_{NVTX_PAYLOAD_TYPE_UNSIGNED_INT32}, value_{} 1966 { 1967 value_.uiValue = value; 1968 } 1969 1970 /** 1971 * @brief Construct a `payload` from a single-precision floating point 1972 * value. 1973 * 1974 * @param value Value to use as contents of the payload 1975 */ 1976 NVTX3_CONSTEXPR_IF_CPP14 explicit payload(float value) noexcept 1977 : type_{NVTX_PAYLOAD_TYPE_FLOAT}, value_{} 1978 { 1979 value_.fValue = value; 1980 } 1981 1982 /** 1983 * @brief Construct a `payload` from a double-precision floating point 1984 * value. 1985 * 1986 * @param value Value to use as contents of the payload 1987 */ 1988 NVTX3_CONSTEXPR_IF_CPP14 explicit payload(double value) noexcept 1989 : type_{NVTX_PAYLOAD_TYPE_DOUBLE}, value_{} 1990 { 1991 value_.dValue = value; 1992 } 1993 1994 /** 1995 * @brief Construct a `payload` from NVTX C API type and value. 1996 * 1997 * @param type nvtxPayloadType_t enum value indicating type of the payload 1998 * @param value nvtxEventAttributes_t::payload_t union containing payload 1999 */ 2000 constexpr payload( 2001 nvtxPayloadType_t const& type, 2002 value_type const& value) noexcept 2003 : type_{type}, value_(value) 2004 { 2005 } 2006 2007 /** 2008 * @brief Return the union holding the value of the payload 2009 * 2010 */ 2011 constexpr value_type get_value() const noexcept { return value_; } 2012 2013 /** 2014 * @brief Return the information about the type the union holds. 2015 * 2016 */ 2017 constexpr nvtxPayloadType_t get_type() const noexcept { return type_; } 2018 2019 private: 2020 nvtxPayloadType_t type_; ///< Type of the payload value 2021 value_type value_; ///< Union holding the payload value 2022 }; 2023 2024 /** 2025 * @brief Represents the registered schema for a payload struct. 2026 * 2027 * This class encapsulates the schema ID obtained by registering a payload struct 2028 * using `nvtxPayloadSchemaRegister`. The primary mechanism for obtaining an 2029 * instance is via the static template function `get<T>()`, which must be 2030 * specialized for each payload struct type `T` using the 2031 * `NVTX3_DEFINE_SCHEMA_GET` (`NVTX3_V1_DEFINE_SCHEMA_GET()`) macro. 2032 * 2033 * The schema ID is used internally when constructing `payload_data` objects. 2034 */ 2035 class schema 2036 { 2037 private: 2038 /** 2039 * @brief Private default constructor. 2040 * 2041 * Used only internally for static_assert(false) cases. 2042 */ 2043 schema() 2044 : _schema_id{0} 2045 {} 2046 2047 public: 2048 schema(schema const&) = delete; 2049 schema& operator=(schema const&) = delete; 2050 schema(schema&&) = delete; 2051 schema& operator=(schema&&) = delete; 2052 2053 /** 2054 * @brief Constructs a schema object directly from a schema ID. 2055 * 2056 * This constructor is primarily for internal use or advanced scenarios where 2057 * the schema ID is obtained manually. 2058 * 2059 * @param id The NVTX schema ID. 2060 */ 2061 explicit schema(uint64_t id) 2062 : _schema_id{id} 2063 {} 2064 2065 /** 2066 * @brief Gets the schema instance for a specific payload struct type. 2067 * 2068 * This function relies on template specialization. Users must provide a 2069 * specialization for each payload struct type `T` using the 2070 * `NVTX3_DEFINE_SCHEMA_GET` (`NVTX3_V1_DEFINE_SCHEMA_GET()`) macro. 2071 * 2072 * @tparam T The payload struct type for which to get the schema. 2073 * @return A constant reference to the schema object for type `T`. 2074 */ 2075 template <typename T> 2076 NVTX3_NO_DISCARD static schema const& get() noexcept 2077 { 2078 NVTX3_STATIC_ASSERT( 2079 detail::always_false<T>::value, 2080 "payload_data schema deduction requires a template specialization. Use the macro " 2081 "NVTX3_DEFINE_SCHEMA_GET to generate this specialization."); 2082 static schema unused; 2083 return unused; 2084 } 2085 2086 /** 2087 * @brief Return the underlying C handle of the schema. 2088 */ 2089 uint64_t get_handle() const noexcept 2090 { 2091 return _schema_id; 2092 } 2093 2094 private: 2095 uint64_t const _schema_id; 2096 }; 2097 2098 /** 2099 * @brief Wrapper around the NVTX C API `nvtxPayloadData_t` struct. 2100 * 2101 * This class facilitates associating a structured payload with an NVTX event. 2102 * It combines a pointer to the payload data instance with its registered schema 2103 * ID and size. 2104 */ 2105 class payload_data 2106 { 2107 public: 2108 /** 2109 * @brief Constructs `payload_data` from an existing NVTX C API struct. 2110 * 2111 * Provides interoperability with code using the NVTX C API directly. 2112 * 2113 * @param pd An existing `nvtxPayloadData_t` struct. 2114 */ 2115 explicit payload_data(nvtxPayloadData_t const& pd) 2116 : data_(pd) 2117 {} 2118 2119 /** 2120 * @brief Constructs `payload_data` for a specific payload struct instance. 2121 * 2122 * This template constructor automatically retrieves the necessary information 2123 * from the given struct type `T` and the reference to the instance. 2124 * The type `T` must be standard layout and trivially copyable as well as 2125 * have a `schema::get<T>()` specialization via `NVTX3_DEFINE_SCHEMA_GET` (`NVTX3_V1_DEFINE_SCHEMA_GET()`). 2126 * 2127 * Make sure the provided referenace is valid for the lifetime of the created 2128 * `payload_data` object. 2129 * 2130 * @param t A constant reference to the payload struct instance. 2131 */ 2132 // We cannot simply delete the rvalue constructor here because with a template 2133 // parameter that would be a forwarding reference. Thus, we have this one 2134 // ctor with a forwarding reference and use a static assert for the rvalue check. 2135 // Disable this for the C-style nvtxPayloadData_t to prefer above ctor for non-const. 2136 template < 2137 typename R, 2138 typename T = typename std::remove_cv<typename std::remove_reference<R>::type>::type, 2139 typename = typename std::enable_if<!std::is_same<T, nvtxPayloadData_t>::value>::type> 2140 explicit payload_data(R&& t) 2141 : data_{schema::get<T>().get_handle(), sizeof(T), &t} 2142 { 2143 #ifndef NVTX3_ALLOW_RVALUE_CONSTRUCTORS 2144 NVTX3_STATIC_ASSERT( 2145 std::is_lvalue_reference<R>::value, 2146 "payload_data requires an lvalue reference to the underlying data. Constructing " 2147 "from an rvalue is potentially unsafe and therefore forbidden."); 2148 #endif 2149 NVTX3_STATIC_ASSERT( 2150 std::is_standard_layout<T>::value && std::is_trivially_copyable<T>::value, 2151 "structs used for NVTX3 payload schema must be standard layout and trivially copyable"); 2152 } 2153 2154 /** 2155 * @brief Constructs `payload_data` for a payload instance with a given schema. 2156 * 2157 * Use this constructor if you have a dynamic schema for your struct rather than 2158 * a static one defined by `NVTX3_DEFINE_SCHEMA_GET` (`NVTX3_V1_DEFINE_SCHEMA_GET()`). 2159 * 2160 * Make sure the provided referenace is valid for the lifetime of the created 2161 * `payload_data` object. 2162 * 2163 * @param t A constant reference to the payload struct instance. 2164 * @param s The schema to use for the payload data. 2165 */ 2166 template <typename T> 2167 explicit payload_data(T const& t, schema s) 2168 : data_{s.get_handle(), sizeof(T), &t} 2169 { 2170 NVTX3_STATIC_ASSERT( 2171 std::is_standard_layout<T>::value && std::is_trivially_copyable<T>::value, 2172 "structs used for NVTX3 payload schema must be standard layout and trivially copyable"); 2173 } 2174 2175 /** 2176 * @return A pointer to the `nvtxPayloadData_t` struct as ullValue to use 2177 * with NVTX C API functions. 2178 */ 2179 uint64_t as_ull_value() const noexcept 2180 { 2181 NVTX3_STATIC_ASSERT( 2182 (detail::is_safe_wrapper_of<payload_data, nvtxPayloadData_t>::value), 2183 "Internal error! payload_data is potentially unsafe."); 2184 return NVTX_POINTER_AS_PAYLOAD_ULLVALUE(&data_); 2185 } 2186 2187 private: 2188 nvtxPayloadData_t data_; 2189 }; 2190 2191 /** 2192 * @brief Describes the attributes of a NVTX event. 2193 * 2194 * NVTX events can be customized via four "attributes": 2195 * 2196 * - color: color used to visualize the event in tools such as Nsight 2197 * Systems. See `color`. 2198 * - message: Custom message string. See `message`. 2199 * - payload: User-defined numerical value. See `payload`. 2200 * - category: Intra-domain grouping. See `category`. 2201 * 2202 * These component attributes are specified via an `event_attributes` object. 2203 * See `nvtx3::color`, `nvtx3::message`, `nvtx3::payload`, and 2204 * `nvtx3::category` for how these individual attributes are constructed. 2205 * 2206 * While it is possible to specify all four attributes, it is common to want 2207 * to only specify a subset of attributes and use default values for the 2208 * others. For convenience, `event_attributes` can be constructed from any 2209 * number of attribute components in any order. 2210 * 2211 * Example: 2212 * \code{.cpp} 2213 * // Set message, same as using nvtx3::message{"message"} 2214 * event_attributes attr{"message"}; 2215 * 2216 * // Set message and color 2217 * event_attributes attr{"message", nvtx3::rgb{127, 255, 0}}; 2218 * 2219 * // Set message, color, payload, category 2220 * event_attributes attr{"message", 2221 * nvtx3::rgb{127, 255, 0}, 2222 * nvtx3::payload{42}, 2223 * nvtx3::category{1}}; 2224 * 2225 * // Same as above -- can use any order of arguments 2226 * event_attributes attr{nvtx3::payload{42}, 2227 * nvtx3::category{1}, 2228 * "message", 2229 * nvtx3::rgb{127, 255, 0}}; 2230 * 2231 * // Multiple arguments of the same type are allowed, but only the first is 2232 * // used -- in this example, payload is set to 42: 2233 * event_attributes attr{ nvtx3::payload{42}, nvtx3::payload{7} }; 2234 * 2235 * // Range `r` will be customized according the attributes in `attr` 2236 * nvtx3::scoped_range r{attr}; 2237 * 2238 * // For convenience, `event_attributes` constructor arguments may be passed 2239 * // to the `scoped_range_in` constructor -- they are forwarded to the 2240 * // `event_attributes` constructor 2241 * nvtx3::scoped_range r{nvtx3::payload{42}, nvtx3::category{1}, "message"}; 2242 * 2243 * // Using the nvtx3 namespace in a local scope makes the syntax more succinct: 2244 * using namespace nvtx3; 2245 * scoped_range r{payload{42}, category{1}, "message"}; 2246 * \endcode 2247 * 2248 */ 2249 class event_attributes { 2250 public: 2251 using value_type = nvtxEventAttributes_t; 2252 2253 /** 2254 * @brief Default constructor creates an `event_attributes` with no 2255 * category, color, payload, nor message. 2256 */ 2257 constexpr event_attributes() noexcept 2258 : attributes_{ 2259 NVTX_VERSION, // version 2260 sizeof(nvtxEventAttributes_t), // size 2261 0, // category 2262 NVTX_COLOR_UNKNOWN, // color type 2263 0, // color value 2264 NVTX_PAYLOAD_UNKNOWN, // payload type 2265 0, // reserved 4B 2266 {0}, // payload value (union) 2267 NVTX_MESSAGE_UNKNOWN, // message type 2268 {nullptr} // message value (union) 2269 } 2270 { 2271 } 2272 2273 /** 2274 * @brief Variadic constructor where the first argument is a `category`. 2275 * 2276 * Sets the value of the `EventAttribute`s category based on `c` and 2277 * forwards the remaining variadic parameter pack to the next constructor. 2278 * 2279 */ 2280 template <typename... Args> 2281 NVTX3_CONSTEXPR_IF_CPP14 explicit event_attributes(category const& c, Args const&... args) noexcept 2282 : event_attributes(args...) 2283 { 2284 attributes_.category = c.get_id(); 2285 } 2286 2287 /** 2288 * @brief Variadic constructor where the first argument is a `color`. 2289 * 2290 * Sets the value of the `EventAttribute`s color based on `c` and forwards 2291 * the remaining variadic parameter pack to the next constructor. 2292 * 2293 */ 2294 template <typename... Args> 2295 NVTX3_CONSTEXPR_IF_CPP14 explicit event_attributes(color const& c, Args const&... args) noexcept 2296 : event_attributes(args...) 2297 { 2298 attributes_.color = c.get_value(); 2299 attributes_.colorType = c.get_type(); 2300 } 2301 2302 /** 2303 * @brief Variadic constructor where the first argument is a `payload`. 2304 * 2305 * Sets the value of the `EventAttribute`s payload based on `p` and forwards 2306 * the remaining variadic parameter pack to the next constructor. 2307 * 2308 */ 2309 template <typename... Args> 2310 NVTX3_CONSTEXPR_IF_CPP14 explicit event_attributes(payload const& p, Args const&... args) noexcept 2311 : event_attributes(args...) 2312 { 2313 attributes_.payload = p.get_value(); 2314 attributes_.payloadType = p.get_type(); 2315 } 2316 2317 /** 2318 * @brief Variadic constructor where the first argument is a single `payload_data`. 2319 * 2320 * Sets the value of the `EventAttribute`s payload data based on `pd` and forwards 2321 * the remaining variadic parameter pack to the next constructor. 2322 * 2323 */ 2324 template <typename... Args> 2325 NVTX3_CONSTEXPR_IF_CPP14 explicit event_attributes(payload_data const& pd, Args const&... args) noexcept 2326 : event_attributes(args...) 2327 { 2328 attributes_.payloadType = NVTX_PAYLOAD_TYPE_EXT; 2329 attributes_.reserved0 = 1; 2330 attributes_.payload.ullValue = pd.as_ull_value(); 2331 } 2332 2333 /** 2334 * @brief Deleted constructor for `payload_data` rvalue references. 2335 * 2336 * `event_attributes` is non-owning and therefore cannot take ownership of an r-value 2337 * `payload_data`. Therefore this constructor is deleted by default to prevent dangling 2338 * pointers. 2339 */ 2340 #ifndef NVTX3_ALLOW_RVALUE_CONSTRUCTORS 2341 template <typename... Args> 2342 NVTX3_CONSTEXPR_IF_CPP14 explicit event_attributes(payload_data&& pd, Args const&... args) = delete; 2343 #endif 2344 2345 /** 2346 * @brief Variadic constructor template for containers of `payload_data`. 2347 * 2348 * Associates multiple structured payloads contained in `pdc` with the event attributes. 2349 * This constructor is enabled for types that have both a `data()` member function 2350 * returning `payload_data*` or `const payload_data*` and a `size()` member function. 2351 * E.g., `std::vector` or `std::array` can be used. 2352 * Forwards the remaining variadic parameter pack to the next constructor. 2353 */ 2354 template < 2355 typename T, 2356 typename... Args, 2357 typename = typename std::enable_if< 2358 detail::has_data_member<T, payload_data>::value && detail::has_size_member<T>::value>::type> 2359 NVTX3_CONSTEXPR_IF_CPP20 explicit event_attributes(T&& pdc, Args const&... args) noexcept 2360 : event_attributes(args...) 2361 { 2362 NVTX3_STATIC_ASSERT( 2363 std::is_lvalue_reference<T>::value, 2364 "event_attributes requires an lvalue reference to the underlying data. " 2365 "Constructing from an rvalue is potentially unsafe and therefore forbidden."); 2366 attributes_.payloadType = NVTX_PAYLOAD_TYPE_EXT; 2367 attributes_.reserved0 = static_cast<int32_t>(pdc.size()); // Cast size to int32_t 2368 attributes_.payload.ullValue = pdc.data()->as_ull_value(); 2369 } 2370 2371 /** 2372 * @brief Variadic constructor where the first argument is a `message`. 2373 * 2374 * Sets the value of the `EventAttribute`s message based on `m` and forwards 2375 * the remaining variadic parameter pack to the next constructor. 2376 * 2377 */ 2378 template <typename... Args> 2379 NVTX3_CONSTEXPR_IF_CPP14 explicit event_attributes(message const& m, Args const&... args) noexcept 2380 : event_attributes(args...) 2381 { 2382 attributes_.message = m.get_value(); 2383 attributes_.messageType = m.get_type(); 2384 } 2385 2386 ~event_attributes() = default; 2387 event_attributes(event_attributes const&) = default; 2388 event_attributes& operator=(event_attributes const&) = default; 2389 event_attributes(event_attributes&&) = default; 2390 event_attributes& operator=(event_attributes&&) = default; 2391 2392 /** 2393 * @brief Get raw pointer to underlying NVTX attributes object. 2394 * 2395 */ 2396 constexpr value_type const* get() const noexcept { return &attributes_; } 2397 2398 private: 2399 value_type attributes_{}; ///< The NVTX attributes structure 2400 }; 2401 2402 /** 2403 * @brief A RAII object for creating a NVTX range local to a thread within a 2404 * domain. 2405 * 2406 * When constructed, begins a nested NVTX range on the calling thread in the 2407 * specified domain. Upon destruction, ends the NVTX range. 2408 * 2409 * Behavior is undefined if a `scoped_range_in` object is 2410 * created/destroyed on different threads. 2411 * 2412 * `scoped_range_in` is neither movable nor copyable. 2413 * 2414 * `scoped_range_in`s may be nested within other ranges. 2415 * 2416 * The domain of the range is specified by the template type parameter `D`. 2417 * By default, the `domain::global` is used, which scopes the range to the 2418 * global NVTX domain. The convenience alias `scoped_range` is provided for 2419 * ranges scoped to the global domain. 2420 * 2421 * A custom domain can be defined by creating a type, `D`, with a static 2422 * member `D::name` whose value is used to name the domain associated with 2423 * `D`. `D::name` must resolve to either `char const*` or `wchar_t const*` 2424 * 2425 * Example: 2426 * \code{.cpp} 2427 * // Define a type `my_domain` with a member `name` used to name the domain 2428 * // associated with the type `my_domain`. 2429 * struct my_domain{ 2430 * static constexpr char const* name{"my domain"}; 2431 * }; 2432 * \endcode 2433 * 2434 * Usage: 2435 * \code{.cpp} 2436 * nvtx3::scoped_range_in<my_domain> r1{"range 1"}; // Range in my domain 2437 * 2438 * // Three equivalent ways to make a range in the global domain: 2439 * nvtx3::scoped_range_in<nvtx3::domain::global> r2{"range 2"}; 2440 * nvtx3::scoped_range_in<> r3{"range 3"}; 2441 * nvtx3::scoped_range r4{"range 4"}; 2442 * 2443 * // Create an alias to succinctly make ranges in my domain: 2444 * using my_scoped_range = nvtx3::scoped_range_in<my_domain>; 2445 * 2446 * my_scoped_range r3{"range 3"}; 2447 * \endcode 2448 */ 2449 template <class D = domain::global> 2450 class NVTX3_MAYBE_UNUSED scoped_range_in { 2451 public: 2452 /** 2453 * @brief Construct a `scoped_range_in` with the specified 2454 * `event_attributes` 2455 * 2456 * Example: 2457 * \code{cpp} 2458 * nvtx3::event_attributes attr{"msg", nvtx3::rgb{127,255,0}}; 2459 * nvtx3::scoped_range range{attr}; // Creates a range with message contents 2460 * // "msg" and green color 2461 * \endcode 2462 * 2463 * @param[in] attr `event_attributes` that describes the desired attributes 2464 * of the range. 2465 */ 2466 explicit scoped_range_in(event_attributes const& attr) noexcept 2467 { 2468 #ifndef NVTX_DISABLE 2469 nvtxDomainRangePushEx(domain::get<D>(), attr.get()); 2470 #else 2471 (void)attr; 2472 #endif 2473 } 2474 2475 /** 2476 * @brief Constructs a `scoped_range_in` from the constructor arguments 2477 * of an `event_attributes`. 2478 * 2479 * Forwards the arguments `args...` to construct an 2480 * `event_attributes` object. The `event_attributes` object is then 2481 * associated with the `scoped_range_in`. 2482 * 2483 * For more detail, see `event_attributes` documentation. 2484 * 2485 * Example: 2486 * \code{cpp} 2487 * // Creates a range with message "message" and green color 2488 * nvtx3::scoped_range r{"message", nvtx3::rgb{127,255,0}}; 2489 * \endcode 2490 * 2491 * @param[in] args Arguments to used to construct an `event_attributes` associated with this 2492 * range. 2493 * 2494 */ 2495 template <typename... Args> 2496 explicit scoped_range_in(Args const&... args) noexcept 2497 : scoped_range_in{event_attributes{args...}} 2498 { 2499 } 2500 2501 /** 2502 * @brief Default constructor creates a `scoped_range_in` with no 2503 * message, color, payload, nor category. 2504 * 2505 */ 2506 scoped_range_in() noexcept : scoped_range_in{event_attributes{}} {} 2507 2508 /** 2509 * @brief Delete `operator new` to disallow heap allocated objects. 2510 * 2511 * `scoped_range_in` must follow RAII semantics to guarantee proper push/pop semantics. 2512 * 2513 */ 2514 void* operator new(std::size_t) = delete; 2515 2516 scoped_range_in(scoped_range_in const&) = delete; 2517 scoped_range_in& operator=(scoped_range_in const&) = delete; 2518 scoped_range_in(scoped_range_in&&) = delete; 2519 scoped_range_in& operator=(scoped_range_in&&) = delete; 2520 2521 /** 2522 * @brief Destroy the scoped_range_in, ending the NVTX range event. 2523 */ 2524 ~scoped_range_in() noexcept 2525 { 2526 #ifndef NVTX_DISABLE 2527 nvtxDomainRangePop(domain::get<D>()); 2528 #endif 2529 } 2530 }; 2531 2532 /** 2533 * @brief Alias for a `scoped_range_in` in the global NVTX domain. 2534 * 2535 */ 2536 using scoped_range = scoped_range_in<domain::global>; 2537 2538 namespace detail { 2539 2540 /// @cond internal 2541 template <typename D = domain::global> 2542 class NVTX3_MAYBE_UNUSED optional_scoped_range_in 2543 { 2544 public: 2545 optional_scoped_range_in() = default; 2546 2547 void begin(event_attributes const& attr) noexcept 2548 { 2549 #ifndef NVTX_DISABLE 2550 // This class is not meant to be part of the public NVTX C++ API and should 2551 // only be used in the `NVTX3_FUNC_RANGE_IF` and `NVTX3_FUNC_RANGE_IF_IN` 2552 // macros. However, to prevent developers from misusing this class, make 2553 // sure to not start multiple ranges. 2554 if (initialized) { return; } 2555 2556 nvtxDomainRangePushEx(domain::get<D>(), attr.get()); 2557 initialized = true; 2558 #else 2559 (void)attr; 2560 #endif 2561 } 2562 2563 ~optional_scoped_range_in() noexcept 2564 { 2565 #ifndef NVTX_DISABLE 2566 if (initialized) { nvtxDomainRangePop(domain::get<D>()); } 2567 #endif 2568 } 2569 2570 void* operator new(std::size_t) = delete; 2571 optional_scoped_range_in(optional_scoped_range_in const&) = delete; 2572 optional_scoped_range_in& operator=(optional_scoped_range_in const&) = delete; 2573 optional_scoped_range_in(optional_scoped_range_in&&) = delete; 2574 optional_scoped_range_in& operator=(optional_scoped_range_in&&) = delete; 2575 2576 private: 2577 #ifndef NVTX_DISABLE 2578 bool initialized = false; 2579 #endif 2580 }; 2581 /// @endcond 2582 2583 } // namespace detail 2584 2585 /** 2586 * @brief Handle used for correlating explicit range start and end events. 2587 * 2588 * A handle is "null" if it does not correspond to any range. 2589 * 2590 */ 2591 struct range_handle { 2592 /// Type used for the handle's value 2593 using value_type = nvtxRangeId_t; 2594 2595 2596 /** 2597 * @brief Construct a `range_handle` from the given id. 2598 * 2599 */ 2600 constexpr explicit range_handle(value_type id) noexcept : _range_id{id} {} 2601 2602 /** 2603 * @brief Constructs a null range handle. 2604 * 2605 * A null range_handle corresponds to no range. Calling `end_range` on a 2606 * null handle is undefined behavior when a tool is active. 2607 * 2608 */ 2609 constexpr range_handle() noexcept = default; 2610 2611 /** 2612 * @brief Checks whether this handle is null 2613 * 2614 * Provides contextual conversion to `bool`. 2615 * 2616 * \code{cpp} 2617 * range_handle handle{}; 2618 * if (handle) {...} 2619 * \endcode 2620 * 2621 */ 2622 constexpr explicit operator bool() const noexcept { return get_value() != null_range_id; } 2623 2624 /** 2625 * @brief Implicit conversion from `nullptr` constructs a null handle. 2626 * 2627 * Satisfies the "NullablePointer" requirement to make `range_handle` comparable with `nullptr`. 2628 * 2629 */ 2630 constexpr range_handle(std::nullptr_t) noexcept {} 2631 2632 /** 2633 * @brief Returns the `range_handle`'s value 2634 * 2635 * @return value_type The handle's value 2636 */ 2637 constexpr value_type get_value() const noexcept { return _range_id; } 2638 2639 private: 2640 /// Sentinel value for a null handle that corresponds to no range 2641 static constexpr value_type null_range_id = nvtxRangeId_t{0}; 2642 2643 value_type _range_id{null_range_id}; ///< The underlying NVTX range id 2644 }; 2645 2646 /** 2647 * @brief Compares two range_handles for equality 2648 * 2649 * @param lhs The first range_handle to compare 2650 * @param rhs The second range_handle to compare 2651 */ 2652 inline constexpr bool operator==(range_handle lhs, range_handle rhs) noexcept 2653 { 2654 return lhs.get_value() == rhs.get_value(); 2655 } 2656 2657 /** 2658 * @brief Compares two range_handles for inequality 2659 * 2660 * @param lhs The first range_handle to compare 2661 * @param rhs The second range_handle to compare 2662 */ 2663 inline constexpr bool operator!=(range_handle lhs, range_handle rhs) noexcept { return !(lhs == rhs); } 2664 2665 /** 2666 * @brief Manually begin an NVTX range. 2667 * 2668 * Explicitly begins an NVTX range and returns a unique handle. To end the 2669 * range, pass the handle to `end_range_in<D>()`. 2670 * 2671 * `nvtx3::start_range(...)` is equivalent to `nvtx3::start_range_in<>(...)` and 2672 * `nvtx3::start_range_in<nvtx3::domain::global>(...)`. 2673 * 2674 * `start_range_in/end_range_in` are the most explicit and lowest level APIs 2675 * provided for creating ranges. Use of `nvtx3::unique_range_in` should be 2676 * preferred unless one is unable to tie the range to the lifetime of an object. 2677 * 2678 * Example: 2679 * \code{.cpp} 2680 * nvtx3::event_attributes attr{"msg", nvtx3::rgb{127,255,0}}; 2681 * // Manually begin a range 2682 * nvtx3::range_handle h = nvtx3::start_range_in<my_domain>(attr); 2683 * ... 2684 * nvtx3::end_range_in<my_domain>(h); // End the range 2685 * \endcode 2686 * 2687 * @tparam D Type containing `name` member used to identify the `domain` 2688 * to which the range belongs. Else, `domain::global` to indicate that the 2689 * global NVTX domain should be used. 2690 * @param[in] attr `event_attributes` that describes the desired attributes 2691 * of the range. 2692 * @return Unique handle to be passed to `end_range_in` to end the range. 2693 */ 2694 template <typename D = domain::global> 2695 NVTX3_NO_DISCARD inline range_handle start_range_in(event_attributes const& attr) noexcept 2696 { 2697 #ifndef NVTX_DISABLE 2698 return range_handle{nvtxDomainRangeStartEx(domain::get<D>(), attr.get())}; 2699 #else 2700 (void)attr; 2701 return {}; 2702 #endif 2703 } 2704 2705 /** 2706 * @brief Manually begin an NVTX range. 2707 * 2708 * Explicitly begins an NVTX range and returns a unique handle. To end the 2709 * range, pass the handle to `end_range_in<D>()`. 2710 * 2711 * `nvtx3::start_range(...)` is equivalent to `nvtx3::start_range_in<>(...)` and 2712 * `nvtx3::start_range_in<nvtx3::domain::global>(...)`. 2713 * 2714 * `start_range_in/end_range_in` are the most explicit and lowest level APIs 2715 * provided for creating ranges. Use of `nvtx3::unique_range_in` should be 2716 * preferred unless one is unable to tie the range to the lifetime of an object. 2717 * 2718 * This overload uses `args...` to construct an `event_attributes` to 2719 * associate with the range. For more detail, see `event_attributes`. 2720 * 2721 * Example: 2722 * \code{cpp} 2723 * // Manually begin a range 2724 * nvtx3::range_handle h = nvtx3::start_range_in<D>("msg", nvtx3::rgb{127,255,0}); 2725 * ... 2726 * nvtx3::end_range_in<D>(h); // Ends the range 2727 * \endcode 2728 * 2729 * @tparam D Type containing `name` member used to identify the `domain` 2730 * to which the range belongs. Else, `domain::global` to indicate that the 2731 * global NVTX domain should be used. 2732 * @param[in] args Variadic parameter pack of the arguments for an `event_attributes`. 2733 * @return Unique handle to be passed to `end_range` to end the range. 2734 */ 2735 template <typename D = domain::global, typename... Args> 2736 NVTX3_NO_DISCARD inline range_handle start_range_in(Args const&... args) noexcept 2737 { 2738 #ifndef NVTX_DISABLE 2739 return start_range_in<D>(event_attributes{args...}); 2740 #else 2741 detail::silence_unused(args...); 2742 return {}; 2743 #endif 2744 } 2745 2746 /** 2747 * @brief Manually begin an NVTX range in the global domain. 2748 * 2749 * Explicitly begins an NVTX range and returns a unique handle. To end the 2750 * range, pass the handle to `end_range()`. 2751 * 2752 * `nvtx3::start_range(...)` is equivalent to `nvtx3::start_range_in<>(...)` and 2753 * `nvtx3::start_range_in<nvtx3::domain::global>(...)`. 2754 * 2755 * `start_range/end_range` are the most explicit and lowest level APIs 2756 * provided for creating ranges. Use of `nvtx3::unique_range` should be 2757 * preferred unless one is unable to tie the range to the lifetime of an object. 2758 * 2759 * Example: 2760 * \code{.cpp} 2761 * nvtx3::event_attributes attr{"msg", nvtx3::rgb{127,255,0}}; 2762 * // Manually begin a range 2763 * nvtx3::range_handle h = nvtx3::start_range(attr); 2764 * ... 2765 * nvtx3::end_range(h); // End the range 2766 * \endcode 2767 * 2768 * @param[in] attr `event_attributes` that describes the desired attributes 2769 * of the range. 2770 * @return Unique handle to be passed to `end_range_in` to end the range. 2771 */ 2772 NVTX3_NO_DISCARD inline range_handle start_range(event_attributes const& attr) noexcept 2773 { 2774 #ifndef NVTX_DISABLE 2775 return start_range_in<domain::global>(attr); 2776 #else 2777 (void)attr; 2778 return {}; 2779 #endif 2780 } 2781 2782 /** 2783 * @brief Manually begin an NVTX range in the global domain. 2784 * 2785 * Explicitly begins an NVTX range and returns a unique handle. To end the 2786 * range, pass the handle to `end_range_in<D>()`. 2787 * 2788 * `nvtx3::start_range(...)` is equivalent to `nvtx3::start_range_in<>(...)` and 2789 * `nvtx3::start_range_in<nvtx3::domain::global>(...)`. 2790 * 2791 * `start_range_in/end_range_in` are the most explicit and lowest level APIs 2792 * provided for creating ranges. Use of `nvtx3::unique_range_in` should be 2793 * preferred unless one is unable to tie the range to the lifetime of an object. 2794 * 2795 * This overload uses `args...` to construct an `event_attributes` to 2796 * associate with the range. For more detail, see `event_attributes`. 2797 * 2798 * Example: 2799 * \code{cpp} 2800 * // Manually begin a range 2801 * nvtx3::range_handle h = nvtx3::start_range("msg", nvtx3::rgb{127,255,0}); 2802 * ... 2803 * nvtx3::end_range(h); // Ends the range 2804 * \endcode 2805 * 2806 * @param[in] args Variadic parameter pack of the arguments for an `event_attributes`. 2807 * @return Unique handle to be passed to `end_range` to end the range. 2808 */ 2809 template <typename... Args> 2810 NVTX3_NO_DISCARD inline range_handle start_range(Args const&... args) noexcept 2811 { 2812 #ifndef NVTX_DISABLE 2813 return start_range_in<domain::global>(args...); 2814 #else 2815 detail::silence_unused(args...); 2816 return {}; 2817 #endif 2818 } 2819 2820 /** 2821 * @brief Manually end the range associated with the handle `r` in domain `D`. 2822 * 2823 * Explicitly ends the NVTX range indicated by the handle `r` returned from a 2824 * prior call to `start_range_in<D>`. The range may end on a different thread 2825 * from where it began. 2826 * 2827 * @tparam D Type containing `name` member used to identify the `domain` to 2828 * which the range belongs. Else, `domain::global` to indicate that the global 2829 * NVTX domain should be used. 2830 * @param r Handle to a range started by a prior call to `start_range_in`. 2831 * 2832 * @warning The domain type specified as template parameter to this function 2833 * must be the same that was specified on the associated `start_range_in` call. 2834 */ 2835 template <typename D = domain::global> 2836 inline void end_range_in(range_handle r) noexcept 2837 { 2838 #ifndef NVTX_DISABLE 2839 nvtxDomainRangeEnd(domain::get<D>(), r.get_value()); 2840 #else 2841 (void)r; 2842 #endif 2843 } 2844 2845 /** 2846 * @brief Manually end the range associated with the handle `r` in the global 2847 * domain. 2848 * 2849 * Explicitly ends the NVTX range indicated by the handle `r` returned from a 2850 * prior call to `start_range`. The range may end on a different thread from 2851 * where it began. 2852 * 2853 * @param r Handle to a range started by a prior call to `start_range`. 2854 * 2855 * @warning The domain type specified as template parameter to this function 2856 * must be the same that was specified on the associated `start_range` call. 2857 */ 2858 inline void end_range(range_handle r) noexcept 2859 { 2860 #ifndef NVTX_DISABLE 2861 end_range_in<domain::global>(r); 2862 #else 2863 (void)r; 2864 #endif 2865 } 2866 2867 /** 2868 * @brief A RAII object for creating a NVTX range within a domain that can 2869 * be created and destroyed on different threads. 2870 * 2871 * When constructed, begins a NVTX range in the specified domain. Upon 2872 * destruction, ends the NVTX range. 2873 * 2874 * Similar to `nvtx3::scoped_range_in`, with a few key differences: 2875 * - `unique_range` objects can be destroyed in an order whereas `scoped_range` objects must be 2876 * destroyed in exact reverse creation order 2877 * - `unique_range` can start and end on different threads 2878 * - `unique_range` is movable 2879 * - `unique_range` objects can be constructed as heap objects 2880 * 2881 * There is extra overhead associated with `unique_range` constructs and therefore use of 2882 * `nvtx3::scoped_range_in` should be preferred. 2883 * 2884 * @tparam D Type containing `name` member used to identify the `domain` 2885 * to which the `unique_range_in` belongs. Else, `domain::global` to 2886 * indicate that the global NVTX domain should be used. 2887 */ 2888 template <typename D = domain::global> 2889 class NVTX3_MAYBE_UNUSED unique_range_in { 2890 public: 2891 /** 2892 * @brief Construct a new unique_range_in object with the specified event attributes 2893 * 2894 * Example: 2895 * \code{cpp} 2896 * nvtx3::event_attributes attr{"msg", nvtx3::rgb{127,255,0}}; 2897 * nvtx3::unique_range_in<my_domain> range{attr}; // Creates a range with message contents 2898 * // "msg" and green color 2899 * \endcode 2900 * 2901 * @param[in] attr `event_attributes` that describes the desired attributes 2902 * of the range. 2903 */ 2904 explicit unique_range_in(event_attributes const& attr) noexcept 2905 : handle_{start_range_in<D>(attr)} 2906 { 2907 } 2908 2909 /** 2910 * @brief Constructs a `unique_range_in` from the constructor arguments 2911 * of an `event_attributes`. 2912 * 2913 * Forwards the arguments `args...` to construct an 2914 * `event_attributes` object. The `event_attributes` object is then 2915 * associated with the `unique_range_in`. 2916 * 2917 * For more detail, see `event_attributes` documentation. 2918 * 2919 * Example: 2920 * \code{.cpp} 2921 * // Creates a range with message "message" and green color 2922 * nvtx3::unique_range_in<> r{"message", nvtx3::rgb{127,255,0}}; 2923 * \endcode 2924 * 2925 * @param[in] args Variadic parameter pack of arguments to construct an `event_attributes` 2926 * associated with this range. 2927 */ 2928 template <typename... Args> 2929 explicit unique_range_in(Args const&... args) noexcept 2930 : unique_range_in{event_attributes{args...}} 2931 { 2932 } 2933 2934 /** 2935 * @brief Default constructor creates a `unique_range_in` with no 2936 * message, color, payload, nor category. 2937 * 2938 */ 2939 constexpr unique_range_in() noexcept : unique_range_in{event_attributes{}} {} 2940 2941 /** 2942 * @brief Destroy the `unique_range_in` ending the range. 2943 * 2944 */ 2945 ~unique_range_in() noexcept = default; 2946 2947 /** 2948 * @brief Move constructor allows taking ownership of the NVTX range from 2949 * another `unique_range_in`. 2950 * 2951 * @param other The range to take ownership of 2952 */ 2953 unique_range_in(unique_range_in&& other) noexcept = default; 2954 2955 /** 2956 * @brief Move assignment operator allows taking ownership of an NVTX range 2957 * from another `unique_range_in`. 2958 * 2959 * @param other The range to take ownership of 2960 */ 2961 unique_range_in& operator=(unique_range_in&& other) noexcept = default; 2962 2963 /// Copy construction is not allowed to prevent multiple objects from owning 2964 /// the same range handle 2965 unique_range_in(unique_range_in const&) = delete; 2966 2967 /// Copy assignment is not allowed to prevent multiple objects from owning the 2968 /// same range handle 2969 unique_range_in& operator=(unique_range_in const&) = delete; 2970 2971 private: 2972 2973 struct end_range_handle { 2974 using pointer = range_handle; /// Override the pointer type of the unique_ptr 2975 void operator()(range_handle h) const noexcept { end_range_in<D>(h); } 2976 }; 2977 2978 /// Range handle used to correlate the start/end of the range 2979 std::unique_ptr<range_handle, end_range_handle> handle_; 2980 }; 2981 2982 /** 2983 * @brief Alias for a `unique_range_in` in the global NVTX domain. 2984 * 2985 */ 2986 using unique_range = unique_range_in<domain::global>; 2987 2988 /** 2989 * @brief Annotates an instantaneous point in time with a "marker", using the 2990 * attributes specified by `attr`. 2991 * 2992 * Unlike a "range" which has a beginning and an end, a marker is a single event 2993 * in an application, such as detecting a problem: 2994 * 2995 * \code{.cpp} 2996 * bool success = do_operation(...); 2997 * if (!success) { 2998 * nvtx3::event_attributes attr{"operation failed!", nvtx3::rgb{255,0,0}}; 2999 * nvtx3::mark_in<my_domain>(attr); 3000 * } 3001 * \endcode 3002 * 3003 * Note that nvtx3::mark_in<D> is a function, not a class like scoped_range_in<D>. 3004 * 3005 * @tparam D Type containing `name` member used to identify the `domain` 3006 * to which the `unique_range_in` belongs. Else, `domain::global` to 3007 * indicate that the global NVTX domain should be used. 3008 * @param[in] attr `event_attributes` that describes the desired attributes 3009 * of the mark. 3010 */ 3011 template <typename D = domain::global> 3012 inline void mark_in(event_attributes const& attr) noexcept 3013 { 3014 #ifndef NVTX_DISABLE 3015 nvtxDomainMarkEx(domain::get<D>(), attr.get()); 3016 #else 3017 (void)(attr); 3018 #endif 3019 } 3020 3021 /** 3022 * @brief Annotates an instantaneous point in time with a "marker", using the 3023 * arguments to construct an `event_attributes`. 3024 * 3025 * Unlike a "range" which has a beginning and an end, a marker is a single event 3026 * in an application, such as detecting a problem: 3027 * 3028 * \code{.cpp} 3029 * bool success = do_operation(...); 3030 * if (!success) { 3031 * nvtx3::mark_in<my_domain>("operation failed!", nvtx3::rgb{255,0,0}); 3032 * } 3033 * \endcode 3034 * 3035 * Note that nvtx3::mark_in<D> is a function, not a class like scoped_range_in<D>. 3036 * 3037 * Forwards the arguments `args...` to construct an `event_attributes` object. 3038 * The attributes are then associated with the marker. For more detail, see 3039 * the `event_attributes` documentation. 3040 * 3041 * @tparam D Type containing `name` member used to identify the `domain` 3042 * to which the `unique_range_in` belongs. Else `domain::global` to 3043 * indicate that the global NVTX domain should be used. 3044 * @param[in] args Variadic parameter pack of arguments to construct an `event_attributes` 3045 * associated with this range. 3046 * 3047 */ 3048 template <typename D = domain::global, typename... Args> 3049 inline void mark_in(Args const&... args) noexcept 3050 { 3051 #ifndef NVTX_DISABLE 3052 mark_in<D>(event_attributes{args...}); 3053 #else 3054 detail::silence_unused(args...); 3055 #endif 3056 } 3057 3058 /** 3059 * @brief Annotates an instantaneous point in time with a "marker", using the 3060 * attributes specified by `attr`, in the global domain. 3061 * 3062 * Unlike a "range" which has a beginning and an end, a marker is a single event 3063 * in an application, such as detecting a problem: 3064 * 3065 * \code{.cpp} 3066 * bool success = do_operation(...); 3067 * if (!success) { 3068 * nvtx3::event_attributes attr{"operation failed!", nvtx3::rgb{255,0,0}}; 3069 * nvtx3::mark(attr); 3070 * } 3071 * \endcode 3072 * 3073 * Note that nvtx3::mark is a function, not a class like scoped_range. 3074 * 3075 * @param[in] attr `event_attributes` that describes the desired attributes 3076 * of the mark. 3077 */ 3078 inline void mark(event_attributes const& attr) noexcept 3079 { 3080 #ifndef NVTX_DISABLE 3081 mark_in<domain::global>(attr); 3082 #else 3083 (void)attr; 3084 #endif 3085 } 3086 3087 /** 3088 * @brief Annotates an instantaneous point in time with a "marker", using the 3089 * arguments to construct an `event_attributes`, in the global domain. 3090 * 3091 * Unlike a "range" which has a beginning and an end, a marker is a single event 3092 * in an application, such as detecting a problem: 3093 * 3094 * \code{.cpp} 3095 * bool success = do_operation(...); 3096 * if (!success) { 3097 * nvtx3::mark("operation failed!", nvtx3::rgb{255,0,0}); 3098 * } 3099 * \endcode 3100 * 3101 * Note that nvtx3::mark is a function, not a class like scoped_range. 3102 * 3103 * Forwards the arguments `args...` to construct an `event_attributes` object. 3104 * The attributes are then associated with the marker. For more detail, see 3105 * the `event_attributes` documentation. 3106 * 3107 * @param[in] args Variadic parameter pack of arguments to construct an 3108 * `event_attributes` associated with this range. 3109 * 3110 */ 3111 template <typename... Args> 3112 inline void mark(Args const&... args) noexcept 3113 { 3114 #ifndef NVTX_DISABLE 3115 mark_in<domain::global>(args...); 3116 #else 3117 detail::silence_unused(args...); 3118 #endif 3119 } 3120 3121 } // namespace NVTX3_MINOR_VERSION_NAMESPACE 3122 } // namespace NVTX3_VERSION_NAMESPACE 3123 } // namespace nvtx3 3124 3125 #ifndef NVTX_DISABLE 3126 /** 3127 * @brief Convenience macro for generating a range in the specified `domain` 3128 * from the lifetime of a function 3129 * 3130 * This macro is useful for generating an NVTX range in `domain` from 3131 * the entry point of a function to its exit. It is intended to be the first 3132 * line of the function. 3133 * 3134 * Constructs a static `registered_string_in` using the name of the immediately 3135 * enclosing function returned by `__func__` and constructs a 3136 * `nvtx3::scoped_range` using the registered function name as the range's 3137 * message. 3138 * 3139 * Example: 3140 * \code{.cpp} 3141 * struct my_domain{static constexpr char const* name{"my_domain"};}; 3142 * 3143 * void foo(...) { 3144 * NVTX3_FUNC_RANGE_IN(my_domain); // Range begins on entry to foo() 3145 * // do stuff 3146 * ... 3147 * } // Range ends on return from foo() 3148 * \endcode 3149 * 3150 * @param[in] D Type containing `name` member used to identify the 3151 * `domain` to which the `registered_string_in` belongs. Else, 3152 * `domain::global` to indicate that the global NVTX domain should be used. 3153 */ 3154 #define NVTX3_V1_FUNC_RANGE_IN(D) \ 3155 static ::nvtx3::v1::registered_string_in<D> const nvtx3_func_name__{__func__}; \ 3156 static ::nvtx3::v1::event_attributes const nvtx3_func_attr__{nvtx3_func_name__}; \ 3157 ::nvtx3::v1::scoped_range_in<D> const nvtx3_range__{nvtx3_func_attr__} 3158 3159 /** 3160 * @brief Convenience macro for generating a range in the specified `domain` 3161 * from the lifetime of a function if the given boolean expression evaluates 3162 * to true. 3163 * 3164 * Similar to `NVTX3_V1_FUNC_RANGE_IN(D)`, the only difference being that 3165 * `NVTX3_V1_FUNC_RANGE_IF_IN(D, C)` only generates a range if the given boolean 3166 * expression evaluates to true. 3167 * 3168 * @param[in] D Type containing `name` member used to identify the 3169 * `domain` to which the `registered_string_in` belongs. Else, 3170 * `domain::global` to indicate that the global NVTX domain should be used. 3171 * 3172 * @param[in] C Boolean expression used to determine if a range should be 3173 * generated. 3174 */ 3175 #define NVTX3_V1_FUNC_RANGE_IF_IN(D, C) \ 3176 ::nvtx3::v1::detail::optional_scoped_range_in<D> optional_nvtx3_range__; \ 3177 if (C) { \ 3178 static ::nvtx3::v1::registered_string_in<D> const nvtx3_func_name__{__func__}; \ 3179 static ::nvtx3::v1::event_attributes const nvtx3_func_attr__{nvtx3_func_name__}; \ 3180 optional_nvtx3_range__.begin(nvtx3_func_attr__); \ 3181 } (void)0 3182 #else /* NVTX_DISABLE */ 3183 #define NVTX3_V1_FUNC_RANGE_IN(D) (void)0 3184 #define NVTX3_V1_FUNC_RANGE_IF_IN(D, C) (void)(C) 3185 #endif /* NVTX_DISABLE */ 3186 3187 /** 3188 * @brief Convenience macro for generating a range in the global domain from the 3189 * lifetime of a function. 3190 * 3191 * This macro is useful for generating an NVTX range in the global domain from 3192 * the entry point of a function to its exit. It is intended to be the first 3193 * line of the function. 3194 * 3195 * Constructs a static `registered_string_in` using the name of the immediately 3196 * enclosing function returned by `__func__` and constructs a 3197 * `nvtx3::scoped_range` using the registered function name as the range's 3198 * message. 3199 * 3200 * Example: 3201 * \code{.cpp} 3202 * void foo(...) { 3203 * NVTX3_FUNC_RANGE(); // Range begins on entry to foo() 3204 * // do stuff 3205 * ... 3206 * } // Range ends on return from foo() 3207 * \endcode 3208 */ 3209 #define NVTX3_V1_FUNC_RANGE() NVTX3_V1_FUNC_RANGE_IN(::nvtx3::v1::domain::global) 3210 3211 /** 3212 * @brief Convenience macro for generating a range in the global domain from the 3213 * lifetime of a function if the given boolean expression evaluates to true. 3214 * 3215 * Similar to `NVTX3_V1_FUNC_RANGE()`, the only difference being that 3216 * `NVTX3_V1_FUNC_RANGE_IF(C)` only generates a range if the given boolean 3217 * expression evaluates to true. 3218 * 3219 * @param[in] C Boolean expression used to determine if a range should be 3220 * generated. 3221 */ 3222 #define NVTX3_V1_FUNC_RANGE_IF(C) NVTX3_V1_FUNC_RANGE_IF_IN(::nvtx3::v1::domain::global, C) 3223 3224 // We need another helper macro because the other one will get undefined 3225 #if __has_cpp_attribute(nodiscard) 3226 #define NVTX3_V1_NO_DISCARD [[nodiscard]] 3227 #else 3228 #define NVTX3_V1_NO_DISCARD 3229 #endif 3230 /** 3231 * @brief Convenience macro for generating a sspecialization of nvtx3::schema::get 3232 * for an existing `struct`. 3233 * 3234 * Use this macro after your struct to enable the struct to be used as a payload. 3235 * 3236 * \note This macro must not be used inside a namespace. 3237 * 3238 * Example: 3239 * \code{.cpp} 3240 * struct SensorData 3241 * { 3242 * int32_t sensorId; 3243 * uint8_t channelId; 3244 * }; 3245 * 3246 * NVTX3_DEFINE_SCHEMA_GET( 3247 * my_domain, 3248 * SensorData, 3249 * "SensorEvent", 3250 * NVTX_PAYLOAD_ENTRIES( 3251 * (sensorId, TYPE_INT32, "SensorID"), 3252 * (channelId, TYPE_UINT8, "ChannelID") 3253 * ) 3254 * ) 3255 * \endcode 3256 * 3257 * @param[in] dom The NVTX domain. 3258 * @param[in] struct_id The name of the struct. 3259 * @param[in] schema_name Name of the payload schema. 3260 * @param[in] entries Payload schema entries using NVTX_PAYLOAD_ENTRIES macro. 3261 */ 3262 #define NVTX3_V1_DEFINE_SCHEMA_GET(dom, struct_id, schema_name, entries) \ 3263 template <> \ 3264 NVTX3_V1_NO_DISCARD inline nvtx3::v1::schema const& nvtx3::v1::schema::get<struct_id>() noexcept \ 3265 { \ 3266 static_assert( \ 3267 std::is_standard_layout<struct_id>::value, \ 3268 "structs used for NVTX3 payload schema must be standard layout"); \ 3269 static_assert( \ 3270 std::is_trivially_copyable<struct_id>::value, \ 3271 "structs used for NVTX3 payload schema must be trivially copyable"); \ 3272 using nvtx_struct_id = struct_id; /* avoids issues with namespaced struct_id */ \ 3273 _NVTX_DEFINE_SCHEMA_FOR_STRUCT(nvtx_struct_id, schema_name, static constexpr, entries) \ 3274 static const schema s{ \ 3275 nvtxPayloadSchemaRegister(nvtx3::v1::domain::get<dom>(), &nvtx_struct_id##Attr)}; \ 3276 return s; \ 3277 } 3278 3279 /* When inlining this version, versioned macros must have unversioned aliases. 3280 * For each NVTX3_Vx_ #define, make an NVTX3_ alias of it here.*/ 3281 #if defined(NVTX3_INLINE_THIS_VERSION) 3282 /* clang format off */ 3283 #define NVTX3_FUNC_RANGE NVTX3_V1_FUNC_RANGE 3284 #define NVTX3_FUNC_RANGE_IF NVTX3_V1_FUNC_RANGE_IF 3285 #define NVTX3_FUNC_RANGE_IN NVTX3_V1_FUNC_RANGE_IN 3286 #define NVTX3_FUNC_RANGE_IF_IN NVTX3_V1_FUNC_RANGE_IF_IN 3287 #define NVTX3_DEFINE_SCHEMA_GET NVTX3_V1_DEFINE_SCHEMA_GET 3288 /* clang format on */ 3289 #endif 3290 3291 #endif // NVTX3_CPP_DEFINITIONS_V1_0 3292 3293 /* Add functionality for new minor versions here, by copying the above section enclosed 3294 * in #ifndef NVTX3_CPP_DEFINITIONS_Vx_y, and incrementing the minor version. This code 3295 * is an example of how additions for version 1.2 would look, indented for clarity. Note 3296 * that the versioned symbols and macros are always provided, and the unversioned symbols 3297 * are only provided if NVTX3_INLINE_THIS_VERSION was defined at the top of this header. 3298 * 3299 * \code{.cpp} 3300 * #ifndef NVTX3_CPP_DEFINITIONS_V1_2 3301 * #define NVTX3_CPP_DEFINITIONS_V1_2 3302 * namespace nvtx3 { 3303 * NVTX3_INLINE_IF_REQUESTED namespace NVTX3_VERSION_NAMESPACE { 3304 * class new_class {}; 3305 * inline void new_function() {} 3306 * } 3307 * } 3308 * 3309 * // Macros must have the major version in their names: 3310 * #define NVTX3_V1_NEW_MACRO_A() ... 3311 * #define NVTX3_V1_NEW_MACRO_B() ... 3312 * 3313 * // If inlining, make aliases for the macros with the version number omitted 3314 * #if defined(NVTX3_INLINE_THIS_VERSION) 3315 * #define NVTX3_NEW_MACRO_A NVTX3_V1_NEW_MACRO_A 3316 * #define NVTX3_NEW_MACRO_B NVTX3_V1_NEW_MACRO_B 3317 * #endif 3318 * #endif // NVTX3_CPP_DEFINITIONS_V1_2 3319 * \endcode 3320 */ 3321 3322 /* Undefine all temporarily-defined unversioned macros, which would conflict with 3323 * subsequent includes of different versions of this header. */ 3324 #undef NVTX3_CPP_VERSION_MAJOR 3325 #undef NVTX3_CPP_VERSION_MINOR 3326 #undef NVTX3_CONCAT 3327 #undef NVTX3_NAMESPACE_FOR 3328 #undef NVTX3_VERSION_NAMESPACE 3329 #undef NVTX3_MINOR_NAMESPACE_FOR 3330 #undef NVTX3_MINOR_VERSION_NAMESPACE 3331 #undef NVTX3_INLINE_IF_REQUESTED 3332 #undef NVTX3_CONSTEXPR_IF_CPP14 3333 #undef NVTX3_MAYBE_UNUSED 3334 #undef NVTX3_NO_DISCARD 3335 3336 #if defined(NVTX3_INLINE_THIS_VERSION) 3337 #undef NVTX3_INLINE_THIS_VERSION 3338 #endif 3339 3340 #if defined(NVTX3_USE_CHECKED_OVERLOADS_FOR_GET_DEFINED_HERE) 3341 #undef NVTX3_USE_CHECKED_OVERLOADS_FOR_GET_DEFINED_HERE 3342 #undef NVTX3_USE_CHECKED_OVERLOADS_FOR_GET 3343 #endif 3344 3345 #if defined(NVTX3_STATIC_ASSERT_DEFINED_HERE) 3346 #undef NVTX3_STATIC_ASSERT_DEFINED_HERE 3347 #undef NVTX3_STATIC_ASSERT 3348 #endif
| [ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
|
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
|