// MIT License // // Copyright (c) 2023 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all // copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #pragma once #include #include #include #include #include #include #include #define ROCPROFILER_DEFINE_NAME_TRAIT(NAME, DESC, ...) \ namespace rocprofiler \ { \ template <> \ struct perfetto_category<__VA_ARGS__> \ { \ static constexpr auto value = NAME; \ static constexpr auto description = DESC; \ }; \ } namespace rocprofiler { template struct perfetto_category; namespace trait { template using name = perfetto_category; } } // namespace rocprofiler #define ROCPROFILER_DEFINE_NS_API(NS, NAME) \ namespace rocprofiler \ { \ namespace NS \ { \ struct NAME; \ } \ } #define ROCPROFILER_DEFINE_CATEGORY(NS, VALUE, DESC) \ ROCPROFILER_DEFINE_NS_API(NS, VALUE) \ ROCPROFILER_DEFINE_NAME_TRAIT(#VALUE, DESC, NS::VALUE) ROCPROFILER_DEFINE_CATEGORY(category, hsa_api, "HSA API function") ROCPROFILER_DEFINE_CATEGORY(category, hip_api, "HIP API function") ROCPROFILER_DEFINE_CATEGORY(category, marker_api, "Marker API region") ROCPROFILER_DEFINE_CATEGORY(category, kernel_dispatch, "GPU kernel dispatch") ROCPROFILER_DEFINE_CATEGORY(category, memory_copy, "Async memory copy") #define ROCPROFILER_PERFETTO_CATEGORY(TYPE) \ ::perfetto::Category(::rocprofiler::perfetto_category<::rocprofiler::TYPE>::value) \ .SetDescription(::rocprofiler::perfetto_category<::rocprofiler::TYPE>::description) #define ROCPROFILER_PERFETTO_CATEGORIES \ ROCPROFILER_PERFETTO_CATEGORY(category::hsa_api), \ ROCPROFILER_PERFETTO_CATEGORY(category::hip_api), \ ROCPROFILER_PERFETTO_CATEGORY(category::marker_api), \ ROCPROFILER_PERFETTO_CATEGORY(category::kernel_dispatch), \ ROCPROFILER_PERFETTO_CATEGORY(category::memory_copy) #include PERFETTO_DEFINE_CATEGORIES(ROCPROFILER_PERFETTO_CATEGORIES); namespace concepts { template struct is_string_type : std::false_type {}; template <> struct is_string_type : std::true_type {}; template <> struct is_string_type : std::true_type {}; template <> struct is_string_type : std::true_type {}; template <> struct is_string_type : std::true_type {}; template struct is_string_type : is_string_type> {}; template struct is_string_type : is_string_type> {}; template struct is_string_type : is_string_type> {}; template struct is_string_type : is_string_type> {}; template struct is_string_type : is_string_type> {}; template struct is_string_type : is_string_type> {}; template struct unqualified_type { using type = std::remove_reference_t>>; }; template using unqualified_type_t = typename unqualified_type::type; template struct can_stringify { private: static constexpr auto sfinae(int) -> decltype(std::declval() << std::declval(), bool()) { return true; } static constexpr auto sfinae(long) { return false; } public: static constexpr bool value = sfinae(0); constexpr auto operator()() const { return sfinae(0); } }; } // namespace concepts using perfetto_event_context_t = ::perfetto::EventContext; template auto add_perfetto_annotation(perfetto_event_context_t& ctx, Np&& _name, Tp&& _val) { using named_type = concepts::unqualified_type_t; using value_type = concepts::unqualified_type_t; static_assert(concepts::is_string_type::value, "Error! name is not a string type"); auto _get_dbg = [&]() { auto* _dbg = ctx.event()->add_debug_annotations(); _dbg->set_name(std::string_view{std::forward(_name)}.data()); return _dbg; }; if constexpr(std::is_same::value) { _get_dbg()->set_string_value(_val.data()); } else if constexpr(concepts::is_string_type::value) { _get_dbg()->set_string_value(std::forward(_val)); } else if constexpr(std::is_same::value) { _get_dbg()->set_bool_value(_val); } else if constexpr(std::is_enum::value) { _get_dbg()->set_int_value(static_cast(_val)); } else if constexpr(std::is_floating_point::value) { _get_dbg()->set_double_value(static_cast(_val)); } else if constexpr(std::is_integral::value) { if constexpr(std::is_unsigned::value) { _get_dbg()->set_uint_value(_val); } else { _get_dbg()->set_int_value(_val); } } else if constexpr(std::is_pointer::value) { _get_dbg()->set_pointer_value(reinterpret_cast(_val)); } else if constexpr(concepts::can_stringify::value) { auto _ss = std::stringstream{}; _ss << std::forward(_val); _get_dbg()->set_string_value(_ss.str()); } else { static_assert(std::is_empty::value, "Error! unsupported data type"); } }