/* * SPDX-FileCopyrightText: Copyright (c) 2024-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Licensed under the Apache License v2.0 with LLVM Exceptions. * See https://nvidia.github.io/NVTX/LICENSE.txt for license information. */ #include #include #include #include "PrettyPrintersNvtxCpp.h" struct a_lib { static constexpr const char* name{"Library A"}; //static constexpr const float name{3.14f}; }; struct cat_x { static constexpr const char* name{"Category X"}; static constexpr uint32_t id{42}; }; struct cat_y { static constexpr const char* name{"Category Y"}; //static constexpr const float name{3.14f}; static constexpr uint32_t id{43}; }; struct regstr_hello { static constexpr const char* message{"Hello"}; }; static void TestFuncRange() { NVTX3_FUNC_RANGE(); nvtx3::mark("Marker in TestFuncRange"); } static void TestFuncRangeV() { NVTX3_V1_FUNC_RANGE(); nvtx3::mark("Marker in TestFuncRangeV"); } static void TestFuncRangeIfDyn(bool cond) { NVTX3_FUNC_RANGE_IF(cond); nvtx3::mark("Marker in TestFuncRangeIfDyn"); } static void TestFuncRangeIfDynV(bool cond) { NVTX3_V1_FUNC_RANGE_IF(cond); nvtx3::mark("Marker in TestFuncRangeIfDynV"); } static void TestFuncRangeIfStat(bool cond) { NVTX3_FUNC_RANGE_IF(cond); nvtx3::mark("Marker in TestFuncRangeIfStat"); } static void TestFuncRangeIfStatV(bool cond) { NVTX3_V1_FUNC_RANGE_IF(cond); nvtx3::mark("Marker in TestFuncRangeIfStatV"); } static void TestFuncRangeIn() { NVTX3_FUNC_RANGE_IN(a_lib); nvtx3::mark("Marker in TestFuncRangeIn"); } static void TestFuncRangeInV() { NVTX3_V1_FUNC_RANGE_IN(a_lib); nvtx3::mark("Marker in TestFuncRangeInV"); } static void TestFuncRangeIfInDyn(bool cond) { NVTX3_FUNC_RANGE_IF_IN(a_lib, cond); nvtx3::mark("Marker in TestFuncRangeIfInDyn"); } static void TestFuncRangeIfInDynV(bool cond) { NVTX3_V1_FUNC_RANGE_IF_IN(a_lib, cond); nvtx3::mark("Marker in TestFuncRangeIfInDynV"); } static void TestFuncRangeIfInStat(bool cond) { NVTX3_FUNC_RANGE_IF_IN(a_lib, cond); nvtx3::mark("Marker in TestFuncRangeIfInStat"); } static void TestFuncRangeIfInStatV(bool cond) { NVTX3_V1_FUNC_RANGE_IF_IN(a_lib, cond); nvtx3::mark("Marker in TestFuncRangeIfInStatV"); } static int RunTestCommon(int argc, const char** argv) { bool verbose = false; const std::string verboseArg = "-v"; for (; *argv; ++argv) { if (*argv == verboseArg) verbose = true; } using namespace nvtx3; { std::cout << "Default attributes:\n"; event_attributes attr; if (verbose) std::cout << attr << '\n'; } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "Set a message (ascii), payload, color, and category:\n"; event_attributes attr{ message{"Hello"}, category{11}, payload{5.0f}, rgb{0,255,0}}; if (verbose) std::cout << attr << '\n'; } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "Set a message with different string types:\n"; event_attributes a{message{"Hello"}}; if (verbose) std::cout << a << '\n'; event_attributes wa{message{L"Hello"}}; if (verbose) std::cout << wa << '\n'; std::string hello{"Hello"}; event_attributes b{message{hello}}; if (verbose) std::cout << b << '\n'; std::wstring whello{L"Hello"}; event_attributes wb{message{whello}}; if (verbose) std::cout << wb << '\n'; // Important! Neither of following will compile: // // event_attributes c{message{std::string{"foo"}}}; // std::cout << c; // // std::string foo{"foo"}; // event_attributes d{message{hello + "bar"}}; // std::cout << d; // // Both of those usages fail with: // "error C2280: 'message::message(std::string &&)': // attempting to reference a deleted function" // // message is a "view" class, not an owning class. // It cannot take ownership of a temporary string and // destroy it when it goes out of scope. Similarly, // event_attributes is not an owning class, so it cannot take // ownership of an message either. // // TODO: Could we add implicit support for this? } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "Set a message (registered):\n"; auto hTacobell = reinterpret_cast(0x7ac0be11); event_attributes attr{message{hTacobell}}; if (verbose) std::cout << attr << '\n'; } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "Convenience: Set a message without the helper type:\n"; event_attributes a{"Hello"}; if (verbose) std::cout << a << '\n'; std::string hello{"Hello"}; event_attributes b{hello}; if (verbose) std::cout << b << '\n'; } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "Set a payload twice (first should win):\n"; event_attributes attr{"test", payload{1.0f}, payload{2}}; if (verbose) std::cout << attr << '\n'; } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "Set a color twice (first should win):\n"; event_attributes attr{"test", argb{127,0,0,255}, rgb{0,255,0}}; if (verbose) std::cout << attr << '\n'; } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "Set a message twice (first should win):\n"; event_attributes attr{L"wide", "narrow"}; if (verbose) std::cout << attr << '\n'; } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "Set a category twice (first should win):\n"; event_attributes attr{"test", category{1}, category{2}}; if (verbose) std::cout << attr << '\n'; } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "Markers\n"; // Global domain event_attributes attr{ message{"Hello1"}, category{11}, payload{5.0f}, rgb{1,2,3}}; mark(attr); mark(event_attributes{ message{"Hello2"}, category{11}, payload{5.0f}, rgb{0,255,0}}); mark( message{"Hello3"}, category{11}, payload{5.0f}, rgb{0,255,0}); // a_lib domain event_attributes a_attr{ message{"a: Hello1"}, category{11}, payload{5.0f}, rgb{1,2,3}}; mark_in(attr); mark_in(event_attributes{ message{"a: Hello2"}, category{11}, payload{5.0f}, rgb{0,255,0}}); mark_in( message{"a: Hello3"}, category{11}, payload{5.0f}, rgb{0,255,0}); } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "Range start/end and range_handle\n"; // Global domain event_attributes attr{ message{"Hello1"}, category{11}, payload{5.0f}, rgb{1,2,3}}; auto h1 = start_range(attr); auto h2 = start_range(event_attributes{ message{"Hello2"}, category{11}, payload{5.0f}, rgb{0,255,0}}); auto h3 = start_range( message{"Hello3"}, category{11}, payload{5.0f}, rgb{0,255,0}); // a_lib domain event_attributes a_attr{ message{"a: Hello1"}, category{11}, payload{5.0f}, rgb{1,2,3}}; auto h4 = start_range_in(attr); auto h5 = start_range_in(event_attributes{ message{"a: Hello2"}, category{11}, payload{5.0f}, rgb{0,255,0}}); auto h6 = start_range_in( message{"a: Hello3"}, category{11}, payload{5.0f}, rgb{0,255,0}); // range_handle operator ==, !=, and cast overloads bool testEq = h1 == h2; bool testNe = h3 != h4; bool testCast = bool(h5); if (verbose) std::cout << std::boolalpha << testEq << "\n" << testNe << "\n" << testCast << "\n"; end_range(h1); end_range(h2); end_range(h3); end_range_in(h4); end_range_in(h5); end_range_in(h6); } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "unique_range\n"; // Global domain event_attributes attr{ message{"Hello1"}, category{11}, payload{5.0f}, rgb{1,2,3}}; unique_range u1{attr}; unique_range u2{event_attributes{ message{"Hello2"}, category{11}, payload{5.0f}, rgb{0,255,0}}}; unique_range u3{ message{"Hello3"}, category{11}, payload{5.0f}, rgb{0,255,0}}; // a_lib domain event_attributes a_attr{ message{"a: Hello1"}, category{11}, payload{5.0f}, rgb{1,2,3}}; unique_range_in u4{attr}; unique_range_in u5{event_attributes{ message{"a: Hello2"}, category{11}, payload{5.0f}, rgb{0,255,0}}}; unique_range_in u6{ message{"a: Hello3"}, category{11}, payload{5.0f}, rgb{0,255,0}}; // movability auto move_in_out_global = [](unique_range u) { return u; }; auto move_in_out_domain = [](unique_range_in u) { return u; }; auto u1moved = move_in_out_global(std::move(u1)); auto u4moved = move_in_out_domain(std::move(u4)); } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "scoped_range\n"; // Global domain event_attributes attr{ message{"Hello1"}, category{11}, payload{5.0f}, rgb{1,2,3}}; scoped_range s1{attr}; scoped_range s2{event_attributes{ message{"Hello2"}, category{11}, payload{5.0f}, rgb{0,255,0}}}; scoped_range s3{ message{"Hello3"}, category{11}, payload{5.0f}, rgb{0,255,0}}; // a_lib domain event_attributes a_attr{ message{"a: Hello1"}, category{11}, payload{5.0f}, rgb{1,2,3}}; scoped_range_in s4{attr}; scoped_range_in s5{event_attributes{ message{"a: Hello2"}, category{11}, payload{5.0f}, rgb{0,255,0}}}; scoped_range_in s6{ message{"a: Hello3"}, category{11}, payload{5.0f}, rgb{0,255,0}}; } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "named_category\n"; // Global domain mark ("Cat", named_category::get ()); mark_in<> ("Cat", named_category_in<>::get ()); mark_in("Cat", named_category_in::get()); // a_lib domain mark_in("Cat", named_category_in::get()); } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "registered_string\n"; // Global domain mark ("RegStr", registered_string::get ()); mark_in<> ("RegStr", registered_string_in<>::get ()); mark_in("RegStr", registered_string_in::get()); // a_lib domain mark_in("RegStr", registered_string_in::get()); } if (verbose) std::cout << "-------------------------------------\n"; { std::cout << "Macros:\n"; TestFuncRange(); TestFuncRangeV(); TestFuncRangeIfDyn(argc == 1001); TestFuncRangeIfDyn(argc != 1001); TestFuncRangeIfDynV(argc == 1002); TestFuncRangeIfDynV(argc != 1002); TestFuncRangeIfStat(true); TestFuncRangeIfStat(false); TestFuncRangeIfStatV(true); TestFuncRangeIfStatV(false); TestFuncRangeIn(); TestFuncRangeInV(); TestFuncRangeIfInDyn(argc == 1003); TestFuncRangeIfInDyn(argc != 1003); TestFuncRangeIfInDynV(argc == 1004); TestFuncRangeIfInDynV(argc != 1004); TestFuncRangeIfInStat(true); TestFuncRangeIfInStat(false); TestFuncRangeIfInStatV(true); TestFuncRangeIfInStatV(false); } if (verbose) std::cout << "-------------------------------------\n"; return 0; }