Files
rocm-systems/tests/common/perfetto.hpp
T
Jonathan R. Madsen 875f53b608 Correlation ID Retirement + misc (#527)
* Correlation ID Retirement

- include/rocprofiler-sdk/buffer_tracing.h
  - add rocprofiler_buffer_tracing_correlation_id_retirement_record_t
- include/rocprofiler-sdk/fwd.h
  - ROCPROFILER_BUFFER_TRACING_CORRELATION_ID_RETIREMENT
- lib/rocprofiler-sdk/buffer_tracing.cpp
  - kind string for correlation id retirement
- lib/rocprofiler-sdk/buffer.hpp
  - emplace returns bool
- lib/rocprofiler-sdk/registration.cpp
  - pass lib_instance to copy_table functions
- lib/rocprofiler-sdk/context/context.*
  - update correlation_id struct
    - make ref_count private
    - {get,add,sub}_ref_count() functions
      - sub_ref_count() performs correlation id retirement
    - use stack for "latest" thread-local correlation id
- lib/rocprofiler-sdk/hip/hip.*
  - migrate to new {get,add,sub}_ref_count() for correlation ids
  - return in iterate_args
  - handle table instance in copy_table
- lib/rocprofiler-sdk/hsa/hsa.*
  - migrate to new {get,add,sub}_ref_count() for correlation ids
  - return in iterate_args
  - handle table instance in copy_table
- lib/rocprofiler-sdk/marker/marker.*
  - migrate to new {get,add,sub}_ref_count() for correlation ids
  - return in iterate_args
  - handle table instance in copy_table
- lib/rocprofiler-sdk/hsa/async_copy.cpp
  - migrate to new {get,add,sub}_ref_count() for correlation ids
  - handle table instance in async_copy_init / async_copy_save
- lib/rocprofiler-sdk/hsa/queue.cpp
  - migrate to new {get,add,sub}_ref_count() for correlation ids
  - tweak to external correlation id mapping in WriteInterceptor
- tests/async-copy-tracing/validate.py
  - check retired_correlation_ids
- tests/common/serialization.hpp
  - support rocprofiler_buffer_tracing_correlation_id_retirement_record_t
- tests/kernel-tracing/validate.py
  - check retired_correlation_ids
- tests/common/CMakeLists.txt
  - perfetto external project
- tests/common/perfetto.hpp
  - perfetto categories + aliases
  - add_perfetto_annotation
  - metaprogramming helpers
- tests/tools/CMakeLists.txt
  - link to tests-perfetto
- tests/tools/json-tool.cpp
  - demangling functions
  - serialization of marker API callback args
  - reduce parallel bottleneck in tool_tracing_callback
  - support correlation id retirement
  - Multiple threads for buffers
  - Support ROCPROFILER_TOOL_CONTEXTS_EXCLUDE env variable
  - write_perfetto() function

* Update tests/rocprofv3/tracing/validate.py

- tweak test_hsa_api_trace

* Update PTL submodule

- fixes for data race during destruction of task

* Update lib/rocprofiler-sdk/buffer.*

- unique_buffer_vec_t uses std::unique_ptr instead of allocator::unique_static_ptr_t

* Reduce timeouts in counter collection samples [skip ci]

* Update tests/tools/json-tool.cpp

- tweak demangle(string_view, int*) -> demangle(string_view, int&)

* Update lib/rocprofiler-sdk/hsa/async_copy.cpp

- move sub_ref_count() to later in async_copy_handler to delay retirement slightly more
2024-02-23 10:30:33 -06:00

226 lines
8.1 KiB
C++

// 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 <cstddef>
#include <ostream>
#include <sstream>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
#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 <typename Tp>
struct perfetto_category;
namespace trait
{
template <typename... Tp>
using name = perfetto_category<Tp...>;
}
} // 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.h>
PERFETTO_DEFINE_CATEGORIES(ROCPROFILER_PERFETTO_CATEGORIES);
namespace concepts
{
template <typename Tp>
struct is_string_type : std::false_type
{};
template <>
struct is_string_type<std::string> : std::true_type
{};
template <>
struct is_string_type<char*> : std::true_type
{};
template <>
struct is_string_type<const char*> : std::true_type
{};
template <>
struct is_string_type<std::string_view> : std::true_type
{};
template <typename Tp>
struct is_string_type<const Tp> : is_string_type<std::decay_t<Tp>>
{};
template <typename Tp>
struct is_string_type<Tp&> : is_string_type<std::decay_t<Tp>>
{};
template <typename Tp>
struct is_string_type<volatile Tp> : is_string_type<std::decay_t<Tp>>
{};
template <typename Tp, size_t N>
struct is_string_type<Tp[N]> : is_string_type<std::decay_t<Tp[N]>>
{};
template <typename Tp, size_t N>
struct is_string_type<const Tp[N]> : is_string_type<std::decay_t<Tp[N]>>
{};
template <typename Tp, size_t N>
struct is_string_type<volatile Tp[N]> : is_string_type<std::decay_t<Tp[N]>>
{};
template <typename Tp>
struct unqualified_type
{
using type = std::remove_reference_t<std::remove_cv_t<std::decay_t<Tp>>>;
};
template <typename Tp>
using unqualified_type_t = typename unqualified_type<Tp>::type;
template <typename Tp>
struct can_stringify
{
private:
static constexpr auto sfinae(int)
-> decltype(std::declval<std::ostream&>() << std::declval<Tp>(), 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 <typename Np, typename Tp>
auto
add_perfetto_annotation(perfetto_event_context_t& ctx, Np&& _name, Tp&& _val)
{
using named_type = concepts::unqualified_type_t<Np>;
using value_type = concepts::unqualified_type_t<Tp>;
static_assert(concepts::is_string_type<named_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<Np>(_name)}.data());
return _dbg;
};
if constexpr(std::is_same<value_type, std::string_view>::value)
{
_get_dbg()->set_string_value(_val.data());
}
else if constexpr(concepts::is_string_type<value_type>::value)
{
_get_dbg()->set_string_value(std::forward<Tp>(_val));
}
else if constexpr(std::is_same<value_type, bool>::value)
{
_get_dbg()->set_bool_value(_val);
}
else if constexpr(std::is_enum<value_type>::value)
{
_get_dbg()->set_int_value(static_cast<int64_t>(_val));
}
else if constexpr(std::is_floating_point<value_type>::value)
{
_get_dbg()->set_double_value(static_cast<double>(_val));
}
else if constexpr(std::is_integral<value_type>::value)
{
if constexpr(std::is_unsigned<value_type>::value)
{
_get_dbg()->set_uint_value(_val);
}
else
{
_get_dbg()->set_int_value(_val);
}
}
else if constexpr(std::is_pointer<value_type>::value)
{
_get_dbg()->set_pointer_value(reinterpret_cast<uint64_t>(_val));
}
else if constexpr(concepts::can_stringify<value_type>::value)
{
auto _ss = std::stringstream{};
_ss << std::forward<Tp>(_val);
_get_dbg()->set_string_value(_ss.str());
}
else
{
static_assert(std::is_empty<value_type>::value, "Error! unsupported data type");
}
}